Hono / Cloudflare Workers
Handle webhooks with hooksentinel on Hono, including Cloudflare Workers where Node's crypto module isn't available.
Install
npm install @hooksentinel/core@hooksentinel/core/hono exports toHonoHandler. The core package uses Web Crypto (SubtleCrypto) rather than Node's crypto module, so it runs unmodified on Cloudflare Workers, Deno Deploy, and other edge/isolate runtimes — there is no Node-only code path to swap out.
Basic setup
import { Hono } from 'hono';
import { createWebhookHandler, stripe } from '@hooksentinel/core';
import { toHonoHandler } from '@hooksentinel/core/hono';
import { memoryStore } from '@hooksentinel/core/stores';
const app = new Hono();
const stripeWebhook = createWebhookHandler({
provider: stripe({ secret: '' }), // see env binding below
idempotency: memoryStore(),
onEvent: async (event) => {
if (event.type === 'checkout.session.completed') {
await fulfillOrder(event.data.object.id);
}
},
});
app.post('/webhooks/stripe', toHonoHandler(stripeWebhook));
async function fulfillOrder(sessionId: string) {
// ...
}
export default app;Cloudflare Workers: reading secrets from bindings
Workers don't have process.env — secrets come from the Env bindings object passed into the request. Build the handler per-request instead of at module scope so it can read the binding:
import { Hono } from 'hono';
import { createWebhookHandler, stripe } from '@hooksentinel/core';
import { toHonoHandler } from '@hooksentinel/core/hono';
import { memoryStore } from '@hooksentinel/core/stores';
type Bindings = {
STRIPE_WEBHOOK_SECRET: string;
};
const app = new Hono<{ Bindings: Bindings }>();
app.post('/webhooks/stripe', async (c) => {
const stripeWebhook = createWebhookHandler({
provider: stripe({ secret: c.env.STRIPE_WEBHOOK_SECRET }),
idempotency: memoryStore(),
onEvent: async (event) => {
if (event.type === 'checkout.session.completed') {
await fulfillOrder(event.data.object.id);
}
},
});
return toHonoHandler(stripeWebhook)(c);
});
async function fulfillOrder(sessionId: string) {
// ...
}
export default app;Idempotency on Workers
memoryStore() doesn't survive across isolate invocations on Workers — each request may hit a cold or different isolate, so in-memory dedup is not reliable there. Use redisStore() pointed at Upstash Redis (which speaks HTTP and works from Workers) or a KV-backed store implementing the same IdempotencyStore interface. See Idempotency for the interface and setup.
Deno
The same toHonoHandler works unmodified under Deno's Hono support, since both the core package and the Hono adapter avoid Node built-ins.
Last updated on