See the best posts from any Bluesky account

README.md

❤️ favs.blue #

A favstar.fm-style web app for Bluesky: type any handle and see that user's most-liked or most-reposted posts, filterable by "all time" or "last month."

Live engagement comes from the Bluesky Jetstream firehose. The first time a handle is looked up, a backfill job pulls historical posts from the Bluesky AppView API.

Stack: TypeScript / AdonisJS, Postgres for engagement counters and metadata, Edge.js templates with Alpine.js (CSP build) on the frontend. Ships as one Docker image with three process entrypoints (web, jetstream consumer, worker).

Local development #

Prerequisites: Mise, Docker.

# 1. Install Node/pnpm
mise trust && mise install

# 1. Copy the env template and generate an APP_KEY
cp .env.example .env
node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"
# paste the output into APP_KEY in .env

# 2. Start Postgres
docker compose up postgres -d

# 3. Install dependencies
pnpm install

# 4. Run migrations and start all three processes
pnpm dev

pnpm dev runs the web server, jetstream consumer, and worker concurrently with hot-reload. The app is at http://localhost:3333.

The first profile lookup for a new handle shows a progress bar while backfill runs. Live engagement updates flow in once the jetstream consumer has been running.

Useful commands #

pnpm test                 # Japa test runner
pnpm lint                 # eslint
pnpm typecheck            # tsc --noEmit
pnpm format               # prettier --write
pnpm build                # production build

# Run a single test file
node ace test --files "tests/unit/services/jetstream_consumer.spec.ts"

# Apply Postgres migrations
node ace migration:run --force

Production (Docker Swarm) #

The repository ships a docker-compose.yml configured for docker stack deploy.

Architecture #

Three process entrypoints:

  • HTTP web server (bin/server.ts) — controllers in app/controllers/, routes in start/routes.ts. Profile pages at /profile/:handle/likes|reposts are the main product surface.
  • Jetstream consumer (node ace jetstream:consume) — connects to the Bluesky Jetstream WebSocket, filters for tracked DIDs, writes per-post engagement counter deltas to Postgres atomically with the cursor, and persists cursor position so it can resume after restart.
  • Worker (node ace worker:run) — pg-boss worker that runs backfill jobs (fetch historical posts from AppView on first lookup) and scheduled cron tasks (engagement lookup pruning).

Configuration #

See .env.example for the full list of environment variables. start/env.ts is the source of truth — variables are validated there at boot.

License #

See LICENSE.