mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
6b9aadf025
Fixes the part of OSS-899 that is hard to defend: every `.d.cts` file we
publish from `@copilotkit/runtime` starts with a `require()` call.
## The bug
A consumer whose only source file is `import { CopilotRuntime } from
"@copilotkit/runtime";`, compiled with `strict` and `skipLibCheck:
false`, gets **81 errors** on a bare install of 1.68.3. **71 of them are
`TS1036` "Statements are not allowed in ambient contexts"**, raised
inside our own shipped declarations.
Cause is in `packages/runtime/tsdown.config.ts`. The banner that
guarantees `reflect-metadata` loads before `type-graphql` was returned
as a **string**. tsdown's `resolveChunkAddon` routes an *object* return
by chunk kind (`js` / `dts` / `css`) but applies a *string* return to
**every** emitted chunk — declarations included. So all 87 published
`.d.cts` files began:
```ts
require("reflect-metadata");
import { CopilotRuntimeLogger, ... } from "./lib/logger.cjs";
```
A `require()` call is a statement, and a `.d.ts` is an ambient context.
One error per file.
Two reasons this went unnoticed for so long:
- Every scaffolder sets `skipLibCheck: true`. Verified in genuine `ng
new` and `create-next-app` output. A developer who scaffolds normally
never sees it.
- The `.d.mts` flavour got `import "reflect-metadata";`, which is a
legal side-effect import in a declaration file. **ESM-resolving
consumers saw zero `TS1036`.** Only CJS resolution is affected.
## The fix
Return an object so tsdown routes by chunk kind — JS keeps its
`reflect-metadata` prologue, declarations get nothing.
The `fileName.includes("_virtual/_rolldown/runtime")` condition is
dropped as well, and that is the more interesting half.
`resolveChunkAddon` reassigns its own closure variable on the first
call:
```js
if (typeof chunkAddon === "function") chunkAddon = chunkAddon({ format, fileName: chunk.fileName });
```
so a function banner is evaluated **once** and its result reused for
every later chunk. The old config's comment ("propagates to all output
files per format") described that as intended behaviour, but it was
really a condition deciding the banner for the entire build based on
whichever chunk happened to be emitted first. Keying on `format` alone —
fixed per build — is order-independent.
The object form is tsdown's declared API, not a workaround:
`ChunkAddonFunction` returns `ChunkAddonObject | string | undefined`
where `ChunkAddonObject` is `{ js?, css?, dts? }`. `tsc --noEmit
--strict` on `tsdown.config.ts` against tsdown's own types is clean —
worth stating because the config is in no tsconfig `include`, so nothing
else typechecks it.
## The guard
`scripts/validate-dts-ambient.ts` parses each built declaration with the
TypeScript compiler API and fails on any top-level node that is not a
declaration, import, or export. Wired as a `check-dts` nx target shaped
exactly like the existing `publint` / `attw` / `compat-check` targets
(`dependsOn: ["build"]`, `inputs` on `dist/**`), and folded into the
`check:packages` script that the `package-quality` CI job already runs.
That job already builds runtime for `publint`, so the added cost is one
177-file parse.
Only `@copilotkit/runtime` opts in, because it is the only offender.
Running the validator itself over the built declarations of all 32
packages: **87 of runtime's 177** bad on the published 1.68.3 artifact,
and **0** in every other package. Others can opt in with the same
one-line script.
## Testing
**1. Reproduce the reported defect on the published package.** Bare `npm
install @copilotkit/runtime@1.68.3 typescript`, `probe.ts` importing
only `CopilotRuntime`, tsconfig with `strict`, `skipLibCheck: false`,
`module`/`moduleResolution` `nodenext`:
```
$ npx tsc --noEmit ; echo exit=$?
exit=1
$ grep -oE 'error TS[0-9]+' tsc.out | sort | uniq -c | sort -rn
71 error TS1036
5 error TS2416
2 error TS7016
2 error TS2307
1 error TS2694
```
81 errors, matching the issue. All 71 `TS1036` are at line 1, column 1
of a `.d.cts`.
**2. Confirm the mechanism.** Every published declaration's first line,
before the fix:
```
-- *.d.cts -- total: 87
87 require("reflect-metadata");
-- *.d.mts -- total: 90
90 import "reflect-metadata";
```
**3. Same probe across every public subpath, before and after.** Built
`packages/runtime` at 1.68.3 with this change and swapped the result
into the probe's `node_modules`. `total` is all errors; `1036` is the
subset this PR addresses.
| subpath | CJS before | CJS after | ESM before | ESM after |
| --- | --- | --- | --- | --- |
| `@copilotkit/runtime` | 81 (71×1036) | **10** (0) | 10 (0) | 10 (0) |
| `/v2` | 32 (29×1036) | **3** (0) | 3 (0) | 3 (0) |
| `/langgraph` | 15 (4×1036) | **7** (0) | 7 (0) | 7 (0) |
| `/v2/express` | 21 (18×1036) | **3** (0) | 3 (0) | 3 (0) |
| `/v2/hono` | 21 (19×1036) | **2** (0) | 2 (0) | 2 (0) |
| `/v2/node` | 22 (20×1036) | **2** (0) | 2 (0) | 2 (0) |
Zero `TS1036` on every subpath in both module modes, and **after the fix
each subpath's CJS count equals its ESM count** — the CJS-only penalty
is gone and nothing else moved. Every ESM column is untouched, which is
the expected result since `.d.mts` never carried the bad banner.
The errors that remain are the separate items catalogued on OSS-899
(optional-peer SDK types, `@types/cors`, a `lru-cache` variance error
from `graphql-yoga`, a zod namespace skew in
`@copilotkit/license-verifier`) and are not touched here.
**4. `reflect-metadata` still runs first in every JS output.** This is
what the banner exists for, so it is the thing most at risk from the
change:
```
cjs files with require("reflect-metadata") as line 1: 131 / total 131
mjs files with import "reflect-metadata" as line 1: 132 / total 132
```
**5. Nothing but the banner line changed.** Diffed every one of the 87
built `.d.cts` files against the published 1.68.3 artifact from line 2
onward. Exactly one file differs, and it is unrelated source drift — a
JSDoc env-var rename from `6f58b2c6a4` (`COPILOTKIT_API_KEY` →
`INTELLIGENCE_API_KEY`, refs OSS-881) that landed on main after 1.68.3
shipped. Line counts are also identical, so declaration sourcemaps do
not shift.
The `_virtual/_rolldown` reference count in declarations is 2 before and
2 after — that item is deliberately out of scope here.
**6. The guard catches the regression it exists for.** Reverted the
banner to its pre-fix string form, rebuilt, and ran the new target:
```
$ pnpm exec tsx ../../scripts/validate-dts-ambient.ts dist
Found 87 statement(s) in published declarations.
A .d.ts is an ambient context: only declarations, imports, and exports are
allowed. Each of these is a TS1036 error for consumers on skipLibCheck: false.
dist/agent/converters/aisdk.d.cts:1 require("reflect-metadata");
...
exit=1
```
Restored the fix and rebuilt:
```
$ pnpm exec tsx ../../scripts/validate-dts-ambient.ts dist
validate-dts-ambient: dist clean (177 files).
exit=0
```
**7. Validator unit tests, mutation-checked.**
`scripts/__tests__/validate-dts-ambient.test.ts`, 7 tests covering the
exact OSS-899 banner, the legal ESM form, every declaration form a real
`.d.ts` uses, line-number reporting, and ignoring sibling `.cjs`/`.map`
files.
```
Test Files 1 passed (1)
Tests 7 passed (7)
```
Then broke the mechanism three ways to confirm the tests are not
self-fulfilling:
| mutation | result |
|---|---|
| allow `ExpressionStatement` in the kind allowlist | 2 failed / 5
passed |
| drop the `line + 1` conversion | 2 failed / 5 passed |
| scan only `.d.ts`, not `.d.mts` / `.d.cts` | 3 failed / 4 passed |
| restored | 7 passed |
**8. Runtime suite and packaging targets, on a clean `pnpm install
--frozen-lockfile` in this worktree.**
```
$ nx run @copilotkit/runtime:test
Test Files 143 passed (143)
Tests 2073 passed (2073)
$ nx run-many -t publint,attw,check-dts --projects=@copilotkit/runtime
NX Successfully ran targets publint, attw, check-dts for project @copilotkit/runtime
```
`attw --profile node16` reports 🟢 from both CJS and ESM; the `node10`
failure is pre-existing and ignored by the profile.
**9. Formatting and types.** `oxfmt --check` clean on all three source
files; `tsc --noEmit --strict` clean on the new script.
## Overlap with #6476
#6476 (`adopt TypeScript 7 and tsdown 0.22`) bumps tsdown to 0.22.14 but
does **not** touch `packages/runtime/tsdown.config.ts`, so it does not
fix this. The two PRs conflict only textually — both add lines to
runtime's `scripts` block and to the root `package.json`. This fix uses
tsdown's documented object-banner form, so it holds whether or not 0.22
changed `resolveChunkAddon`'s memoization.
No changeset: this ships through the normal release scopes.
186 lines
7.6 KiB
JSON
186 lines
7.6 KiB
JSON
{
|
|
"name": "CopilotKit",
|
|
"private": true,
|
|
"scripts": {
|
|
"build": "nx run-many -t build --projects=packages/** --exclude=@copilotkit/demo-agents",
|
|
"build:examples": "nx run-many -t build --projects=examples/**",
|
|
"build:storybook": "nx run-many -t storybook:build --projects=examples/v2/*/storybook",
|
|
"build:vue": "nx run @copilotkit/vue:build",
|
|
"check-types": "nx run-many -t check-types",
|
|
"clean": "git clean -fdX --exclude=\"!.env\"",
|
|
"lint": "oxlint .",
|
|
"format": "oxfmt --write .",
|
|
"check-format": "oxfmt --check .",
|
|
"test": "nx run-many -t test --projects=packages/**",
|
|
"test:watch": "pnpm run test && nx watch --all -- pnpm run test",
|
|
"test:coverage": "nx run-many -t test:coverage --projects=packages/**",
|
|
"dev": "pnpm run build && nx watch --projects=packages/** -- pnpm run build",
|
|
"dev:examples": "pnpm run build:examples && nx watch --projects=examples/** -- pnpm run build:examples",
|
|
"storybook:angular": "pnpm -C examples/v2/angular/storybook dev",
|
|
"storybook:react": "pnpm -C examples/v2/react/storybook dev",
|
|
"storybook:vue": "nx run @copilotkit-storybook/vue:dev",
|
|
"storybook": "pnpm storybook:react",
|
|
"docs": "pnpm -C examples/v2/docs dev",
|
|
"demo:angular": "nx run-many -t dev --projects=examples/v2/angular/demo,examples/v2/angular/demo-server",
|
|
"demo:react": "pnpm -C examples/v2/react/demo dev",
|
|
"demo:vue": "nx run @copilotkit/vue-demo:dev",
|
|
"release:prepare:dry": "tsx scripts/release/prepare-release.ts --scope monorepo --bump patch --dry-run",
|
|
"release:prerelease:dry": "tsx scripts/release/prerelease.ts --scope monorepo --dry-run",
|
|
"verify:channels-umbrella": "nx run @copilotkit/channels:build && tsx scripts/release/verify-channels-umbrella.ts",
|
|
"verify:channels-umbrella:registry": "nx run @copilotkit/channels:build && tsx scripts/release/verify-channels-umbrella.ts --registry",
|
|
"verify:angular-package": "nx run-many -t build,check-types,test,publint,attw --projects=@copilotkit/angular && tsx scripts/release/verify-angular-package.ts",
|
|
"verify:runtime-package": "nx run @copilotkit/runtime:build && tsx scripts/release/verify-runtime-package.ts",
|
|
"prepare": "lefthook install",
|
|
"graph": "nx graph",
|
|
"publint": "nx run-many -t publint --projects=packages/**",
|
|
"attw": "nx run-many -t attw --projects=packages/**",
|
|
"check:packages": "nx run-many -t publint,attw,check-dts --projects=packages/**",
|
|
"validate:model-names": "tsx scripts/validate-doc-model-names.ts",
|
|
"validate:retired-anthropic-models": "nx run repo-scripts:validate-retired-anthropic-models",
|
|
"check:intelligence-env-names": "tsx scripts/validate-intelligence-env-names.ts",
|
|
"check:plugin-skills": "tsx scripts/sync-plugin-skills.ts --check",
|
|
"generate:channel-native-catalogs": "node scripts/channel-native-catalogs.mjs generate",
|
|
"check:channel-native-catalogs": "node scripts/channel-native-catalogs.mjs check",
|
|
"audit:channel-native-catalogs": "node scripts/channel-native-catalogs.mjs audit",
|
|
"generate:public-api-manifest": "tsx scripts/release/generate-public-api-manifest.ts --write",
|
|
"check:public-api-manifest": "tsx scripts/release/generate-public-api-manifest.ts --check",
|
|
"sync:plugin-skills": "tsx scripts/sync-plugin-skills.ts",
|
|
"parity:sync": "tsx examples/integrations/_parity/sync.ts",
|
|
"parity:verify": "tsx examples/integrations/_parity/verify.ts",
|
|
"parity:check": "tsx examples/integrations/_parity/verify.ts --no-color"
|
|
},
|
|
"devDependencies": {
|
|
"@anthropic-ai/claude-code": "2.1.207",
|
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
"@commitlint/cli": "^20.3.0",
|
|
"@commitlint/config-conventional": "^20.3.0",
|
|
"@size-limit/file": "12.1.0",
|
|
"@storybook/addon-docs": "^10.2.10",
|
|
"@storybook/addon-webpack5-compiler-swc": "^4.0.2",
|
|
"@storybook/react-webpack5": "^10.2.10",
|
|
"@types/jscodeshift": "^17.3.0",
|
|
"@types/node": "^18.11.17",
|
|
"@types/semver": "^7.7.1",
|
|
"@vitest/coverage-v8": "^3.2.4",
|
|
"browserslist": "^4.24.0",
|
|
"danger": "^12.3.3",
|
|
"es-check": "9.6.4",
|
|
"glob": "^10.3.12",
|
|
"install": "^0.13.0",
|
|
"jscodeshift": "^17.3.0",
|
|
"lefthook": "^2.1.1",
|
|
"npm": "^10.7.0",
|
|
"nx": "22.7.5",
|
|
"oxfmt": "^0.36.0",
|
|
"oxlint": "^1.51.0",
|
|
"publint": "^0.3.17",
|
|
"remark": "^15.0.1",
|
|
"remark-mdx": "^3.1.1",
|
|
"remark-parse": "^11.0.0",
|
|
"semver": "^7.8.1",
|
|
"size-limit": "12.1.0",
|
|
"storybook": "^10.2.10",
|
|
"ts-node": "^10.9.2",
|
|
"tsdown": "^0.20.3",
|
|
"tsx": "^4.21.0",
|
|
"typescript": "^5.2.3",
|
|
"unified": "^11.0.5",
|
|
"unist-util-visit": "^5.1.0",
|
|
"vitest": "^4.1.3"
|
|
},
|
|
"engines": {
|
|
"node": ">=18"
|
|
},
|
|
"packageManager": "pnpm@10.33.4",
|
|
"pnpm": {
|
|
"peerDependencyRules": {
|
|
"ignoreMissing": [
|
|
"react",
|
|
"react-dom"
|
|
],
|
|
"allowedVersions": {
|
|
"react": "*",
|
|
"react-dom": "*"
|
|
}
|
|
},
|
|
"overrides": {
|
|
"@ag-ui/mcp-middleware>@ag-ui/client": "0.0.53",
|
|
"streamdown>react": "^19.0.0",
|
|
"@types/react": "19.1.8",
|
|
"@types/react-dom": "^19.0.2",
|
|
"react": "19.2.3",
|
|
"react-dom": "19.2.3",
|
|
"next@<=15.4.11": "15.4.11",
|
|
"next@>=15.5.0 <15.5.15": "15.5.15",
|
|
"send@<=0.19.0": "0.19.0",
|
|
"path-to-regexp@<=0.1.12": "0.1.13",
|
|
"serve-static@<=1.16.0": "1.16.0",
|
|
"prismjs@<=1.30.0": "1.30.0",
|
|
"pino@<=10.1.1": "10.1.1",
|
|
"@copilotkit/license-verifier": "~0.5.0",
|
|
"next": "^16.0.10",
|
|
"defu@<=6.1.4": ">=6.1.5",
|
|
"minimatch": ">=9.0.6",
|
|
"minimatch@>=10.0.0 <10.2.1": ">=10.2.1",
|
|
"handlebars": ">=4.7.9",
|
|
"axios": ">=1.15.0",
|
|
"tar": ">=7.5.11",
|
|
"node-forge": ">=1.4.0",
|
|
"hono": ">=4.11.7",
|
|
"dompurify": ">=3.3.2",
|
|
"vite@>=6.0.0 <6.4.2": ">=6.4.2",
|
|
"vite@>=7.0.0 <7.3.2": "7.3.2",
|
|
"esbuild": ">=0.25.4",
|
|
"fast-xml-parser": ">=4.5.2",
|
|
"lodash": ">=4.18.1",
|
|
"lodash-es": ">=4.18.1",
|
|
"basic-ftp": ">=5.2.0",
|
|
"@hono/node-server": ">=1.19.13",
|
|
"flatted": ">=3.4.0",
|
|
"body-parser": ">=1.20.3",
|
|
"serialize-javascript": ">=7.0.3",
|
|
"socket.io-parser": ">=4.2.6",
|
|
"svgo": ">=3.3.3",
|
|
"@isaacs/brace-expansion": ">=5.0.1",
|
|
"@modelcontextprotocol/sdk": ">=1.26.0",
|
|
"immutable@>=3.0.0 <3.8.3": ">=3.8.3",
|
|
"immutable@>=5.0.0 <5.1.5": ">=5.1.5",
|
|
"rollup@>=4.0.0 <4.59.0": ">=4.59.0",
|
|
"brace-expansion@>=2.0.0 <2.0.3": ">=2.0.3",
|
|
"ajv@>=8.0.0 <8.18.0": ">=8.18.0",
|
|
"bn.js": ">=5.2.3",
|
|
"picomatch@>=4.0.0 <4.0.4": ">=4.0.4",
|
|
"js-yaml": ">=4.1.1",
|
|
"jsondiffpatch": ">=0.7.2",
|
|
"yaml@>=2.0.0 <2.8.3": ">=2.8.3",
|
|
"zod": ">=3.22.3",
|
|
"cookie": ">=0.7.0",
|
|
"diff@>=4.0.0 <4.0.4": ">=4.0.4",
|
|
"diff@>=5.0.0 <5.2.2": ">=5.2.2",
|
|
"diff@>=8.0.0 <8.0.3": ">=8.0.3",
|
|
"qs": ">=6.14.2",
|
|
"@octokit/plugin-paginate-rest": ">=9.2.2",
|
|
"@octokit/request": ">=8.4.1",
|
|
"@octokit/request-error": ">=5.1.1",
|
|
"express": ">=4.20.0",
|
|
"@tootallnate/once": ">=3.0.1",
|
|
"file-type": ">=21.3.1",
|
|
"@langchain/community": ">=1.1.14",
|
|
"langsmith": ">=0.5.18",
|
|
"next@>=16.0.0 <16.2.3": "16.2.3",
|
|
"validator": ">=13.15.20",
|
|
"markdown-it": ">=14.1.1",
|
|
"mdast-util-to-hast@>=13.0.0 <13.2.1": ">=13.2.1",
|
|
"@smithy/config-resolver": ">=4.4.0",
|
|
"defu": ">=6.1.5",
|
|
"ai": ">=5.0.52",
|
|
"@ai-sdk/mcp": "1.0.21",
|
|
"storybook@>=8.0.0 <8.6.17": "8.6.17",
|
|
"path-to-regexp@>=8.0.0 <8.4.0": ">=8.4.0"
|
|
},
|
|
"patchedDependencies": {
|
|
"eventsource@3.0.7": "patches/eventsource@3.0.7.patch"
|
|
}
|
|
}
|
|
}
|