Skip to content

chore(packaging): every published package declares a files whitelist (#4248) - #4262

Merged
os-zhuang merged 1 commit into
mainfrom
claude/published-packages-files-whitelist-trhgv6
Jul 31, 2026
Merged

chore(packaging): every published package declares a files whitelist (#4248)#4262
os-zhuang merged 1 commit into
mainfrom
claude/published-packages-files-whitelist-trhgv6

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #4248.

问题

那 20 个包没有 files,npm 就按默认规则打包整个目录。实测 @objectstack/plugin-webhooks:21 个文件,其中 15 个在 src/ 下、3 个是单元测试,外加构建期的 scripts/i18n-extract.config.ts。发布时 dist/叠在这些之上,不是取代它们 —— 消费者装到的是「制品 + 源码 + 测试套件」。

改了什么

1. 补齐 20 个包的 files,统一为 ["dist", "README.md"],和已经声明的 29 个对齐。

消费者 import 的东西一个都没挪:这 20 个包的 main / types / exports 目标本来就全在 dist/ 里面 —— 这一点不是靠人眼确认的,是下面那道闸门的 SUFFICIENT 断言验出来的。构建后实测 plugin-webhooks:

之前 之后
文件数 21(未构建;dist/ 会再叠上去) 22,全部是 dist/** + LICENSE + package.json
单元测试 3 0
构建期脚本 1 0

2. 新增 check:published-files 闸门,挂在始终必跑的 lint job 上。

issue 里说得对:补完这一轮不是治本 —— 一半包声明一半不声明,是 #3786 那类「手抄清单没有闸门」的形状,漏掉的人拿不到任何信号。闸门对每个非 private workspace 包断言四条:

  • DECLARED —— files 存在,且是非空字符串数组。
  • SUFFICIENT —— 覆盖每一个入口路径。收紧白名单的反向失败是发出一个解析不了的包,而一道只查 DECLARED 的闸门恰恰会鼓励这种收紧,所以这条必须一起查。
  • MINIMAL —— 白名单放行的东西里没有测试、测试框架配置、构建工具配置或 scripts/
  • REGISTERED —— 超出 dist + README.md 的条目必须在 EXTRA_ENTRIES 里写明理由,并且双向核对 —— 表里有、files 里没有的条目同样报错,免得留下一段没人执行却仍然像政策的死文本。

@objectstack/spec 是唯一有登记豁免的包(.zod.ts 源码、JSON Schema、liveness 账本、CHANGELOG.md —— 这些是产品本身,不是构建输入)。

3. MINIMAL 顺带补上了 #4206 依赖的那个假设。

<包根>/scripts/** 排除出 docs-drift 的实现改动判定,只有在「没有包把 scripts/ 当运行时代码发布」时才成立。这个前提是成立的 —— 但它成立是因为有人逐个人工核对过三个包的内容,没有任何机制在守着它。现在每个 PR 都会验。

验证

  • pnpm check:published-files —— 改前精确复现 issue 的 20 个包;改后 69 个可发布包全绿。
  • --self-test 先跑(29 个断言):模式语义是这道闸门里唯一「所有包都对、它自己却可能错」的部分,而且两个方向都是静默失败 —— 匹配过宽会把 MINIMAL 变成噪音,过窄会让 SUFFICIENT 放行一个坏包。
  • 反向测试:逐一注入「删掉 files」「整个发布 src/scripts/」「入口指向白名单外」「spec 增删登记条目」「负向 ! 模式」,五种都如期报错并给出可执行的修法。
  • pnpm lint 通过;check:nul-bytescheck:changeset-fixedcheck:changeset-no-major 通过。
  • 真实构建后 npm pack --dry-run 验证 tarball 内容(上表)。

顺带发现,已单独开 issue

#4261:files: ["dist", "README.md"] 不含 CHANGELOG.md,npm 也不无条件打包它(实测 @objectstack/types:70KB 的 CHANGELOG 不在 tarball 里)。而 AGENTS.md 写着 breaking changeset 的迁移说明「ships to consumers as CHANGELOG.md inside the npm package」,升级者会去 grep 它 —— 69 个包里只有 spec 显式列了它,其余 68 个这条送达路径是断的。

这不是本 PR 造成的回归(那 49 个早就声明 files 的包一直如此),但它是一个发布产物范围的决定,不该顺手塞进这里,所以单独开。本 PR 的 canonical set 先按 issue 里写的 ["dist", "README.md"] 落地。

🤖 Generated with Claude Code

https://claude.ai/code/session_0132i4uupnWgjajiL8KDqzR1


Generated by Claude Code

#4248)

20 of the 49 publishable packages declared no `files` field, so npm fell back
to packing the whole package directory. `npm pack --dry-run` on
@objectstack/plugin-webhooks listed 21 files -- 15 under src/, three of them
unit tests, plus the build-time scripts/i18n-extract.config.ts. dist/ lands on
top of that at publish time rather than instead of it, so consumers were
installing TypeScript sources and the test suite alongside the artifact.

Each now declares ["dist", "README.md"], matching the 29 packages that already
did. Nothing a consumer imports moves: every main / types / exports target in
all 20 already resolved inside dist/. plugin-webhooks packs 2 files + dist/.

The other half is the gate. Half the packages declaring `files` and half not
was the #3786 shape -- a hand-copied convention with nothing enforcing it,
where whoever forgets the line gets no signal at all. check:published-files
(wired into the always-required lint job) holds every non-private workspace
package to four invariants:

  DECLARED    `files` exists and is a non-empty array of strings.
  SUFFICIENT  it covers every entry point, so tightening a whitelist cannot
              ship a package that fails to resolve -- the opposite failure,
              and one this guard would otherwise encourage.
  MINIMAL     nothing it admits is a test, a test-harness config or a build
              script.
  REGISTERED  anything beyond dist + README.md carries a reason, reconciled in
              BOTH directions so a stale exemption is an error, not dead text.

@objectstack/spec is the one package with registered extras: its .zod.ts
sources, JSON Schemas, liveness ledgers and CHANGELOG.md are product rather
than build input.

MINIMAL also closes an assumption #4206 rested on. Excluding <pkg>/scripts/**
from the docs-drift implementation test is sound only while no package
publishes scripts/ as runtime code; that held, but it held because someone
read all three offenders by hand. It is now checked on every PR.

The guard runs its own --self-test first: the pattern semantics are the one
part that can be wrong while every package is right, and both failure
directions are silent -- an over-matching matcher turns MINIMAL into noise, an
under-matching one waves a broken package through SUFFICIENT.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132i4uupnWgjajiL8KDqzR1
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 31, 2026 1:06am

Request Review

@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation ci/cd dependencies Pull requests that update a dependency file tooling labels Jul 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 20 package(s): @objectstack/connector-mcp, @objectstack/connector-openapi, @objectstack/connector-rest, @objectstack/connector-slack, @objectstack/formula, @objectstack/embedder-openai, @objectstack/knowledge-memory, @objectstack/knowledge-ragflow, @objectstack/plugin-approvals, @objectstack/plugin-email, @objectstack/plugin-pinyin-search, @objectstack/plugin-reports, @objectstack/plugin-sharing, @objectstack/plugin-webhooks, @objectstack/sdui-parser, @objectstack/service-cluster-redis, @objectstack/service-cluster, @objectstack/service-datasource, @objectstack/service-sms, @objectstack/trigger-api.

23 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/knowledge-rag.mdx (via @objectstack/embedder-openai, @objectstack/knowledge-memory, @objectstack/knowledge-ragflow)
  • content/docs/api/client-sdk.mdx (via @objectstack/plugin-reports)
  • content/docs/automation/approvals.mdx (via @objectstack/plugin-approvals)
  • content/docs/automation/webhooks.mdx (via packages/plugins/plugin-webhooks)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/formula)
  • content/docs/data-modeling/queries.mdx (via @objectstack/plugin-pinyin-search)
  • content/docs/data-modeling/validation.mdx (via @objectstack/formula)
  • content/docs/deployment/environment-variables.mdx (via @objectstack/plugin-pinyin-search, @objectstack/service-cluster-redis, @objectstack/service-cluster)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/connector-mcp, @objectstack/connector-openapi, @objectstack/connector-rest)
  • content/docs/kernel/cluster.mdx (via @objectstack/service-cluster-redis, @objectstack/service-cluster)
  • content/docs/permissions/authentication.mdx (via @objectstack/service-sms)
  • content/docs/permissions/authorization.mdx (via packages/plugins/plugin-sharing)
  • content/docs/permissions/permissions-matrix.mdx (via packages/plugins/plugin-sharing)
  • content/docs/plugins/packages.mdx (via @objectstack/formula, @objectstack/plugin-approvals, @objectstack/plugin-email, @objectstack/plugin-reports, @objectstack/plugin-sharing, @objectstack/plugin-webhooks, @objectstack/service-sms)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/service-cluster-redis, @objectstack/service-cluster)
  • content/docs/protocol/knowledge.mdx (via @objectstack/knowledge-memory, @objectstack/knowledge-ragflow)
  • content/docs/protocol/objectql/security.mdx (via packages/plugins/plugin-sharing)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/formula)
  • content/docs/releases/implementation-status.mdx (via @objectstack/plugin-approvals, @objectstack/plugin-sharing, @objectstack/plugin-webhooks, @objectstack/trigger-api)
  • content/docs/releases/v14.mdx (via @objectstack/service-sms)
  • content/docs/releases/v15.mdx (via @objectstack/formula, @objectstack/plugin-pinyin-search)
  • content/docs/releases/v16.mdx (via @objectstack/formula)
  • content/docs/releases/v9.mdx (via @objectstack/plugin-approvals)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang marked this pull request as ready for review July 31, 2026 02:05
@os-zhuang
os-zhuang merged commit cc2de0e into main Jul 31, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/published-packages-files-whitelist-trhgv6 branch July 31, 2026 02:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/l tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

20 个已发布包没有 files 白名单,把 src/、测试文件和构建脚本一起发到 npm

2 participants