@k-msg/webhook
Runtime-first webhook package for message events.
This package now follows a DX-first flow:
- Start in 5 minutes with in-memory persistence
- Move to production by swapping persistence to D1
- Extend to SQLite/Drizzle(Postgres) with the same store contract
Install
Section titled “Install”npm install @k-msg/webhook# orbun add @k-msg/webhookRuntime API (root)
Section titled “Runtime API (root)”@k-msg/webhook root exports runtime-only APIs:
WebhookRuntimeServicecreateInMemoryWebhookPersistenceaddEndpoints,probeEndpointvalidateEndpointUrl
Advanced building blocks are now exposed from subpaths:
@k-msg/webhook/toolkit@k-msg/webhook/adapters/cloudflare
Quickstart (in-memory)
Section titled “Quickstart (in-memory)”import { WebhookEventType, WebhookRuntimeService, createInMemoryWebhookPersistence, type WebhookConfig,} from "@k-msg/webhook";
const config: WebhookConfig = { maxRetries: 3, retryDelayMs: 1_000, timeoutMs: 30_000, enableSecurity: false, enabledEvents: [ WebhookEventType.MESSAGE_SENT, WebhookEventType.MESSAGE_FAILED, WebhookEventType.SYSTEM_MAINTENANCE, ], batchSize: 10, batchTimeoutMs: 5_000,};
const runtime = new WebhookRuntimeService({ delivery: config, persistence: createInMemoryWebhookPersistence(),});
await runtime.addEndpoint({ url: "https://example.com/webhooks/k-msg", active: true, events: [WebhookEventType.MESSAGE_SENT, WebhookEventType.MESSAGE_FAILED],});
await runtime.emitSync({ id: crypto.randomUUID(), type: WebhookEventType.MESSAGE_SENT, timestamp: new Date(), data: { messageId: "msg_123", status: "sent" }, metadata: { providerId: "iwinv", messageId: "msg_123" }, version: "1.0",});
await runtime.shutdown();D1 quickstart (same runtime API)
Section titled “D1 quickstart (same runtime API)”import { WebhookEventType, WebhookRuntimeService, type WebhookConfig,} from "@k-msg/webhook";import { createD1WebhookPersistence } from "@k-msg/webhook/adapters/cloudflare";
type Env = { DB: D1Database;};
const config: WebhookConfig = { maxRetries: 3, retryDelayMs: 1_000, timeoutMs: 30_000, enableSecurity: false, enabledEvents: [WebhookEventType.MESSAGE_SENT, WebhookEventType.MESSAGE_FAILED], batchSize: 10, batchTimeoutMs: 5_000,};
function createRuntime(env: Env): WebhookRuntimeService { return new WebhookRuntimeService({ delivery: config, persistence: createD1WebhookPersistence(env.DB), security: { allowPrivateHosts: true, }, });}createD1WebhookPersistence() initializes schema automatically by default.
Schema helpers (Cloudflare)
Section titled “Schema helpers (Cloudflare)”import { buildWebhookSchemaSql, initializeWebhookSchema,} from "@k-msg/webhook/adapters/cloudflare";
const statements = buildWebhookSchemaSql();// run statements in your migration system, or:await initializeWebhookSchema(env.DB);SQLite / Drizzle(Postgres) snippets
Section titled “SQLite / Drizzle(Postgres) snippets”WebhookRuntimeService accepts custom stores via endpointStore + deliveryStore.
Implement the same interfaces to plug any backend:
import type { WebhookDeliveryStore, WebhookEndpointStore,} from "@k-msg/webhook";
class SqliteEndpointStore implements WebhookEndpointStore { async add() {} async update() {} async remove() {} async get() { return null; } async list() { return []; }}
class SqliteDeliveryStore implements WebhookDeliveryStore { async add() {} async list() { return []; }}Then wire it without changing runtime logic:
const runtime = new WebhookRuntimeService({ delivery: config, endpointStore: new SqliteEndpointStore(), deliveryStore: new SqliteDeliveryStore(),});Security defaults
Section titled “Security defaults”- Private hosts are blocked by default
http://localhoststyle URLs require explicit allowance (runtime security options)
Migration notes (breaking)
Section titled “Migration notes (breaking)”| Old usage | New usage |
|---|---|
WebhookService (root) | WebhookRuntimeService (root) |
registerEndpoint() auto test call | addEndpoint() only; test with probeEndpoint() |
| Advanced classes from root | import from @k-msg/webhook/toolkit |
| Cloudflare persistence from custom wiring | use @k-msg/webhook/adapters/cloudflare |
Toolkit subpath
Section titled “Toolkit subpath”import { LoadBalancer, QueueManager } from "@k-msg/webhook/toolkit";License
Section titled “License”MIT