Skip to content

@lastshotlabs/slingshot-webhooks

npm install @lastshotlabs/slingshot-webhooks

Creates an ephemeral in-memory webhook adapter suitable for tests and local development.

function createMemoryWebhookAdapter(): MemoryWebhookAdapter

Source: packages/slingshot-webhooks/src/adapters/memory.ts

Build a SecretCipher. When keyB64 is undefined, the cipher acts as a no-op passthrough; the plugin warns at boot when this happens in production-like environments.

function createSecretCipher(keyB64: string | undefined | null): SecretCipher

Source: packages/slingshot-webhooks/src/lib/secretCipher.ts

Create an in-memory sliding-window rate limiter.

Tracks request timestamps per key in a Map. On each check() call, timestamps older than windowMs are pruned. If the remaining entry count is at or above maxRequests, the request is denied.

function createSlidingWindowRateLimiter(options: Partial<SlidingWindowRateLimiterOptions> = {},): RateLimiter

Source: packages/slingshot-webhooks/src/lib/rateLimit.ts

Creates an in-process, non-durable webhook delivery queue for development and testing.

Jobs are processed inline — no external dependencies required. All pending jobs are lost on process restart. Use createBullMQWebhookQueue for durable, Redis-backed delivery.

When config.dlqStoragePath is provided, dead-lettered jobs are also persisted to a JSON-lines file. Use replayWebhookDlq to re-process them after restart.

function createWebhookMemoryQueue(config?: MemoryQueueConfig): WebhookQueue

Source: packages/slingshot-webhooks/src/queues/memory.ts

Create the webhooks package using the definePackage authoring path.

Mounts the WebhookEndpoint and WebhookDelivery entities (each with manual adapter wiring that wraps the standard adapter in subscription normalization, secret encryption, and the transition state machine), starts the queue lifecycle, supplies the bespoke /endpoints/:id/test and /admin/deliveries/:id/replay routes plus the inbound webhook receiver, and publishes the unified WebhooksAdapterCap capability once the runtime is ready.

When config.adapter is supplied, the package skips entity wiring and uses the caller-provided adapter directly — the entity modules and routes remain unmounted in that mode.

function createWebhooksPackage(rawConfig: WebhookPluginConfig): SlingshotPackageDefinition

Source: packages/slingshot-webhooks/src/plugin.ts

Re-process every dead-lettered webhook job stored in the given JSON-lines file by passing each to the provided enqueueFn callback. Jobs that are successfully enqueued are removed from the file; jobs whose callback rejects are retained.

async function replayWebhookDlq(storagePath: string, enqueueFn: (job: WebhookJob) => Promise<void>,): Promise<

Source: packages/slingshot-webhooks/src/queues/memory.ts

Safely parse a raw inbound webhook body string as JSON.

Returns { ok: true, payload } on success, or { ok: false, reason } for any non-string input, empty body, or JSON.parse failure. Implementers should map a failed result to { verified: false, reason } in their InboundProvider.verify() return value so the route can respond with HTTP 400.

function safeParseInboundBody(rawBody: string): SafeParseInboundBodyResult

Source: packages/slingshot-webhooks/src/lib/inbound.ts

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

Verifies a webhook signature header produced by signPayload.

Parses the t=... timestamp and v1=... hex HMAC from the header, recomputes the expected HMAC, and uses a constant-time comparison via crypto.subtle.verify. Rejects signatures where the timestamp differs from now by more than toleranceSeconds to prevent replay attacks.

async function verifySignature(secret: string, body: string, header: string, toleranceSeconds = 300,): Promise<boolean>

Source: packages/slingshot-webhooks/src/lib/signing.ts

Zod schema for validating WebhookPluginConfig.

FieldDescription
`/**
  • Advanced outbound dispatch overrides. Production traffic should normally
  • use the default safeFetch transport; tests can inject fetchImpl and 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-After and X-RateLimit-* headers.
  • Provide a custom RateLimiter instance 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

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

Provider-owned package contract for slingshot-webhooks.

Source: packages/slingshot-webhooks/src/public.ts

Capability handle for the unified webhook adapter.

Cross-package consumers resolve it through ctx.capabilities.require(WebhooksAdapterCap) to send and manage outbound webhook deliveries.

Source: packages/slingshot-webhooks/src/public.ts

Thrown by the webhook dispatcher when an HTTP delivery attempt fails.

The retryable flag controls queue behaviour: non-retryable errors (e.g. 4xx client errors except 429) are dead-lettered immediately; retryable errors (e.g. network timeout, 5xx, 429) are re-queued up to config.queueConfig.maxAttempts.

Source: packages/slingshot-webhooks/src/types/queue.ts

Thrown when the secret cipher fails to decrypt a stored webhook endpoint secret. Falling back to the ciphertext (or any plaintext) would either permanently sign deliveries with the wrong key or, worse, leak the encrypted blob to the receiver — so the runtime fails closed and the caller is expected to skip the affected endpoint.

The error message intentionally never embeds the cipher value so it is safe to log.

Source: packages/slingshot-webhooks/src/types/queue.ts

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

Optional configuration for createWebhookMemoryQueue.

Remarks: All fields are optional — the queue uses safe defaults when omitted.

Source: packages/slingshot-webhooks/src/queues/memory.ts

In-memory WebhookAdapter with synchronous endpoint management helpers for testing.

Source: packages/slingshot-webhooks/src/adapters/memory.ts

Contract for rate limiter implementations used by the inbound webhook router.

Source: packages/slingshot-webhooks/src/lib/rateLimit.ts

Result returned by RateLimiter.check.

Source: packages/slingshot-webhooks/src/lib/rateLimit.ts

AES-256-GCM cipher for at-rest webhook endpoint secrets.

Plaintexts are written as enc:v1:<iv-b64>:<ciphertext-b64>:<tag-b64>. When the cipher is created with no key (or with an explicit null key), it acts as a no-op passthrough — used in test fixtures and during the migration window before operators provision an encryption key.

Legacy plaintext values that pre-date encryption are detected by the missing enc:v1: prefix and returned unchanged from decrypt. Operators should rotate those rows by writing the same value back through the update path, which re-encrypts on write.

Source: packages/slingshot-webhooks/src/lib/secretCipher.ts

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 decrypt unchanged.
  • 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

Options for createSlidingWindowRateLimiter.

Source: packages/slingshot-webhooks/src/lib/rateLimit.ts

Runtime persistence contract used by webhook orchestration.

Source: packages/slingshot-webhooks/src/types/adapter.ts

Metadata for a single delivery attempt.

Source: packages/slingshot-webhooks/src/types/models.ts

Persisted outbound delivery record.

The version field carries the optimistic concurrency token used by the dispatcher to coordinate concurrent updates against the same delivery row (P-WEBHOOKS-6). Adapters bump it on every successful update; callers pass the value they read alongside their write so a stale write becomes a conflict instead of clobbering newer state.

Source: packages/slingshot-webhooks/src/types/models.ts

Persisted outbound webhook endpoint.

Source: packages/slingshot-webhooks/src/types/models.ts

A single event subscription attached to a webhook endpoint.

Source: packages/slingshot-webhooks/src/types/models.ts

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

Interface that every webhook queue implementation must satisfy.

Extends QueueLifecycle with webhook-specific enqueue and start(processor). The in-process MemoryQueue and BullMQ-backed queue both implement this interface.

Remarks: Implement this interface to integrate a custom queue backend (e.g. SQS, RabbitMQ).

Source: packages/slingshot-webhooks/src/types/queue.ts

Identity of the entity that owns or receives a webhook delivery.

Source: packages/slingshot-webhooks/src/types/models.ts

Lifecycle status of a webhook delivery.

Source: packages/slingshot-webhooks/src/types/models.ts

Result of safeParseInboundBody.

Source: packages/slingshot-webhooks/src/lib/inbound.ts

Input union for subscribing an endpoint to a specific event key or a glob pattern.

Source: packages/slingshot-webhooks/src/types/models.ts

Discriminator indicating who owns a webhook endpoint or subscription.

Source: packages/slingshot-webhooks/src/types/models.ts

Configuration object accepted by createWebhooksPackage.

Source: packages/slingshot-webhooks/src/types/config.ts

Union of valid route group names that can be passed to WebhookPluginConfig.disableRoutes.

Source: packages/slingshot-webhooks/src/routes/index.ts

Canonical configuration name matching the plural package name.

Source: packages/slingshot-webhooks/src/types/config.ts

Visibility scope that determines which callers may manage a subscription.

Source: packages/slingshot-webhooks/src/types/models.ts