Machine-produced by `pnpm run rescope-vendor --apply` plus the regeneration it prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`, `verify-translation-pairing --write` for the touched bilingual pairs, `gen-doc-graphs`, and one typert snapshot whose ids embed character offsets. `pnpm run rescope-vendor --check` verifies the result. Renames nine vendored packages (cordis, cosmokit, schemastery and the six @cordisjs plugins) and every reference that resolves them: manifest names and dependency keys, module specifiers including declare-module merges, cordis.yml plugin names, tsconfig paths, every Markdown fence, and `docs/` prose. Directory names, upstream versions, and dependency ranges are unchanged, so vendor/README.md still reads as an upstream snapshot; its manifest table gains an upstream-name column so THIRD_PARTY_NOTICES keeps MIT attribution pointed at each fork's origin. The tutorial tier follows the rename end to end: its yaml fences named plugins the Loader can no longer resolve, its `ts ignore-check` fences disagreed with the compiled fences beside them, and its prose quoted both. The contracts that told readers to keep upstream names — the root convention and the vendoring cookbook's tree comment and manifest invariant — now say to rescope instead. Two rules read `@deepseek-ai/` as "another workspace plugin": the client bundle purity gate now names the vendored libraries a browser bundle inlines, and the files where a bare `cordis` is an agent-preset id keep that product data.
60 lines
4.1 KiB
Markdown
60 lines
4.1 KiB
Markdown
# Cookbook: adding a vendored package
|
|
|
|
English | [中文](adding-a-vendored-package.zh.md)
|
|
|
|
When the harness needs another upstream Cordis package (e.g. `@cordisjs/plugin-http`), it is **vendored** as pinned source under `vendor/`, not added as an npm dependency — see [the vendoring decision](../../.agents/notes/implemented/process/2026-06-11-vendor-cordis-as-source.md) for why. [vendor/README.md](../../vendor/README.md) covers *updating* an already-vendored package; this guide is the file-by-file checklist for adding a **new** one. (Verified against the existing vendored set; if it drifts, fix it here.)
|
|
|
|
## 1. Copy the source in
|
|
|
|
```
|
|
vendor/<dir>/
|
|
package.json # from upstream; set "private": true, rescope the name, keep exports/type
|
|
tsconfig.json # extends ../../tsconfig.base.json (see configuration below)
|
|
src/ # the upstream src/ verbatim
|
|
README.md LICENSE # if upstream ships them
|
|
```
|
|
|
|
`tsconfig.json` mirrors the other vendored packages — `rootDir: src`, `outDir: lib/types`, the strictness relaxations upstream code needs, and a `references` entry for every other vendored package it imports:
|
|
|
|
```jsonc
|
|
{
|
|
"extends": "../../tsconfig.base.json",
|
|
"compilerOptions": {
|
|
"rootDir": "src", "outDir": "lib/types",
|
|
"noUncheckedIndexedAccess": false, "exactOptionalPropertyTypes": false,
|
|
"noImplicitOverride": false, "noUnusedLocals": false, "noUnusedParameters": false
|
|
},
|
|
"include": ["src"],
|
|
"references": [{ "path": "../cordis" }, { "path": "../cosmokit" }]
|
|
}
|
|
```
|
|
|
|
`package.json` invariants: `"private": true` (vendored packages are never published), rescope the `name` ([mapping](../rescope.md)) while keeping upstream's `version`/`exports`/`type`, point declaration metadata at `lib/types`, publish `.d.ts` and `.d.ts.map` declaration outputs, and list its cordis deps in `peerDependencies` (matching the upstream manifest). Transitive upstream deps must themselves be vendored or already present — vendoring one package often means vendoring its dependency tree (e.g. `@cordisjs/plugin-http` pulls `@cordisjs/fetch-file`).
|
|
|
|
Local relative imports/exports in vendored TypeScript source use explicit `.ts` specifiers after copying. This is a repo-local build difference from upstream: `rewriteRelativeImportExtensions` emits `.js` runtime imports while declarations keep explicit `.ts` specifiers that NodeNext/Node16 TypeScript consumers can resolve.
|
|
|
|
## 2. Register it in the root configs
|
|
|
|
| File | Change |
|
|
|---|---|
|
|
| `tsconfig.base.json` | add `"<npm-name>": ["./vendor/<dir>/src"]` to `paths` |
|
|
| `tsconfig.host.json` | add `{ "path": "./vendor/<dir>" }` to `references` (before the `packages/*` entries; vendored code enters the graph through the host aggregate only) |
|
|
| `vendor/README.md` | add a manifest table row (dir, npm name, version, upstream repo, commit SHA) and log any local modifications |
|
|
| `scripts/publint-all.ts` | only if the vendored package is itself published from here (vendored deps normally are not — skip) |
|
|
|
|
Covered automatically by globs — no edits needed: root `package.json` workspaces (`vendor/*`), `tsdown.config.ts`, `vitest.config.ts`, `.oxlintrc.json`. A per-package `vendor/<dir>/tsdown.config.ts` is needed ONLY if the build configuration differs from the root default (dual ESM/CJS or multiple entries — see `vendor/schemastery` and `vendor/logger-console`); its entry should read the JS emitted under `lib/types`.
|
|
|
|
## 3. Mind the manifest guard
|
|
|
|
`scripts/check-vendor-manifest.sh` (a pre-commit hook) fails if anything under `vendor/*/src` is staged without `vendor/README.md` also staged. Stage the manifest update alongside the source so the commit passes.
|
|
|
|
## 4. Verify
|
|
|
|
```sh
|
|
pnpm install # registers the workspace
|
|
pnpm run typecheck
|
|
pnpm run build && pnpm run constraints
|
|
```
|
|
|
|
Run the behavior checks selected by the [testing policy](../testing.md). The source `paths` map lives once in `tsconfig.base.json` and serves every graph. The important isolation boundary is the project-reference graph: vendored source must be referenced through its own `vendor/<dir>/tsconfig.json`, not pulled into an aggregate's strict program ([layout](../development.md#typescript-project-layout)).
|