Skip to content

Commit

Permalink
feat: refactor types
Browse files Browse the repository at this point in the history
  • Loading branch information
G-Rath committed Feb 5, 2021
1 parent ca8c6f1 commit 8e81a5a
Show file tree
Hide file tree
Showing 9 changed files with 40 additions and 67 deletions.
6 changes: 3 additions & 3 deletions src/event-handler/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type {
EmitterEventName,
EmitterWebhookEvent,
EmitterWebhookEventName,
HandlerFunction,
Options,
State,
Expand All @@ -15,13 +15,13 @@ import { receiverHandle as receive } from "./receive";
import { removeListener } from "./remove-listener";

interface EventHandler<TTransformed = unknown> {
on<E extends EmitterEventName>(
on<E extends EmitterWebhookEventName>(
event: E | E[],
callback: HandlerFunction<E, TTransformed>
): void;
onAny(handler: (event: EmitterWebhookEvent) => any): void;
onError(handler: (event: WebhookEventHandlerError) => any): void;
removeListener<E extends EmitterEventName>(
removeListener<E extends EmitterWebhookEventName>(
event: E | E[],
callback: HandlerFunction<E, TTransformed>
): void;
Expand Down
6 changes: 3 additions & 3 deletions src/event-handler/on.ts
Original file line number Diff line number Diff line change
@@ -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]) {
Expand All @@ -19,7 +19,7 @@ function handleEventHandlers(
}
export function receiverOn(
state: State,
webhookNameOrNames: EmitterEventName | EmitterEventName[],
webhookNameOrNames: EmitterWebhookEventName | EmitterWebhookEventName[],
handler: Function
) {
if (Array.isArray(webhookNameOrNames)) {
Expand Down
7 changes: 4 additions & 3 deletions src/event-handler/receive.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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["*"]];

Expand Down Expand Up @@ -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);
}

Expand Down
4 changes: 2 additions & 2 deletions src/event-handler/remove-listener.ts
Original file line number Diff line number Diff line change
@@ -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)) {
Expand Down
21 changes: 6 additions & 15 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -26,13 +24,13 @@ class Webhooks<
> {
public sign: (payload: string | object) => string;
public verify: (eventPayload: string | object, signature: string) => boolean;
public on: <E extends EmitterEventName>(
public on: <E extends EmitterWebhookEventName>(
event: E | E[],
callback: HandlerFunction<E, TTransformed>
) => void;
public onAny: (callback: (event: EmitterWebhookEvent) => any) => void;
public onError: (callback: (event: WebhookEventHandlerError) => any) => void;
public removeListener: <E extends EmitterEventName>(
public removeListener: <E extends EmitterWebhookEventName>(
event: E | E[],
callback: HandlerFunction<E, TTransformed>
) => void;
Expand All @@ -46,7 +44,7 @@ class Webhooks<
options: EmitterWebhookEventMap[WebhookEventName] & { signature: string }
) => Promise<void>;

constructor(options?: Options<E>) {
constructor(options?: Options<E, TTransformed>) {
if (!options || !options.secret) {
throw new Error("[@octokit/webhooks] options.secret required");
}
Expand All @@ -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,
Expand Down
4 changes: 1 addition & 3 deletions src/middleware/middleware.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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(
Expand Down
6 changes: 2 additions & 4 deletions src/middleware/verify-and-receive.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
31 changes: 12 additions & 19 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -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>;
[K in keyof EmitterEventWebhookPayloadMap]: BaseWebhookEvent<K>;
};

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<TName>;
payload: EmitterEventPayloadMap[TName];
payload: EmitterEventWebhookPayloadMap[TName];
}

export interface Options<T extends EmitterWebhookEvent> {
export interface Options<
T extends EmitterWebhookEvent,
TTransformed = unknown
> {
path?: string;
secret?: string;
transform?: TransformMethod<T>;
transform?: TransformMethod<T, TTransformed>;
}

type TransformMethod<T extends EmitterWebhookEvent, V = T> = (
Expand All @@ -46,11 +39,11 @@ type EnsureArray<T> = T extends any[] ? T : [T];
// type MaybeArray<T> = T | T[];

export type HandlerFunction<
TName extends EmitterEventName | EmitterEventName[],
TName extends EmitterWebhookEventName | EmitterWebhookEventName[],
TTransformed
> = (
event: EmitterEventMap[Extract<
EmitterEventName,
event: EmitterWebhookEventMap[Extract<
EmitterWebhookEventName,
EnsureArray<TName>[number]
>] &
TTransformed
Expand Down
22 changes: 7 additions & 15 deletions test/typescript-validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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();
Expand All @@ -76,7 +68,7 @@ export default async function () {
});

// Check all supported options
const webhooks = new Webhooks<EmitterWebhookEvent, { foo: string }>({
const webhooks = new Webhooks({
secret: "bleh",
path: "/webhooks",
transform: (event) => {
Expand Down

0 comments on commit 8e81a5a

Please sign in to comment.