Skip to content

Fix: mark the five MikroORM database drivers as optional peer dependencies (stacked on #387) - #500

Open
AmaadMartin wants to merge 2 commits into
feat/optional-gcp-dependenciesfrom
fix/optional-mikro-orm-peer-deps
Open

Fix: mark the five MikroORM database drivers as optional peer dependencies (stacked on #387)#500
AmaadMartin wants to merge 2 commits into
feat/optional-gcp-dependenciesfrom
fix/optional-mikro-orm-peer-deps

Conversation

@AmaadMartin

Copy link
Copy Markdown
Owner

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

  1. Link to an existing issue (if applicable):
    Closes: #issue_number
    Related: #issue_number
  2. Or, if no issue exists, describe the change:
    Problem: core/package.json lists the five MikroORM SQL drivers under peerDependencies but has no peerDependenciesMeta block. As of npm v7 peer dependencies are installed by default and are only skipped when marked peerDependenciesMeta.<name>.optional = true, so anyone who runs npm install @google/adk also receives @mikro-orm/mariadb, @mikro-orm/mssql, @mikro-orm/mysql, @mikro-orm/postgresql, @mikro-orm/sqlite, plus @mikro-orm/knex, knex and their transitive native client stacks — even when they never construct a DatabaseSessionService.

Solution: add the missing peerDependenciesMeta entries (five keys, {"optional": true} each) to core/package.json and refresh package-lock.json. The runtime half of this design already landed: getConnectionOptionsFromUri (core/src/sessions/db/operations.ts) resolves each driver through a dynamic await import() selected by the connection-URI scheme, and core/build.js builds with esbuild packages: 'external', so nothing is imported at module load time and nothing is inlined into dist/. Only the manifest marker was missing — no core/src/**file is touched. This mirrors the packaging postureadk-pythonalready uses for its SQL stack (an opt-indb extra rather than a base dependency).

Measured effect (method below, so it can be re-run):

# scratch consumer that depends on this checkout's core/ via file:
printf '{"name":"c","private":true,"dependencies":{"@google/adk":"file:<adk-js>/core"}}' > package.json
npm install --package-lock-only --no-audit --no-fund
node -e "console.log(Object.keys(require('./package-lock.json').packages).length)"
manifest state resolved packages
main 592
this PR's base (#387, GCP deps already optional) 524
this PR 295

That is a 229-package (43.7%) reduction against the base. After the change the
only @mikro-orm/knex entries left in the tree are @mikro-orm/core and
@mikro-orm/reflection, which are real (statically imported) dependencies of
@google/adk.

Note: the task write-up quoted 278 → 36 packages for this measurement. Those
figures did not reproduce here; the numbers in the table are what this checkout
actually resolves, measured on both sides of the change with the command above.

Collision check (required before implementation) — gh pr list --repo AmaadMartin/adk-js --state open --limit 1000, then gh pr diff on every plausibly adjacent PR:

No open PR lands this change.

Behaviour change for downstream consumers (not an API break): nothing in the
public TypeScript surface changes. A consumer who today relies on the implicit
auto-install and connects with postgres://, mysql://, mariadb://,
mssql:// or — most likely in local development — sqlite:// must now install
that one driver themselves; until they do, DatabaseSessionService.init()
rejects with Cannot find module '@mikro-orm/sqlite'. That is the intended
meaning of an optional peer dependency and matches adk-python's db extra,
but it is a real migration step. Nothing inside this repository is affected:
@google/adk-devtools hard-depends on all five drivers and core keeps
@mikro-orm/sqlite in its own devDependencies.

Deliberately out of scope: any core/src/** change (including a friendlier
missing-driver error message), dev/package.json, removing
@mikro-orm/sqlite from core.devDependencies, and a driver-free
build_setup fixture — that would add a seventh network npm install to an
already install-heavy suite for a property the manifest test plus the manual
E2E below already establish.

Testing Plan

Please describe the tests that you ran to verify your changes. This is required for all PRs that are not small documentation or typo fixes.
Unit Tests:
[x] I have added or updated unit tests for my change.
[x] All unit tests pass locally.

New regression test:
tests/integration/lazy_load_db_drivers/optional_peer_deps_test.ts (new file, the
existing lazy_load_db_drivers_test.ts is untouched). It pins three things:
each of the five drivers is declared in peerDependencies and marked
optional: true; the key sets of peerDependencies and peerDependenciesMeta
are equal, so a future driver added to only one of them trips the test; and
packages.core.peerDependenciesMeta in package-lock.json deep-equals the
manifest block, catching a manifest edited without a lock refresh.

npx vitest run --project integration tests/integration/lazy_load_db_drivers
  ✓ optional_peer_deps_test.ts (7 tests)
  ✓ lazy_load_db_drivers_test.ts (5 tests)
  Test Files  2 passed (2)   Tests  12 passed (12)

npx vitest run --project unit:core core/test/sessions
  Test Files  6 passed (6)   Tests  130 passed (130)

npx vitest run --project integration tests/integration/build_setup
  Test Files  1 passed (1)   Tests  20 passed | 4 skipped (24)

Proof the tests can fail (run against the unfixed manifest):

  • Mutation A — git stash push -- core/package.json, dropping the five
    peerDependenciesMeta entries: all 7 tests fail.
    • declares @mikro-orm/mariadb as an optional peer dependency of @google/adk
      AssertionError: expected undefined to be true // Object.is equality
      (same for mssql / mysql / postgresql / sqlite)
    • gives every peer dependency a peerDependenciesMeta entry
      AssertionError: expected [ …(3) ] to deeply equal [ …(8) ]
    • mirrors peerDependenciesMeta into package-lock.json
      AssertionError: expected { …(8) } to deeply equal { …(3) }
  • Mutation B — keep the manifest fix but git stash push -- package-lock.json
    (simulating a manifest edit shipped without refreshing the lock): the lock
    test fails aloneAssertionError: expected { …(3) } to deeply equal { …(8) }
    — while the other 6 pass, showing the third assertion has independent signal.

No coverage shortfall to report: the change adds no executable source lines, so
core/src line/branch coverage and the vitest.config.ts thresholds are
unaffected.

Manual End-to-End (E2E) Tests:
Please provide instructions on how to manually test your changes, including any necessary setup or configuration.

Run against a packed tarball (not a file: link — a linked package resolves
up into the monorepo's hoisted node_modules and would hide the effect), from a
scratch directory that has no node_modules in any parent:

npm pack ./core --pack-destination /tmp        # -> google-adk-1.5.0.tgz
mkdir /var/tmp/adk-peer-check && cd /var/tmp/adk-peer-check
printf '{"name":"c","private":true,"type":"module"}' > package.json
npm install /tmp/google-adk-1.5.0.tgz
ls node_modules/@mikro-orm
cat > check.mjs <<'EOF'
import {DatabaseSessionService} from '@google/adk';
try {
  await new DatabaseSessionService('sqlite://:memory:').init();
  console.log('DB_INIT_SUCCESS');
} catch (e) { console.log('DB_INIT_FAILED', e.code, e.message.split('\n')[0]); }
process.exit(0);
EOF
node check.mjs
npm install @mikro-orm/sqlite   # the opt-in step
node check.mjs

Observed:

added 294 packages            # 295 entries in the lockfile, incl. the root
ls node_modules/@mikro-orm -> core  reflection      # no driver, no knex
node check.mjs -> DB_INIT_FAILED MODULE_NOT_FOUND Cannot find module '@mikro-orm/sqlite'
npm install @mikro-orm/sqlite -> added 138 packages
node check.mjs -> DB_INIT_SUCCESS

i.e. the drivers are gone from a plain install, the missing-driver failure is
the documented opt-in prompt, and installing the single driver the URI needs
restores a working DatabaseSessionService against a real in-memory SQLite
database (no mocks).

CI status: absent, validated locally instead. .github/workflows/validation.yaml
and license-check.yml both trigger on pull_request: branches: [main], so a
stacked PR based on feat/optional-gcp-dependencies runs no test job. On the
exact commit pushed here:

npm run build          -> ok
npm run lint           -> ok (0 problems)
npm run format:check   -> "All matched files use Prettier code style!"
npm run docs:check     -> ok (typedoc --treatWarningsAsErrors)
bash scripts/check_license.sh -> "All files have the correct license header."
npx vitest run --project integration tests/integration/lazy_load_db_drivers -> 12 passed
npx vitest run --project unit:core core/test/sessions                       -> 130 passed
npx vitest run --project integration tests/integration/build_setup          -> 20 passed, 4 skipped

(npm run ts:check fails on this checkout both with and without this change —
2847 pre-existing errors from test files that import @google/adk, which the
root tsconfig.json cannot resolve; it is not part of the CI workflow. The new
test file contributes zero of them.)

Checklist

[x] I have read the CONTRIBUTING.md document.
[x] I have performed a self-review of my own code.
[x] I have commented my code, particularly in hard-to-understand areas.
[x] I have added tests that prove my fix is effective or that my feature works.
[x] New and existing unit tests pass locally with my changes.

Amaad Martin added 2 commits August 1, 2026 22:00
npm >= 7 installs peerDependencies by default, so every consumer of
@google/adk received @mikro-orm/mariadb, mssql, mysql, postgresql and
sqlite (plus @mikro-orm/knex, knex and their native client stacks) even
when they never construct a DatabaseSessionService.

The drivers are already resolved through dynamic imports keyed off the
connection URI scheme, so marking them optional in peerDependenciesMeta
makes them opt-in without touching any runtime code.
Asserts that every MikroORM driver stays declared in both
peerDependencies and peerDependenciesMeta (optional: true), that the two
key sets match so a future driver cannot be added to only one, and that
package-lock.json mirrors the manifest block.
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