beam

Design notes

The sticky decisions behind beam — idFromName, hibernation, base64 envelopes, kong.

beam is small on purpose. A handful of decisions do most of the work; here's why each one is the way it is.

Name = identity

idFromName(name) makes routing trivially consistent: the Durable Object that accepted the WebSocket is exactly the one a delivery lands on. There's no registry mapping names to connections, no pub/sub fan-out layer — the addressing is the routing. A name maps 1:1 to a DO instance, globally.

Hibernation by default

acceptWebSocket plus a ping/pong auto-response pair means an idle tunnel isn't pinned in memory. Two payoffs:

  • Idle tunnels cost ~nothing — the DO can be evicted while the socket sleeps.
  • Reconnects survive eviction — the hibernation API restores the socket cleanly, and the CLI's backoff loop reconnects if anything does drop.

Constant-time token check, before the DO

Auth runs in the Worker, before the upgrade reaches the Durable Object — so failed auth never touches durable state. The comparison is constant-time so the token isn't probeable by timing. See the Security model.

Base64 envelope

Bodies ride inside a JSON frame as base64 so binary payloads survive the WebSocket transport; the CLI decodes and replays verbatim. The trade-off is the WebSocket frame cap (~1 MiB), which bounds payload size — acceptable for webhooks, which are almost always small JSON.

Fire-and-forget v1

The sender gets an immediate 202 and the local response is not relayed back. Most providers only want a 2xx to mark the webhook delivered, and not waiting on localhost keeps the edge simple and fast. Round-tripping the real response is the obvious next step — see the FAQ.

kong for the CLI

The CLI is a kong command struct, with env-var fallbacks layered under the config file. That gives a clean beam webhook listen|send <name> tree, generated help, and the flag > env > config > default precedence for free.

The whole system

One Worker, one Durable Object class, one Go binary. That's the system.

DecisionWhy
idFromNameRouting == addressing; no registry.
Hibernation APIIdle tunnels are free; reconnects survive eviction.
Constant-time authToken isn't timing-probeable; failures skip durable state.
Base64 envelopeBinary-safe payloads over JSON frames.
Fire-and-forgetSimple, fast edge; providers only need a 2xx.
kong + env + configOne ergonomic CLI, zero-flag in the common case.

On this page