Skip to content

Fix: declare @types/node in the CommonJS TypeScript build_setup fixtures - #383

Open
AmaadMartin wants to merge 1 commit into
fix/build-setup-fixtures-declare-genaifrom
fix/build-setup-cjs-fixtures-types-node
Open

Fix: declare @types/node in the CommonJS TypeScript build_setup fixtures#383
AmaadMartin wants to merge 1 commit into
fix/build-setup-fixtures-declare-genaifrom
fix/build-setup-cjs-fixtures-types-node

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):
    N/A — no existing issue.
  2. Or, if no issue exists, describe the change:

Problem: The tests/integration/build_setup/* fixtures are miniature standalone npm
projects, and build_setup_test.ts runs a real npm install plus a real tsc build in each
one, so a fixture's package.json is meant to be the complete declaration of what it needs.
Two of them are incomplete. ts_commonjs and ts_commonjs_native_addon use the CommonJS
ambient globals require and module, which TypeScript only knows about when @types/node
is present, and neither manifest declares it:

File Line(s) Global
ts_commonjs/agent.ts 16, 17, 18 require(...)
ts_commonjs/agent.ts 61 module.exports
ts_commonjs/db_init_check.ts 7, 8 require(...)
ts_commonjs_native_addon/agent.ts 73 module.exports

Neither fixture tsconfig.json sets compilerOptions.types, so tsc auto-includes every
package it can find under a visible node_modules/@types. Today that succeeds for two reasons,
neither of which the fixture manifest controls:

  1. The fixture install hoists a copy of @types/node in through unrelated transitive edges.
    Measured in this checkout with npm ls @types/node before the change: @types/node@26.1.2
    at the fixture root, reachable via @google/genai@2.15.0 -> protobufjs@7.6.5,
    @google/adk-devtools -> @mikro-orm/{mssql,mysql} -> tedious/mysql2, and
    @google/adk -> @google-cloud/storage -> retry-request -> @types/request.
  2. tsc's automatic @types inclusion also walks ancestor node_modules/@types
    directories, so while the fixtures live inside this repo they additionally see the repo
    root's own @types/node devDependency.

Correction to the original problem statement. The task I was given asserted that deleting
the fixture-local node_modules/@types/node breaks the build. I verified that and it is not
true in-tree
: with only the fixture-local copy removed, npm run build still printed
Build complete, and tsc --noEmit --listFiles showed it resolving the repo root's copy
instead. I am not shipping that claim. The real, measurable defects are the two below.

Solution: declare the build-time type dependency each fixture actually consumes, adding
only a devDependencies block to the two CommonJS TypeScript manifests:

"devDependencies": {
  "@types/node": "^20.12.7"
}

This fixes two things that are real:

  • The manifest is now honest. These fixtures exist to model a user's standalone ADK
    project. Extracted from this repo — which is the scenario they simulate — the ancestor
    @types fallback disappears and the manifest is the only source. The negative control below
    reproduces exactly that and shows the build failing without the declaration.
  • The fixtures are now pinned to the repo's Node typings. Before this change they compiled
    against @types/node@26.1.2, i.e. whatever major the transitive graph happened to hoist.
    After it they compile against 20.19.43, deduped with every transitive consumer.

devDependencies rather than dependencies because type definitions are build-time only,
following commit 59b99b9b ("Move openapi-types to devDependencies": "This package provides
type definitions and is not needed at runtime, only during development and build processes."
).
^20.12.7 is not a new fact — it is the exact range already pinned in the root package.json
and in dev/package.json, which are the only two @types/node declarations in the repo, so a
future bump stays a single consistent sweep.

Deliberately not done, per scope: no .ts source is touched (require/module.exports is
the CommonJS behaviour under test), no types/typeRoots array is added to the fixture
tsconfigs (that would additionally exclude every other @types package), and the four
untouched fixtures (ts_esm, ts_esm_native_addon, js_commonjs, js_esm) are left alone —
the ESM TypeScript fixtures use no Node globals, and the JS fixtures are never compiled by tsc.

Collision check. gh pr list --repo AmaadMartin/adk-js --state open --limit 100 plus
gh pr diff --name-only on every plausibly adjacent PR. One overlap: PR #329 ("declare
@google/genai in the build_setup integration fixture manifests") edits these same two files,
adding an entry to dependencies on the line immediately above my insertion point. It does not
add @types/node, so it does not land this change, but the two diffs would conflict textually.
This PR is therefore stacked on fix/build-setup-fixtures-declare-genai rather than branched
from main
, and its diff is exactly the six added lines below. PR #327 also mentions
@types/node but is a different package (core/package.json) and does not touch these fixtures.

tests/integration/build_setup/ts_commonjs/package.json              | 3 +++
tests/integration/build_setup/ts_commonjs_native_addon/package.json | 3 +++
2 files changed, 6 insertions(+)

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:
[ ] I have added or updated unit tests for my change.
[x] All unit tests pass locally.

No new test file. This change adds zero lines of executable code — it adds a JSON key to two
test fixtures — and tests/ is outside the vitest coverage include
(core/src, dev/src, integrations/src), so there is nothing to cover. The existing
tests/integration/build_setup/build_setup_test.ts already is the test: its beforeAll runs
a real npm install then npm run build (tsc && echo Build complete) in each ts_* fixture
and asserts stderr === '' and that stdout contains Build complete. That hook is precisely
the assertion this change concerns.

Integration suite (npx vitest run --project integration tests/integration/build_setup/build_setup_test.ts):

Failed suites (beforeAll) Failed tests Passed Skipped
stack base (no change) 0 16 4 4
with this change 0 14 6 4

All six beforeAll build hooks pass — including both fixtures this PR touches. The remaining
test failures are pre-existing and environmental in my sandbox, not caused by this change: they
are npx @google/adk-devtools --version failing with npm ERR! could not determine executable to run and the spawned agent not emitting test-llm-model-response, and they hit fixtures this
PR never touches (js_esm, ts_esm, ts_esm_native_addon). I diffed the failing sets: the
set with the change is a strict subset of the baseline's, so no test regressed.

Two environment notes for anyone reproducing this locally. The repo configures no
hookTimeout, so vitest's 10s default applies to a beforeAll that performs a cold
npm install; on a cold npm cache all six suites time out in the hook regardless of this
change. Pre-installing the six fixtures once makes the hooks fit the budget. Passing
--hookTimeout on the CLI does not help — it is not propagated into the project config.

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

Negative control — proof the declaration is load-bearing. The existing test passes both
with and without this change (that is the whole point of the defect), so a green run alone
proves nothing. Because the in-tree build is also satisfied by the repo root's @types/node
via ancestor @types resolution, the control has to remove both sources — which is exactly
the standalone-project situation these fixtures model:

npm install && npm run build                 # repo root, so core/dist and dev/dist exist
mv node_modules/@types/node /tmp/hidden      # remove the ancestor @types fallback
cd tests/integration/build_setup/ts_commonjs
npm install
npm ls @types/node                           # => "└── @types/node@20.19.43" as a DIRECT dep
rm -rf node_modules/@types/node              # simulate the transitive edge going away
npm run build                                # MUST fail
npm install                                  # restores it BECAUSE the manifest declares it
npm run build                                # MUST print "Build complete"
rm -rf node_modules dist package-lock.json
cd - && mv /tmp/hidden node_modules/@types/node

ts_commonjs, npm run build with no @types/node reachable — exit code 1:

agent.ts:16:5   - error TS2580: Cannot find name 'require'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`.
agent.ts:17:55  - error TS2580: Cannot find name 'require'. ...
agent.ts:18:29  - error TS2580: Cannot find name 'require'. ...
agent.ts:61:1   - error TS2580: Cannot find name 'module'. ...
db_init_check.ts:7:34 - error TS2580: Cannot find name 'require'. ...
db_init_check.ts:8:20 - error TS2580: Cannot find name 'require'. ...

Found 6 errors in 2 files.

ts_commonjs_native_addon, same procedure — exit code 1:

agent.ts:73:1 - error TS2580: Cannot find name 'module'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node`.

Found 1 error in agent.ts:73

Then, with the repo root's copy still hidden, npm install in each fixture restored
@types/node@20.19.43 from the fixture's own manifest and npm run build printed
Build complete in both. Before this change that restoration was an accident of the transitive
graph; now it is what the manifest asked for.

Local validation in place of CI. This PR is stacked, and the validation workflow triggers on
pull_request: branches: [main], so no test job runs against a non-main base. On the exact
pushed commit I ran:

  • npm run build — exit 0
  • npm run lint — exit 0
  • npx vitest run --project integration tests/integration/build_setup/build_setup_test.ts — results in the table above
  • npx tsc --noEmit --listFiles in ts_commonjs — confirms the fixture-local
    @types/node@20.19.43 is what the fixture now compiles against

git status --short after every run shows exactly the two modified package.json files: the
fixture node_modules/, dist/, and package-lock.json are all git-ignored and are removed by
the test's afterAll. The root package-lock.json is untouched — the fixtures are not npm
workspace members.

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.

The ts_commonjs and ts_commonjs_native_addon fixtures use the CommonJS
ambient globals require and module, which TypeScript only knows about
when @types/node is present, but neither manifest declared it. They
typecheck today only because @types/node reaches them by accident: the
fixture install hoists a copy through unrelated transitive edges, and
tsc's automatic @types inclusion also walks up to the repo root's
node_modules/@types.

Declare the build-time type dependency each fixture actually consumes,
at the ^20.12.7 the repo root and dev/package.json already pin.

devDependencies rather than dependencies: type definitions are
build-time only, matching 59b99b9 ("Move openapi-types to
devDependencies").
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