Connects to the Bluesky Jetstream WebSocket firehose and republishes post-create events to a Redis Pub/Sub channel.

Files
README.md

jetstream-relay #

Connects to the Bluesky Jetstream WebSocket firehose and republishes post-create events to a Redis Pub/Sub channel. This allows multiple downstream consumers to subscribe to the Redis channel independently, without each needing its own Jetstream connection.

How it works #

  1. Opens a WebSocket connection to one of the Jetstream endpoints (US-East / US-West, with automatic failover across four servers).
  2. Filters for app.bsky.feed.post events and validates them with Zod via @vinerima/jetstream-types.
  3. Publishes each validated post-create event as JSON to a configurable Redis Pub/Sub channel.
  4. Tracks the time_us cursor of the last successfully published event, persists it to Redis, and resumes from it on reconnects and restarts.

Delivery semantics #

  • At-least-once across reconnects. The relay resumes from the cursor of the last event that reached Redis, so events around a disconnect or restart are replayed and consumers may see duplicates. Deduplicate by time_us + did (or commit.rev) if duplicates matter to you.
  • Pub/Sub is fire-and-forget. Redis Pub/Sub does not buffer for disconnected subscribers — consumers only receive events while subscribed. If consumers must not miss events while offline, put a Redis Streams consumer behind the channel (or adapt the relay to XADD).
  • Fail-fast on outages. While Redis is unreachable, publishes fail immediately (nothing buffers in process memory) and the cursor stops advancing, so the missed window is replayed once Redis recovers. If every Jetstream endpoint stays unreachable through all reconnect cycles, the process exits with code 1 — run it under a supervisor (systemd, Docker --restart, pm2) so it gets restarted.

Prerequisites #

  • Node.js (v20+)
  • A running Redis instance

Configuration #

Variable Default Description
REDIS_URL redis://localhost:6379 Redis connection string
REDIS_CHANNEL jetstream:posts Pub/Sub channel name
REDIS_CURSOR_KEY jetstream:cursor Redis key the cursor is persisted to (every 5s and on shutdown)

Running the relay #

1. Install dependencies #

pnpm install

2. Start Redis #

The relay requires a running Redis instance. If you don't have one, install and start it:

# macOS (Homebrew)
brew install redis
brew services start redis

# or run in the foreground
redis-server
# Docker
docker run -d --name redis -p 6379:6379 redis:7-alpine

To use a remote or non-default Redis instance, set REDIS_URL:

export REDIS_URL=redis://your-host:6379

3. Start the relay #

# development
pnpm start

# production
pnpm build
node dist/index.js

You can verify events are flowing by subscribing to the channel in a separate terminal:

redis-cli SUBSCRIBE jetstream:posts

Tests #

pnpm test

Dependencies #

License #

MIT