Skip to content

Typert 是类型基础设施生成器:它把源码分析运行时存储Loader 发现分开,使某业务包中只写一次的类型级契约能够在 monorepo 其他地方被反射、校验与对外服务,而无需手写胶水代码。本页引用 packages/typert/*

包地图

Typert 是 packages/typert/ 下的一个四件套:

角色Cordis 键 / 消费方
packages/typert/protocol@deepseek-ai/dsh-typert-protocol与编译器无关的声明:@Remote、作用域、调用描述符、编解码器、provider 契约纯声明,无服务
packages/typert/generator@deepseek-ai/dsh-typert-generatorTypeScript 工程分析器 + 模型驱动发射器构建期库
packages/typert/registry@deepseek-ai/dsh-typert-registry生成反射与 schema 的运行时存储提供 ctx.typert
packages/typert/loader@deepseek-ai/dsh-typert-loader发现 Loader 条目并注册生成的 host 工件消费 ctx.loaderctx.typert

数据意义上流水线是“注册表 → 生成器 → 产出”,但各模块形成一个三角:分析器读源码并构建模型,发射器把模型变成工件,loader 在运行时发现这些工件并交给注册表,而所有一切都以协议的类型对话。

text
 源码(/packages/*)            构建期                      运行时
 --------------------                  ----------           -------
 *.ts  ----->  WorkspaceAnalyzer  --> FaceModel / TypeGraph
                (check 或 write 模式)       |
                                           v
                                    发射器(FaceModelEmitter、
                                    WorkspaceTypertGenerator)
                                           |
                         lib/typert.host.{js,d.ts}   (package/typert 导出)
                         lib/typert.client.{js,d.ts} (package/client/typert)
                                           |
 运行时  <-- dsh-typert-loader <-- ctx.loader 发现 package.json ./typert
                 校验 TYPERT --> ctx.typert(TypertRegistry)存储 <package>#<face>

分析器:WorkspaceAnalyzer

packages/typert/generator/src/analyzer.ts渲染任何工件之前,先把开发者手写的源码类型树转换成与编译器无关的数据模型。要点:

  • 使用以 tsconfig.host.jsontsconfig.client.json 为种子的独立 ts.Program
  • 两种模式(AnalysisMode = 'check' | 'write')。check(默认)在语法/语义诊断、缺失的可达公共注解、私有跨包引用,以及模型无法无损保留的可达声明合并上失败。write 会插入 checker 推导的注解、重建程序,并返回一个干净的 check 模式模型。
  • tsconfig.base.{host,client}.json 面;直接的工程引用确立编译器面的成员关系;package.json#exports 确立每条跨包公共边界;源码导入/再导出是唯一允许的跨面边。
  • NPM 依赖所拥有的类型(包括 @types 全局声明)以 external 引用保留,而非被展开。
  • WorkspaceCaches 跨运行保留工作成果。

WorkspaceTypertGeneratorsrc/workspace.ts)是更高层的驱动:它通过遍历“从 Cordis ContextEvents 增广可达的包公共导出”以及显式 @typert 声明来发现贡献者,并发射工件。

生成器发射什么

FaceModelEmittersrc/emitter.ts)只消费模型(没有 AST,没有 checker)。它发射可执行的 JavaScript,内含受支持的 Zod schema 与一个 TYPERT 贡献,外加一份声明文件,其 schema 通过包的公共导出被定义为 z.ZodType<SourceType>。不受支持的 Zod 投影会失败,而不是弱化源类型。

工件落点(选择性发布):

工件package.json#exports 条目
hostlib/typert.host.js / lib/typert.host.d.ts./typertpackage/typert
clientlib/typert.client.js / lib/typert.client.d.ts./client/typertpackage/client/typert

生成的声明把 TYPERT 暴露为 unknown,因此贡献的业务包不依赖运行时注册表。没有相应公共条目的业务包根本不需要 Typert 工件。

dsh 如何调用它:tsdown 插件

tsdown.config.ts 通过 typertPluginpackages/typert/generator/src/tsdown-plugin.ts)把 Typert 接进普通构建:

ts
// tsdown.config.ts(节选)
import { typertPlugin } from './packages/typert/generator/lib/types/tsdown-plugin.js'
// host 通道:
plugins: [typertPlugin({ mode: 'workspace', faces: ['host'] })]

驱动它的根脚本(package.json):

脚本命令
buildbuild:libbuild:web
build:lib:hosttsc -b tsconfig.host.json && tsdown --env.DSH_BUILD_FACE host
build:lib:clienttsc -b tsconfig.client.json && tsdown --env.DSH_BUILD_FACE client
typecheckbuild:lib:hosttypecheck:contracts-ready

该插件在 host 通道做两件事:(1)打包前先降低 TypeScript 依赖中的标准装饰器(经 ts.transpileModule,目标 ES2024/ESNext);(2)writeBundle 时以 tsconfig.host.json 作为唯一程序种子运行 workspace 级 Typert 生成,既产出 Host 反射工件,也产出给 Client 用的 Host Remote 契约的 typert.remote-client.* 投影。随后的 Client tsdown 既不起动 Typert,也不分析 tsconfig.client.json

运行时注册表:ctx.typert

packages/typert/registry/src/service.ts 提供 TypertRegistry,即 ctx.typert 背后的默认插件。它存储生成的反射与可选的活跃 Zod schema,并在随 Cordis fiber 调用方的生命周期内原子地注册与移除。

  • 键:包反射以 <package>#<face> 为键;schema 以 <package>#<name> 为键(它们省略面,因为 host 与 client 运行在独立上下文中)。
  • register(contribution) 在提交任何东西之前就拒绝非法的身份与重复键,然后返回确切的 Cordis effect 处置器。
  • 查询:get(key)resolve(key)list(filter?)getPackage(packageName, face?)listPackages(...),以及用 z.toJSONSchema() 按需投影活跃 schema 的 toJSONSchema(key, params?)
  • 身份辅助:typertKey()typertPackageKey()
  • protocol 包的贡献/记录契约位于 @deepseek-ai/dsh-typert-registry/types 子路径。注册表存储反射,但不做 host/client 图合并,也不解析 TypeScript 引用——这些是分析器与发射器的职责。

Loader 发现

packages/typert/loader 仅限 Node。它需要 ctx.loaderctx.typert(它自己不提供注册表)。激活期间扫描现有 Loader 条目,然后跟随 Cordis internal/plugin 生命周期通知,解析每个条目包的 package.json,在导出 ./typert 时导入它,校验 TYPERT 清单,并把贡献注册到该条目或本插件卸载为止。packages 配置可列出嵌在另一个 Loader 条目后面的插件的额外工件。包解析与导入的清单会在进程生命周期内缓存(新增导出需要重启)。目前它只导入 host 面。

协议包:@deepseek-ai/dsh-typert-protocol

packages/typert/protocol/src/types.ts 持有其他所有部分共享的、与编译器无关的词汇表——这是 Typert 与 Host Gateway 及 Client API 之间最接近“线上契约”的东西:

  • @Remote / @RemoteScope(key) 装饰器把公共实例方法标记为可在已注册的 Cordis Service 上直接调用。
  • TypertRemoteServicebindTypertRemoteremoteMethods
  • InvocationDescriptor——注册表、Gateway 与 Client Remote 共享的运行时形态;以 AbortSignal 作为最后一个参数会加入协作式取消(被注入的 signal 永远不会变成 JSON 参数)。
  • 可合并扩展的地图:TypertLookupMapTypertContextMapTypertRemoteMapTypertRemoteScopeMapTypertRemoteNamespaceMap
  • 严格编解码器携带生成的 schema;src-json 编解码器标识较弱的源码启动路径。

Typert 与文档目录——什么被生成、什么没有

一个常见的混淆点:docs/config-catalog.md(配置目录)是被生成的,但不是由 Typert 生成。它由 scripts/gen-config-catalog.tspnpm run gen-config-catalog)产出,该脚本用一次直接的 TypeScript AST 遍历来扫描包入口点、配置类型与静态 Schemastery schema,并对未知类型名硬报错。

Typert 确实驱动着 Cordis API/目录投影。scripts/gen-cordis-catalog.ts@deepseek-ai/dsh-typert-generator 导入 WorkspaceAnalyzer / CordisCatalogProjector / projectCordisCatalog(见 packages/typert/generator/src/cordis-catalog.ts),把与编译器无关的 FaceModel 重新投射成 docs/cordis-api/* 以及运行时 API 目录 packages/extensions/tool-cordis/src/api-catalog.ts。换句话说:Typert 的分析器是共享的抽取核心;config-catalog 的生成器则是一个独立、聚焦于 schema 的工具。

关键生成器导出

来自 packages/typert/generator/src/index.ts

导出类别用途
WorkspaceAnalyzerWorkspaceCachesTypertAnalysisError源码分析为模型
AnalysisModeDiscoveredTypertPackageWorkspaceAnalyzerOptions类型分析器选项
FaceModelEmitterTypertEmitError模型 → JS + d.ts + schemas
WorkspaceTypertGenerator贡献者发现 + 发射驱动
TypeGraphRenderer确定性文本渲染
CordisCatalogProjectorprojectCordisCatalogcollectEventscollectServices类/函数仓库文档投影

已知局限

局限位置
跳过包导出模式;贡献者需要具体导出目标生成器
跨面 namespace 再导出会失败生成器
Zod 发射器只支持模型的限定子集(条件/映射根在出现具体 schema-factory 策略前会失败)发射器
注册表不做 host/client 图合并,也不解析 TS 引用注册表
Loader 只导入 host 面loader
装饰器标记只携带方法名与调用模式;参数/schema 反射需要构建流水线协议

nameversion
协议@deepseek-ai/dsh-typert-protocol
生成器@deepseek-ai/dsh-typert-generator
注册表@deepseek-ai/dsh-typert-registry
Loader@deepseek-ai/dsh-typert-loader

延伸阅读

  • SDK 协议SDK 客户端SDK 服务端——Typert 与之同属 SDK 章;注意它们是无关的系统(Typert 处理类型/schema 反射,SDK 处理基于 stdio 的 JSON-RPC)。
  • 仓库构建接线:tsdown.config.ts 与根 package.json 中的 build:lib:host|client 脚本。
  • Cordis 目录投影:scripts/gen-cordis-catalog.tspackages/typert/generator/src/cordis-catalog.ts
  • config-catalog 的独立性:scripts/gen-config-catalog.tsdocs/config-catalog.md)。
  • 运行时注册表 API:packages/typert/registry/src/service.ts
  • 协议声明:packages/typert/protocol/src/types.ts