@whispering233/ai-editor-server 0.0.57 → 0.0.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client-dist/assets/index-BGcP0euU.js +669 -0
- package/client-dist/assets/{index-CV6h1YsD.css → index-F-JE9HKi.css} +1 -1
- package/client-dist/index.html +2 -2
- package/dist/backup.d.ts +31 -7
- package/dist/backup.d.ts.map +1 -1
- package/dist/backup.js +49 -12
- package/dist/backup.js.map +1 -1
- package/dist/chat-runtime.d.ts +3 -0
- package/dist/chat-runtime.d.ts.map +1 -1
- package/dist/chat-runtime.js +1 -0
- package/dist/chat-runtime.js.map +1 -1
- package/dist/cloud/sync.d.ts +3 -2
- package/dist/cloud/sync.d.ts.map +1 -1
- package/dist/cloud/sync.js +3 -2
- package/dist/cloud/sync.js.map +1 -1
- package/dist/http-dispatcher.d.ts.map +1 -1
- package/dist/http-dispatcher.js +4 -2
- package/dist/http-dispatcher.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/kind.d.ts +19 -0
- package/dist/middleware/kind.d.ts.map +1 -0
- package/dist/middleware/kind.js +34 -0
- package/dist/middleware/kind.js.map +1 -0
- package/dist/middleware/project.d.ts +2 -2
- package/dist/middleware/project.d.ts.map +1 -1
- package/dist/middleware/project.js +6 -3
- package/dist/middleware/project.js.map +1 -1
- package/dist/routes/chat.d.ts +4 -2
- package/dist/routes/chat.d.ts.map +1 -1
- package/dist/routes/chat.js +79 -6
- package/dist/routes/chat.js.map +1 -1
- package/dist/routes/cloud.js +7 -5
- package/dist/routes/cloud.js.map +1 -1
- package/dist/routes/practice.d.ts +4 -0
- package/dist/routes/practice.d.ts.map +1 -0
- package/dist/routes/practice.js +209 -0
- package/dist/routes/practice.js.map +1 -0
- package/dist/routes/project.d.ts +17 -10
- package/dist/routes/project.d.ts.map +1 -1
- package/dist/routes/project.js +143 -83
- package/dist/routes/project.js.map +1 -1
- package/dist/routes/settings.js +1 -1
- package/dist/routes/settings.js.map +1 -1
- package/package.json +7 -7
- package/client-dist/assets/index-DH9B3drg.js +0 -625
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// 作家文风练习路由(/api/v1/practice/*,2026-10 改版)——13 个端点
|
|
2
|
+
//
|
|
3
|
+
// 契约:`docs/api/120-api-practice.md`(13 个端点的 Req/Res 形状与语义)、
|
|
4
|
+
// `docs/api/error-code.md`(`KIND_MISMATCH` 400 / `VALIDATION_ERROR` 400 / `PRACTICE_NOT_FOUND` 404);
|
|
5
|
+
// 设计与不变式见 `docs/design/60-practice.md` §2 / §5 / §6。
|
|
6
|
+
//
|
|
7
|
+
// 分工(**库写入唯一入口 = db 包 `queries/practice.ts`,本层不碰表**):
|
|
8
|
+
// - 请求 schema 单一来源 = shared `types/api.ts`(本层只 parse 请求;**响应 schema 是类型契约,
|
|
9
|
+
// 响应不 `.parse()`**——由本层按文档逐字段拼出);schema 全 `.strict()` ⇒ 多余字段被拒
|
|
10
|
+
// - **长度上限校验落 shared schema**(db 层有意不校验):超限 → 400 `VALIDATION_ERROR`
|
|
11
|
+
// - 本层另做两件 db 层不做的校验:① `work_id` 成员校验(shared `resolveWork`);
|
|
12
|
+
// ② 不存在 → 404 `PRACTICE_NOT_FOUND`(**文案按资源**:样本「练习样本不存在」、自由练习「自由练习不存在」)
|
|
13
|
+
//
|
|
14
|
+
// 前置守卫(单点函数 `requirePracticeWorkspace`,本组全部端点共用):
|
|
15
|
+
// ① `kind ≠ "practice"` → 400 `KIND_MISMATCH`(文案与服务端 `requireKind` 同源,见 middleware/kind.ts;
|
|
16
|
+
// 整组中间件 `requireKind("practice")` 另挂在 index.ts,本函数是端点级同口径兜底,不改错误语义);
|
|
17
|
+
// ② `author_id` 解析不到预置作家 → 400 `VALIDATION_ERROR`「练习工作区未关联预置作家」(存量 / 坏值工作区)。
|
|
18
|
+
import { Hono } from "hono";
|
|
19
|
+
import { createPracticePiece, createPracticeSample, deletePracticePiece, deletePracticeSample, deleteStylePack, getPracticePiece, getPracticeSample, getStylePack, listPracticePieces, listPracticeSamples, updatePracticePieceDraft, updatePracticeSampleDraft, upsertStylePack, } from "@whispering233/ai-editor-db";
|
|
20
|
+
import { resolveAuthor, resolveWork } from "@whispering233/ai-editor-shared";
|
|
21
|
+
import { practiceDraftPutReqSchema, practicePieceCreateReqSchema, practiceSampleCreateReqSchema, practiceStylePackPutReqSchema, } from "@whispering233/ai-editor-shared/schemas";
|
|
22
|
+
import { HttpError, ok } from "../middleware/error.js";
|
|
23
|
+
import { assertWorkspaceKind } from "../middleware/kind.js";
|
|
24
|
+
import { requireCurrentProject } from "../middleware/project.js";
|
|
25
|
+
/** 练习路由(挂载于 /api/v1/practice,index.ts) */
|
|
26
|
+
export const practiceRoutes = new Hono();
|
|
27
|
+
/** 样本不存在(详情 / 保存稿件 / 删除)→ 404 `PRACTICE_NOT_FOUND` */
|
|
28
|
+
function sampleNotFound() {
|
|
29
|
+
return new HttpError(404, "PRACTICE_NOT_FOUND", "练习样本不存在");
|
|
30
|
+
}
|
|
31
|
+
/** 自由练习篇不存在(详情 / 保存稿件 / 删除)→ 404 `PRACTICE_NOT_FOUND` */
|
|
32
|
+
function pieceNotFound() {
|
|
33
|
+
return new HttpError(404, "PRACTICE_NOT_FOUND", "自由练习不存在");
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 前置守卫(本组端点共用的**单点**):当前工作区必须 `kind = "practice"` 且 `author_id` 能解析到
|
|
37
|
+
* 预置作家(shared `AUTHOR_CATALOG`);无当前工作区 → 409 `NO_PROJECT_OPEN`(`requireCurrentProject`)。
|
|
38
|
+
* 返回已解析的作家条目,供素材包端点取预置风格说明(不重复解析)。
|
|
39
|
+
*/
|
|
40
|
+
function requirePracticeWorkspace() {
|
|
41
|
+
const project = requireCurrentProject();
|
|
42
|
+
assertWorkspaceKind(project, "practice");
|
|
43
|
+
const author = resolveAuthor(project.config.author_id);
|
|
44
|
+
if (author === null) {
|
|
45
|
+
throw new HttpError(400, "VALIDATION_ERROR", "练习工作区未关联预置作家");
|
|
46
|
+
}
|
|
47
|
+
return { project, author };
|
|
48
|
+
}
|
|
49
|
+
/** 请求体解析:空 body / 非法 JSON → null,统一交给 schema 报校验失败(同 names.ts 口径) */
|
|
50
|
+
async function readJson(c) {
|
|
51
|
+
return c.req.json().catch(() => null);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 样本详情的 API 投影(详情与新建样本的响应共用同一形状)。
|
|
55
|
+
* `feedback` 只透传:写入侧唯一入口是提交点评工具,读取侧的坏 JSON 防御解析在 db 层
|
|
56
|
+
* (**非对象** → null,合法 JSON 对象一律透传)——本层不重复校验、也不做键名转换。
|
|
57
|
+
*/
|
|
58
|
+
function toSampleDetail(row) {
|
|
59
|
+
return {
|
|
60
|
+
id: row.id,
|
|
61
|
+
workId: row.work_id,
|
|
62
|
+
excerptLabel: row.excerpt_label,
|
|
63
|
+
text: row.text,
|
|
64
|
+
draft: row.draft,
|
|
65
|
+
feedback: row.feedback,
|
|
66
|
+
createdAt: row.created_at,
|
|
67
|
+
updatedAt: row.updated_at,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** 自由练习详情的 API 投影(详情与新建的响应共用同一形状) */
|
|
71
|
+
function toPieceDetail(row) {
|
|
72
|
+
return {
|
|
73
|
+
id: row.id,
|
|
74
|
+
topic: row.topic,
|
|
75
|
+
brief: row.brief,
|
|
76
|
+
topicSource: row.topic_source,
|
|
77
|
+
draft: row.draft,
|
|
78
|
+
feedback: row.feedback,
|
|
79
|
+
createdAt: row.created_at,
|
|
80
|
+
updatedAt: row.updated_at,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// ============ 范文样本(五端点) ============
|
|
84
|
+
// GET /api/v1/practice/samples —— 本工作区全部样本(按 updatedAt 倒序;列表不回正文与卡体)
|
|
85
|
+
practiceRoutes.get("/samples", (c) => {
|
|
86
|
+
const { project } = requirePracticeWorkspace();
|
|
87
|
+
return c.json(ok({ samples: listPracticeSamples(project.db) }));
|
|
88
|
+
});
|
|
89
|
+
// POST /api/v1/practice/samples —— 新建样本(粘贴或导入文本均走这里)
|
|
90
|
+
practiceRoutes.post("/samples", async (c) => {
|
|
91
|
+
const { project, author } = requirePracticeWorkspace();
|
|
92
|
+
const parsed = practiceSampleCreateReqSchema.safeParse(await readJson(c));
|
|
93
|
+
if (!parsed.success)
|
|
94
|
+
throw parsed.error; // → 400 VALIDATION_ERROR(含 fields)
|
|
95
|
+
const workId = parsed.data.work_id ?? null;
|
|
96
|
+
// work_id 成员校验:给了就必须在预置作品清单内(未知 id 不静默落成「其他」——那会让用户以为选上了)
|
|
97
|
+
if (workId !== null && resolveWork(author.id, workId) === null) {
|
|
98
|
+
throw new HttpError(400, "VALIDATION_ERROR", `未知的作品 id: ${workId}(须为预置作品清单内的 id)`);
|
|
99
|
+
}
|
|
100
|
+
const row = createPracticeSample(project.db, {
|
|
101
|
+
workId,
|
|
102
|
+
excerptLabel: parsed.data.excerpt_label,
|
|
103
|
+
text: parsed.data.text,
|
|
104
|
+
});
|
|
105
|
+
return c.json(ok(toSampleDetail(row)));
|
|
106
|
+
});
|
|
107
|
+
// GET /api/v1/practice/samples/:id —— 样本详情(唯一返回范文全文与点评卡的读端点)
|
|
108
|
+
practiceRoutes.get("/samples/:id", (c) => {
|
|
109
|
+
const { project } = requirePracticeWorkspace();
|
|
110
|
+
const row = getPracticeSample(project.db, c.req.param("id"));
|
|
111
|
+
if (row === null)
|
|
112
|
+
throw sampleNotFound();
|
|
113
|
+
return c.json(ok(toSampleDetail(row)));
|
|
114
|
+
});
|
|
115
|
+
// PUT /api/v1/practice/samples/:id —— 保存仿写稿(strict 单字段;唯一的用户写稿入口,后写覆盖)
|
|
116
|
+
practiceRoutes.put("/samples/:id", async (c) => {
|
|
117
|
+
const { project } = requirePracticeWorkspace();
|
|
118
|
+
const parsed = practiceDraftPutReqSchema.safeParse(await readJson(c));
|
|
119
|
+
if (!parsed.success)
|
|
120
|
+
throw parsed.error;
|
|
121
|
+
const result = updatePracticeSampleDraft(project.db, c.req.param("id"), parsed.data.draft);
|
|
122
|
+
if (result === null)
|
|
123
|
+
throw sampleNotFound();
|
|
124
|
+
return c.json(ok(result));
|
|
125
|
+
});
|
|
126
|
+
// DELETE /api/v1/practice/samples/:id —— 删除样本(物理删)
|
|
127
|
+
practiceRoutes.delete("/samples/:id", (c) => {
|
|
128
|
+
const { project } = requirePracticeWorkspace();
|
|
129
|
+
if (!deletePracticeSample(project.db, c.req.param("id")))
|
|
130
|
+
throw sampleNotFound();
|
|
131
|
+
return c.json(ok({ deleted: true }));
|
|
132
|
+
});
|
|
133
|
+
// ============ 作家风格说明素材包(三端点) ============
|
|
134
|
+
//
|
|
135
|
+
// 预置文本 = shared 常量(无端点);这里读写的是当前工作区作者的**用户覆盖**(单行)。
|
|
136
|
+
/** 生效内容 = 用户覆盖 `??` 预置(无覆盖 → 预置,恒非空) */
|
|
137
|
+
function toStylePack(author, override) {
|
|
138
|
+
return {
|
|
139
|
+
authorId: author.id,
|
|
140
|
+
content: override?.content ?? author.styleNotes,
|
|
141
|
+
customized: override !== null,
|
|
142
|
+
updatedAt: override?.updated_at ?? null,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
// GET /api/v1/practice/style-pack —— 生效内容 + 是否有用户覆盖
|
|
146
|
+
practiceRoutes.get("/style-pack", (c) => {
|
|
147
|
+
const { project, author } = requirePracticeWorkspace();
|
|
148
|
+
return c.json(ok(toStylePack(author, getStylePack(project.db, author.id))));
|
|
149
|
+
});
|
|
150
|
+
// PUT /api/v1/practice/style-pack —— 写入用户覆盖(trim 非空;清空请用 DELETE)
|
|
151
|
+
practiceRoutes.put("/style-pack", async (c) => {
|
|
152
|
+
const { project, author } = requirePracticeWorkspace();
|
|
153
|
+
const parsed = practiceStylePackPutReqSchema.safeParse(await readJson(c));
|
|
154
|
+
if (!parsed.success)
|
|
155
|
+
throw parsed.error;
|
|
156
|
+
return c.json(ok(toStylePack(author, upsertStylePack(project.db, author.id, parsed.data.content))));
|
|
157
|
+
});
|
|
158
|
+
// DELETE /api/v1/practice/style-pack —— 删除用户覆盖 = 恢复预置(幂等:无覆盖也 200)
|
|
159
|
+
practiceRoutes.delete("/style-pack", (c) => {
|
|
160
|
+
const { project, author } = requirePracticeWorkspace();
|
|
161
|
+
deleteStylePack(project.db, author.id);
|
|
162
|
+
return c.json(ok(toStylePack(author, null)));
|
|
163
|
+
});
|
|
164
|
+
// ============ 自由练习(五端点) ============
|
|
165
|
+
// GET /api/v1/practice/free —— 本工作区全部自由练习篇(按 updatedAt 倒序;列表不回稿件与卡体)
|
|
166
|
+
practiceRoutes.get("/free", (c) => {
|
|
167
|
+
const { project } = requirePracticeWorkspace();
|
|
168
|
+
return c.json(ok({ pieces: listPracticePieces(project.db) }));
|
|
169
|
+
});
|
|
170
|
+
// POST /api/v1/practice/free —— 新建自由练习篇(自拟题,或建「待出题」空题行)
|
|
171
|
+
practiceRoutes.post("/free", async (c) => {
|
|
172
|
+
const { project } = requirePracticeWorkspace();
|
|
173
|
+
const parsed = practicePieceCreateReqSchema.safeParse(await readJson(c));
|
|
174
|
+
if (!parsed.success)
|
|
175
|
+
throw parsed.error; // topic 与 topic_source 的一致性在 schema(superRefine)
|
|
176
|
+
const row = createPracticePiece(project.db, {
|
|
177
|
+
topicSource: parsed.data.topic_source,
|
|
178
|
+
topic: parsed.data.topic,
|
|
179
|
+
brief: parsed.data.brief,
|
|
180
|
+
});
|
|
181
|
+
return c.json(ok(toPieceDetail(row)));
|
|
182
|
+
});
|
|
183
|
+
// GET /api/v1/practice/free/:id —— 自由练习详情(唯一返回稿件全文与点评卡的读端点)
|
|
184
|
+
practiceRoutes.get("/free/:id", (c) => {
|
|
185
|
+
const { project } = requirePracticeWorkspace();
|
|
186
|
+
const row = getPracticePiece(project.db, c.req.param("id"));
|
|
187
|
+
if (row === null)
|
|
188
|
+
throw pieceNotFound();
|
|
189
|
+
return c.json(ok(toPieceDetail(row)));
|
|
190
|
+
});
|
|
191
|
+
// PUT /api/v1/practice/free/:id —— 保存自由练习稿(与仿写稿同一口径:strict 单字段、允许空串、后写覆盖)
|
|
192
|
+
practiceRoutes.put("/free/:id", async (c) => {
|
|
193
|
+
const { project } = requirePracticeWorkspace();
|
|
194
|
+
const parsed = practiceDraftPutReqSchema.safeParse(await readJson(c));
|
|
195
|
+
if (!parsed.success)
|
|
196
|
+
throw parsed.error;
|
|
197
|
+
const result = updatePracticePieceDraft(project.db, c.req.param("id"), parsed.data.draft);
|
|
198
|
+
if (result === null)
|
|
199
|
+
throw pieceNotFound();
|
|
200
|
+
return c.json(ok(result));
|
|
201
|
+
});
|
|
202
|
+
// DELETE /api/v1/practice/free/:id —— 删除自由练习篇(物理删;不满意的 AI 出题 = 删掉重建)
|
|
203
|
+
practiceRoutes.delete("/free/:id", (c) => {
|
|
204
|
+
const { project } = requirePracticeWorkspace();
|
|
205
|
+
if (!deletePracticePiece(project.db, c.req.param("id")))
|
|
206
|
+
throw pieceNotFound();
|
|
207
|
+
return c.json(ok({ deleted: true }));
|
|
208
|
+
});
|
|
209
|
+
//# sourceMappingURL=practice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"practice.js","sourceRoot":"","sources":["../../src/routes/practice.ts"],"names":[],"mappings":"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"}
|
package/dist/routes/project.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
+
import type { WorkspaceKind } from "@whispering233/ai-editor-shared";
|
|
2
3
|
/** 设置创作根(index.ts startServer 调用;测试隔离用传 null 重置) */
|
|
3
4
|
export declare function setProjectRoot(root: string | null): void;
|
|
4
|
-
/**
|
|
5
|
+
/** 读创作根(工作区模式:创作根 / `<kind 目录>/<名字>/`;未初始化 → null) */
|
|
5
6
|
export declare function getProjectRoot(): string | null;
|
|
6
|
-
/** books/ 子目录名(书架模式:创作根/books/<书名>/) */
|
|
7
|
-
export declare const BOOKS_DIR_NAME = "books";
|
|
8
7
|
/**
|
|
9
8
|
* 规范化并校验项目路径(create/open 通用):
|
|
10
9
|
*
|
|
@@ -33,17 +32,25 @@ export declare const projectRoutes: Hono<import("hono/types").BlankEnv, import("
|
|
|
33
32
|
*/
|
|
34
33
|
export declare function isBookNameValid(name: string): boolean;
|
|
35
34
|
/**
|
|
36
|
-
* 按 project_id
|
|
37
|
-
*
|
|
35
|
+
* 按 project_id 在创作根下定位工作区目录(唯一 key = project_id):
|
|
36
|
+
* 遍历**各工作区目录**(`WORKSPACE_KINDS` 全量,不只 books/——练习工作区同在书架列表里)
|
|
37
|
+
* 下各子目录的 project.json 读 id 比对;无匹配返回 null。
|
|
38
|
+
* 命中时一并返回**目录位置推出的 kind**(命中路径就是该 kind 目录的直接子目录)——
|
|
39
|
+
* 覆盖恢复的 kind 归一用它(目录是事实,不读包内 kind)。
|
|
38
40
|
* 损坏的 project.json 抛错向上传播(与 list/open 语义一致:坏数据不静默吞)。
|
|
39
41
|
* 导出供 `/cloud/remote-books`(`localExists`)与 `/cloud/import-book`(同 id 拒重复导入)复用。
|
|
40
42
|
*/
|
|
41
|
-
export declare function findBookDirById(root: string, id: string):
|
|
43
|
+
export declare function findBookDirById(root: string, id: string): {
|
|
44
|
+
dir: string;
|
|
45
|
+
kind: WorkspaceKind;
|
|
46
|
+
} | null;
|
|
42
47
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
48
|
+
* 新工作区目标目录去重(import / 云端导入节):`<kind 目录>/<name>/` 已存在 →
|
|
49
|
+
* `<kind 目录>/<name> (N)/`(N 为最小正整数,从 2 起,避免与去重命名惯例冲突);
|
|
45
50
|
* 返回去重后的目录绝对路径。project.json 内部 name 由调用方同步为去重名
|
|
46
|
-
* (「目录名 =
|
|
51
|
+
* (「目录名 = 名字」不变式)。
|
|
52
|
+
*
|
|
53
|
+
* `kind` 取**包内 project.json** 的值(备份是权威)——目录名一律取 shared `WORKSPACE_DIRS`。
|
|
47
54
|
*/
|
|
48
|
-
export declare function uniqueBookDir(root: string, name: string): string;
|
|
55
|
+
export declare function uniqueBookDir(root: string, name: string, kind: WorkspaceKind): string;
|
|
49
56
|
//# sourceMappingURL=project.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/routes/project.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/routes/project.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAE1C,OAAO,KAAK,EAAsC,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAuEzG,oDAAoD;AACpD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAExD;AAED,sDAAsD;AACtD,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAE9C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAkBzD;AAED,yCAAyC;AACzC,eAAO,MAAM,aAAa,4EAAa,CAAC;AAuTxC;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAkBD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,aAAa,CAAA;CAAE,GAAG,IAAI,CAiBrG;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,CAOrF"}
|