diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..50188e9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +.git +**/node_modules +.env +.env.* +!.env.example diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7005b56..caa533c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,6 +41,57 @@ jobs: - name: Test run: pnpm test + # dev2 runs services/api on Bun (see Dockerfile). vitest above stays the gate; + # this job runs the API's portable tests under the runtime prod uses and + # boots the built API on Bun against Postgres. Files using vitest-only APIs + # (vi.stubEnv / vi.stubGlobal / vi.mocked ...) are skipped here. + api-bun: + runs-on: ubuntu-latest + services: + postgres: + image: postgres:16-alpine + env: + POSTGRES_HOST_AUTH_METHOD: trust # throwaway CI database, no password + ports: ["5432:5432"] + options: >- + --health-cmd "pg_isready -U postgres" --health-interval 2s + --health-timeout 5s --health-retries 20 + env: + DATABASE_URL: postgres://postgres@127.0.0.1:5432/postgres + steps: + - uses: actions/checkout@v5 + - uses: pnpm/action-setup@v6 + - uses: actions/setup-node@v5 + with: + node-version-file: .nvmrc + cache: pnpm + - uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.4.0 # keep in step with BUN_IMAGE in the Dockerfile + + - name: Install + build the API + run: | + pnpm install --frozen-lockfile --filter @tronbrowser/api... + pnpm --filter @tronbrowser/browser-core --filter @tronbrowser/agent-runtime --filter @tronbrowser/sdk --filter @tronbrowser/api build + + - name: Portable API tests under bun test + working-directory: services/api + run: | + set -e + for f in $(git ls-files 'src/*.test.ts' 'src/*.test.js' | xargs grep -L -E 'vi\.(stub|unstub|mocked|importActual|hoisted|mock\()'); do + echo "::group::bun test $f"; bun test "./$f"; echo "::endgroup::" + done + + - name: Migrate + boot the API on Bun + run: | + set -e + MIGRATIONS_DIR=packages/storage/migrations-pg bun scripts/db-migrate.mjs + PORT=8090 bun services/api/dist/index.js > api.log 2>&1 & + for i in $(seq 1 30); do curl -fsS http://127.0.0.1:8090/api/healthz && break; sleep 1; done + curl -fsS http://127.0.0.1:8090/api/1/push + curl -fsS http://127.0.0.1:8090/api/store/extensions + cat api.log + # package + release jobs are stubbed until the Chromium build lands in CI. package: runs-on: ubuntu-latest diff --git a/Dockerfile b/Dockerfile index f0ae2fc..1901ead 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,12 @@ ARG UNGOOGLED_CHROMIUM_VERSION=152.0.7977.82-1 ARG OBSCURA_VERSION=0.2.2 +# The API runs on Bun (fleet Node -> Bun migration). The repo itself stays a +# pnpm workspace on Node 24 (desktop, mobile, extensions and release builds use +# it), so pnpm still builds the API below; only the container's runtime moves. +ARG BUN_IMAGE=oven/bun:1.4.0-slim + +FROM ${BUN_IMAGE} AS bun # --- build the API (a pnpm workspace member: it imports @tronbrowser/sdk) --- FROM node:24-bookworm-slim AS api @@ -40,11 +46,13 @@ RUN set -eu; arch="$(uname -m)"; case "$arch" in x86_64) uc=x86_64; ob=x86_64 ;; | tar -xz -C /opt/obscura; \ test -x /opt/obscura/obscura -# --- final: caddy + node + tor + the engines --- +# --- final: caddy + bun + tor + the engines --- # Debian rather than Alpine: the portable ungoogled-chromium and Obscura are -# glibc binaries. Caddy is a static binary, copied from its own image. -FROM node:24-bookworm-slim +# glibc binaries. Caddy and Bun are single binaries, copied from their images. +# There is no Node in this stage: the API and the migration runner run on Bun. +FROM debian:bookworm-slim COPY --from=caddy:2 /usr/bin/caddy /usr/bin/caddy +COPY --from=bun /usr/local/bin/bun /usr/local/bin/bun # openssh-client: the store provisions BBS publisher accounts and generates # ed25519 keypairs via `ssh`/`ssh-keygen` (services/api/src/store/fileshost.ts). # tor: runs a Tor v3 hidden service in this same container so tronbrowser.dev is diff --git a/start.sh b/start.sh index 3876123..6ae4d7d 100644 --- a/start.sh +++ b/start.sh @@ -4,8 +4,8 @@ set -e # Apply any pending DB migrations on boot (idempotent, forward-only). Non-fatal: # a transient DB hiccup shouldn't block the whole service from starting. -MIGRATIONS_DIR=/api/migrations node /api/db-migrate.mjs || echo "[migrate] FAILED — continuing" -PORT=8090 node /api/dist/index.js & +MIGRATIONS_DIR=/api/migrations bun /api/db-migrate.mjs || echo "[migrate] FAILED — continuing" +PORT=8090 bun /api/dist/index.js & # --- Tor v3 hidden service --------------------------------------------------- # Expose the site over a stable .onion. Tor forwards onion:80 -> Caddy on $PORT