Something went wrong. Try again.
Gardenable group chats in the Atmosphere.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187#!/usr/bin/env bash## dev-local — Start the full local Roomy stack for development.## Boots two layers, all on localhost, no tunnel or production services needed:## 1. PLC directory + PLC DB (docker compose, port 3001)# 2. Appserver (host Bun process, port 8080)# 3. app-lite (SvelteKit dev server) (host Vite process, port 5180)## The appserver owns its own event store (local SQLite); no Leaf server is# involved. app-lite talks to the local appserver via VITE_APPSERVER_WS_ORIGIN# (which drives both the sync WebSocket and the XRPC HTTP client — see# commit 47d283e4).## Nothing needs to be publicly exposed: app-lite calls the appserver directly,# and dev OAuth uses the standard atproto loopback client id whose only# redirect is http://127.0.0.1:<app-port>/ — no extra env needed.## Usage:# ./scripts/dev-local # start everything (foreground, Ctrl-C stops all)# ./scripts/dev-local --port 8080 # custom appserver port# ./scripts/dev-local --app-port 5180 # custom app-lite port## Run from the repo root.## Requirements:# - Docker with the compose plugin# - bun and pnpm on PATH (or install via .local)# - Dependencies installed: `pnpm install` at repo root## Notes:# - The first `docker compose up` pull is slow (amd64 images via QEMU on# arm64 hosts). Subsequent starts reuse cached images.# - The appserver SQLite DB lives at packages/appserver/data/ and persists# across restarts. Wipe it (rm packages/appserver/data/*.sqlite) for a# clean slate.set -euo pipefailREPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"cd "$REPO_ROOT"# ── Defaults ──────────────────────────────────────────────────────────────APPSERVER_PORT=8080APP_LITE_PORT=5180while [[ $# -gt 0 ]]; do case "$1" in --port) APPSERVER_PORT="$2"; shift 2 ;; --app-port) APP_LITE_PORT="$2"; shift 2 ;; -h|--help) sed -n '2,/^$/p' "$0" | sed 's/^# \{0,1\}//' exit 0 ;; *) echo "Unknown option: $1"; exit 1 ;; esacdone# ── Preflight ────────────────────────────────────────────────────────────if ! command -v docker >/dev/null 2>&1; then echo "✗ docker not found on PATH." exit 1fiif ! command -v bun >/dev/null 2>&1; then echo "✗ bun not found on PATH." exit 1fiif ! command -v pnpm >/dev/null 2>&1; then echo "✗ pnpm not found on PATH." exit 1fiif [[ ! -d packages/appserver ]] || [[ ! -d packages/app-lite ]]; then echo "✗ Run from the repo root — packages/appserver and packages/app-lite not found." exit 1fiif [[ ! -d node_modules ]]; then echo "✗ node_modules missing. Run 'pnpm install' first." exit 1fi# ── Track child PIDs for cleanup ────────────────────────────────────────PIDS=()cleanup() { echo "" echo "Stopping dev-local …" for pid in "${PIDS[@]}"; do if kill -0 "$pid" 2>/dev/null; then kill "$pid" 2>/dev/null || true fi done # Give them a moment, then force-kill sleep 1 for pid in "${PIDS[@]}"; do kill -9 "$pid" 2>/dev/null || true done}trap cleanup EXIT INT TERM# ── 1. PLC directory (docker compose) ────────────────────────────────────echo "▸ Starting local PLC directory (docker compose) …"# The compose file declares the network as external — create it if missing.if ! docker network inspect roomy-dev >/dev/null 2>&1; then echo " creating network roomy-dev …" docker network create roomy-dev >/dev/nullfidocker compose up plc-directory plc-db -d# ── 2. Appserver (host Bun process) ──────────────────────────────────────echo "▸ Starting appserver on port $APPSERVER_PORT …"# Use the REAL PLC directory for DID resolution — the local PLC only has# test DIDs, but JWT verification needs to resolve the PDS's signing key# (e.g. bsky.social's DID) which lives in the real PLC directory.APPSERVER_ENV=( "PORT=$APPSERVER_PORT" "APPSERVER_DID=did:web:localhost" "APPSERVER_ORIGIN=http://localhost:$APPSERVER_PORT" "CORS_ORIGIN=*" "PLC_DIRECTORY_URL=https://plc.directory")# Export and runenv "${APPSERVER_ENV[@]}" \ bun run --watch packages/appserver/src/index.ts &APPSERVER_PID=$!PIDS+=("$APPSERVER_PID")echo " waiting for appserver to be ready …"for i in $(seq 1 15); do if curl -sf -o /dev/null "http://127.0.0.1:$APPSERVER_PORT/xrpc/space.roomy.space.getSpaces" 2>/dev/null; then echo " ✔ appserver ready (port $APPSERVER_PORT)" break fi sleep 1 [[ $i -eq 15 ]] && { echo "✗ appserver did not start in 15s"; exit 1; }done# Pass through PUBLIC_TEST_* vars from packages/app-lite/.env if present,# enabling headless E2E testing via app-password auto-login.TEST_ENV=()if [[ -f packages/app-lite/.env ]]; then while IFS= read -r line; do case "$line" in PUBLIC_TEST_IDENTIFIER=*) TEST_ENV+=("$line") ;; PUBLIC_TEST_APP_PASSWORD=*) TEST_ENV+=("$line") ;; esac done < packages/app-lite/.envfienv "${TEST_ENV[@]}" \VITE_APPSERVER_DID=did:web:localhost \VITE_APPSERVER_WS_ORIGIN=ws://127.0.0.1:$APPSERVER_PORT \PUBLIC_WEB_ORIGIN=http://127.0.0.1:$APP_LITE_PORT \VITE_PUBLIC_WEB_ORIGIN=http://127.0.0.1:$APP_LITE_PORT \VITE_PORT=$APP_LITE_PORT \ pnpm --filter app-lite exec vite dev --host 127.0.0.1 --port "$APP_LITE_PORT" &APP_LITE_PID=$!PIDS+=("$APP_LITE_PID")echo " waiting for app-lite to be ready …"for i in $(seq 1 20); do if curl -sf -o /dev/null "http://127.0.0.1:$APP_LITE_PORT/" 2>/dev/null; then echo " ✔ app-lite ready (port $APP_LITE_PORT)" break fi sleep 1 [[ $i -eq 20 ]] && { echo "✗ app-lite did not start in 20s"; exit 1; }done# ── Done ─────────────────────────────────────────────────────────────────echo ""echo "════════════════════════════════════════════════════════════════"echo " Roomy local dev stack is running."echo ""echo " app-lite: http://127.0.0.1:$APP_LITE_PORT/"echo " appserver: http://127.0.0.1:$APPSERVER_PORT/"echo " plc-dir: http://127.0.0.1:3001/ (local)"echo ""echo " Press Ctrl-C to stop everything."echo "════════════════════════════════════════════════════════════════"# Wait for either process to exit (or Ctrl-C)wait