npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dshkit/tsdown-client

v0.2.2

Published

Build preset and conformance suite for DeepSeek Harness (dsh) UI plugin client bundles. A transitional layer: dsh does not publish its own client build preset yet.

Readme

@dshkit/tsdown-client

你写的东西,第一次就出现在屏幕上。

English | 中文

你写完一个 dsh 界面插件,dsh plugin add 装上,刷新页面 —— 什么都没有。

没有报错。没有警告。控制台干净。插件在 profile 的清单里、boot 也过了, 它就是不在界面上。于是你去翻自己的组件、翻 React、翻 CSS,两个小时之后才想到去看构建配置。

这不是你的错,也不是一次意外。这是 dsh 浏览器端插件的默认失败方式:安静地什么都不发生。 生态里 1081 个插件、应用层插件是 0,这道门槛是原因之一 —— 一个人试过一次、什么都没看到,就不会试第二次了。

为什么会这样

dsh 的浏览器端产物不是一个模块,是一句把 factory 交给 loader 的话:

window.__ModuleLoader__.load({ id: "<你的包名>", factory: (require) => { … } })

手工复刻这套约定,要同时把 banner、footer、intro、CJS 产物形态、externals 表、内联规则、 构建期替换、CSS 管线全部弄对。任何一处偏一点,产物照样生成、照样能装、照样能 boot —— 只是 loader 认不出它。没有任何一环会告诉你。

用起来

npm i -D @dshkit/tsdown-client tsdown

发布状态: 本仓 package manifest 是 0.2.1,但 npm registry 当前只发布到 0.2.00.2.1 尚未发布。所以上面的安装命令解析到的是 registry release,不是本仓较新的 manifest。请用 npm view @dshkit/tsdown-client version --jsonnpm view @dshkit/tsdown-client versions --json 现场重取这条边界。

⚠️ 如果你同时要装 harness 那几个包,从 @next 取。 本包的 peer 范围写的是 它镜像的那个 release,而 dsh 客户端那几个包的 latest 至今指着已废弃的 0.0.1-rc.1 线 —— 裸 npm i @deepseek-ai/dsh-client-modules 会解析到另一条版本线上去,peer 根本满足不了。 跟哪个 channel、各个包的 latest 今天实际服务什么,gate:drift 每次都印。

// tsdown.config.ts
import { dshClientBundle } from '@dshkit/tsdown-client'

export default [
  // 你自己的 node 半边,原样保留
  { entry: ['src/index.ts'], outDir: 'lib', format: ['esm'], platform: 'node', dts: false, clean: false },
  dshClientBundle({ id: '@you/your-plugin', entry: 'src/client/index.ts' }),
]

两条规矩是 loader 定的,不是我们定的:id 必须等于你已发布的包名(loader 用它作模块表的键); 产物文件名恒为 <outDir>/client.js(boot manifest 按这个名字寻址)。

跨插件的 @deepseek-ai/* 值导入是构建错误,这是有意的:协作请走 cordis service。 type-only 导入会被擦除,永远到不了这道闸。

它替你挡掉的七个坑

每一条弄错,表现出来都是「插件不出现」,而不是一条报错:

| # | 条款 | 弄错的后果 | |---|---|---| | 1 | banner 打开 __ModuleLoader__.load({ id, factory }) 交接 | id 写错:注册在一个没人问的名字下 | | 2 | intro 声明 module/exportsfooter 归还它们 | 缺失:factory 返回 undefined | | 3 | format: 'cjs'platform: 'browser'entryFileNames: 'client.js'dts: falseclean: false | dts 会把 banner 卷进 .d.cts;默认 clean 会抹掉你的 node 半边 | | 4 | external = 平台模块表 | 内联 React 或 cordis → 运行时身份分裂,报错指向一个不相干的地方 | | 5 | noExternal = 表外一律内联 | 被外部化的依赖会产出模块表答不上来的 require() | | 6 | defineprocess.env.NODE_ENVimport.meta.env.MODE,以及裸 import.meta.env / 裸 process.env 两个命名空间 | zustand 探 import.meta.env ? .MODE : …;任何一个命名空间没被替换,CJS 产物在 boot 时抛 ReferenceError | | 7 | CSS Modules 经 lightningcss、[hash]_[local]、注入 <style data-plugin> | loader 卸载时按这个属性回收样式;属性不对,样式就留在页面上 |

本预设刻意比官方内部那份窄 —— 不做 host/client 两趟、不做 lib/types 分期、不管 node 半边。 窄签名才能保证官方实现将来总能满足它,反过来不成立。

你不用信我们,自己验

首选的公开检查直接读取你真正打进包里的字节,不需要源码 fixture、兄弟 checkout 或构建器适配层。 jsdom 和官方 loader 是可选的公开 peer,运行检查的项目必须自行安装两者(loader 请 pin 到本包瞄准的 release):

pnpm add -D jsdom@^29.1.1 @deepseek-ai/[email protected]
import { checkArtifactConformance } from '@dshkit/tsdown-client/conformance'

const { ok, checks } = await checkArtifactConformance({
  id: '@you/your-plugin',
  artifactPath: 'package/lib/client.js', // 从将要发布的包中解出的文件
  css: true, // 可选:要求至少有一份同步样式
})

它验证规范信封与 id,用 dsh 已发布的真实 ClientModuleSystem materialize 产物,并在 factory 返回时(loader 自动认领样式之前)检查同步 <style> 是否已经带上预期 data-plugin。 它使用 Acorn 解析完整产物,定位实际的规范 loader 注册及 factory,然后追踪该 factory 的 require 绑定:每个引用都必须是直接调用,且只有一个位于 CLIENT_EXTERNALS 的字符串字面量参数; 动态参数、别名、传参、赋值、遮蔽或其他逃逸一律 fail closed;原生 import() 会绕开 loader 模块表, 因此也会被拒绝。字符串、注释、正则字面量和无关属性键不会误报;Unicode 转义标识符由 parser 正确解析。作为保守的语法防线,任何语法上可见的 evalFunction 引用、对这两个名称的静态成员或解构访问,以及静态 constructor 访问都会被拒绝, 包括别名和 dormant code。

这是一项诚实的基线运行时导入检查,不是 JavaScript sandbox。它无法证明任意反射或计算值绝不会 到达代码生成器,而且 loader materialization 会在调用者进程内执行。对于不可信产物,必须通过具有 外部隔离的 clean-room runner 执行;artifact pass 不是安全或 boot verdict。只看一份 JavaScript 产物也无法证明任意平台库没有被复制并内联,因为内联代码未必保留可识别的 import 或包名。它能证明 所有残留运行时查找都是字面量且 loader 模块表能够应答,并会在 materialization 前拒绝上面枚举的 动态代码语法。

构建器作者套件

构建器作者还应运行 fixture 套件;它保留单独一份打包产物无法证明的构建专属检查:

import { checkConformance } from '@dshkit/tsdown-client/conformance'

const { ok, checks } = await checkConformance({
  // 用你自己的构建器构建 fixture,返回产出的 client.js 绝对路径。
  // 构建失败必须 reject —— 有一个 fixture 就是要求构建失败的。
  buildFixture: async (fixture) => { … },
})

构建器套件会让构建出的 platform/CSS 产物通过同一个公开 primitive,再追加平台 marker/外部化、 define、CSS class map、构建路径和构建期跨插件 purity 检查。两个 API 都使用取自已发布 @deepseek-ai/dsh-client-modules 的真实 ClientModuleSystem;没有 loader mock,也不探测私有源码。

| 检查 | 断言 | |---|---| | banner-contract | 产物带着属于自己 id 的交接信封 | | upstream-control | 官方自己发布的 bundle 满足同一份定义 —— 证明契约没有过拟合到本构建器 | | loader-registration | bundle 加载即注册,一个从不注册的 bundle 会被 loader 报出来 | | module-table-resolution | 平台模块全部经模块表应答;普通依赖已内联;表外 require 被拒绝 | | define-substitutions | 两个裸命名空间 + 两个精确键都生效 | | css-modules | 哈希类名映射,以及一个 loader 能回收的 <style data-plugin> | | purity-gate | 跨插件值导入必须构建失败 |

跑它需要三个 dev 依赖:jsdomclsxplatform fixture 故意把它声明为 dependency —— 这正是套件抓「构建器把普通依赖外部化了」的手段),以及一个显式 pin 住的 @deepseek-ai/dsh-client-modules:该包的 latest dist-tag 指向旧线(0.0.1-rc.1), 当前版本发在 next 上。pin 到本预设瞄准的那个 release —— 今天是 0.1.0-rc.8:peer 精确声明就是这个版本,本仓套件也在它上面 materialize。 rc.8 换掉了模块系统的构造方式(解析过的 boot 图、显式的注册门面、一个 bootstrap 行), 所以为 rc.6 写的 harness 在它上面跑不起来,反之亦然 —— 套件跟着常量跟的那个 release 走。

上游一动,这里就红

上面那些常量抄自尚未发布的 dsh 源码。没人看的副本会静默过期, 而最坏的情况恰恰是安静的:PLATFORM_MODULES 列少了会让 bundle 内联一份自己的 React 或 cordis —— 它不抛错,只是行为不一致,而你会去查一个根本不在那儿的 bug。 列多了则是响的那种:bundle 去要一个模块表已经没有的行,materialize 当场死。 0.1.0-rc.8 一次拿掉三项,所以两个方向都真实存在。

以下命令从 dshkit monorepo 根目录运行(它们是维护者 gate,不是随 npm 包发布的 script):

pnpm run gate:drift        # 对上游比对承重常量
pnpm run gate:drift:pin    # 同一比对,跑在副本抄自的那个 sha 上(正对照)

每次运行的第一行都印它自己的分母:看了几条、几条相同、几条动了、几条没比上 —— 所以这页不写那个数。

退出码 0 干净、1 有漂移、2 读数有洞。2 不是「网络抖了,重试一次」: 它表示至少有一条被看的常量根本没被比较(上游读不到,或那个常量已经不在闸看的地方), 而且它压过 1 —— 一次 2 的正文里可能正躺着真漂移。要读正文。

gate:drift:pin 是正对照:在 pin 住的那个 sha 上必须条条相同。它不绿,问题在这份副本或闸的 pattern,不在上游。

这个包希望自己被删掉

dsh 自己有一份 client 构建预设 —— packages/client/tsdown.client.ts —— 但它没有发布:所在目录没有 package.json、没有任何导出,文件本身还用相对路径伸进兄弟包的源码。

等官方发布那天,本包发一个 major 版本,实现体换成对官方的 export { … } from, 消费者零改动,等价性由契约套件证明。那个结局是目的达成,不是失败 —— 要拆的一直是门槛,不是要占住一个包名。

上游相关讨论:#2269

许可

MIT

与 DeepSeek 无隶属关系。dshkit 是独立的社区项目。