smee-client
A CLI and Node client that forwards webhooks from smee.io to your local development server.
Repository Health
Technical Analysis
smee-client is the official client and command-line tool for smee.io, a hosted webhook relay service maintained by the Probot project. It solves a specific, recurring pain point in webhook-driven development: services like GitHub, Stripe, and Slack can only deliver webhooks to a publicly reachable URL, but developers usually build and debug against localhost. smee-client opens a persistent Server-Sent Events connection to a smee.io channel and re-POSTs every payload it receives to a target URL on your machine, so you can iterate on webhook handlers without deploying or tunneling.
It ships two ways to use it: a global smee CLI binary for zero-code forwarding, and an importable SmeeClient class for embedding the same behavior inside a Node process (this is how Probot itself wires up local development). Under the hood it’s a thin, carefully hardened wrapper around the eventsource and undici packages, with explicit handling of proxy environment variables, connection timeouts, and header stripping to avoid breaking downstream servers.
What You Get
- A global
smeeCLI command that creates or connects to a smee.io channel and forwards events to a local port with a single call - An importable
SmeeClientclass for programmatic use inside Node apps, withstart()/stop()and dynamicstartForwarding()/stopForwarding()controls - Automatic respect for standard HTTP/HTTPS proxy environment variables via
undici’sEnvHttpProxyAgent - Configurable connection timeout handling that rejects and cleans up the EventSource connection if a channel never opens
- Optional query-string forwarding from the source webhook event to the target URL
- URL validation on both source and target that fails fast with a clear error instead of silently connecting to something malformed
Common Use Cases
- Developing and debugging a GitHub App or Probot bot locally against real GitHub webhook events
- Testing Stripe, Slack, or other third-party webhook integrations without deploying a public endpoint
- Embedding webhook forwarding directly into a local dev-server bootstrap script via the
SmeeClientAPI - Running a shared, disposable webhook relay in CI or a demo environment via the CLI’s
--url/--targetflags
Under The Hood
Architecture
The entire library is a single class, SmeeClient in index.ts, with a companion CLI entry point in bin/smee.js that does argument parsing (via Node’s built-in parseArgs) and delegates to the class. The class wraps an EventSource (Server-Sent Events) connection to the smee.io channel, registering open/message/error listeners that drive an internal #forward flag; start()/stop() toggle the connection lifecycle while startForwarding()/stopForwarding() toggle relaying independently, so a consumer can hold a live connection open without forwarding traffic. Private class fields (#source, #target, #events, etc.) keep internal state fully encapsulated, and getter/setter pairs for onmessage/onerror/onopen transparently proxy to the underlying EventSource once it exists, buffering assignments made before start() is called. There is effectively no layering beyond this one class plus the CLI wrapper, which is appropriate for the tool’s narrow scope.
Tech Stack
Written in TypeScript targeting native ESM ("type": "module"), compiled with tsc against @octokit/tsconfig. Runtime dependencies are minimal and deliberate: eventsource (a spec-compliant SSE client with custom-fetch support) and undici (Node’s own low-level HTTP client, used both for its fetch implementation and its EnvHttpProxyAgent for proxy-aware dispatching). The CLI layer uses only Node built-ins (node:util’s parseArgs, node:fs/promises). Tests run on Vitest with @vitest/coverage-v8 and a small get-port helper for spinning up ephemeral local servers; linting is Prettier-only (no ESLint), enforced in CI alongside a CodeQL scan and a license-compliance check via license-checker.
Code Quality
The test suite is genuinely thorough for a project this size: separate spec files cover connection errors, connection timeouts, channel creation, forwarding behavior, query-forwarding, and each of the onopen/onmessage/onerror accessor pairs, using a WebhookServer test helper to assert on real HTTP requests rather than mocks. Error handling is explicit throughout — validateURL() throws descriptive errors for malformed URLs, setter methods throw TypeError for non-function assignments, and the forwarding path wraps its fetch call in try/catch and logs rather than crashing the process. TypeScript is used with private class fields and precise types (FetchLike, EventSourceFetchInit) from the eventsource package rather than any where avoidable. CI runs a dependency-review action, a license allowlist check, and CodeQL static analysis on every PR.
What Makes It Unique
smee-client’s specific value is narrowness done well: rather than being a general tunneling tool (like ngrok), it solves exactly one problem — relaying webhook POST bodies from a public SSE channel to a local HTTP target — with careful attention to details that matter in that domain, such as stripping the Host header before re-forwarding (documented as a fix for real server-compatibility issues) and defaulting to environment-aware proxy support so it works transparently behind corporate proxies. It is deliberately unopinionated about what channel service backs it, since any smee.io-compatible SSE source will work with the same client.
Used by 2 apps in this directory
Huly Platform
Project Management · Team Chat · Collaboration
Open-source all-in-one workspace that replaces Linear, Jira, Slack, and Notion for product and engineering teams.
Infisical
Security · Devops
The open-source platform for secrets, certificates, privileged access, and AI agent security — all in one self-hostable system.