diff --git a/README.md b/README.md
index cbc6359e..60548722 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 */ });
```
-
-
-
- secret
-
- (String)
- |
-
- Required.
- Secret as configured in GitHub Settings.
- |
-
-
-
-
- path
-
- (String)
- |
-
- Only relevant for webhooks.middleware.
- Custom path to match requests against. Defaults to /.
- |
-
-
-
-
- transform
-
- (Function)
+ |
+
+
+
+ secret
+
+ (String)
+ |
+
+ Required.
+ Secret as configured in GitHub Settings.
+ |
+
+
+
+
+ transform
+
+ (Function)
+ |
+
+ Only relevant for webhooks.on.
+ Transform emitted event before calling handlers. Can be asynchronous.
+ |
+
+
+
+ log
+
+ object
+
|
- Only relevant for webhooks.on.
- Transform emitted event before calling handlers. Can be asynchronous.
- |
-
+
+Used for internal logging. Defaults to [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console) with `debug` and `info` doing nothing.
+
+
+
+
Returns the `webhooks` API.
@@ -150,20 +152,22 @@ webhooks.sign(eventPayload);
```
-
-
-
- eventPayload
-
-
- (Object)
-
- |
-
- Required.
- Webhook request payload as received from GitHub
- |
-
+
+
+
+
+ eventPayload
+
+
+ (Object)
+
+ |
+
+ Required.
+ Webhook request payload as received from GitHub
+ |
+
+
Returns a `signature` string. Throws error if `eventPayload` is not passed.
@@ -177,34 +181,36 @@ webhooks.verify(eventPayload, signature);
```
-
-
-
- eventPayload
-
-
- (Object)
-
- |
-
- Required.
- Webhook event request payload as received from GitHub.
- |
-
-
-
-
- signature
-
-
- (String)
-
- |
-
- Required.
- Signature string as calculated by webhooks.sign().
- |
-
+
+
+
+
+ eventPayload
+
+
+ (Object)
+
+ |
+
+ Required.
+ Webhook event request payload as received from GitHub.
+ |
+
+
+
+
+ signature
+
+
+ (String)
+
+ |
+
+ Required.
+ Signature string as calculated by webhooks.sign().
+ |
+
+
Returns `true` or `false`. Throws error if `eventPayload` or `signature` not passed.
@@ -218,62 +224,64 @@ webhooks.verifyAndReceive({ id, name, payload, signature });
```
-
-
-
- id
-
-
- String
-
- |
-
- Unique webhook event request id
- |
-
-
-
-
- name
-
-
- String
-
- |
-
- Required.
- Name of the event. (Event names are set as X-GitHub-Event header
- in the webhook event request.)
- |
-
-
-
-
- payload
-
-
- Object
-
- |
-
- Required.
- Webhook event request payload as received from GitHub.
- |
-
-
-
-
- signature
-
-
- (String)
-
- |
-
- Required.
- Signature string as calculated by webhooks.sign().
- |
-
+
+
+
+
+ id
+
+
+ String
+
+ |
+
+ Unique webhook event request id
+ |
+
+
+
+
+ name
+
+
+ String
+
+ |
+
+ Required.
+ Name of the event. (Event names are set as X-GitHub-Event header
+ in the webhook event request.)
+ |
+
+
+
+
+ payload
+
+
+ Object
+
+ |
+
+ Required.
+ Webhook event request payload as received from GitHub.
+ |
+
+
+
+
+ signature
+
+
+ (String)
+
+ |
+
+ Required.
+ Signature string as calculated by webhooks.sign().
+ |
+
+
Returns a promise.
@@ -309,48 +317,50 @@ webhooks.receive({ id, name, payload });
```
-
-
-
- id
-
-
- String
-
- |
-
- Unique webhook event request id
- |
-
-
-
-
- name
-
-
- String
-
- |
-
- Required.
- Name of the event. (Event names are set as X-GitHub-Event header
- in the webhook event request.)
- |
-
-
-
-
- payload
-
-
- Object
-
- |
-
- Required.
- Webhook event request payload as received from GitHub.
- |
-
+
+
+
+
+ id
+
+
+ String
+
+ |
+
+ Unique webhook event request id
+ |
+
+
+
+
+ name
+
+
+ String
+
+ |
+
+ Required.
+ Name of the event. (Event names are set as X-GitHub-Event header
+ in the webhook event request.)
+ |
+
+
+
+
+ payload
+
+
+ Object
+
+ |
+
+ Required.
+ Webhook event request payload as received from GitHub.
+ |
+
+
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);
```
-
-
-
- eventName
-
-
- String
-
- |
-
- Required.
- Name of the event. One of GitHub's supported event names.
- |
-
-
-
-
- eventNames
-
-
- Array
-
- |
-
- Required.
- Array of event names.
- |
-
-
-
-
- handler
-
-
- Function
-
- |
-
- Required.
- Method to be run each time the event with the passed name is received.
- the handler function can be an async function, throw an error or
- return a Promise. The handler is called with an event object: {id, name, payload}.
- |
-
+
+
+
+
+ eventName
+
+
+ String
+
+ |
+
+ Required.
+ Name of the event. One of GitHub's supported event names.
+ |
+
+
+
+
+ eventNames
+
+
+ Array
+
+ |
+
+ Required.
+ Array of event names.
+ |
+
+
+
+
+ handler
+
+
+ Function
+
+ |
+
+ Required.
+ Method to be run each time the event with the passed name is received.
+ the handler function can be an async function, throw an error or
+ return a Promise. The handler is called with an event object: {id, name, payload}.
+ |
+
+
The `.on()` method belongs to the `event-handler` module which can be used [standalone](src/event-handler/).
@@ -420,22 +432,24 @@ webhooks.onAny(handler);
```
-
-
-
- handler
-
-
- Function
-
- |
-
- Required.
- Method to be run each time any event is received.
- the handler function can be an async function, throw an error or
- return a Promise. The handler is called with an event object: {id, name, payload}.
- |
-
+
+
+
+
+ handler
+
+
+ Function
+
+ |
+
+ Required.
+ Method to be run each time any event is received.
+ the handler function can be an async function, throw an error or
+ return a Promise. The handler is called with an event object: {id, name, payload}.
+ |
+
+
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.
-
-
-
- handler
-
-
- Function
-
- |
-
- Required.
- Method to be run each time a webhook event handler throws an error or returns a promise that rejects.
- The handler 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: {id, name, payload}.
- |
-
+
+
+
+
+ handler
+
+
+ Function
+
+ |
+
+ Required.
+ Method to be run each time a webhook event handler throws an error or returns a promise that rejects.
+ The handler 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: {id, name, payload}.
+ |
+
+
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);
```
-
-
-
- eventName
-
-
- String
-
- |
-
- Required.
- Name of the event. One of GitHub’s supported event names, or '*' for the onAny() method or 'error' for the onError() method.
- |
-
-
-
-
- eventNames
-
-
- Array
-
- |
-
- Required.
- Array of event names.
- |
-
-
-
-
- handler
-
-
- Function
-
- |
-
- Required.
- Method which was previously passed to webhooks.on(). If the same handler was registered multiple times for the same event, only the most recent handler gets removed.
- |
-
+
+
+
+
+ eventName
+
+
+ String
+
+ |
+
+ Required.
+ Name of the event. One of GitHub’s supported event names, or '*' for the onAny() method or 'error' for the onError() method.
+ |
+
+
+
+
+ eventNames
+
+
+ Array
+
+ |
+
+ Required.
+ Array of event names.
+ |
+
+
+
+
+ handler
+
+
+ Function
+
+ |
+
+ Required.
+ Method which was previously passed to webhooks.on(). If the same handler was registered multiple times for the same event, only the most recent handler gets removed.
+ |
+
+
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 /
```
-
-
-
- request
-
-
- Object
-
- |
-
- Required.
- A Node.js http.ClientRequest.
- |
-
-
-
-
- response
-
-
- Object
-
- |
-
- Required.
- A Node.js http.ServerResponse.
- |
-
-
-
-
- next
-
-
- Function
-
- |
-
- Optional function which invokes the next middleware, as used by Connect and Express.
- |
-
-
+
+
+
+ webhooks
+
+ Webhooks instance
+
+ |
+
+ Required.
+ |
+
+
+
+ path
+
+ string
+
+ |
+
+ Custom path to match requests against. Defaults to /api/github/webhooks.
+ |
+
+
+
+ log
+
+ object
+
+ |
+
+
+Used for internal logging. Defaults to [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console) with `debug` and `info` doing nothing.
+
+ |
+
+
+
+ onUnhandledRequest
+
+ function
+
+ |
+
+
+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), Express 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/).
+ |
+
+
+
### Webhook events
diff --git a/package-lock.json b/package-lock.json
index c7e9b4f7..6662d2ee 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2209,6 +2209,29 @@
"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",
@@ -2270,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",
@@ -2447,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",
@@ -2741,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",
@@ -2918,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",
@@ -3352,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",
@@ -3660,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",
@@ -3937,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",
@@ -4060,6 +4185,12 @@
"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.701",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.701.tgz",
@@ -4084,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",
@@ -4146,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",
@@ -4198,6 +4341,12 @@
"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.6",
"resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz",
@@ -4291,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",
@@ -4474,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",
@@ -4521,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",
@@ -4530,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",
@@ -5012,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",
@@ -5384,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",
@@ -7037,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",
@@ -7102,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",
@@ -7114,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",
@@ -7260,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",
@@ -11106,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",
@@ -11327,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",
@@ -11363,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",
@@ -11553,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",
@@ -11605,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",
@@ -12630,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",
@@ -12659,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",
@@ -13190,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",
@@ -13704,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",
@@ -13839,6 +14275,16 @@
"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",
@@ -13922,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",
@@ -14114,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",
@@ -14159,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",
diff --git a/package.json b/package.json
index 2e6d4281..3f982d01 100644
--- a/package.json
+++ b/package.json
@@ -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 85299665..e86d953b 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 => ({
diff --git a/src/index.ts b/src/index.ts
index b936d915..98e4d1a0 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,6 +16,8 @@ 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 {
public sign: (payload: string | object) => string;
@@ -31,14 +33,18 @@ class Webhooks {
callback: HandlerFunction
) => void;
public receive: (event: EmitterWebhookEvent) => Promise;
+ public verifyAndReceive: (
+ options: EmitterWebhookEvent & { signature: string }
+ ) => Promise;
+
+ /**
+ * @deprecated use `createNodeMiddleware(webhooks)` instead
+ */
public middleware: (
request: IncomingMessage,
response: ServerResponse,
next?: (err?: any) => void
) => void | Promise;
- public verifyAndReceive: (
- options: EmitterWebhookEvent & { signature: string }
- ) => Promise;
constructor(options: Options) {
if (!options || !options.secret) {
@@ -53,6 +59,12 @@ class Webhooks {
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,14 +72,25 @@ class Webhooks {
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);
+ };
}
}
/** @deprecated `createWebhooksApi()` is deprecated and will be removed in a future release of `@octokit/webhooks`, please use the `Webhooks` class instead */
const createWebhooksApi = (options: Options) => {
- console.error(
+ 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(options);
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 654045f6..b7478dbc 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 00000000..6b25de82
--- /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 00000000..f764d389
--- /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 {
+ // 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 00000000..06312ba3
--- /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);
+}
diff --git a/src/middleware/node/middleware.ts b/src/middleware/node/middleware.ts
new file mode 100644
index 00000000..499a1c7f
--- /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,
+ 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 00000000..c32ef7aa
--- /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 00000000..c114ce22
--- /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 09ce118c..0f1655e5 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)
);
diff --git a/test/integration/middleware-test.ts b/test/integration/middleware-test.ts
index b5da7002..51e5b715 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 00000000..737bbffe
--- /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 f9fbbfba..2c979551 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/unit/deprecation.test.ts b/test/unit/deprecation.test.ts
index ab4c36d8..359c39c1 100644
--- a/test/unit/deprecation.test.ts
+++ b/test/unit/deprecation.test.ts
@@ -1,12 +1,67 @@
-import { createWebhooksApi } from "../../src";
+import { createWebhooksApi, Webhooks } from "../../src";
describe("Deprecated methods", () => {
test("createWebhooksApi", () => {
- const spy = jest.spyOn(console, "error");
- createWebhooksApi({ secret: "foo" });
- expect(spy).toBeCalledWith(
+ 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"
);
- spy.mockClear();
+ 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 e3403cc5..70eac396 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 e18147b5..2ade1f49 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;