diff --git a/src/event-handler/index.ts b/src/event-handler/index.ts index 1536db07..0150f9ee 100644 --- a/src/event-handler/index.ts +++ b/src/event-handler/index.ts @@ -1,6 +1,6 @@ import type { - EmitterEventName, EmitterWebhookEvent, + EmitterWebhookEventName, HandlerFunction, Options, State, @@ -15,13 +15,13 @@ import { receiverHandle as receive } from "./receive"; import { removeListener } from "./remove-listener"; interface EventHandler { - on( + on( event: E | E[], callback: HandlerFunction ): void; onAny(handler: (event: EmitterWebhookEvent) => any): void; onError(handler: (event: WebhookEventHandlerError) => any): void; - removeListener( + removeListener( event: E | E[], callback: HandlerFunction ): void; diff --git a/src/event-handler/on.ts b/src/event-handler/on.ts index d09bb9bf..ae7b8058 100644 --- a/src/event-handler/on.ts +++ b/src/event-handler/on.ts @@ -1,14 +1,14 @@ import { emitterEventNames } from "../generated/webhook-names"; import { - EmitterEventName, EmitterWebhookEvent, + EmitterWebhookEventName, State, WebhookEventHandlerError, } from "../types"; function handleEventHandlers( state: State, - webhookName: EmitterEventName | "error" | "*", + webhookName: EmitterWebhookEventName | "error" | "*", handler: Function ) { if (!state.hooks[webhookName]) { @@ -19,7 +19,7 @@ function handleEventHandlers( } export function receiverOn( state: State, - webhookNameOrNames: EmitterEventName | EmitterEventName[], + webhookNameOrNames: EmitterWebhookEventName | EmitterWebhookEventName[], handler: Function ) { if (Array.isArray(webhookNameOrNames)) { diff --git a/src/event-handler/receive.ts b/src/event-handler/receive.ts index 92181647..87207eb0 100644 --- a/src/event-handler/receive.ts +++ b/src/event-handler/receive.ts @@ -1,9 +1,9 @@ // @ts-ignore to address #245 import AggregateError from "aggregate-error"; import { EmitterEventWebhookPayloadMap } from "../generated/get-webhook-payload-type-from-event"; -import { - EmitterEventName, +import type { EmitterWebhookEvent, + EmitterWebhookEventName, State, WebhookError, WebhookEventHandlerError, @@ -18,7 +18,7 @@ type EventAction = Extract< function getHooks( state: State, eventPayloadAction: EventAction | null, - eventName: EmitterEventName + eventName: EmitterWebhookEventName ): Function[] { const hooks = [state.hooks[eventName], state.hooks["*"]]; @@ -67,6 +67,7 @@ export function receiverHandle(state: State, event: EmitterWebhookEvent) { let promise = Promise.resolve(event); if (state.transform) { + // @ts-expect-error promise = promise.then(state.transform); } diff --git a/src/event-handler/remove-listener.ts b/src/event-handler/remove-listener.ts index 6a488b3d..92a39fda 100644 --- a/src/event-handler/remove-listener.ts +++ b/src/event-handler/remove-listener.ts @@ -1,8 +1,8 @@ -import { EmitterEventName, State } from "../types"; +import { EmitterWebhookEventName, State } from "../types"; export function removeListener( state: State, - webhookNameOrNames: EmitterEventName | EmitterEventName[], + webhookNameOrNames: EmitterWebhookEventName | EmitterWebhookEventName[], handler: Function ) { if (Array.isArray(webhookNameOrNames)) { diff --git a/src/index.ts b/src/index.ts index 4c540138..a3e4349f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,16 +1,14 @@ +import type { WebhookEventName } from "@octokit/webhooks-definitions/schema"; import { IncomingMessage, ServerResponse } from "http"; import { createEventHandler } from "./event-handler/index"; import { createMiddleware } from "./middleware/index"; import { middleware } from "./middleware/middleware"; -import { - verifyAndReceive, - WebhookEventName, -} from "./middleware/verify-and-receive"; +import { verifyAndReceive } from "./middleware/verify-and-receive"; import { sign } from "./sign/index"; import { - EmitterEventName, EmitterWebhookEvent, EmitterWebhookEventMap, + EmitterWebhookEventName, HandlerFunction, Options, State, @@ -26,13 +24,13 @@ class Webhooks< > { public sign: (payload: string | object) => string; public verify: (eventPayload: string | object, signature: string) => boolean; - public on: ( + public on: ( event: E | E[], callback: HandlerFunction ) => void; public onAny: (callback: (event: EmitterWebhookEvent) => any) => void; public onError: (callback: (event: WebhookEventHandlerError) => any) => void; - public removeListener: ( + public removeListener: ( event: E | E[], callback: HandlerFunction ) => void; @@ -46,7 +44,7 @@ class Webhooks< options: EmitterWebhookEventMap[WebhookEventName] & { signature: string } ) => Promise; - constructor(options?: Options) { + constructor(options?: Options) { if (!options || !options.secret) { throw new Error("[@octokit/webhooks] options.secret required"); } @@ -72,13 +70,6 @@ class Webhooks< const createWebhooksApi = Webhooks.prototype.constructor; -export { - EmitterEventMap, - EmitterEventName, - EmitterEventMap as EventTypesPayload, - EmitterEventName as WebhookEvents, -} from "./types"; - export { createEventHandler, createMiddleware, diff --git a/src/middleware/middleware.ts b/src/middleware/middleware.ts index b5b8f11a..e1b8053b 100644 --- a/src/middleware/middleware.ts +++ b/src/middleware/middleware.ts @@ -1,4 +1,4 @@ -import { EventPayloadMap } from "@octokit/webhooks-definitions/schema"; +import { WebhookEventName } from "@octokit/webhooks-definitions/schema"; import { isntWebhook } from "./isnt-webhook"; import { getMissingHeaders } from "./get-missing-headers"; import { getPayload } from "./get-payload"; @@ -7,8 +7,6 @@ import { debug } from "debug"; import { IncomingMessage, ServerResponse } from "http"; import { State, WebhookEventHandlerError } from "../types"; -export type WebhookEventName = keyof EventPayloadMap; - const debugWebhooks = debug("webhooks:receiver"); export function middleware( diff --git a/src/middleware/verify-and-receive.ts b/src/middleware/verify-and-receive.ts index f795577f..709118ea 100644 --- a/src/middleware/verify-and-receive.ts +++ b/src/middleware/verify-and-receive.ts @@ -1,8 +1,6 @@ -import { EventPayloadMap } from "@octokit/webhooks-definitions/schema"; +import { WebhookEventName } from "@octokit/webhooks-definitions/schema"; +import { EmitterWebhookEventMap, State } from "../types"; import { verify } from "../verify/index"; -import { State, EmitterWebhookEventMap } from "../types"; - -export type WebhookEventName = keyof EventPayloadMap; export function verifyAndReceive( state: State, diff --git a/src/types.ts b/src/types.ts index 296c6d88..303da130 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,41 +1,34 @@ import type { RequestError } from "@octokit/request-error"; import type { EmitterEventWebhookPayloadMap } from "./generated/get-webhook-payload-type-from-event"; -type EmitterEventPayloadMap = EmitterEventWebhookPayloadMap; - export type EmitterWebhookEventMap = { - [K in keyof EmitterEventPayloadMap]: BaseWebhookEvent; + [K in keyof EmitterEventWebhookPayloadMap]: BaseWebhookEvent; }; export type EmitterWebhookEventName = keyof EmitterWebhookEventMap; export type EmitterWebhookEvent = EmitterWebhookEventMap[EmitterWebhookEventName]; -/** - * A map of all possible emitter events to their event type. - * AKA "if the emitter emits x, the handler will be passed y" - */ -export type EmitterEventMap = EmitterWebhookEventMap; -export type EmitterEventName = keyof EmitterEventMap; -export type EmitterEvent = EmitterEventMap[EmitterEventName]; - -export type ToWebhookEvent< +type ToWebhookEvent< TEmitterEvent extends string > = TEmitterEvent extends `${infer TWebhookEvent}.${string}` ? TWebhookEvent : TEmitterEvent; interface BaseWebhookEvent< - TName extends keyof EmitterEventPayloadMap = keyof EmitterEventPayloadMap + TName extends EmitterWebhookEventName = EmitterWebhookEventName > { id: string; name: ToWebhookEvent; - payload: EmitterEventPayloadMap[TName]; + payload: EmitterEventWebhookPayloadMap[TName]; } -export interface Options { +export interface Options< + T extends EmitterWebhookEvent, + TTransformed = unknown +> { path?: string; secret?: string; - transform?: TransformMethod; + transform?: TransformMethod; } type TransformMethod = ( @@ -46,11 +39,11 @@ type EnsureArray = T extends any[] ? T : [T]; // type MaybeArray = T | T[]; export type HandlerFunction< - TName extends EmitterEventName | EmitterEventName[], + TName extends EmitterWebhookEventName | EmitterWebhookEventName[], TTransformed > = ( - event: EmitterEventMap[Extract< - EmitterEventName, + event: EmitterWebhookEventMap[Extract< + EmitterWebhookEventName, EnsureArray[number] >] & TTransformed diff --git a/test/typescript-validate.ts b/test/typescript-validate.ts index aed1daeb..9e5e3af5 100644 --- a/test/typescript-validate.ts +++ b/test/typescript-validate.ts @@ -5,10 +5,8 @@ import { createWebhooksApi, sign, verify, - EventPayloads, EmitterWebhookEvent, WebhookError, - WebhookEvents, } from "../src/index"; import { createServer } from "http"; import { HandlerFunction, EmitterWebhookEventName } from "../src/types"; @@ -51,21 +49,15 @@ on("code_scanning_alert.fixed", (event) => { console.log("a run was completed!"); } + // @ts-expect-error TS2367: + // This condition will always return 'false' since the types '"fixed"' and '"completed"' have no overlap. + if (event.payload.action === "random-string") { + console.log("a run was completed!"); + } + fn(event); }); -const myEventName: WebhookEvents = "check_run.completed"; - -const myEventPayload: EventPayloads.WebhookPayloadCheckRunCheckRunOutput = { - annotations_count: 0, - annotations_url: "", - summary: "", - text: "", - title: "", -}; - -console.log(myEventName, myEventPayload); - export default async function () { // Check empty constructor new Webhooks(); @@ -76,7 +68,7 @@ export default async function () { }); // Check all supported options - const webhooks = new Webhooks({ + const webhooks = new Webhooks({ secret: "bleh", path: "/webhooks", transform: (event) => {