Repository: octokit/webhooks.js
Pull request #372 (2020-12-04 02:09:52)

fix(typescript): export `EventTypesPayload` type
This lets us use `EventTypesPayload` without having to import it the long way, i.e

```
import { WebhookEvents, Webhooks, sign, verify } from '@octokit/webhooks';
import { EventTypesPayload } from '@octokit/webhooks/dist-types/generated/get-webhook-payload-type-from-event';
```

I need this type in order to attempt to do narrowing via:

```
const isSpecificGithubEvent = <TName extends WebhookEvents>(
  event: EventTypesPayload[keyof EventTypesPayload],
  name: TName
): event is EventTypesPayload[TName] => event.name === name;
```

On an aside: `EventTypesPayload` isn't entirely correct as it's not the actual event payloads, which makes it harder to write a setup that narrows based on the event name; in general it'd be nice if there was a union type that let you narrow based on the `name` :/

gr2m: > On an aside: `EventTypesPayload` isn't entirely correct as it's not the actual event payloads, which makes it harder to write a setup that narrows based on the event name; in general it'd be nice if there was a union type that let you narrow based on the `name` :/

you can access the payload with e.g. `EventTypesPayload["check_run"]["payload"]`. I Agree that `EventTypesPayload` is maybe not the right name here, maybe just `Events` might be better, or `OctokitEvents` to avoid conflicts with other declarations?

We also have `*` and `error` keys in there, which is something we will remove in the next version

Patch:
diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml
index 6dfa273..ccfe854 100644
--- a/.github/workflows/update.yml
+++ b/.github/workflows/update.yml
@@ -5,13 +5,13 @@ on:
     types: [octokit/webhooks release]
 
 jobs:
-  test:
+  update:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v2
       - uses: actions/setup-node@v1
       - run: npm ci
-      - run: npm install @octokit/webhooks@latest
+      - run: npm install @octokit/webhooks-definitions@latest
       - run: npm run update-known-events
       - run: npm run generate-types
       - name: create pull request
@@ -21,7 +21,7 @@ jobs:
         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"
-          branch: "${{ github.ref }}"
+          branch: "update-octokit-webhooks"
           author: Octokit Bot <octokitbot@martynus.net>
           commit-message: "WIP: Webhooks changed - please review"
           labels: "maintenance"
diff --git a/package-lock.json b/package-lock.json
index dc6a98f..8b6b141 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2210,9 +2210,9 @@
       }
     },
     "@octokit/webhooks-definitions": {
-      "version": "3.20.0",
-      "resolved": "https://registry.npmjs.org/@octokit/webhooks-definitions/-/webhooks-definitions-3.20.0.tgz",
-      "integrity": "sha512-W7RbyhVmCRDV1BfJ5wK25nysPb1EAPVztzUsJFDfxW4t6grx4eE/bGI/elel6yqd7r8sH0boHNrIlEQ03haOzg==",
+      "version": "3.21.0",
+      "resolved": "https://registry.npmjs.org/@octokit/webhooks-definitions/-/webhooks-definitions-3.21.0.tgz",
+      "integrity": "sha512-GhGFxG/pVIf0J2/bdMqfMkzfLimHFIL57/3Rts4HASga05t1G/Ga+daBfEeiB2FBkxvbWGheS5AhtMeuzkKG1g==",
       "dev": true,
       "requires": {
         "prettier": "^2.0.5"
diff --git a/package.json b/package.json
index 6c1ea0b..1467e75 100644
--- a/package.json
+++ b/package.json
@@ -17,7 +17,7 @@
   "devDependencies": {
     "@gimenete/type-writer": "^0.1.5",
     "@octokit/tsconfig": "^1.0.1",
-    "@octokit/webhooks-definitions": "^3.20.0",
+    "@octokit/webhooks-definitions": "^3.21.0",
     "@pika/pack": "^0.5.0",
     "@pika/plugin-build-node": "^0.9.2",
     "@pika/plugin-build-types": "^0.9.2",
@@ -81,7 +81,7 @@
     },
     "globals": {
       "ts-jest": {
-        "tsConfig": {
+        "tsconfig": {
           "esModuleInterop": true
         }
       }
diff --git a/src/event-handler/receive.ts b/src/event-handler/receive.ts
index 90051c3..b90ceb3 100644
--- a/src/event-handler/receive.ts
+++ b/src/event-handler/receive.ts
@@ -20,8 +20,7 @@ function getHooks(
   hooks.push(state.hooks[eventName]);
   hooks.push(state.hooks["*"]);
 
-  // @ts-ignore
-  return [].concat(...hooks.filter(Boolean));
+  return ([] as Function[]).concat(...hooks.filter(Boolean));
 }
 
 // main handler function
diff --git a/src/generated/event-payloads.ts b/src/generated/event-payloads.ts
index d1c4f9f..502799f 100644
--- a/src/generated/event-payloads.ts
+++ b/src/generated/event-payloads.ts
@@ -2827,6 +2827,20 @@ export declare module EventPayloads {
     installation?: WebhookPayloadProjectCardInstallation;
     organization?: WebhookPayloadProjectCardOrganization;
   };
+  type WebhookPayloadPingOrganization = {
+    login: string;
+    id: number;
+    node_id: string;
+    url: string;
+    repos_url: string;
+    events_url: string;
+    hooks_url: string;
+    issues_url: string;
+    members_url: string;
+    public_members_url: string;
+    avatar_url: string;
+    description: string;
+  };
   type WebhookPayloadPingSender = {
     login: string;
     id: number;
@@ -2856,6 +2870,7 @@ export declare module EventPayloads {
     content_type: string;
     url: string;
     insecure_ssl: string;
+    secret?: string;
   };
   type WebhookPayloadPingHook = {
     type: string;
@@ -2867,16 +2882,17 @@ export declare module EventPayloads {
     updated_at: string;
     created_at: string;
     url: string;
-    test_url: string;
+    test_url?: string;
     ping_url: string;
-    last_response: WebhookPayloadPingHookLastResponse;
+    last_response?: WebhookPayloadPingHookLastResponse;
   };
   type WebhookPayloadPing = {
     zen: string;
     hook_id: number;
     hook: WebhookPayloadPingHook;
-    repository: PayloadRepository;
+    repository?: PayloadRepository;
     sender: WebhookPayloadPingSender;
+    organization?: WebhookPayloadPingOrganization;
   };
   type WebhookPayloadPageBuildInstallation = { id: number; node_id: string };
   type WebhookPayloadPageBuildSender = {
diff --git a/src/index.ts b/src/index.ts
index 18bdc1b..ba01cc3 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -18,7 +18,7 @@ import { WebhookEvents } from "./generated/get-webhook-payload-type-from-event";
 // U holds the return value of `transform` function in Options
 class Webhooks<T extends WebhookEvent = WebhookEvent, U = {}> {
   public sign: (payload: string | object) => string;
-  public verify: (eventPayload?: object, signature?: string) => boolean;
+  public verify: (eventPayload: object, signature: string) => boolean;
   public on: <E extends WebhookEvents>(
     event: E | E[],
     callback: HandlerFunction<E, U>
@@ -70,7 +70,10 @@ class Webhooks<T extends WebhookEvent = WebhookEvent, U = {}> {
 const createWebhooksApi = Webhooks.prototype.constructor;
 
 export { EventPayloads } from "./generated/event-payloads";
-export { WebhookEvents } from "./generated/get-webhook-payload-type-from-event";
+export {
+  EventTypesPayload,
+  WebhookEvents,
+} from "./generated/get-webhook-payload-type-from-event";
 
 export {
   createEventHandler,
diff --git a/src/middleware/get-payload.ts b/src/middleware/get-payload.ts
index 51243ba..7595cc1 100644
--- a/src/middleware/get-payload.ts
+++ b/src/middleware/get-payload.ts
@@ -10,7 +10,7 @@ export function getPayload(
   // If request.body already exists we can stop here
   // See https://github.com/octokit/webhooks.js/pull/23
 
-  // @ts-ignore
+  // @ts-expect-error
   if (request.body) return Promise.resolve(request.body);
 
   return new Promise((resolve, reject) => {
diff --git a/src/middleware/verify-and-receive.ts b/src/middleware/verify-and-receive.ts
index add8a9a..613b223 100644
--- a/src/middleware/verify-and-receive.ts
+++ b/src/middleware/verify-and-receive.ts
@@ -5,7 +5,12 @@ export function verifyAndReceive(
   state: State,
   event: WebhookEvent & { signature: string }
 ): any {
-  const matchesSignature = verify(state.secret, event.payload, event.signature);
+  // verify will validate that the secret is not undefined
+  const matchesSignature = verify(
+    state.secret!,
+    event.payload,
+    event.signature
+  );
 
   if (!matchesSignature) {
     const error = new Error(
diff --git a/src/sign/index.ts b/src/sign/index.ts
index cb0baff..ec1d857 100644
--- a/src/sign/index.ts
+++ b/src/sign/index.ts
@@ -7,7 +7,7 @@ export enum Algorithm {
 
 type SignOptions = {
   secret: string;
-  algorithm?: string;
+  algorithm?: Algorithm | "sha1" | "sha256";
 };
 
 export function sign(
@@ -22,7 +22,6 @@ export function sign(
           algorithm: options.algorithm || Algorithm.SHA1,
         };
 
-  // @ts-ignore throw friendly error message when required options are missing
   if (!secret || !payload) {
     throw new TypeError("[@octokit/webhooks] secret & payload required");
   }
diff --git a/src/verify/README.md b/src/verify/README.md
index 3fb0315..de6e415 100644
--- a/src/verify/README.md
+++ b/src/verify/README.md
@@ -4,7 +4,7 @@ The `verify` method can be used as a standalone method.
 
 ```js
 const { verify } = require('@octokit/webhooks')
-const matchesSignature = verify(secret, eventData, signature)
+const matchesSignature = verify(secret, eventPayload, signature)
 // true or false
 ```
 
@@ -12,7 +12,7 @@ const matchesSignature = verify(secret, eventData, signature)
   <tr>
     <td>
       <code>
-        options.secret
+        secret
       </code>
       <em>(String)</em>
     </td>
@@ -51,6 +51,6 @@ const matchesSignature = verify(secret, eventData, signature)
   </tr>
 </table>
 
-Returns `true` or `false`. Throws error if `secret, ``eventPayload` or `signature` not passed.
+Returns `true` or `false`. Throws error if `secret`, `eventPayload` or `signature` not passed.
 
 Back to [@octokit/webhooks README](..).
diff --git a/src/verify/index.ts b/src/verify/index.ts
index af689cb..e769a9d 100644
--- a/src/verify/index.ts
+++ b/src/verify/index.ts
@@ -7,9 +7,9 @@ const getAlgorithm = (signature: string) => {
 };
 
 export function verify(
-  secret?: string,
-  eventPayload?: object,
-  signature?: string
+  secret: string,
+  eventPayload: object,
+  signature: string
 ): boolean {
   if (!secret || !eventPayload || !signature) {
     throw new TypeError(


Test patch:
diff --git a/test/integration/server-test.ts b/test/integration/server-test.ts
index 57834bb..06a241d 100644
--- a/test/integration/server-test.ts
+++ b/test/integration/server-test.ts
@@ -182,7 +182,7 @@ describe("server-test", () => {
     const server = http.createServer((req, res) => {
       req.once("data", (chunk) => dataChunks.push(chunk));
       req.once("end", () => {
-        // @ts-ignore
+        // @ts-expect-error
         req.body = JSON.parse(Buffer.concat(dataChunks).toString());
         api.middleware(req, res);
 
diff --git a/test/integration/sign-test.ts b/test/integration/sign-test.ts
index 1fff22a..901f5c7 100644
--- a/test/integration/sign-test.ts
+++ b/test/integration/sign-test.ts
@@ -6,24 +6,23 @@ const eventPayload = {
 const secret = "mysecret";
 
 test("sign() without options throws", () => {
-  // @ts-ignore
+  // @ts-expect-error
   expect(() => sign()).toThrow();
 });
 
 test("sign(undefined, eventPayload) without secret throws", () => {
-  // @ts-ignore
+  // @ts-expect-error
   expect(() => sign.bind(null, undefined, eventPayload)()).toThrow();
 });
 
 test("sign(secret) without eventPayload throws", () => {
-  // @ts-ignore
+  // @ts-expect-error
   expect(() => sign.bind(null, secret)()).toThrow();
 });
 
 test("sign({secret, algorithm}) with invalid algorithm throws", () => {
-  // @ts-ignore
   expect(() =>
-    sign.bind(null, { secret, algorithm: "sha2" }, eventPayload)()
+    sign.bind(null, { secret, algorithm: "sha2" as "sha1" }, eventPayload)()
   ).toThrow();
 });
 
diff --git a/test/integration/verify-test.ts b/test/integration/verify-test.ts
index 163a94e..5d4464e 100644
--- a/test/integration/verify-test.ts
+++ b/test/integration/verify-test.ts
@@ -9,18 +9,22 @@ const signatureSHA256 =
   "sha256=4864d2759938a15468b5df9ade20bf161da9b4f737ea61794142f3484236bda3";
 
 test("verify() without options throws", () => {
+  // @ts-expect-error
   expect(() => verify()).toThrow();
 });
 
 test("verify(undefined, eventPayload) without secret throws", () => {
+  // @ts-expect-error
   expect(() => verify.bind(null, undefined, eventPayload)()).toThrow();
 });
 
 test("verify(secret) without eventPayload throws", () => {
+  // @ts-expect-error
   expect(() => verify.bind(null, secret)()).toThrow();
 });
 
 test("verify(secret, eventPayload) without options.signature throws", () => {
+  // @ts-expect-error
   expect(() => verify.bind(null, secret, eventPayload)()).toThrow();
 });
 
diff --git a/test/unit/event-handler-on-test.ts b/test/unit/event-handler-on-test.ts
index c94738f..89d7a29 100644
--- a/test/unit/event-handler-on-test.ts
+++ b/test/unit/event-handler-on-test.ts
@@ -11,7 +11,7 @@ const state: State = {
 // Test broken with TypeScript without the ignore
 test("receiver.on with invalid event name", () => {
   simple.mock(console, "warn").callFn(function () {});
-  // @ts-ignore
+  // @ts-expect-error
   receiverOn(state, "foo", noop);
   expect((console.warn as simple.Stub<void>).callCount).toBe(1);
   expect((console.warn as simple.Stub<void>).lastCall.arg).toBe(
diff --git a/test/unit/event-handler-receive-test.ts b/test/unit/event-handler-receive-test.ts
index d889f0e..9c3415b 100644
--- a/test/unit/event-handler-receive-test.ts
+++ b/test/unit/event-handler-receive-test.ts
@@ -7,20 +7,20 @@ const state: State = {
 };
 
 test("options: none", () => {
-  // @ts-ignore
+  // @ts-expect-error
   expect(() => receive(state)).toThrow();
 });
 
 test("options: name", () => {
   expect(() => {
-    // @ts-ignore
+    // @ts-expect-error
     receive(state, { name: "foo" });
   }).toThrow();
 });
 
 test("options: name, payload", () => {
   expect(() => {
-    // @ts-ignore
+    // @ts-expect-error
     receive(state, { name: "foo", payload: {} });
   }).not.toThrow();
 });