78 lines
3.6 KiB
Markdown
78 lines
3.6 KiB
Markdown
# AGENTS.md — @app/trpc
|
||
|
||
## 职责
|
||
|
||
API 层:**tRPC 路由 + service 业务逻辑**。service 可不依赖 tRPC 独立调用(脚本/测试);DB 读写经 `@app/dao`,不直接写 SQL。
|
||
|
||
域划分:
|
||
- 账户域:`user`、`auth`
|
||
- 媒体域:挂在 `media` 路由下的 mount / library / stream / danmaku / scrape / playback
|
||
|
||
新域按同样模式追加。
|
||
|
||
## 结构
|
||
|
||
```
|
||
src/
|
||
context.ts # initTRPC 单例 + TrpcContext
|
||
router/
|
||
index.ts # appRouter 组装(权威定义:user / auth / media)
|
||
user.router.ts # user 路由(与 index.ts 内定义重复,改路由时两边同步或收敛到一处)
|
||
auth.router.ts # auth 路由
|
||
media.router.ts # 媒体域扁平 procedure(mount* / library* / scrape* / playback* / danmaku*)
|
||
services/
|
||
user.service.ts # userService
|
||
auth.service.ts # authService:会话 / 密码
|
||
password.ts # scrypt 哈希(与 @app/db seed 一致)
|
||
procedure.ts # protectedProcedure 等
|
||
secret.ts # 媒体流密钥
|
||
mount.service.ts # mountService:WebDAV 挂载
|
||
webdav-client.ts # WebDAV 客户端(含单测)
|
||
library.service.ts # libraryService:扫描 / 分组 / 剧集
|
||
stream.service.ts # 流式输出(含单测)
|
||
danmaku.service.ts # danmakuService:弹幕拉取 / 导入 / 设置(含单测)
|
||
scrape.service.ts # scrapeService:番剧识别 / 绑定(含单测)
|
||
playback.service.ts # playbackService:进度上报 / 续播
|
||
load-env.ts
|
||
server.ts # 独立 HTTP 服务(PORT,默认 4000)
|
||
index.ts # 对外:appRouter、类型、services
|
||
router.ts # 兼容旧入口的再导出
|
||
```
|
||
|
||
构建:`vite build`(`emptyOutDir: false`)→ `tsc -p tsconfig.dts.json` 产出 `.d.ts`。勿开 dts 的 incremental(vite 会先清产物,缓存会导致 tsc 跳过 emit);勿改回 vite-plugin-dts。
|
||
|
||
## 请求流
|
||
|
||
```
|
||
web /api/trpc ──► appRouter ──► service ──► @app/dao ──► @app/db
|
||
```
|
||
|
||
也可 `yarn dev:api` 跑 `server.ts`(独立端口);web SSR 内嵌时通常不用。
|
||
|
||
媒体域 procedure 用 `protectedProcedure`(需登录,取 `ctx.userId`);路由层只做 input 映射 + 调 service。
|
||
|
||
## 修改指南
|
||
|
||
1. **改入参**:先改 `@app/types` 的 Zod schema,再挂到 `t.procedure.input(...)`。
|
||
2. **加 procedure**:路由只做 input 映射 + 调 service;业务在 `services/*.service.ts`;SQL 在 `@app/dao`。
|
||
3. **加领域**:新建 `services/x.service.ts` + 在 `media.router.ts`(或新 `router/x.router.ts`)挂 procedure,接到 `appRouter`,并在 `index.ts` 导出。
|
||
4. 导出给前端的类型用 `RouterInputs` / `RouterOutputs`(来自 `router/index.ts`)。
|
||
5. 外部 API(弹幕/刮削)调用集中在对应 service,注意超时与错误包装;SSRF/路径穿越防护见 `stream.service` / `webdav-client`。
|
||
|
||
## 约束
|
||
|
||
- `exactOptionalPropertyTypes`:service 的 update 入参写成 `name?: string | undefined`。
|
||
- `noUncheckedIndexedAccess`:判空逻辑在 DAO 内处理(参考 `userDao.create`)。
|
||
- 不要在 router/service 里写 SQL;不在 service 里依赖 HTTP/tRPC context(除非鉴权明确需要)。
|
||
- `router.ts` 仅兼容旧 import,新代码从 `index.ts` / `./router/index.js` 引入。
|
||
- service 旁的 `*.test.ts` 用 vitest/vite 跑(`vite.config.ts`),改行为时同步补测。
|
||
|
||
## 命令
|
||
|
||
```bash
|
||
yarn workspace @app/trpc typecheck
|
||
yarn workspace @app/trpc lint
|
||
yarn workspace @app/trpc build
|
||
yarn workspace @app/trpc dev # tsx watch src/server.ts
|
||
```
|