Skip to content

refactor(db): embed migrations + tars via Bun macros, drop folder-tar plugin#22

Merged
maxscharwath merged 2 commits intomainfrom
fix/migrations-embed-json
May 6, 2026
Merged

refactor(db): embed migrations + tars via Bun macros, drop folder-tar plugin#22
maxscharwath merged 2 commits intomainfrom
fix/migrations-embed-json

Conversation

@maxscharwath
Copy link
Copy Markdown
Contributor

@maxscharwath maxscharwath commented May 6, 2026

Summary

Fixes the canary docker image crash:

Error: Can't find meta/_journal.json file

Drizzle's migrate({ migrationsFolder }) reads _journal.json and *.sql files via fs.readFileSync at runtime. In bun build --compile, import.meta.dir resolves to \$bunfs/... with no migration files on disk → throw.

Approach

A single @brika/db/macros module, imported with with { type: 'macro' }. Bun evaluates the macro at bundle time (or first import in dev), inlining the result as a literal — zero fs at startup, zero codegen step, zero committed artifacts.

Two macros:

  • loadMigrations(repoRelativePath): MigrationMeta[] — wraps drizzle's public readMigrationFiles(...).
  • loadTarBytes(repoRelativePath): Promise<number[]> — walks the folder with Bun.Glob, packs with Bun.Archive (gzip).

A small applyMigrations in @brika/db replicates drizzle's sqlite migrate logic directly (CREATE __drizzle_migrations, gate by folderMillis, transactional apply), so we don't depend on the protected db.dialect.migrate internal API.

Why drop the folder-tar plugin

The previous runtime preload (which registered folderTarPlugin via Bun.plugin()) silently broke macro substitution in transitively imported files — a Bun bug. Removing the preload makes macros work uniformly in dev, test, and compile mode.

The two *.tar import sites — templates init and i18n — switch to loadTarBytes calls. The plugin and its preload become unnecessary.

DX

Add a migration with drizzle-kit generate, restart, done. No codegen step, no committed JSON, no plugin to register.

Files

  • packages/db/src/macros.ts — the two macros (paths from repo root)
  • packages/db/src/database.tsdefineDatabase signature + applyMigrations
  • 5 callers: auth, http/cache, hub state/sparks/logs
  • apps/hub/src/runtime/config/brika-initializer.ts — templates via macro
  • apps/hub/src/runtime/i18n/i18n-service.ts — locales via macro
  • delete: folder-tar plugin, pack-folder helper, preload.ts, bunfig.toml
  • compile.ts + bundle.ts — drop plugins: [folderTarPlugin()]

Net diff: +102 / −138 across 18 files.

Test plan

  • bun --filter @brika/db --filter @brika/auth --filter @brika/http --filter @brika/hub typecheck — clean
  • bun --filter @brika/db test — 17/17
  • bun --filter @brika/auth test — 288/288 (includes a re-migration test that exercises the gate)
  • bun --filter @brika/http test — 272/272
  • bun --filter @brika/hub test — 2176/2176 (includes `cli-start.test.ts` which previously broke under macro+preload)
  • `docker build && docker run -p 3001:3001` → container `healthy`, `/api/health` returns `{ok:true,ready:true}`
  • Logs show `I18n system initialized` with `availableLocales: [ "fr", "en" ]` (locales tar inlined correctly)
  • Zero `_journal.json` errors in container logs

… plugin

Fixes the canary docker image crash on startup:

  Error: Can't find meta/_journal.json file

Drizzle's `migrate({ migrationsFolder })` reads `_journal.json` and the
`*.sql` files at runtime via `fs.readFileSync`. When `bun build --compile`
produces a standalone binary, `import.meta.dir` resolves to a `$bunfs/...`
virtual path with no migration files on disk, so the migrator throws.

Replace the runtime fs lookup (and the previous `folder-tar` plugin used
for templates/locales) with a single `@brika/db/macros` module imported
with `with { type: 'macro' }`. Bun evaluates the macro at bundle time
(or first import in dev), inlining the resulting `MigrationMeta[]` and
gzipped tar bytes as literals.

Two macros:
  - loadMigrations(repoRelativePath): MigrationMeta[]
    Drizzle's public `readMigrationFiles(...)` against the absolute path.
  - loadTarBytes(repoRelativePath): Promise<number[]>
    Walks the folder with Bun.Glob, packs into Bun.Archive (gzip).

Why drop the folder-tar plugin: the runtime preload that registered it
(via `Bun.plugin()`) silently broke macro substitution in transitively
imported files. Without the preload, macros work in dev, test, and
compile mode uniformly. The two `*.tar` import sites (templates init
and i18n) move to `loadTarBytes` calls; the plugin and its preload
become unnecessary.

A small `applyMigrations` in `@brika/db` replicates drizzle's sqlite
migrate logic against `bun:sqlite` directly (CREATE `__drizzle_migrations`,
gate by `folderMillis`, transactional apply), so we don't depend on the
protected `db.dialect.migrate` internal API.

DX win: add a migration with `drizzle-kit generate`, restart, done.
No codegen step, no committed JSON, no plugin to register.

- packages/db/src/macros.ts: the macros, paths resolved from repo root
- packages/db/src/database.ts: defineDatabase signature + applyMigrations
- 5 database.ts callers (auth, http/cache, hub state/sparks/logs)
- apps/hub/src/runtime/config/brika-initializer.ts: templates via macro
- apps/hub/src/runtime/i18n/i18n-service.ts: locales via macro
- delete folder-tar plugin, pack-folder, preload, bunfig.toml
- compile.ts + bundle.ts: drop the plugins arg
@maxscharwath maxscharwath force-pushed the fix/migrations-embed-json branch from b2be2fc to 66592b9 Compare May 6, 2026 10:59
@maxscharwath maxscharwath changed the title refactor(db): inline migrations as JSON, drop runtime fs lookup refactor(db): embed migrations + tars via Bun macros, drop folder-tar plugin May 6, 2026
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 6, 2026

@maxscharwath maxscharwath merged commit c866689 into main May 6, 2026
6 checks passed
@maxscharwath maxscharwath deleted the fix/migrations-embed-json branch May 6, 2026 15:18
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