npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@beignet/provider-webhooks-github

v0.0.34

Published

GitHub webhook verifier provider for Beignet

Readme

@beignet/provider-webhooks-github

GitHub webhook verifier provider for Beignet applications.

This package adapts GitHub's X-Hub-Signature-256 HMAC verification to @beignet/core/webhooks. Use it when an app receives repository, organization, or GitHub App webhook deliveries.

Install

bun add @beignet/provider-webhooks-github @beignet/core

Configure

Set the webhook secret for the GitHub webhook endpoint you are receiving:

GITHUB_WEBHOOK_SECRET=...

GitHub sends the event name in X-GitHub-Event, the delivery ID in X-GitHub-Delivery, and the HMAC-SHA256 signature in X-Hub-Signature-256.

beignet doctor --strict checks GITHUB_WEBHOOK_SECRET when this package is installed. The package is optional by registration metadata because verifier packages are wired at the route/server boundary instead of installed in server/providers.ts; remove the dependency if the app is not using a GitHub webhook endpoint.

Installed ports

This package does not install Beignet lifecycle ports. It exports createGitHubWebhookVerifier(...), which you pass to createWebhookRoute(...) or verifyWebhook(...) at the route/server boundary.

It does not expose a provider escape hatch; the verifier itself is the route-bound adapter.

Instrumentation

This verifier package does not record provider instrumentation directly. createWebhookRoute(...) owns the route response, and your handler should record app-specific audit entries, jobs, outbox messages, or custom devtools events after verification when those side effects matter.

Define a webhook catalog

Keep the event catalog near the feature that owns the workflow:

// features/integrations/webhooks.ts
import { defineWebhook } from "@beignet/core/webhooks";
import { z } from "zod";

const issuePayloadSchema = z.object({
  action: z.string(),
  issue: z.object({
    number: z.number(),
    title: z.string(),
  }),
  repository: z.object({
    full_name: z.string(),
  }),
});

export const githubWebhook = defineWebhook("integrations.github", {
  provider: "github",
  events: {
    issues: issuePayloadSchema,
  },
});

The verified Beignet event has provider: "github", id from X-GitHub-Delivery, type from X-GitHub-Event, and the parsed JSON request body as event.payload.

Expose a Next.js route

Wire the provider verifier at the route/server boundary so feature webhook catalogs stay provider-runtime free. beignet lint enforces this boundary: contract-reachable feature code cannot import @beignet/provider-* packages, so the verifier attaches through the verify option of createWebhookRoute(...) instead of the webhook definition:

// app/api/webhooks/github/route.ts
import { createWebhookRoute } from "@beignet/next";
import { createGitHubWebhookVerifier } from "@beignet/provider-webhooks-github";
import { githubWebhook } from "@/features/integrations/webhooks";
import { handleGitHubWebhookUseCase } from "@/features/integrations/use-cases";
import { env } from "@/lib/env";
import { getServer } from "@/server";

export const runtime = "nodejs";

const githubWebhookVerifier = createGitHubWebhookVerifier({
  secret: () => env.GITHUB_WEBHOOK_SECRET,
});

export const { POST } = createWebhookRoute({
  server: getServer,
  webhook: githubWebhook,
  verify: ({ input }) => githubWebhookVerifier.verify(input),
  handle: async ({ ctx, event }) => {
    await handleGitHubWebhookUseCase.run({
      ctx,
      input: event,
    });

    return {
      status: 200,
      body: { received: true },
    };
  },
});

Handlers should key idempotency on event.id. GitHub may redeliver the same delivery, and webhook handlers should update app-owned state or enqueue durable work before acknowledging.

Generic webhook routes reject verified event types that are not listed in the catalog by default. Set allowUnknownEvents: true only when a broad GitHub endpoint should acknowledge valid event names the app does not handle.

export const { POST } = createWebhookRoute({
  server: getServer,
  webhook: githubWebhook,
  verify: ({ input }) => githubWebhookVerifier.verify(input),
  allowUnknownEvents: true,
  handle: async ({ event }) => {
    if (event.type !== "issues") {
      return { status: 200, body: { ignored: true } };
    }

    return { status: 200, body: { received: true } };
  },
});

Custom headers

The defaults match GitHub's webhook delivery headers:

createGitHubWebhookVerifier({
  secret: () => env.GITHUB_WEBHOOK_SECRET,
  signatureHeader: "x-hub-signature-256",
  eventHeader: "x-github-event",
  deliveryHeader: "x-github-delivery",
});

Most apps should not change these options.

Verification model

The verifier follows GitHub's documented validation flow:

  • compute an HMAC-SHA256 hex digest over the exact raw request body
  • compare it to X-Hub-Signature-256, including the sha256= prefix
  • use a timing-safe comparison
  • parse JSON only after the signature is valid

Invalid signatures, missing headers, and invalid JSON throw Beignet WebhookVerificationError values that createWebhookRoute(...) maps to a 400 response.

Failure behavior

  • Missing or invalid GitHub signatures return 400 through createWebhookRoute(...).
  • Handler failures return 500 so GitHub can redeliver the event.
  • Verified duplicate deliveries should be acknowledged after app idempotency confirms the original result.
  • Long-running work should be recorded through Beignet jobs, outbox delivery, listeners, or notifications instead of blocking the route.

Local and tests

Use a fake verifier for use-case tests and test createWebhookRoute(...) with signed requests when verification behavior matters. Keep webhook catalogs near the feature that owns the workflow so handler tests can assert app-owned idempotency and side effects.

Deployment notes

Configure one secret per GitHub webhook endpoint and keep it out of client env. Unknown but valid GitHub event names fail by default. Set allowUnknownEvents: true only when the endpoint intentionally accepts a wider catalog than the app handles.