Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(types): accept string event.name for receive() #434

Closed
wants to merge 3 commits into from

Conversation

jablko
Copy link
Contributor

@jablko jablko commented Feb 3, 2021

Since #428 I get the following type error:

webhooks.receive({
  id: request.headers["x-github-delivery"],
  name: request.headers["x-github-event"],
  ^^^^ TS2322: Type 'string' is not assignable to type '"status" | "delete" | "package" | "installation" | "repository" | "team" | "member" | "project" | "public" | "push" | "deployment" | "label" | "milestone" | "release" | "organization" | ... 187 more ... | "workflow_run.requested"'.
  payload: request.body,
});

Instead of changing webhooks.receive() to match eventHandler.receive() (as in #428), can we do the reverse and change eventHandler.receive() to match webhooks.receive() (as in this PR)?

I additionally added | undefined because:

  1. It's checked in .receive()
    if (!event || !event.name) {
    throw new AggregateError(["Event name not passed"]);
    }
  2. It avoids having to either non-null assert request.headers["x-github-event"]! or test it before calling .receive() (redundant since it's checked again by .receive()) when running with --noUncheckedIndexedAccess

@ghost ghost added this to Inbox in JS Feb 3, 2021
@wolfy1339
Copy link
Member

wolfy1339 commented Feb 3, 2021

I disagree with you, I think you should use this code

webhooks.receive({
  id: request.headers["x-github-delivery"],
  name: request.headers["x-github-event"] as EmitterWebhookEventName,
  payload: request.body,
});

@G-Rath
Copy link
Member

G-Rath commented Feb 3, 2021

It's checked in .receive()

That's a runtime check targeted as JS users - allowing undefined defeats the benefit that you get by using TypeScript, since you'll not be told at compile-time if the value you're passing in could be undefined.

@jablko
Copy link
Contributor Author

jablko commented Feb 3, 2021

@G-Rath Okay, I've removed the | undefined addition from this PR.

@wolfy1339 EmitterWebhookEventName seems like a postcondition of .receive() (it checks event.name against a list of hooks before running the matching handlers) vs. a precondition? What am I missing?

@jablko jablko marked this pull request as ready for review February 3, 2021 22:11
@G-Rath
Copy link
Member

G-Rath commented Feb 3, 2021

What am I missing?

Pretty much the same thing as with the | undefined - it's a runtime check that we do to warn people when they're passing in an event name we don't know about, but if they're using TypeScript we can tell them about this at compile-time rather than as runtime.

Again as with | undefined, your change would mean I'd not know if my variable is valid.

(Also note that we're warning not erroring for this check)

@oscard0m oscard0m added the Type: Bug Something isn't working as documented, or is being fixed label Feb 3, 2021
@ghost ghost moved this from Inbox to Bugs in JS Feb 3, 2021
@jablko
Copy link
Contributor Author

jablko commented Feb 3, 2021

name: string hides the fact that event.name might be bogus from the caller, whereas name: EmitterWebhookEventName hides that fact from the .receive() implementation (if it might be bogus?). Which side is responsible for confirming that event.name is in fact an EmitterWebhookEventName?

The examples in the docs had me thinking that e.g. webhooks.on(["check_run", "code_scanning_alert"], handler) was a convenient way to validate request.headers["x-github-event"].

@G-Rath
Copy link
Member

G-Rath commented Feb 3, 2021

Which side is responsible for confirming that event.name is in fact an EmitterWebhookEventName?

Neither side is - that responsibility lies with the caller of the function (aka whoevers consuming the dependency).

The example in the documentation is using the x-github-event header from a request, which Github sets accordingly and so we expect to be correct. If you're passing in values from other sources, then the responsibility falls on you to ensure they're correct.

We do some basic runtime checking for our JS users for the things that are cheap and easy to check, but we only warn on the actual event names because we don't want to be too restrictive - otherwise the library would be unusable if we were ever missing an event (i.e a bug/typo in our schemas, using a fancy new event that we'd not implemented schemas for, or even maybe custom endpoints or prototyping because you're working at Github on implementing that fancy new event).

@jablko
Copy link
Contributor Author

jablko commented Feb 3, 2021

The example in the documentation is using the x-github-event header from a request, which Github sets accordingly and so we expect to be correct. If you're passing in values from other sources, then the responsibility falls on you to ensure they're correct.

Isn't webhooks.on(["check_run", "code_scanning_alert"], handler) a convenient way to do that?

@G-Rath
Copy link
Member

G-Rath commented Feb 3, 2021

That would require us to error instead of warn on event names, which we don't want to do because we don't want to be too restrictive.

There are pros and cons to both approaches, but this library has gone the route of warning meaning at the very least changing it to error would be a breaking change.

@G-Rath G-Rath closed this in #435 Feb 4, 2021
JS automation moved this from Bugs to Done Feb 4, 2021
@github-actions

This comment has been minimized.

@G-Rath
Copy link
Member

G-Rath commented Feb 4, 2021

🤦 I used the wrong issue number, sorry - I meant to close #431 with that PR.

@G-Rath G-Rath reopened this Feb 4, 2021
@ghost ghost moved this from Done to Bugs in JS Feb 4, 2021
@G-Rath G-Rath removed the released label Feb 4, 2021
@jablko
Copy link
Contributor Author

jablko commented Feb 4, 2021

I see my mistake: if webhooks.onAny() is going to be handler: (event: EmitterAnyEvent) => any vs. handler: (event: { name: string, payload: unknown }) => any then the input needs to be correspondingly typed. Thanks for your patience and sorry for the noise!

@jablko jablko closed this Feb 4, 2021
JS automation moved this from Bugs to Done Feb 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug Something isn't working as documented, or is being fixed typescript Relevant to TypeScript users only
Projects
No open projects
JS
  
Done
Development

Successfully merging this pull request may close these issues.

None yet

4 participants