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"] +}