feat(source): 输入登记服务与 sf CLI(content-addressed 快照)

- registerSource(db, input):wxr/sitemap/媒体目录三类输入登记为 content-addressed
  快照——流式 copy+sha256 单遍双算(64KB 块),副本落
  storage/snapshots/<kind>/<sha256前2>/<sha256>(文件)或 <sha256>/(媒体整树),
  后续任务只读副本;UNIQUE(site,kind,sha256) 幂等(重复登记复用既有行)
- media_bundle 哈希钉死:排序相对路径('/' 归一)+ 每文件 sha256 → canonical
  JSON(键排序无空白)→ 再 sha256;不含 mtime、不依赖遍历顺序;完整清单
  (path/bytes/sha256)入 metadata jsonb;符号链接(含 junction)跳过并记录
- site 按 key select-then-insert upsert(23505 竞态重查);connection 判重键
  (site_id,name) 为应用层 select-then-insert(表无库级唯一,注释注明)
- 路径安全:输入 realpath 后须在 allowedRoots 白名单内(缺省 storage/incoming),
  ENOENT/越界/类型不符抛带 code 的 SourceRegisterError;全部输入先校验后摄取,
  任何失败零落库零复制
- 报告落 artifacts/register/<runId>/reports/register.json(runId=时间戳+随机;
  输入清单/哈希/大小/耗时)
- scripts/sf.ts(commander):wxr:probe 只读诊断(任意可读路径,IO/损坏文件出
  报告不崩——Task 6 fatalError 契约)出 JSON/HTML 报告;source:register 调服务
  出摘要。CLI 机制钉死:根 devDep tsx + 根 script sf + commander 根依赖,TS 源码
  直连(@sf/* 经 tsconfig paths,不经 dist)
- source.module.ts:Nest 注册 SourceRegisterService(standalone context 用);
  register.service.ts 刻意零装饰器(CLI/测试直 import 不拉 reflect-metadata)
- launder 类型垫片改经 triple-slash 引用随 html.ts 进任意编译程序(apps/api 与
  根程序直连适配器源码的新场景);apps/api 增 @sf/adapter-wp workspace 依赖与
  paths 映射(register.service 消费 ADAPTER_VERSION 单源)
- 测试 +7(tests/integration/source-register.test.ts,临时库 + tmpdir storage/
  报告根 finally 清理):三输入登记/清单哈希定义对拍/重复登记幂等/mtime 排除/
  副本布局与内容一致/路径安全六分支/junction 跳过/报告契约;全套 260 绿

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-10-21 12:31:15 +08:00
parent a535cde270
commit 586d715455
10 changed files with 1246 additions and 3 deletions
@@ -42,6 +42,12 @@
// "allowIframe: false"的等价物就是 allowedTags 缺席(本库无此独立开关)。
// - style 属性与 <style> 标签均拒绝(ADR-009:内联样式是风险面,清洗后进产出的
// 内容不得携带 CSS;未来若放开须走 allowedStyles 显式子集评审)。
// 挂载 launder 的环境模块声明(本包自带的类型垫片):declare module 只能经 d.ts
// 进入程序、无法用 import 表达,故用 triple-slash 引用使其随本文件进任何编译程序
// ——含 apps/api 与根程序经 tsconfig paths 直连本包源码的场景(Plan 2 Task 7 起;
// 否则垫片只在本包自身 tsconfig 的 include 下生效)。
// eslint-disable-next-line @typescript-eslint/triple-slash-reference -- 垫片无 import 形态
/// <reference path="../types/launder.d.ts" />
// - class/id 透传:WP 对齐类(alignleft 等)与锚点依赖之;class 值是惰性文本,
// 安全边界在标签/属性白名单,不 class 名单(阶段 3 主题自行取舍是否消费)。
// - **追踪像素策略(本切片钉死)**:外链 <img>(含 1x1 追踪像素形态)一律保留——