Skip to content
This repository was archived by the owner on May 11, 2026. It is now read-only.

chore: migrate package manager from Yarn to Bun#638

Merged
bonustrack merged 8 commits into
masterfrom
feat/bun-support
May 8, 2026
Merged

chore: migrate package manager from Yarn to Bun#638
bonustrack merged 8 commits into
masterfrom
feat/bun-support

Conversation

@bonustrack

Copy link
Copy Markdown
Member

Summary

  • Swap yarn.lockbun.lock; package.json scripts now invoke bun run / bunx instead of yarn
  • Pin prettier, @snapshot-labs/eslint-config, @snapshot-labs/prettier-config to exact versions and add a single overrides entry for @snapshot-labs/eslint-config-base@0.1.0-beta.18 to preserve the resolutions yarn had (Bun's stricter prerelease semver would otherwise pull newer stables that break lint cleanliness)
  • Point CI workflows at snapshot-labs/actions@feat/bun-support with package_manager: bun

Notes

  • bun install, bun run lint, and bun run typecheck pass cleanly locally
  • CI on this branch will stay red until snapshot-labs/actions#feat/bun-support is fixed: that PR currently uses bun test / bun build in the reusable workflow, which invoke Bun's built-in test runner / bundler instead of the package.json scripts. They need to be bun run test / bun run build
  • Once the actions PR lands on main, repoint the three workflow files from @feat/bun-support@main
  • Holding off on dropping ts-node/nodemon (Bun could replace them natively) for a later pass to keep this diff minimal

Test plan

  • bun install produces a clean bun.lock
  • bun run lint passes
  • bun run typecheck passes
  • bun run test:setup && bun run test passes against local MySQL/Redis
  • CI lint job green after actions PR merges
  • CI test job green after actions PR merges
  • CI sentry-release job green on master after actions PR merges

🤖 Generated with Claude Code

bonustrack and others added 4 commits May 5, 2026 02:16
Swaps yarn.lock for bun.lock and updates package.json scripts to invoke
`bun run` / `bunx` instead of `yarn`. Doc comments in scripts/ and the
test setup error message are updated accordingly.

Three deps are pinned to exact versions to preserve the resolutions
yarn.lock had (Bun's stricter prerelease semver otherwise upgrades the
shared lint/format configs and breaks lint cleanliness):
- prettier 3.0.3
- @snapshot-labs/eslint-config 0.1.0-beta.18
- @snapshot-labs/prettier-config 0.1.0-beta.7

A single `overrides` entry pins @snapshot-labs/eslint-config-base to
0.1.0-beta.18 for the same reason.

CI workflows are pointed at snapshot-labs/actions@feat/bun-support with
`package_manager: bun`; will need to be repointed to @main once that PR
lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ts-jest, jest, jest-environment-node-single-context, @types/jest, and
lodash drifted upward when Bun resolved fresh against the ^x.y.z
ranges. ts-jest 29.4 in particular was 35x slower at compiling the
test suite (~1s under 29.1.1, >30s under 29.4.9), which pushed the CI
test step past the 2-minute timeout.

Pins them to the exact versions yarn.lock had to keep test behavior
unchanged across the package-manager swap.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@snapshot-labs/snapshot.js requests ajv ^8.11.0; yarn happened to lock
this at 8.11.0, but Bun resolves fresh and gets 8.20.0, which generates
invalid JS in compiled validators ("SyntaxError: Unexpected token ':'")
for the snapshot.js space schema. This caused 19 test failures in CI.

Adding ajv@8.11.0 as a direct dependency hoists it to root, so
snapshot.js picks it up. eslint's transitive ajv (^6.x) lands nested
under node_modules/eslint/node_modules/ajv and stays untouched.

A scoped override would have been cleaner but Bun does not yet support
nested overrides (oven-sh/bun#6608).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@snapshot-labs/pineapple requests ofetch ^1.3.3; yarn locked 1.3.3 but
Bun resolves to 1.5.1 fresh, which breaks the integration tests in
test/integration/ingestor.test.ts (real pin calls return "pinning
failed" instead of succeeding).

Pineapple is the only consumer of ofetch in this project, so a global
override is safe.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bonustrack
bonustrack requested review from ChaituVR and wa0x6e and removed request for wa0x6e May 4, 2026 21:55
@bonustrack

bonustrack commented May 4, 2026

Copy link
Copy Markdown
Member Author

This PR is deployed in production in livenet and testnet already

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates this Node/TypeScript service from Yarn to Bun by updating package scripts, CI workflow inputs, and developer-facing script instructions. The goal is to keep local development and CI aligned on Bun while preserving existing lint/test/build behavior.

Changes:

  • Replaced Yarn-oriented package scripts and usage messages with Bun equivalents (bun run / bunx).
  • Updated reusable GitHub Actions workflows to pass package_manager: bun and consume a Bun-support branch.
  • Pinned several dependency versions and added package overrides to stabilize Bun resolution behavior.

Reviewed changes

Copilot reviewed 12 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/setup.ts Updates test DB setup guidance from Yarn to Bun.
scripts/refresh-space-leaderboard.ts Updates script usage comment to Bun.
scripts/refresh_spaces_counters.ts Updates script usage comment to Bun.
scripts/refresh_leaderboard_counters.ts Updates script usage comment to Bun.
scripts/init_leaderboard_counters.ts Updates script usage comment to Bun.
scripts/import-statements.ts Updates script usage comment to Bun.
scripts/import-skins.ts Updates script usage comment to Bun.
scripts/hibernate.ts Updates CLI error message to Bun.
package.json Converts scripts to Bun, pins dependency versions, and adds overrides.
.github/workflows/test.yml Switches test workflow to Bun-enabled reusable workflow.
.github/workflows/lint.yml Switches lint workflow to Bun-enabled reusable workflow.
.github/workflows/create-sentry-release.yml Switches release workflow to Bun-enabled reusable workflow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/test.yml Outdated
jobs:
test:
uses: snapshot-labs/actions/.github/workflows/test.yml@main
uses: snapshot-labs/actions/.github/workflows/test.yml@feat/bun-support
jobs:
create-sentry-release:
uses: snapshot-labs/actions/.github/workflows/create-sentry-release.yml@main
uses: snapshot-labs/actions/.github/workflows/create-sentry-release.yml@feat/bun-support
Comment thread package.json
Comment on lines +54 to +56
"overrides": {
"@snapshot-labs/eslint-config-base": "0.1.0-beta.18",
"ofetch": "1.3.3"
Comment thread package.json
"@snapshot-labs/snapshot-metrics": "^1.4.1",
"@snapshot-labs/snapshot-sentry": "^1.5.5",
"@snapshot-labs/snapshot.js": "^0.14.20",
"ajv": "8.11.0",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this new dependency ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ajv is not used directly by sequencer, and will be cleaned up by a agent in the future.

@tony8713 what is adding this dependency resolving ? is there other way to do it ?

@wa0x6e wa0x6e left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tAck

Not a fan of this undocumented ajv dependency hack, as it can be cleaned in a future PR by someone not aware of this workaround.

A cleaner way would be to just upgrade s.js to use the newer ajv version

@tony8713

tony8713 commented May 7, 2026

Copy link
Copy Markdown

@wa0x6e following up on the ajv override comment — opened snapshot-labs/snapshot.js#1197 to pin ajv exact at 8.11.0 inside snapshot.js itself. Once that ships in 0.14.21 I'll bump snapshot.js here and drop the direct ajv dependency from this PR.

Quick context on why pinning rather than upgrading: I ran the bisect locally (bun + jest + ts-jest, like CI). ajv-errors@3.0.0 emits {"str":"errN"}.keyword instead of errN.keyword in compiled validators when paired with ajv@8.20.0, throwing SyntaxError: Unexpected token ':'. ajv-errors has no newer release and there's no working ajv 8.21+ yet, so until one of those moves we can't actually use a "newer" ajv. Pinning at the snapshot.js source means downstream services don't each need to repeat the override.

bonustrack pushed a commit to snapshot-labs/snapshot.js that referenced this pull request May 7, 2026
Tightens the ajv constraint from `^8.11.0` to an exact pin so transitive
resolution is deterministic across yarn/bun/npm consumers.

Why: ajv-errors@3.0.0 (latest) emits broken validator code when paired
with ajv@8.20.0 — compiled validators reference `{"str":"errN"}.keyword`
instead of `errN.keyword`, throwing `SyntaxError: Unexpected token ':'`
at runtime. This surfaces in downstream services that use bun (which
resolves `^8.11.0` to the latest 8.20.0) but not yarn (which had locked
8.11.0 historically). 8.11.0 is the version production has been running
on for years.

Pinning here means consumers no longer need their own `ajv` overrides
(see snapshot-labs/snapshot-sequencer#638 for the workaround this lets
them drop).

Co-authored-by: Tony <tony@Tonys-Mac-mini.local>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0.14.21 pins ajv at exact 8.11.0 (was ^8.11.0), which prevents bun from
resolving snapshot.js's transitive ajv to the broken 8.20.0 (codegen bug
in `ajv-errors@3.0.0` paired with ajv@8.20.0 — `SyntaxError: Unexpected
token ':'`).

The direct `ajv: 8.11.0` dep stays because bun's hoisting still installs
separate ajv copies under snapshot.js / ajv-formats / ajv-errors when
their peer ajv constraint is `^8.0.0` rather than `8.11.0` — different
copies break ajv-errors's vocabulary registration even when versions
match. Forcing a single ajv at root (via this direct dep) is still the
only way to deduplicate until bun supports nested overrides.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tony8713

tony8713 commented May 7, 2026

Copy link
Copy Markdown

Pushed 08c838b on this branch — bumps @snapshot-labs/snapshot.js 0.14.20 → 0.14.21.

About the ajv: 8.11.0 direct dep — I tried to drop it as part of this bump and it didn't quite work. Honest write-up:

What 0.14.21 ships
snapshot-labs/snapshot.js#1197 tightens the ajv constraint inside snapshot.js from ^8.11.0 to exact 8.11.0. So now snapshot.js can never resolve to the broken ajv@8.20.0 regardless of which package manager pulls it.

Why the sequencer's ajv dep still has to stay (verified locally)
With the bump but the direct ajv dep removed:

  • node_modules/ajv resolves to 6.15.0 (eslint's transitive copy lands at root because nothing else fights for that slot).
  • snapshot.js, ajv-formats, ajv-errors each get their own nested ajv@8.11.0.
  • They're the right version now but they're three different constructor identities, which breaks ajv-errors's vocabulary registration — same SyntaxError: Unexpected token ':' from compiled validators. 63 unit tests fail.

With the bump + the direct ajv: 8.11.0 retained:

  • node_modules/ajv is 8.11.0 at root, shared by snapshot.js / ajv-formats / ajv-errors.
  • eslint/node_modules/ajv and @eslint/eslintrc/node_modules/ajv stay nested at 6.15.0.
  • Schema-validation tests (spaceValidation.test.ts, envelope.test.ts) pass; lint + typecheck clean.

I also tried "overrides": { "ajv": "8.11.0" } at the top level — it forces the override into eslint's tree too, eslint can't find a 6.x ajv, and bun run lint crashes. Scoped overrides like "@snapshot-labs/snapshot.js > ajv" aren't supported by bun yet (oven-sh/bun#6608).

So the snapshot.js pin is now defense-in-depth (no consumer can accidentally pull ajv@8.20.0), and the sequencer's direct ajv dep is the deduplication lever — which is the part bun's hoisting still requires until #6608 ships. Happy to add a code comment near the dep referencing this, if useful.

Add a //ajv field explaining that the explicit ajv dependency exists
purely to force bun to hoist a single ajv 8.x copy at the root, since
bun won't dedupe ajv across snapshot.js / ajv-formats / ajv-errors when
eslint's transitive ajv@^6.x is also in the tree. Without it, each
8.x consumer gets its own nested copy (same version, different module
identities) and ajv-errors's vocabulary registration breaks.

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

@wa0x6e wa0x6e left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tAck

@bonustrack
bonustrack merged commit f577889 into master May 8, 2026
2 checks passed
@bonustrack
bonustrack deleted the feat/bun-support branch May 8, 2026 07:54
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants