@lastshotlabs/slingshot-webhooks
npm install @lastshotlabs/slingshot-webhooks
Functions
Section titled “Functions”createMemoryWebhookAdapter
Section titled “createMemoryWebhookAdapter”In-memory WebhookAdapter with synchronous endpoint management helpers for testing.
function createMemoryWebhookAdapter(): MemoryWebhookAdapterSource: packages/slingshot-webhooks/src/adapters/memory.ts
createSecretCipher
Section titled “createSecretCipher”Pluggable encryptor for at-rest webhook endpoint secrets.
Apps can supply a custom implementation backed by KMS, HashiCorp Vault, or
any other key manager. The default implementation built from
createSecretCipher performs local AES-256-GCM with a base64 key, but
the framework only depends on this interface so an external provider can be
dropped in without touching the storage path.
Implementations should:
- Return strings that round-trip through
decryptunchanged. - Tolerate values produced before encryption was enabled (the local implementation passes such values through and operators rotate by re-saving).
encrypt/decrypt may be sync or async; the runtime awaits both.
function createSecretCipher(keyB64: string | undefined | null): SecretCipherSource: packages/slingshot-webhooks/src/lib/secretCipher.ts
createSlidingWindowRateLimiter
Section titled “createSlidingWindowRateLimiter”In-memory sliding-window rate limiter for inbound webhook endpoints.
Each provider name is tracked independently with a configurable maximum number of requests within a rolling time window. Old entries are pruned on every check so memory does not grow unbounded under low-traffic conditions.
This limiter is per-process only. In multi-instance deployments, pair it with
a distributed rate limiter (e.g. Redis-backed) — the RateLimiter interface
is intentionally narrow so consumers can swap in a different backend without
changing the route code.
function createSlidingWindowRateLimiter(options: Partial<SlidingWindowRateLimiterOptions> = {},): RateLimiterSource: packages/slingshot-webhooks/src/lib/rateLimit.ts
createWebhookMemoryQueue
Section titled “createWebhookMemoryQueue”Optional configuration for createWebhookMemoryQueue.
Remarks: All fields are optional — the queue uses safe defaults when omitted.
function createWebhookMemoryQueue(config?: MemoryQueueConfig): WebhookQueueSource: packages/slingshot-webhooks/src/queues/memory.ts
createWebhooksPackage
Section titled “createWebhooksPackage”Webhooks package factory.
Creates a SlingshotPackageDefinition that mounts the WebhookEndpoint and
WebhookDelivery entities, wires the queue lifecycle, dispatches delivery
jobs, supplies the /endpoints/:id/test and /admin/deliveries/:id/replay
routes, and mounts the inbound webhook receiver router. Cross-package
consumers resolve the runtime adapter via WebhooksAdapterCap.
Every adapter ref, queue handle, rate-limit backend, and inbound router closure is owned by the factory’s closure (Rule 3) — multiple package instances in the same process do not share state.
function createWebhooksPackage(rawConfig: WebhookPluginConfig): SlingshotPackageDefinitionSource: packages/slingshot-webhooks/src/plugin.ts
replayWebhookDlq
Section titled “replayWebhookDlq”Optional configuration for createWebhookMemoryQueue.
Remarks: All fields are optional — the queue uses safe defaults when omitted.
async function replayWebhookDlq(storagePath: string, enqueueFn: (job: WebhookJob) => Promise<void>,): Promise<Source: packages/slingshot-webhooks/src/queues/memory.ts
safeParseInboundBody
Section titled “safeParseInboundBody”Helpers for implementing InboundProvider.verify() safely.
Inbound webhook bodies arrive as raw strings supplied by an external sender. A naive
JSON.parse(rawBody) will throw a SyntaxError when the sender (whether buggy or
malicious) posts a malformed payload, which would otherwise propagate up into the
route handler and surface as a generic 500. safeParseInboundBody keeps that failure
mode local to the provider so it can return { verified: false, reason } cleanly.
function safeParseInboundBody(rawBody: string): SafeParseInboundBodyResultSource: packages/slingshot-webhooks/src/lib/inbound.ts
signPayload
Section titled “signPayload”Signs a webhook payload using HMAC-SHA256 and returns a Stripe-style signature header value.
Signature format: t=<unix_timestamp>,v1=<hex_hmac> where the signed data is <ts>.<body>.
This format is intentionally compatible with Stripe’s webhook signature scheme.
async function signPayload(secret: string, body: string, timestamp?: number,): Promise<string>Source: packages/slingshot-webhooks/src/lib/signing.ts
verifySignature
Section titled “verifySignature”Signs a webhook payload using HMAC-SHA256 and returns a Stripe-style signature header value.
Signature format: t=<unix_timestamp>,v1=<hex_hmac> where the signed data is <ts>.<body>.
This format is intentionally compatible with Stripe’s webhook signature scheme.
async function verifySignature(secret: string, body: string, header: string, toleranceSeconds = 300,): Promise<boolean>Source: packages/slingshot-webhooks/src/lib/signing.ts
webhookPluginConfigSchema
Section titled “webhookPluginConfigSchema”Zod schema for validating WebhookPluginConfig.
Config Fields
Section titled “Config Fields”| Field | Description |
|---|---|
| `/** |
- Advanced outbound dispatch overrides. Production traffic should normally
- use the default safeFetch transport; tests can inject
fetchImpland a - deterministic resolver without weakening SSRF validation.
/
dispatch
| Optional host resolver override for outbound delivery validation. | |/* Delivery queue implementation. Defaults to the in-process memory queue. / queue| In-memory webhook delivery queue (development only). | |/* Mount path for webhook routes. Default| URL path prefix for webhook routes. Omit to use '/webhooks'. | |/** Role required for webhook management routes. Default| Role required for webhook management routes. Omit to use 'admin'. | |each inbound provider (e.g. ‘stripe’, ‘github’) is rate-limited - independently using an in-memory sliding window counter. Requests that exceed
- the limit receive HTTP 429 with
Retry-AfterandX-RateLimit-*headers. - Provide a custom
RateLimiterinstance for distributed deployments (e.g. Redis - sliding window) or use the shorthand object form for the built-in per-process
- limiter.
- Omit entirely to disable inbound rate limiting (not recommended in production).
*/
inboundRateLimit
| Custom RateLimiter instance (e.g. Redis-backed). | |in bytes. Default` | Maximum body size (bytes) accepted on inbound webhook routes. Defaults to 1 MiB. |
Source: packages/slingshot-webhooks/src/types/config.ts
Constants
Section titled “Constants”WEBHOOK_ROUTES
Section titled “WEBHOOK_ROUTES”Named constants for the two route groups mounted by the webhook plugin.
Pass values to WebhookPluginConfig.disableRoutes to skip mounting specific route groups.
Source: packages/slingshot-webhooks/src/routes/index.ts
Webhooks
Section titled “Webhooks”Public contract for slingshot-webhooks.
Cross-package consumers resolve WebhooksAdapterCap through ctx.capabilities.require(...)
to send/manage outbound webhook deliveries through the unified adapter.
Source: packages/slingshot-webhooks/src/public.ts
WebhooksAdapterCap
Section titled “WebhooksAdapterCap”Public contract for slingshot-webhooks.
Cross-package consumers resolve WebhooksAdapterCap through ctx.capabilities.require(...)
to send/manage outbound webhook deliveries through the unified adapter.
Source: packages/slingshot-webhooks/src/public.ts
Classes
Section titled “Classes”WebhookDeliveryError
Section titled “WebhookDeliveryError”A single webhook delivery job tracked by the queue.
Contains all the data needed to execute one HTTP delivery attempt without additional
database lookups. Exposed to queue processors and onDeadLetter callbacks.
Source: packages/slingshot-webhooks/src/types/queue.ts
WebhookSecretDecryptError
Section titled “WebhookSecretDecryptError”A single webhook delivery job tracked by the queue.
Contains all the data needed to execute one HTTP delivery attempt without additional
database lookups. Exposed to queue processors and onDeadLetter callbacks.
Source: packages/slingshot-webhooks/src/types/queue.ts
Interfaces
Section titled “Interfaces”InboundProvider
Section titled “InboundProvider”Interface for verifying and processing inbound webhook payloads from external services.
Each provider handles one external service (e.g. Stripe, GitHub). On receipt of a
POST /webhooks/inbound/<provider> request, the plugin calls verify(). If verification
passes, the payload is re-emitted as webhook:inbound.<provider> on the bus.
Implementers MUST handle malformed JSON. The rawBody is attacker-controlled, so a
naive JSON.parse(rawBody) will throw on bad input and surface as an unhelpful 500.
Use the safeParseInboundBody helper exported from this package, or wrap JSON.parse
in your own try/catch and return { verified: false, reason } on failure.
Source: packages/slingshot-webhooks/src/types/inbound.ts
MemoryQueueConfig
Section titled “MemoryQueueConfig”Optional configuration for createWebhookMemoryQueue.
Remarks: All fields are optional — the queue uses safe defaults when omitted.
Source: packages/slingshot-webhooks/src/queues/memory.ts
MemoryWebhookAdapter
Section titled “MemoryWebhookAdapter”In-memory WebhookAdapter with synchronous endpoint management helpers for testing.
Source: packages/slingshot-webhooks/src/adapters/memory.ts
RateLimiter
Section titled “RateLimiter”In-memory sliding-window rate limiter for inbound webhook endpoints.
Each provider name is tracked independently with a configurable maximum number of requests within a rolling time window. Old entries are pruned on every check so memory does not grow unbounded under low-traffic conditions.
This limiter is per-process only. In multi-instance deployments, pair it with
a distributed rate limiter (e.g. Redis-backed) — the RateLimiter interface
is intentionally narrow so consumers can swap in a different backend without
changing the route code.
Source: packages/slingshot-webhooks/src/lib/rateLimit.ts
RateLimitResult
Section titled “RateLimitResult”In-memory sliding-window rate limiter for inbound webhook endpoints.
Each provider name is tracked independently with a configurable maximum number of requests within a rolling time window. Old entries are pruned on every check so memory does not grow unbounded under low-traffic conditions.
This limiter is per-process only. In multi-instance deployments, pair it with
a distributed rate limiter (e.g. Redis-backed) — the RateLimiter interface
is intentionally narrow so consumers can swap in a different backend without
changing the route code.
Source: packages/slingshot-webhooks/src/lib/rateLimit.ts
SecretCipher
Section titled “SecretCipher”Pluggable encryptor for at-rest webhook endpoint secrets.
Apps can supply a custom implementation backed by KMS, HashiCorp Vault, or
any other key manager. The default implementation built from
createSecretCipher performs local AES-256-GCM with a base64 key, but
the framework only depends on this interface so an external provider can be
dropped in without touching the storage path.
Implementations should:
- Return strings that round-trip through
decryptunchanged. - Tolerate values produced before encryption was enabled (the local implementation passes such values through and operators rotate by re-saving).
encrypt/decrypt may be sync or async; the runtime awaits both.
Source: packages/slingshot-webhooks/src/lib/secretCipher.ts
SecretEncryptor
Section titled “SecretEncryptor”Pluggable encryptor for at-rest webhook endpoint secrets.
Apps can supply a custom implementation backed by KMS, HashiCorp Vault, or
any other key manager. The default implementation built from
createSecretCipher performs local AES-256-GCM with a base64 key, but
the framework only depends on this interface so an external provider can be
dropped in without touching the storage path.
Implementations should:
- Return strings that round-trip through
decryptunchanged. - Tolerate values produced before encryption was enabled (the local implementation passes such values through and operators rotate by re-saving).
encrypt/decrypt may be sync or async; the runtime awaits both.
Source: packages/slingshot-webhooks/src/lib/secretCipher.ts
SlidingWindowRateLimiterOptions
Section titled “SlidingWindowRateLimiterOptions”In-memory sliding-window rate limiter for inbound webhook endpoints.
Each provider name is tracked independently with a configurable maximum number of requests within a rolling time window. Old entries are pruned on every check so memory does not grow unbounded under low-traffic conditions.
This limiter is per-process only. In multi-instance deployments, pair it with
a distributed rate limiter (e.g. Redis-backed) — the RateLimiter interface
is intentionally narrow so consumers can swap in a different backend without
changing the route code.
Source: packages/slingshot-webhooks/src/lib/rateLimit.ts
WebhookAdapter
Section titled “WebhookAdapter”Runtime persistence contract used by webhook orchestration.
Source: packages/slingshot-webhooks/src/types/adapter.ts
WebhookAttempt
Section titled “WebhookAttempt”Lifecycle status of a webhook delivery.
Source: packages/slingshot-webhooks/src/types/models.ts
WebhookDelivery
Section titled “WebhookDelivery”Lifecycle status of a webhook delivery.
Source: packages/slingshot-webhooks/src/types/models.ts
WebhookEndpoint
Section titled “WebhookEndpoint”Lifecycle status of a webhook delivery.
Source: packages/slingshot-webhooks/src/types/models.ts
WebhookEndpointSubscription
Section titled “WebhookEndpointSubscription”Lifecycle status of a webhook delivery.
Source: packages/slingshot-webhooks/src/types/models.ts
WebhookJob
Section titled “WebhookJob”A single webhook delivery job tracked by the queue.
Contains all the data needed to execute one HTTP delivery attempt without additional
database lookups. Exposed to queue processors and onDeadLetter callbacks.
Source: packages/slingshot-webhooks/src/types/queue.ts
WebhookQueue
Section titled “WebhookQueue”A single webhook delivery job tracked by the queue.
Contains all the data needed to execute one HTTP delivery attempt without additional
database lookups. Exposed to queue processors and onDeadLetter callbacks.
Source: packages/slingshot-webhooks/src/types/queue.ts
WebhookSubscriber
Section titled “WebhookSubscriber”Lifecycle status of a webhook delivery.
Source: packages/slingshot-webhooks/src/types/models.ts
DeliveryStatus
Section titled “DeliveryStatus”Lifecycle status of a webhook delivery.
Source: packages/slingshot-webhooks/src/types/models.ts
SafeParseInboundBodyResult
Section titled “SafeParseInboundBodyResult”Helpers for implementing InboundProvider.verify() safely.
Inbound webhook bodies arrive as raw strings supplied by an external sender. A naive
JSON.parse(rawBody) will throw a SyntaxError when the sender (whether buggy or
malicious) posts a malformed payload, which would otherwise propagate up into the
route handler and surface as a generic 500. safeParseInboundBody keeps that failure
mode local to the provider so it can return { verified: false, reason } cleanly.
Source: packages/slingshot-webhooks/src/lib/inbound.ts
WebhookEndpointSubscriptionInput
Section titled “WebhookEndpointSubscriptionInput”Lifecycle status of a webhook delivery.
Source: packages/slingshot-webhooks/src/types/models.ts
WebhookOwnerType
Section titled “WebhookOwnerType”Lifecycle status of a webhook delivery.
Source: packages/slingshot-webhooks/src/types/models.ts
WebhookPluginConfig
Section titled “WebhookPluginConfig”Zod schema for validating WebhookPluginConfig.
Source: packages/slingshot-webhooks/src/types/config.ts
WebhookRoute
Section titled “WebhookRoute”Named constants for the two route groups mounted by the webhook plugin.
Pass values to WebhookPluginConfig.disableRoutes to skip mounting specific route groups.
Source: packages/slingshot-webhooks/src/routes/index.ts
WebhooksPluginConfig
Section titled “WebhooksPluginConfig”Zod schema for validating WebhookPluginConfig.
Source: packages/slingshot-webhooks/src/types/config.ts
WebhookSubscriptionExposure
Section titled “WebhookSubscriptionExposure”Lifecycle status of a webhook delivery.
Source: packages/slingshot-webhooks/src/types/models.ts