From ce88968f322e324295de87832eef3a99b63a22bb Mon Sep 17 00:00:00 2001 From: Saurabh Nandwana Date: Mon, 17 Aug 2026 13:23:05 +0530 Subject: [PATCH] fix(build): add the root tsconfig.json typecheck has always pointed at MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `npm run typecheck` is `tsc --noEmit -p tsconfig.json` and there is no root tsconfig.json in the repository — it was never committed, and it is not gitignored. The script has therefore failed with TS5058 for every person who has ever run it. CI never ran it, so nothing noticed. The gap it left is not cosmetic. core and cdp are type-checked as a side effect of emitting declarations during their build; mcp is bundled by esbuild alone, which strips types without reading them. Nothing has type-checked packages/mcp/src since it was written. The config covers all three packages and emits nothing. `pretypecheck` runs the build first, because mcp imports its siblings by package name and those resolve through the workspace links to their built declarations — without it, a fresh clone gets TS2307 instead of an answer. Wired into CI as its own job. It needs no Chrome, so it reports in well under a minute rather than after a browser download, and a broken script cannot go unnoticed for another release. test/*.mjs stays outside the config. Type-checking the tests is worth doing and is not this change: they reach for fields the public types do not carry (`census.targetType`), so it is a change with real edits in it, not a config line. Co-Authored-By: Claude Opus 5 --- .github/workflows/ci.yml | 23 +++++++++++++++++++++++ CHANGELOG.md | 7 +++++++ CONTRIBUTING.md | 13 +++++++++++++ package.json | 1 + tsconfig.json | 21 +++++++++++++++++++++ 5 files changed, 65 insertions(+) create mode 100644 tsconfig.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 516e3a6..1b62b98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,29 @@ on: - cron: '0 6 * * 1' jobs: + typecheck: + # Its own job, not a step in `test`: it needs no Chrome, so it answers in + # under a minute instead of after a browser download. The mcp package is + # bundled by esbuild alone, which strips types without reading them — this + # is the only thing that type-checks it at all. + name: typecheck + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + + - run: npm ci + + # Builds first: mcp imports its siblings by package name, which resolve + # to their built declarations. + - run: npm run typecheck + test: name: test (Chrome ${{ matrix.chrome }}) runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c2cbaa..ed3281d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,11 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - `webcodecs_leak_sites` attributed only the default frame types, so an agent asking which line is leaking got nothing back for a codec leak. Attribution is not a verdict — it now covers every type unless one is named. +- `npm run typecheck` pointed at a root `tsconfig.json` that was never + committed, so it failed instantly with TS5058 for anyone who ran it. The + config now exists and covers all three packages. This matters most for the + mcp package, which esbuild bundles by stripping types without reading them — + nothing had type-checked it since it was written. ### Added @@ -39,6 +44,8 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - `test/assert.test.mjs`, which pins the verdict layer against synthetic censuses — including a `VideoDecoder` collected without `close()`, which no browser test can produce on demand. +- A `typecheck` CI job, so the script cannot rot unnoticed again. It needs no + Chrome, so it answers in under a minute. ## [0.2.1] - 2026-08-14 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 65d78cd..5743eec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,8 +6,21 @@ npm install npm run build:all npm test +npm run typecheck ``` +`typecheck` builds first, because the mcp package imports its siblings by +package name and those resolve to their built declarations. It is the only +thing that type-checks mcp at all — esbuild bundles it by stripping types +without reading them. + +**In a git worktree, run `npm ci` inside the worktree before trusting it.** A +worktree with no `node_modules` of its own resolves `@motionvector/*` upwards +to the main checkout's build, so mcp gets type-checked against whatever version +is built over there — reporting errors against code that is fine, or missing +errors in code that is not. The tests are unaffected; they import their +packages by relative path. + Tests drive a real Chrome. They find one from the Puppeteer cache, or you can point at your own: diff --git a/package.json b/package.json index f7074d4..c7a3e47 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "scripts": { "build": "npm run build -w @motionvector/webcodecs-census && npm run build -w @motionvector/webcodecs-census-cdp && npm run build -w @motionvector/webcodecs-census-mcp", "test": "node --test --test-timeout=240000 test/*.test.mjs", + "pretypecheck": "npm run build", "typecheck": "tsc --noEmit -p tsconfig.json", "release": "npm run preflight && npm run build && npm test && npm publish -w @motionvector/webcodecs-census && npm publish -w @motionvector/webcodecs-census-cdp && npm publish -w @motionvector/webcodecs-census-mcp", "preflight": "node scripts/preflight.mjs", diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..78f0063 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +// Type-checks every package's source in one pass, emitting nothing. The +// per-package `tsconfig.build.json` files emit declarations for core and cdp; +// mcp is bundled by esbuild alone, which strips types without checking them, +// so this config is the only thing that reads them at all. +// +// mcp imports its siblings by package name, which resolve through the +// workspace symlinks to their built `dist/*.d.ts` — so this checks the type +// surface consumers actually get, and needs `npm run build` to have run first. +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["node"], + "strict": true, + "noEmit": true, + "skipLibCheck": true + }, + "include": ["packages/core/src", "packages/cdp/src", "packages/mcp/src"] +}