smee-client

A CLI and Node client that forwards webhooks from smee.io to your local development server.

Tool
npm
v5.0.0
556stars
ISC

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
76/100Good
Development Activity76
Maintenance64
Community76
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
74/100Good
Architecture78
Code Quality82
Innovation55
Learning Curve80

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 smee CLI command that creates or connects to a smee.io channel and forwards events to a local port with a single call
  • An importable SmeeClient class for programmatic use inside Node apps, with start()/stop() and dynamic startForwarding()/stopForwarding() controls
  • Automatic respect for standard HTTP/HTTPS proxy environment variables via undici’s EnvHttpProxyAgent
  • 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 SmeeClient API
  • Running a shared, disposable webhook relay in CI or a demo environment via the CLI’s --url/--target flags

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.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search