Skip to content

chore: fix CI — replace ESLint with Biome, unbreak fastify 5 and native builds - #92

Merged
fey merged 5 commits into
mainfrom
chore/migrate-to-biome
Aug 3, 2026
Merged

chore: fix CI — replace ESLint with Biome, unbreak fastify 5 and native builds#92
fey merged 5 commits into
mainfrom
chore/migrate-to-biome

Conversation

@fey

@fey fey commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Node CI has been red on main since 12.03.2026. #91 is not the cause — it only bumps action versions and the base image. The breakage came from #89 (e3413d7), which bumped several things at once, and CI never got past the first failing step, so the later ones stayed hidden.

Four problems, found one at a time by pushing the pipeline forward:

1. make setupERESOLVE

eslint went ^8.22.0^10.0.3 while eslint-config-airbnb-base@15 declares peer eslint@"^7.32.0 || ^8.2.0".

npm error Could not resolve dependency:
npm error peer eslint@"^7.32.0 || ^8.2.0" from eslint-config-airbnb-base@15.0.0

airbnb-base has no flat-config support and ESLint 10 dropped .eslintrc.* entirely, so there is no in-place upgrade. Replaced with Biome 2.5.6 — one native binary, no peer dependencies, covers both the linter and the style rules airbnb-base used to provide.

  • .eslintrc.yml, .eslintignorebiome.json
  • make lintnpx biome ci ., plus npm run lint / npm run lint:fix
  • 18 findings fixed: node: protocol on builtin imports, unused handler params, a forEach callback that returned a value, @ts-ignore@ts-expect-error, optional chaining
  • formatter applied in its own commit (11 files, no behaviour change)

The relaxations from .eslintrc.yml (no-console, import/extensions, new-cap, no-param-reassign, no-underscore-dangle) were all loosenings of airbnb rules that have no counterpart in Biome's recommended set, so nothing was carried over.

2. make setup — native build failure

fastify-objectionjs declares better-sqlite3 as a peer dependency, so npm installs it even though nothing imports it. The resolved 8.7.0 has no prebuilds for Node 24, fell back to a source build and failed against the V8 headers. Pinned to ^13 via overrides.

3. make test — all 6 tests failed

The same bump moved fastify 4 → 5:

FastifyError: The fastify-method-override plugin being registered mixes async and callback styles.

fastify-method-override@1.5.10 (last release Feb 2023) is declared async (fastify, opts, next) and calls next(). Fastify 4 tolerated it, Fastify 5 rejects it. The package is unmaintained and there is no maintained fastify-native replacement, so server/lib/methodOverride.js calls it directly with a no-op next and re-wraps it in fastify-plugin to keep its onRoute hook and setNotFoundHandler on the parent instance.

The _method override is load-bearing — the sign-out button POSTs _method=delete to reach DELETE /session. Verified that route is reached again.

4. Runtime, outside CI — left to #91

The built image crashes on start:

libm.so.6: version `GLIBC_2.38' not found (required by /app/node_modules/sqlite3/build/Release/node_sqlite3.node)

sqlite3@6's prebuild needs glibc 2.38, and node:25-slim is bookworm (glibc 2.36). node:26-slim is trixie (glibc 2.41) — exactly the bump #91 makes, so this is not fixed here. The deploy job only builds and pushes the image, so it stays green either way.

Verification

Full pipeline from a clean tree, matching CI:

make setup ok
make lint ok — 0 findings
make test ok — 3 suites, 6 tests
make build ok
docker build on node:25-slim ok
container on node:25-slim ✗ glibc 2.38 (problem 4)
container on node:26-slim ok — GET / and GET /users → 200

Merge order

Merge this, then @dependabot rebase on #91 and merge that — #91 goes green and its node:26-slim bump fixes problem 4.

🤖 Generated with Claude Code

fey and others added 5 commits August 3, 2026 21:37
ESLint 10 (bumped in #89) is incompatible with eslint-config-airbnb-base@15,
whose peer range is ^7.32.0 || ^8.2.0 — `npm install` failed with ERESOLVE and
Node CI has been red on main since 12.03.2026. airbnb-base has no flat-config
support either, while ESLint 10 dropped .eslintrc.* entirely, so an in-place
upgrade is not possible.

Biome replaces both the linter and the airbnb style rules with a single native
binary and no peer dependencies.

Also pin better-sqlite3 to ^13 via overrides: fastify-objectionjs declares it
as a peer dependency, and the resolved 8.7.0 has no prebuilds for Node 24, so
it fell back to a source build that fails against the V8 headers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- node: protocol for builtin imports (path, url, fs, crypto)
- prefix unused fastify handler params with _ (positional, cannot be dropped)
- wrap the forEach callback body so it stops returning a value
- @ts-ignore -> @ts-expect-error
- optional chaining in FormStrategy
- biome-ignore for knexConfig[mode]: knexfile exports configs per env name
  and its shape is read by `knex migrate:latest`
- drop the orphaned eslint-disable comment; biome already ignores _-prefixed params

Also switch biome.json to rules.preset, the non-deprecated form.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
One-off reformat of the 11 files biome flagged. No behaviour changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The same bump as the eslint one (#89) moved fastify 4 -> 5, which made every
test fail at startup:

  FastifyError: The fastify-method-override plugin being registered mixes
  async and callback styles.

fastify-method-override@1.5.10 (last release Feb 2023) is declared as
`async (fastify, opts, next)` and calls `next()`. Fastify 4 tolerated that;
Fastify 5 rejects it. The package is unmaintained, and there is no maintained
fastify-native replacement.

Wrap it in a local shim that calls the plugin directly with a no-op `next` and
re-wraps it in fastify-plugin, so its onRoute hook and setNotFoundHandler still
apply to the parent instance. The `_method` form override (used by the sign-out
button) works again — DELETE /session is reached and all 6 tests pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
npm records hasInstallScript for better-sqlite3 once its install script has
actually run, so a fresh `make setup` left the lockfile dirty.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@fey
fey merged commit 4a5b86e into main Aug 3, 2026
2 checks passed
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