Skip to content

Run on Bun: bun install, bun --bun next, standalone server under Bun - #263

Merged
ralyodio merged 1 commit into
masterfrom
chore/bun-runtime
Oct 1, 2026
Merged

ralyodio merged 1 commit into
masterfrom
chore/bun-runtime

Conversation

@ralyodio

@ralyodio ralyodio commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Part of the fleet Node → Bun migration (recipe from the phonenumbers.bot pilot). qrypt.chat moves off Node + pnpm onto Bun as package manager, runtime and test runtime.

Changes

  • Lockfile: bun.lock is migrated from pnpm-lock.yaml, so every resolved version is unchanged (next 15.5.19, react 19.2.7, supabase-js 2.74.0, sharp 0.34.4, ...). Bun's migration writes the github: dependency @profullstack/autoblog with an empty cache key, and a frozen install then fails. That one entry now carries the key a fresh resolve writes. pnpm's onlyBuiltDependencies becomes trustedDependencies. pnpm-workspace.yaml, .nvmrc and engines.node are removed.
  • Runtime: the scripts run bun --bun next. next.config.js builds standalone and names community-plugins/ in the tracing includes, because /api/plugins reads that folder from process.cwd() at request time.
  • Image: the base is oven/bun:1.4.0-slim (Debian trixie) with tor and tini. The same entrypoint.sh now starts bun server.js instead of pnpm next start.
    • Unchanged: port 8080, the NEXT_PUBLIC_*/PUBLIC_*/VITE_* build args dev2's compose passes, the onion-key volume, and root at startup (Tor needs it).
    • Secret ARGs that the compose never passed are no longer declared.
  • Tests and CI:
    • vitest now runs on the Bun runtime (bun --bun vitest run); all 560 tests pass.
    • The test workflow installs with Bun, runs them, then builds and boots the standalone server under Bun.
    • npm audit becomes bun audit.

Verified locally

I built the image from git archive HEAD through a compose file shaped like dev2's (same build args, env file, port, memory limit and tor volume) and compared it with live https://qrypt.chat.

  • docker top shows bun server.js beside tor.
  • Pages match live:
    • /, /auth, /warrant-canary and /blog return 200 with the same title and sizes; the only differences are a few bytes of build id.
    • /blog/rss.xml (1.65 MB, from Supabase) is byte-identical.
    • A blog post (Supabase) returns 200 within 8 bytes of live.
  • Other routes:
    • /robots.txt, /manifest.json, /llms.txt and /api/plugins (which reads files from disk) are byte-identical.
    • /sitemap.xml differs only in lastmod.
  • /blog and the RSS feed are ISR (revalidate = 60). They prerender empty at build time, because the service key is runtime-only, exactly as on Node, and fill on the first revalidation.
  • Memory was 207 MiB including tor. The container stops in 0.6 s.

Next stays on 15.5.x: this PR swaps the runtime only.

🤖 Generated with Claude Code

Moves qrypt.chat off Node + pnpm onto Bun, following the fleet recipe
(phonenumbers.bot pilot; hqtui and outreachgraph run Next standalone the same way).

- Package manager: bun.lock migrated from pnpm-lock.yaml, so every resolved
  version is unchanged (next 15.5.19, react 19.2.7, supabase-js 2.74.0, ...).
  Bun's migration leaves the github: dependency (@profullstack/autoblog) with an
  empty cache key, which fails install; that one entry carries the key a fresh
  resolve writes. pnpm's onlyBuiltDependencies becomes trustedDependencies;
  pnpm-workspace.yaml, .nvmrc and engines.node go.
- Runtime: scripts use `bun --bun next`; next.config builds standalone and names
  community-plugins/ for /api/plugins, which reads it from process.cwd().
- Image: oven/bun:1.4.0-slim (Debian trixie) with tor + tini, the same
  entrypoint now starting `bun server.js`. Port 8080, the build args dev2's
  compose passes, the onion volume and root (Tor needs it at startup) unchanged.
  Build-arg secrets the compose never passed are no longer declared.
- Tests: vitest now runs on the Bun runtime (560/560 pass); CI installs with
  bun, runs them, builds and boots the standalone server under Bun. npm audit
  becomes bun audit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

ThreatCrush Security Scan

13 finding(s)

MEDIUM: 9 | LOW: 4

Severity Rule Location
MEDIUM redos-nested-quantifier src/app/api/profile/update/route.js:73
MEDIUM js-unescaped-html-sink src/app/blog/[slug]/page.jsx:38
MEDIUM js-unescaped-html-sink src/app/blog/[slug]/page.jsx:66
MEDIUM js-unescaped-html-sink src/app/faq/page.jsx:57
MEDIUM js-unescaped-html-sink src/app/layout.jsx:137
MEDIUM js-unescaped-html-sink src/app/layout.jsx:141
MEDIUM js-unescaped-html-sink src/app/page.jsx:47
MEDIUM redos-nested-quantifier src/lib/auth/dns-name.js:88
MEDIUM js-unescaped-html-sink src/lib/components/chat/MessageItem.jsx:60
LOW secret-generic-credential src/app/api/auth/register-anon/route.test.js:32
LOW secret-jwt tests/debug-sms.js:10
LOW secret-generic-credential tests/private-key-import-export.test.js:252
LOW secret-generic-credential tests/private-key-import-export.test.js:264

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio

ralyodio commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

The red bun audit job is non-gating (continue-on-error; the security workflow still passes). It flags 2 critical Next.js advisories on next@15.5.19 (fixed in 15.5.24), which is what production already runs: master's npm audit only passed because it ran npm install without the pnpm lock and resolved the newest 15.x. Bun reads the real lockfile. The Next bump is a separate pass, deliberately kept out of this runtime-only change.

🤖 Generated with Claude Code

@ralyodio
ralyodio merged commit d1c0493 into master Oct 1, 2026
10 of 11 checks passed
@ralyodio
ralyodio deleted the chore/bun-runtime branch October 1, 2026 14:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant