@molecule/api-webhook-http
Provider bond · webhook · API (Node) · v1.0.3 · Apache-2.0
HTTP webhook provider for molecule.dev
npm install @molecule/api-webhook-httpnpm · Source on GitHub · Implements @molecule/api-webhook
How it works
@molecule/api-webhook-http is a provider bond on the API (Node) side: it implements the webhook core interface (@molecule/api-webhook) with a concrete vendor or library behind it.
Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.
import { setProvider } from '@molecule/api-webhook'
import { createProvider } from '@molecule/api-webhook-http'
// Bond at startup
setProvider(createProvider())
// Or with custom configuration
setProvider(
createProvider({
timeout: 10_000,
retryCount: 5,
retryDelay: 2000,
}),
)Works with: @molecule/api-logger, @molecule/api-webhook
Live demos
Running apps built with Molecule that install this package — open the app or study the template.
Reference
HTTP webhook provider for molecule.dev.
Implements the @molecule/api-webhook interface using direct HTTP POST
delivery with HMAC signature verification and automatic retries.
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Quick Start
import { setProvider } from '@molecule/api-webhook'
import { createProvider } from '@molecule/api-webhook-http'
// Bond at startup
setProvider(createProvider())
// Or with custom configuration
setProvider(
createProvider({
timeout: 10_000,
retryCount: 5,
retryDelay: 2000,
}),
)
Type
provider
Installation
npm install @molecule/api-webhook-http @molecule/api-logger @molecule/api-webhook undici
API
Interfaces
HttpWebhookConfig
Configuration for the HTTP webhook provider.
interface HttpWebhookConfig {
/** HTTP request timeout in milliseconds. Defaults to 30000 (30 seconds). */
timeout?: number
/** Default number of automatic retries on delivery failure. Defaults to 3. */
retryCount?: number
/** Delay between retry attempts in milliseconds. Defaults to 1000. */
retryDelay?: number
/** HTTP header name used to send the HMAC payload signature. Defaults to `'x-webhook-signature'`. */
signatureHeader?: string
}
Functions
createProvider(config)
Creates an HTTP-backed WebhookProvider.
Webhook registrations and delivery logs are stored in memory.
For asynchronous background delivery with retry backoff, use
@molecule/api-webhook-queue (note: also in-memory).
function createProvider(config?: HttpWebhookConfig): WebhookProvider
config— HTTP webhook provider configuration.
Returns: A fully initialised WebhookProvider backed by direct HTTP delivery.
isPrivateIPv4(ip)
True for an IPv4 address in any private/loopback/link-local/CGNAT/reserved range.
function isPrivateIPv4(ip: string): boolean
isPrivateIPv6(ip)
True for an IPv6 loopback/unspecified/unique-local/link-local (or mapped-private v4).
function isPrivateIPv6(ip: string): boolean
isPrivateAddress(ip)
True if ip (a literal IPv4/IPv6 string) is private/internal/metadata.
function isPrivateAddress(ip: string): boolean
safeFetch(rawUrl, init)
SSRF-safe replacement for fetch when the URL is (or derives from) untrusted input.
Only http(s) is allowed; the connection is pinned away from private/internal/metadata
addresses (both IP-literal hosts — checked synchronously since they skip DNS — and
hostnames — validated inside the connect lookup). Redirects are not auto-followed so
a 3xx cannot rebind to an internal host.
function safeFetch(rawUrl: string, init?: RequestInit): Promise<Response>
rawUrl— The (untrusted) URL to fetch.init— Standard fetch init.
Returns: The fetch Response.
Core Interface
Implements @molecule/api-webhook interface.
Injection Notes
Requirements
Peer dependencies:
@molecule/api-logger^1.0.1@molecule/api-webhook^1.0.1
Runtime Dependencies
-
@molecule/api-logger -
@molecule/api-webhook -
undici -
All state is in-memory. Registrations and delivery logs live in the provider instance and are lost on restart — persist registrations in your own datastore and re-
register()at startup. (The queue bond adds async delivery + backoff, NOT persistence — it is in-memory too.) -
Signature scheme: each delivery is a JSON POST with
x-webhook-event: <event>and<signatureHeader>(defaultx-webhook-signature) set to the hex HMAC-SHA256 of the raw JSON body, keyed by the registration's secret. Receivers verify by recomputing the HMAC over the raw request body. -
SSRF is enforced at connect time: deliveries resolve DNS through a pinned lookup that refuses private/link-local/metadata addresses (no validate-then-connect rebinding window).
register()itself does NOT validate the URL — a blocked destination surfaces asstatus: 0, success: falsedelivery results. Still allowlist at registration time for a friendly 4xx (see the core's remarks). -
dispatch()never throws on delivery failure — check each result'ssuccess(network errors/timeouts appear asstatus: 0). Retries are synchronous:dispatch()resolves only after all attempts finish.
E2E Tests
Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:
- Registering a webhook endpoint through the app's UI/API succeeds, and
an event the app dispatches actually produces a delivery. The sandbox
CAPTURES outbound deliveries instead of POSTing — read them with the
read_activitytool (filter type 'webhook'); never mock the dispatch or modify production code to expose the payload. - The captured delivery carries the signature header (derived from the registration's secret), a stable delivery-id header the receiver can dedup on (at-least-once), and an event payload free of secrets/unrelated PII.
- A registration targeting a private/link-local/metadata destination
(
localhost,10.…,169.254.169.254) is REJECTED before any dispatch.