chore(deno): migrate toolchain from Node 24 + pnpm to Deno 2.9.7 + TypeScript 7.0.2 (W1.5)
- root deno.json workspace (nodeModulesDir auto), npm versions registered once in imports, deno.lock; remove pnpm-lock/pnpm-workspace/root package.json; members keep minimal package.json (name/type/exports) - tasks: dev, typecheck (tsc 7.0.2 per member + deno check), lint/fmt (biome, useImportExtensions), test (vitest via deno), check:tokens, build (web + deno compile), ci, db:migrate/reset, gen:types - tsconfig base moved to config/ (no root tsconfig.json); deno types -> types/deno.d.ts; web drops baseUrl - server: Deno.serve entry with graceful shutdown, --role migrate|preflight|probe, WEB_ROOT static SPA hosting; drop @hono/node-server, tsx, esbuild build.mjs - logger: redact child() bindings and serialize err by message/stack; sync stdout destination; tests - relative imports get explicit extensions (sites/mp-sync paths left for follow-up) - crash-recovery tests spawn `deno run -A`; tasks tests use unique per-file schemas - single-container Dockerfile + entrypoint (migrate -> preflight -> api+worker watchdog), docker-compose.yml - docs: README, runbook, ADR-001 superseded, plan §1 validation row Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
1 parent
d9f2af2f3c
commit
304feea141
226 files changed
+6601
-8620
No files matched your search
@@ -1,6 +1,8 @@
|
||||
# ADR-001:运行时采用 Node.js 24 LTS + pnpm workspace,而非 Deno
|
||||
|
||||
- 状态:已采纳(2026-09-27)
|
||||
> **Superseded by [ADR-004](ADR-004-deno-runtime.md)**(2026-09-27,W1.5 已迁移到 Deno 2.9.7 + TypeScript 7.0.2)。以下内容仅作历史记录。
|
||||
|
||||
- 状态:已被 ADR-004 取代(2026-09-27);原状态:已采纳(2026-09-27)
|
||||
- 关联:REQ §9(技术架构选择)、docs/plan/00-first-version-plan.md §1
|
||||
|
||||
## 背景
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
|
||||
## 硬规则
|
||||
|
||||
1. **新增语义先加 token 再用。** 需要新的颜色、字号、圆角、时长或缓动时,先在 `app.css` 定义语义 token(日夜两套值都给),跑 `pnpm --filter @umt/web gen:tokens`,再在组件里引用。
|
||||
1. **新增语义先加 token 再用。** 需要新的颜色、字号、圆角、时长或缓动时,先在 `app.css` 定义语义 token(日夜两套值都给),跑 `deno task gen:tokens`,再在组件里引用。
|
||||
2. **禁止原色与十六进制。** 组件里不写 `#xxxxxx`、`text-[#..]`、`bg-red-500` 这类 Tailwind 调色板色、`white/10` 之类的黑白透明度,也不写 `text-[13px]`、`duration-300`、`ease-[cubic..]`、裸 `rounded`。状态只用 `success` / `warning` / `destructive`,并且配文字,不只靠颜色。
|
||||
3. **材质按层级只有三种**,不在玻璃上叠玻璃:已在卡片里的空态用 `<EmptyState plain>`。
|
||||
4. 确需例外(第三方库的颜色参数等),在该行或上一行写 `token-allow: 原因`。
|
||||
|
||||
以上规则由 `pnpm check:tokens`(`apps/web/scripts/check-design-tokens.sh` + 生成物校验)在 `pnpm run ci` 中守住。
|
||||
以上规则由 `deno task check:tokens`(`apps/web/scripts/check-design-tokens.sh` + 生成物校验)在 `deno task ci` 中守住。
|
||||
|
||||
## 控制台共享件
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
2026-09-12 迁移时零散字号并入最近一档(10.5 → 11、13.5 → 14、0.72rem → 11、1.05rem → 17 等,最大偏差 0.6px,约 120 处),经页面级截图复验;标题阶逐档保留现状值,流式标题各处原值保留,收敛是设计决定另议。
|
||||
|
||||
tailwind-merge 不认识的 `text-*` 会被当成文字颜色,`text-control text-muted-foreground` 合并时字号会被丢掉。登记表不再手写:[gen-design-tokens.mjs](../../apps/web/scripts/gen-design-tokens.mjs) 从 app.css 抽出字号、缓动、圆角、时长 token 生成 `app/lib/design-tokens.generated.ts`,`cn()` 读它;改了 app.css 跑 `pnpm gen:tokens`,`pnpm run ci` 校验生成物是最新的。
|
||||
tailwind-merge 不认识的 `text-*` 会被当成文字颜色,`text-control text-muted-foreground` 合并时字号会被丢掉。登记表不再手写:[gen-design-tokens.mjs](../../apps/web/scripts/gen-design-tokens.mjs) 从 app.css 抽出字号、缓动、圆角、时长 token 生成 `app/lib/design-tokens.generated.ts`,`cn()` 读它;改了 app.css 跑 `deno task gen:tokens`,`deno task ci` 校验生成物是最新的。
|
||||
|
||||
## 圆角
|
||||
|
||||
@@ -81,11 +81,11 @@ tailwind-merge 不认识的 `text-*` 会被当成文字颜色,`text-control text
|
||||
- 组件里不出现 Tailwind 调色板颜色(`emerald-*`、`amber-*`、`rose-*`、`blue-*` 等):状态用 `success` / `warning` / `destructive`,装饰性图标与强调用 `foreground` 的透明度。
|
||||
- 组件里不出现 `text-[Npx]` / `text-[Nrem]` / `text-[clamp(...)]`,字号只从阶梯取。
|
||||
- 组件里不出现 `duration-N`、`ease-[...]`、裸 `rounded`、`rounded-[...]`。
|
||||
- 改了 app.css 里的 token 就跑 `pnpm gen:tokens`,让 tailwind-merge 的登记表跟上;CI 会校验。
|
||||
- 改了 app.css 里的 token 就跑 `deno task gen:tokens`,让 tailwind-merge 的登记表跟上;CI 会校验。
|
||||
- 播放器(`app/routes/stream/player/`)里压在画面上的东西用 `on-media` 族;流媒体浏览页用 `content` / `wash` 族。分不清就问一句:主题切到浅色时它应不应该变色。
|
||||
- 新的语义需求先加 token 再用,不在组件里临时拼色。
|
||||
- 按钮 hover 不填实心 `primary` / `foreground`;浮层不手写 `shadow-2xl`,用 `pg-float`。
|
||||
- `scripts/check-design-tokens.sh` 在 `pnpm run ci` 里对整个 `app/` 做守卫(落地页组件与 `/dev/ui` 除外)。确实需要例外时(二维码必须白底、支付品牌色),在该行或上一行写注释 `token-allow: 原因`,不另开白名单。
|
||||
- `scripts/check-design-tokens.sh` 在 `deno task ci` 里对整个 `app/` 做守卫(落地页组件与 `/dev/ui` 除外)。确实需要例外时(二维码必须白底、支付品牌色),在该行或上一行写注释 `token-allow: 原因`,不另开白名单。
|
||||
|
||||
## 迁移状态
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
- 流媒体页面的内容区统一用 `max-w-[1800px]` 加 `px-4 sm:px-6 lg:px-10`,标题、海报行和顶栏对齐。
|
||||
7. **动效只做一次性的**。入场、按压回弹、悬停反馈可以做;持续运动的装饰不做。主按钮的光谱环是唯一的例外,而且在减少动态效果时停转。
|
||||
|
||||
这些规则里能机器检查的,由 [check-design-tokens.sh](../../apps/web/scripts/check-design-tokens.sh) 在 `pnpm run ci` 中守住(见[设计 token](design-tokens.md#规则))。
|
||||
这些规则里能机器检查的,由 [check-design-tokens.sh](../../apps/web/scripts/check-design-tokens.sh) 在 `deno task ci` 中守住(见[设计 token](design-tokens.md#规则))。
|
||||
|
||||
## 结构
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
| 数据库 | PostgreSQL 16;Kysely + pg;SQL 迁移文件 + Kysely Migrator;`kysely-codegen` 或手写 DB 类型 | 开发用 docker-compose 起 `postgres:16-alpine`,端口 55433。 |
|
||||
| 持久任务引擎 | 优先 `[email protected]`(peer: postgres.js);**须先通过 spike 验证**(重启恢复/等待信号/取消/重试)。未通过则用 `packages/tasks` 内的 PG 租约式任务表(lease + attempts + dead-letter)。 | 结论写 ADR-002。 |
|
||||
| Agent 内核 | `@earendil-works/[email protected]` + `@earendil-works/[email protected]`,锁版本;通过自有 `AgentRuntimePort` 封装,显式工具白名单,不开放 bash/文件系统/任意网络 | 测试用脚本化 fake 模型 provider;真实上游由设置页配置。 |
|
||||
| 校验/测试 | 测试运行器以 Deno spike 结论为准(vitest via Deno 或 `deno test`);web 沿用 token 守卫脚本;lint/format 用 `deno lint/fmt` 或 biome(spike 定) | `deno task ci` = typecheck(tsgo 7)+ lint + test + check:tokens + build |
|
||||
| 校验/测试 | vitest 5(`deno run -A npm:vitest run`,`deno task test` 逐成员执行);类型门禁两道:tsc 7.0.2(`npm:[email protected]`,Go 原生实现,入口 `tsc`)+ `deno check`(Deno 内置 TS 6.0.3);lint/format 用 biome 2.5.14(开启 `useImportExtensions`,相对 import 必须带扩展名);web 沿用 token 守卫脚本 | `deno task ci` = typecheck(tsc 7.0.2 + deno check)+ lint + test + check:tokens + build(web 构建 + `deno compile` 单文件 server)。W1.5 实测(2026-09-27)连跑 3 次全绿,约 75 秒/次;测试数 server 24、adapters 214(+2 skip)、agent 27、contracts 361、db 11、domain 230、tasks 15、testkit 1、web 2 |
|
||||
| 端口 | web dev 5180,API 4380,PG 55433 | 本机 3000/5175/5176/55432 已被占用,不要用 |
|
||||
| 参考源码 | MoviePilot v3: `/opt/moviepilot-plus/upstream/MoviePilot`(提交 e6820a8,GPLv3,只做行为对照与 TS 重写,不复制文件)。**数据来源适配(站点 spider、馒头、RSS、TMDB、qB)照抄 MP v3 实现迁移**(用户 2026-09-27 明确):`app/modules/indexer/spider/__init__.py`、`spider/mtorrent.py`、`app/application/rss.py`、`app/modules/themoviedb/tmdbapi.py`、`app/modules/qbittorrent/qbittorrent.py`;站点定义按 `app/application/site/sites.pyi` 的 schema 手写(MP 的定义文件 `user.sites.v3.bin` 是加密的,无法取用)。**用户 2026-09-27 追加:MP 开源的站点框架全部移植**——所有专用 spider(haidan/hddolby/rousi/sunnypt/tnode/torrentleech/yema/mtorrent)与所有站点类型用户信息解析器(nexus_php/nexus_audiences/nexus_hhanclub/nexus_project/nexus_rabbit/gazelle/unit3d/discuz/ipt/file_list/small_horse/zhixing/bitpt/…),文件与函数一一对应,并维护 `docs/porting/mp-sync-ledger.md` + `scripts/mp-sync` 差异脚本,以后跟随 MP 提交增量移植;MovieClaw 若本机不存在则按 REQ 附录链接对照 | 迁移对照记录写 `docs/porting/` |
|
||||
|
||||
|
||||
+42
-13
@@ -2,20 +2,20 @@
|
||||
|
||||
## 前置
|
||||
|
||||
- Node.js ≥ 24(当前开发机 24.15)、pnpm 11(`packageManager` 已锁)、Docker。
|
||||
- Deno 2.9.7(锁定;`curl -fsSL https://deno.land/install.sh | sh -s v2.9.7`)、Docker。不需要 Node.js / pnpm。
|
||||
- 端口:web 5180、API 4380、PG 55433。本机 3000/5175/5176/55432 已被其他项目占用,不要改用。
|
||||
|
||||
## 首次启动
|
||||
|
||||
```sh
|
||||
cp .env.example .env # 按需修改;server 与 db 脚本都读仓库根 .env
|
||||
pnpm db:up # 起 postgres:16-alpine(docker-compose.dev.yml,数据卷 umt-pg-data)
|
||||
pnpm install
|
||||
pnpm db:migrate # 执行 packages/db/migrations 下全部迁移
|
||||
pnpm dev # 同时起 server(4380)与 web(5180)
|
||||
deno task db:up # 起 postgres:16-alpine(docker-compose.dev.yml,数据卷 umt-pg-data)
|
||||
deno install # 按 deno.lock 装依赖到 node_modules(成员包软链到 node_modules/@umt/*)
|
||||
deno task db:migrate # 执行 packages/db/migrations 下全部迁移
|
||||
deno task dev # 同时起 server(4380)与 web(5180)
|
||||
```
|
||||
|
||||
单独起:`pnpm dev:server`(默认 `--role all`,API + worker 同进程)、`pnpm dev:web`。
|
||||
单独起:`deno task dev:server`(`deno run --watch`,默认 `--role all`,API + worker 同进程)、`deno task dev:web`。
|
||||
|
||||
## 验证
|
||||
|
||||
@@ -32,18 +32,47 @@ curl -N -H "Authorization: Bearer umt-dev-admin-key" "localhost:4380/api/v1/even
|
||||
|
||||
| 命令 | 作用 |
|
||||
|---|---|
|
||||
| `pnpm run ci` | typecheck + lint + test + check:tokens + build,提交前必须全绿。注意 `pnpm ci` 在 pnpm 11 是内置的 clean-install 命令,不会执行本脚本 |
|
||||
| `pnpm format` | biome 自动修复格式与 import 排序 |
|
||||
| `pnpm db:reset` | 清空 public schema 并重新迁移(生产环境拒绝执行) |
|
||||
| `pnpm --filter @umt/web gen:tokens` | 改了 app.css 后重新生成 token 登记表 |
|
||||
| `pnpm --filter @umt/server start` | 运行 `pnpm build` 产出的 `apps/server/dist/main.js` |
|
||||
| `deno task ci` | typecheck(tsc 7.0.2 + deno check)→ lint(biome)→ test(vitest)→ check:tokens → build,提交前必须全绿 |
|
||||
| `deno task typecheck` | `deno types` 生成 `types/deno.d.ts` 后,逐个成员跑 tsc 7.0.2,再跑 `deno check`(Deno 内置 TS 6.0.3) |
|
||||
| `deno task lint` / `deno task fmt` | biome 检查 / 自动修复(含 import 排序;相对 import 必须带扩展名) |
|
||||
| `deno task test` | 逐个成员跑 vitest(`deno run -A npm:vitest run`);单包:`cd packages/<x> && deno task test` |
|
||||
| `deno task db:reset` | 清空 public schema 并重新迁移(生产环境拒绝执行) |
|
||||
| `deno task gen:types` | 从已迁移的库反射生成 `packages/db/src/types.ts` |
|
||||
| `deno task gen:tokens` | 改了 app.css 后重新生成 token 登记表 |
|
||||
| `deno task build` | web 构建到 `apps/web/build/client` + server 编译为单文件 `dist/umt-server` |
|
||||
| `cd apps/server && deno task start` | 以受限权限(net/env/sys/read)直接跑源码 |
|
||||
|
||||
依赖:npm 包版本只在根 `deno.json` 的 `imports` 里登记(web 的前端依赖仍在 `apps/web/package.json`)。改完跑 `deno install` 更新 `deno.lock`。有安装脚本的新依赖需要 `deno approve-scripts` 显式批准。
|
||||
|
||||
## 进程角色
|
||||
|
||||
`node dist/main.js --role api|worker|all`。`all` 下 worker 心跳会发布到进程内事件总线,SSE 可见;分进程部署时事件总线需改为 PG 投影(W2)。
|
||||
`umt-server --role api|worker|all`(源码:`deno run ... apps/server/src/main.ts --role ...`)。`all` 下 worker 心跳会发布到进程内事件总线,SSE 可见;分进程部署时事件总线需改为 PG 投影(W2)。
|
||||
|
||||
一次性子命令(容器入口用):`--role migrate`(迁移到最新,迁移文件已编进二进制)、`--role preflight`(启动自检:生产环境拒绝占位符密钥与 root、DB 可达、`WEB_ROOT/index.html` 存在)、`--role probe`(打本机 `/api/v1/health`,HEALTHCHECK 用)。
|
||||
|
||||
设置 `WEB_ROOT` 后 API 进程在同一端口托管 web 构建产物:存在的文件直接返回,其余非 `/api` 路径回退 `index.html`。
|
||||
|
||||
## Docker 单容器部署
|
||||
|
||||
```sh
|
||||
export SECRET_MASTER_KEY=$(openssl rand -hex 32) POSTGRES_PASSWORD=$(openssl rand -hex 16)
|
||||
docker compose up -d --build # 服务:app(4380)+ postgres(数据卷 umt-pg-data)
|
||||
curl localhost:4380/api/v1/health
|
||||
```
|
||||
|
||||
- 镜像:`denoland/deno:2.9.7` 构建 web 与 `deno compile` 出二进制,运行时 `debian:trixie-slim`,非 root(uid 10001),约 270 MB。
|
||||
- 入口 `docker/entrypoint.sh`:迁移 → 自检 → 同时起 api 与 worker 两个进程;任一退出则停掉另一个并以非 0 退出,由 `restart: unless-stopped` 拉起。
|
||||
- 二进制编译时固定权限:`--allow-net --allow-env --allow-sys --allow-read=/app`,不给 `--allow-run` / 写权限。
|
||||
- 构建版本号:`APP_VERSION=v0.1.0 docker compose build`(写入 web 的 `version.json`)。
|
||||
|
||||
## 测试数据库
|
||||
|
||||
需要 PG 的测试(db、tasks)默认连 `DATABASE_URL` 或 55433 开发库,不可达时跳过。tasks 包可用 `TASKS_TEST_DATABASE_URL` 指定独立库;每个测试文件使用带 pid+随机后缀的独立 schema,结束时删除,多份测试并发跑也不冲突。
|
||||
|
||||
## 排障
|
||||
|
||||
- `配置无效`:按提示检查 `.env`,`SECRET_MASTER_KEY` 至少 16 字符,`DATABASE_URL` 必须是 postgres://。
|
||||
- health 返回 `db: "down"`:`docker compose -f docker-compose.dev.yml ps` 看容器健康状态。
|
||||
- 日志中的 passkey/token/cookie/authorization/password 字段与 URL query 参数会被替换为 `[REDACTED]`;若发现明文,属于缺陷。
|
||||
- `deno check` 报找不到 `Deno`:检查根目录是否误放了 `tsconfig.json`(tsc 基座在 `config/tsconfig.base.json`)。
|
||||
- tsc 报 `Deno` 未定义:先跑 `deno task types` 生成 `types/deno.d.ts`(已 gitignore)。
|
||||
- 日志中的 passkey/token/cookie/authorization/password 字段与 URL query 参数会被替换为 `[REDACTED]`(含 `logger.child()` 绑定字段与 `err` 的 message/stack);若发现明文,属于缺陷。
|
||||
Reference in new issue
Block a user