Skip to content

WebhookEventHandler

Handles Discord webhook events with type-safe modes for standard and Cloudflare Workers environments.

  • T - Discord webhook event type from ApplicationWebhookEventType (inferred from constructor)
  • Env (default: {}) - Environment bindings type, must include DISCORD_PUBLIC_KEY?: string
  • Variables (default: {}) - Additional context variables
  • ForWorker (default: false) - Set to true for Cloudflare Workers mode (no return type required), false for standard mode (must return Response)
  • Data (default: derived from T) - Typed webhook event data payload
new WebhookEventHandler<T, Env, Variables, ForWorker, Data>(
eventType: T,
forWorker?: ForWorker
)

Parameters:

  • eventType - The Discord webhook event type to handle (from ApplicationWebhookEventType)
  • forWorker (optional) - Set to true for Cloudflare Workers mode, false or omit for standard mode

Examples:

import { WebhookEventHandler } from "honocord";
import { ApplicationWebhookEventType } from "discord-api-types/v10";
interface MyEnv {
DISCORD_PUBLIC_KEY: string;
DATABASE: D1Database;
}
// Standard mode - handler must return Response
// T is inferred from constructor argument
const standardHandler = new WebhookEventHandler(ApplicationWebhookEventType.EntitlementCreate);
// With custom environment types
const typedHandler = new WebhookEventHandler<ApplicationWebhookEventType.EntitlementCreate, MyEnv>(
ApplicationWebhookEventType.EntitlementCreate
);
// Worker mode - handler can return anything
const workerHandler = new WebhookEventHandler(ApplicationWebhookEventType.EntitlementCreate, true);

Registers the handler function for this webhook event.

Type Signature:

addHandler(
handlerFn: ForWorker extends true
? WebhookEventHandlerFnForWorkers<Data, Env, Variables>
: WebhookEventHandlerFnWithRequest<Data, Env, Variables>
): void

Parameters:

  • handlerFn - The handler function. In standard mode, must return Response | Promise<Response>. In worker mode, can return anything (Return value is ignored).

Examples:

// Standard mode
standardHandler.addHandler(async (c) => {
const data = c.var.data;
console.log("Received event:", data);
return c.json({ ok: true }); // ✅ Required
});
// Worker mode
workerHandler.addHandler(async (c) => {
const data = c.var.data;
console.log("Received event:", data);
// No return required ✅
});

Executes the handler with pre-verified event data. This method is called internally by Honocord’s webhookHandler.

Type Signature:

async execute(
eventData: Data,
c: Context<{ Bindings: Env; Variables: BlankVariables & { data: Data } }>
): Promise<Response | any>

Parameters:

  • eventData - The pre-verified webhook event data
  • c - The Hono context

Returns: The response from the handler function (or any value in worker mode)

Returns the fetch handler for standalone usage. Only available in standard mode (ForWorker = false).

Type Signature:

get fetch(): ForWorker extends true ? never : typeof this.app.fetch

Throws: Error if called in worker mode

Example:

const handler = new WebhookEventHandler(
ApplicationWebhookEventType.EntitlementCreate
// Standard mode (default)
);
handler.addHandler(async (c) => {
return c.json({ ok: true });
});
// Use as fetch handler
export default {
fetch: handler.fetch.bind(handler),
};

Returns the internal Hono app for standalone usage. Only available in standard mode (ForWorker = false).

Type Signature:

getApp(): ForWorker extends true ? never : typeof this.app

Throws: Error if called in worker mode

Example:

import { Hono } from "hono";
const handler = new WebhookEventHandler(ApplicationWebhookEventType.LobbyMessageCreate);
handler.addHandler(async (c) => {
return c.json({ received: true });
});
// Mount in Hono app
const app = new Hono();
app.route("/discord", handler.getApp());

The Discord webhook event type this handler responds to.

Type: ApplicationWebhookEventType

Always "webhook". Used internally for handler type identification.

Type: "webhook"

import { Honocord, WebhookEventHandler } from "honocord";
import { ApplicationWebhookEventType } from "discord-api-types/v10";
const bot = new Honocord({ isCFWorker: true });
// Worker mode for CF Workers
const handler = new WebhookEventHandler(ApplicationWebhookEventType.EntitlementCreate, true);
handler.addHandler(async (c) => {
const entitlement = c.var.data;
// Process entitlement
// No return needed
});
bot.loadHandlers(handler);
export default bot.getApp(); // /webhook endpoint
const handler = new WebhookEventHandler(
ApplicationWebhookEventType.ApplicationAuthorized
);
handler.addHandler(async (c) => {
const authData = c.var.data;
console.log(\`App authorized by \${authData.user.username}\`);
return c.json({ success: true });
});
export default handler.getApp();

The following diagram illustrates how webhook events are processed through Honocord:

sequenceDiagram
    participant Discord
    participant Honocord
    participant Verification
    participant Handler
    participant UserCode

    Discord->>Honocord: POST /webhook<br/>(signed request)

    Note over Honocord: webhookHandler()

    Honocord->>Honocord: Check isCFWorker flag

    Honocord->>Verification: verifyDiscordRequest()
    Verification->>Verification: Validate signature<br/>Parse body

    alt Invalid Signature
        Verification-->>Honocord: isValid: false
        Honocord-->>Discord: 401 Unauthorized
    end

    Verification-->>Honocord: isValid: true<br/>data: APIWebhookEvent

    alt Ping Event
        Note over Honocord: data.type === Ping
        Honocord-->>Discord: 200 OK<br/>{ type: 1 }
    end

    Honocord->>Honocord: Lookup handler by<br/>event type

    alt No Handler Found
        Honocord-->>Discord: 404 Not Found
    end

    alt Cloudflare Workers Mode
        Note over Honocord: isCFWorker === true
        Honocord->>Honocord: executionCtx.waitUntil()
        Honocord-->>Discord: 200 OK<br/>{ ok: true }
        Note over Discord: Response sent<br/>immediately

        par Async Processing
            Honocord->>Handler: execute(event, context)
            Handler->>UserCode: Call handler function
            Note over UserCode: Process event<br/>(no return needed)
            UserCode-->>Handler: void | any
            Handler-->>Honocord: Complete
        end

        Note over Honocord: Worker lifetime<br/>extended until complete
    end

    alt Standard Mode
        Note over Honocord: isCFWorker === false
        Honocord->>Handler: execute(event, context)
        Handler->>Handler: Set context data
        Handler->>UserCode: Call handler function
        Note over UserCode: Process event<br/>(must return Response)
        UserCode-->>Handler: Response
        Handler-->>Honocord: Response
        Honocord-->>Discord: Forward Response
    end