Skip to content

Run aiornot.vote on Bun instead of Node + pnpm (nixpacks) - #174

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

ralyodio merged 3 commits 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.

What changes

  • Lockfile: bun.lock migrated from pnpm-lock.yaml with the old lock still present, so every version is kept (all 519 pnpm entries match). packageManager: bun@1.4.0, workspaces moved into package.json, trustedDependencies replaces pnpm.onlyBuiltDependencies.
  • Image: .nixpacks/Dockerfile (the path dev2's compose builds) is now a hand-written oven/bun:1.4.0-slim image. It has production deps only, runs as USER bun with every source COPY --chowned, and has a HEALTHCHECK. The start sequence is unchanged: migrate, seed:tags, seed:demo, the media daemon in the background, then bun --bun next start. The nixpacks .nix and build.sh are removed.
  • CLIs: the db/worker scripts run as bun <file>.ts instead of through tsx.
  • next.config.ts -> next.config.mjs: next start loads a .ts config through typescript, which is a devDependency the production image doesn't install. Without the rename, Next tries npm install typescript at boot and the container exits.
  • Workspace-root lookup (local file: DB and the .media default) now looks for bun.lock, since pnpm-workspace.yaml is gone. Prod sets DATABASE_URL and MEDIA_STORAGE_DIR, so the lookup doesn't affect it.
  • CI on Bun: typecheck, vitest (still the gate, because the suite uses vi.hoisted/vi.stubEnv/vi.stubGlobal), the portable 22 files / 127 tests under bun test, the build, then a boot under Bun that renders pages and the OG PNG. A non-blocking bun audit job is added.

Verified (image built from the commit, with group-only file modes like dev2's checkout)

  • Web only, with dev2's env, against the live DB: 16 routes (pages, RSS, sitemap, robots, llms.txt, OG image, /media/*, /_next/image webp + jpeg, GPTBot 402). Statuses and content match the live Node site. The OG PNG, media file and robots/llms.txt are byte-identical, and so is /_next/image output size. The only text differences are the random tip and one media item the live daemon added mid-check.
  • Full CMD against a throwaway local Postgres: 0000_init.sql migration, tag and demo seeds, and the daemon started under Bun. Signup, login and a wrong-password 401 work, which exercises argon2 under Bun. A sharp -> webp write to the media volume as uid 1000 is served back by /media. The container reached healthy, and docker stop took 0.6 s.
  • The prod volume is 777 (dirs) / 644 (files, root), so uid 1000 can add new media.

🤖 Generated with Claude Code

ralyodio and others added 3 commits October 1, 2026 13:59
- bun.lock migrated from pnpm-lock.yaml (every version kept), packageManager
  bun@1.4.0, workspaces in package.json, trustedDependencies in place of
  pnpm.onlyBuiltDependencies
- .nixpacks/Dockerfile (the path dev2's compose builds) is now a hand-written
  oven/bun:1.4.0-slim image: production-only deps, USER bun, HEALTHCHECK.
  Same start sequence as before: migrate, seed:tags, seed:demo, the media
  daemon in the background, then `bun --bun next start`
- db/worker CLIs run with bun directly instead of tsx
- workspace-root lookup keys on bun.lock now that pnpm-workspace.yaml is gone
- CI on Bun: typecheck, vitest (still the gate), the portable suite under
  bun test, build, boot under Bun and render pages + the OG image; bun audit

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The production image installs runtime deps only, and next start loads a .ts
config through the typescript package; without it Next tries to npm install
it at boot and the container exits.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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

11 finding(s)

MEDIUM: 9 | LOW: 2

Severity Rule Location
MEDIUM js-unescaped-html-sink apps/web/app/about/page.tsx:40
MEDIUM sql-template-interpolation apps/web/app/api/admin/media/[id]/route.ts:30
MEDIUM sql-template-interpolation apps/web/app/api/admin/tags/[id]/route.ts:22
MEDIUM sql-template-interpolation apps/web/app/api/admin/users/[id]/route.ts:23
MEDIUM js-unescaped-html-sink apps/web/app/layout.tsx:56
MEDIUM js-unescaped-html-sink apps/web/app/pricing/page.tsx:17
MEDIUM js-unescaped-html-sink apps/web/components/NewsletterComposer.tsx:87
MEDIUM sql-template-interpolation apps/web/lib/queries.ts:169
MEDIUM sql-template-interpolation apps/web/lib/rewards.ts:198
LOW sql-template-interpolation apps/web/lib/rewards.test.ts:86
LOW js-unescaped-html-sink docs/design_handoff_aiornot_vote/image-slot.js:455

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit f9c4385 into master Oct 1, 2026
6 of 7 checks passed
@ralyodio
ralyodio deleted the chore/bun-runtime branch October 1, 2026 14:11
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