@musnows/scriverse 0.7.3 → 0.7.4

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.
Files changed (54) hide show
  1. package/README.en.md +3 -0
  2. package/README.md +3 -0
  3. package/dist/ai-connectivity-test.js +109 -0
  4. package/dist/ai-connectivity-test.js.map +1 -0
  5. package/dist/ai-conversation-export.js +70 -0
  6. package/dist/ai-conversation-export.js.map +1 -0
  7. package/dist/ai-stream-timeout.js +18 -0
  8. package/dist/ai-stream-timeout.js.map +1 -0
  9. package/dist/ai.js +681 -107
  10. package/dist/ai.js.map +1 -1
  11. package/dist/app.js +326 -53
  12. package/dist/app.js.map +1 -1
  13. package/dist/character-extraction.js +133 -0
  14. package/dist/character-extraction.js.map +1 -0
  15. package/dist/cli-core.js +7 -6
  16. package/dist/cli-core.js.map +1 -1
  17. package/dist/database.js +175 -2
  18. package/dist/database.js.map +1 -1
  19. package/dist/epub-export.js +319 -0
  20. package/dist/epub-export.js.map +1 -0
  21. package/dist/hybrid-search.js +8 -0
  22. package/dist/hybrid-search.js.map +1 -1
  23. package/dist/public/ai-connectivity-test.d.ts +7 -0
  24. package/dist/public/ai-connectivity-test.js +82 -0
  25. package/dist/public/ai-request-manager.js +99 -0
  26. package/dist/public/ai-stream-protocol.js +51 -0
  27. package/dist/public/app.js +2567 -265
  28. package/dist/public/chapter-version-diff.d.ts +20 -0
  29. package/dist/public/chapter-version-diff.js +116 -0
  30. package/dist/public/foreshadow-reminder.d.ts +32 -0
  31. package/dist/public/foreshadow-reminder.js +73 -0
  32. package/dist/public/global-replace-refresh.js +60 -0
  33. package/dist/public/index.html +120 -12
  34. package/dist/public/outline-board.d.ts +61 -0
  35. package/dist/public/outline-board.js +137 -0
  36. package/dist/public/page-route.d.ts +1 -0
  37. package/dist/public/page-route.js +8 -0
  38. package/dist/public/reading-preview.d.ts +32 -0
  39. package/dist/public/reading-preview.js +136 -0
  40. package/dist/public/styles.css +485 -4
  41. package/dist/public/upload-progress.d.ts +2 -0
  42. package/dist/public/upload-progress.js +10 -0
  43. package/dist/security.js +5 -2
  44. package/dist/security.js.map +1 -1
  45. package/dist/server-runtime.js +2 -0
  46. package/dist/server-runtime.js.map +1 -1
  47. package/dist/store.js +825 -88
  48. package/dist/store.js.map +1 -1
  49. package/dist/user-auth.js +45 -9
  50. package/dist/user-auth.js.map +1 -1
  51. package/dist/utils.js +3 -0
  52. package/dist/utils.js.map +1 -1
  53. package/dist/version.js +1 -1
  54. package/package.json +2 -1
@@ -0,0 +1,319 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import JSZip from "jszip";
3
+ import sharp from "sharp";
4
+ export const EPUB_MIME_TYPE = "application/epub+zip";
5
+ const bidiControlCharacters = /[\u202a-\u202e\u2066-\u2069]/gu;
6
+ const unsafeFileNameCharacters = /[\u0000-\u001f\u007f-\u009f<>:"/\\|?*]/gu;
7
+ function xml(value) {
8
+ return value
9
+ .replaceAll("&", "&amp;")
10
+ .replaceAll("<", "&lt;")
11
+ .replaceAll(">", "&gt;")
12
+ .replaceAll('"', "&quot;")
13
+ .replaceAll("'", "&apos;");
14
+ }
15
+ function normalizeLanguage(value) {
16
+ const language = String(value ?? "").trim();
17
+ return /^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/u.test(language) ? language : "zh-CN";
18
+ }
19
+ function normalizeModifiedAt(value) {
20
+ const parsed = value ? new Date(value) : new Date();
21
+ const date = Number.isNaN(parsed.getTime()) ? new Date() : parsed;
22
+ return { date, value: date.toISOString().replace(/\.\d{3}Z$/u, "Z") };
23
+ }
24
+ function xhtmlPage(input) {
25
+ const bodyType = input.bodyType ? ` epub:type="${xml(input.bodyType)}"` : "";
26
+ const stylePath = input.stylePath ?? "../styles/book.css";
27
+ return `<?xml version="1.0" encoding="UTF-8"?>
28
+ <!DOCTYPE html>
29
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="${xml(input.language)}" xml:lang="${xml(input.language)}">
30
+ <head>
31
+ <meta charset="UTF-8" />
32
+ <title>${xml(input.title)}</title>
33
+ <link rel="stylesheet" type="text/css" href="${xml(stylePath)}" />
34
+ </head>
35
+ <body${bodyType}>
36
+ ${input.body}
37
+ </body>
38
+ </html>
39
+ `;
40
+ }
41
+ function renderChapterBody(content) {
42
+ const lines = String(content ?? "").replace(/\r\n?/gu, "\n").split("\n");
43
+ const blocks = [];
44
+ let paragraph = [];
45
+ let code = null;
46
+ const flushParagraph = () => {
47
+ if (!paragraph.length)
48
+ return;
49
+ blocks.push(` <p>${paragraph.map(xml).join("<br />\n")}</p>`);
50
+ paragraph = [];
51
+ };
52
+ const flushCode = () => {
53
+ if (code === null)
54
+ return;
55
+ blocks.push(` <pre class="code-block"><code>${xml(code.join("\n"))}</code></pre>`);
56
+ code = null;
57
+ };
58
+ for (const line of lines) {
59
+ if (/^\s*`{3,}[^`]*$/u.test(line)) {
60
+ if (code === null) {
61
+ flushParagraph();
62
+ code = [];
63
+ }
64
+ else {
65
+ flushCode();
66
+ }
67
+ continue;
68
+ }
69
+ if (code !== null) {
70
+ code.push(line);
71
+ continue;
72
+ }
73
+ if (!line.trim()) {
74
+ flushParagraph();
75
+ continue;
76
+ }
77
+ paragraph.push(line);
78
+ }
79
+ flushParagraph();
80
+ flushCode();
81
+ return blocks.join("\n");
82
+ }
83
+ async function prepareCover(cover) {
84
+ if (cover.mimeType === "image/jpeg") {
85
+ return { content: cover.content, extension: "jpg", mediaType: "image/jpeg" };
86
+ }
87
+ if (cover.mimeType === "image/png") {
88
+ return { content: cover.content, extension: "png", mediaType: "image/png" };
89
+ }
90
+ return {
91
+ content: await sharp(cover.content, { limitInputPixels: 16_777_216 }).png().toBuffer(),
92
+ extension: "png",
93
+ mediaType: "image/png"
94
+ };
95
+ }
96
+ function packageDocument(input) {
97
+ const creator = input.author ? `\n <dc:creator>${xml(input.author)}</dc:creator>` : "";
98
+ const description = input.description ? `\n <dc:description>${xml(input.description)}</dc:description>` : "";
99
+ const coverMetadata = input.cover ? '\n <meta name="cover" content="cover-image" />' : "";
100
+ const coverManifest = input.cover
101
+ ? `\n <item id="cover-image" href="images/cover.${input.cover.extension}" media-type="${input.cover.mediaType}" properties="cover-image" />\n <item id="cover-page" href="text/cover.xhtml" media-type="application/xhtml+xml" />`
102
+ : "";
103
+ const documentManifest = input.documents
104
+ .map((document) => ` <item id="${document.id}" href="${document.href}" media-type="application/xhtml+xml" />`)
105
+ .join("\n");
106
+ const coverSpine = input.cover ? '\n <itemref idref="cover-page" linear="no" />' : "";
107
+ const documentSpine = input.documents.map((document) => ` <itemref idref="${document.id}" />`).join("\n");
108
+ const guide = input.cover ? '\n <guide>\n <reference type="cover" title="封面" href="text/cover.xhtml" />\n </guide>' : "";
109
+ return `<?xml version="1.0" encoding="UTF-8"?>
110
+ <package xmlns="http://www.idpf.org/2007/opf" xmlns:dc="http://purl.org/dc/elements/1.1/" version="3.0" unique-identifier="pub-id" xml:lang="${xml(input.language)}" prefix="dcterms: http://purl.org/dc/terms/">
111
+ <metadata>
112
+ <dc:identifier id="pub-id">${xml(input.identifier)}</dc:identifier>
113
+ <dc:title>${xml(input.title)}</dc:title>
114
+ <dc:language>${xml(input.language)}</dc:language>${creator}${description}
115
+ <meta property="dcterms:modified">${xml(input.modifiedAt)}</meta>${coverMetadata}
116
+ </metadata>
117
+ <manifest>
118
+ <item id="nav" href="nav.xhtml" media-type="application/xhtml+xml" properties="nav" />
119
+ <item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml" />
120
+ <item id="style" href="styles/book.css" media-type="text/css" />${coverManifest}
121
+ ${documentManifest}
122
+ </manifest>
123
+ <spine toc="ncx">${coverSpine}
124
+ ${documentSpine}
125
+ </spine>${guide}
126
+ </package>
127
+ `;
128
+ }
129
+ function navigationDocument(input) {
130
+ const volumeContents = input.volumes.map(({ document, chapters }) => {
131
+ const children = chapters.length
132
+ ? `\n <ol>\n${chapters.map((chapter) => ` <li><a href="${chapter.href}">${xml(chapter.title)}</a></li>`).join("\n")}\n </ol>`
133
+ : "";
134
+ return ` <li><a href="${document.href}">${xml(document.title)}</a>${children}</li>`;
135
+ }).join("\n");
136
+ const contents = volumeContents || ' <li><a href="text/title.xhtml">书名页</a></li>';
137
+ const coverLandmark = input.hasCover ? '\n <li><a epub:type="cover" href="text/cover.xhtml">封面</a></li>' : "";
138
+ const body = ` <nav epub:type="toc" id="toc" aria-labelledby="toc-title">
139
+ <h1 id="toc-title">目录</h1>
140
+ <ol>
141
+ ${contents}
142
+ </ol>
143
+ </nav>
144
+ <nav epub:type="landmarks" aria-label="阅读导航">
145
+ <ol>${coverLandmark}
146
+ <li><a epub:type="titlepage" href="text/title.xhtml">书名页</a></li>
147
+ <li><a epub:type="bodymatter" href="${input.volumes[0]?.document.href ?? "text/title.xhtml"}">正文</a></li>
148
+ </ol>
149
+ </nav>`;
150
+ return xhtmlPage({ language: input.language, title: `${input.title}目录`, body, stylePath: "styles/book.css" });
151
+ }
152
+ function ncxDocument(input) {
153
+ let playOrder = 0;
154
+ const volumeNavigation = input.volumes.map(({ document, chapters }) => {
155
+ playOrder += 1;
156
+ const volumeOrder = playOrder;
157
+ const children = chapters.map((chapter) => {
158
+ playOrder += 1;
159
+ return ` <navPoint id="${chapter.id}" playOrder="${playOrder}">
160
+ <navLabel><text>${xml(chapter.title)}</text></navLabel>
161
+ <content src="${chapter.href}" />
162
+ </navPoint>`;
163
+ }).join("\n");
164
+ return ` <navPoint id="${document.id}" playOrder="${volumeOrder}">
165
+ <navLabel><text>${xml(document.title)}</text></navLabel>
166
+ <content src="${document.href}" />${children ? `\n${children}` : ""}
167
+ </navPoint>`;
168
+ }).join("\n");
169
+ const navigation = volumeNavigation || ` <navPoint id="title-page" playOrder="1">
170
+ <navLabel><text>${xml(input.title)}</text></navLabel>
171
+ <content src="text/title.xhtml" />
172
+ </navPoint>`;
173
+ return `<?xml version="1.0" encoding="UTF-8"?>
174
+ <ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
175
+ <head>
176
+ <meta name="dtb:uid" content="${xml(input.identifier)}" />
177
+ <meta name="dtb:depth" content="2" />
178
+ <meta name="dtb:totalPageCount" content="0" />
179
+ <meta name="dtb:maxPageNumber" content="0" />
180
+ </head>
181
+ <docTitle><text>${xml(input.title)}</text></docTitle>
182
+ <navMap>
183
+ ${navigation}
184
+ </navMap>
185
+ </ncx>
186
+ `;
187
+ }
188
+ const bookStyles = `@charset "UTF-8";
189
+ @namespace epub "http://www.idpf.org/2007/ops";
190
+ html { writing-mode: horizontal-tb; }
191
+ body { margin: 5%; color: #1f1f1f; font-family: serif; line-height: 1.8; }
192
+ h1 { margin: 1.5em 0 1em; font-size: 1.65em; line-height: 1.35; }
193
+ p { margin: 0 0 1em; text-align: justify; }
194
+ .title-page, .cover-page { min-height: 80vh; text-align: center; }
195
+ .title-page { display: flex; flex-direction: column; justify-content: center; }
196
+ .title-page p { text-align: center; }
197
+ .book-description { margin: 2em auto 0; max-width: 32em; color: #555; }
198
+ .cover-page img { display: block; max-width: 100%; max-height: 90vh; margin: 0 auto; object-fit: contain; }
199
+ .volume-label { color: #666; font-size: .85em; }
200
+ .code-block { margin: 1em 0; padding: .8em; overflow-wrap: anywhere; white-space: pre-wrap; font-family: monospace; font-size: .9em; line-height: 1.55; }
201
+ nav ol { padding-left: 1.5em; }
202
+ nav li { margin: .45em 0; }
203
+ nav[epub|type~="landmarks"] { margin-top: 2em; }
204
+ `;
205
+ export function epubDownloadFileName(title) {
206
+ const normalized = String(title ?? "")
207
+ .normalize("NFKC")
208
+ .replace(bidiControlCharacters, "")
209
+ .replace(unsafeFileNameCharacters, " ")
210
+ .replace(/\.{2,}/gu, " ")
211
+ .replace(/\s+/gu, " ")
212
+ .trim()
213
+ .replace(/[. ]+$/gu, "");
214
+ const stem = Array.from(normalized).slice(0, 120).join("") || "novel";
215
+ return `${stem}.epub`;
216
+ }
217
+ function asciiFallbackFileName(value) {
218
+ const stem = String(value ?? "")
219
+ .replace(/[^A-Za-z0-9._-]+/gu, "-")
220
+ .replace(/\.{2,}/gu, "-")
221
+ .replace(/-+/gu, "-")
222
+ .replace(/^[.-]+|[.-]+$/gu, "")
223
+ .slice(0, 80) || "novel";
224
+ return `${stem}.epub`;
225
+ }
226
+ function encodeRfc5987(value) {
227
+ return encodeURIComponent(value).replace(/['()*]/gu, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`);
228
+ }
229
+ export function epubContentDisposition(title, fallbackStem) {
230
+ return `attachment; filename="${asciiFallbackFileName(fallbackStem)}"; filename*=UTF-8''${encodeRfc5987(epubDownloadFileName(title))}`;
231
+ }
232
+ export async function createEpubArchive(input) {
233
+ const title = String(input.title || "未命名作品");
234
+ const author = String(input.author ?? "").trim();
235
+ const description = String(input.description ?? "").trim();
236
+ const language = normalizeLanguage(input.language);
237
+ const identifier = String(input.identifier ?? `urn:uuid:${randomUUID()}`);
238
+ const modified = normalizeModifiedAt(input.modifiedAt);
239
+ const cover = input.cover ? await prepareCover(input.cover) : null;
240
+ const archive = new JSZip();
241
+ const fileOptions = { date: modified.date };
242
+ archive.file("mimetype", EPUB_MIME_TYPE, { ...fileOptions, compression: "STORE" });
243
+ archive.file("META-INF/container.xml", `<?xml version="1.0" encoding="UTF-8"?>
244
+ <container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
245
+ <rootfiles>
246
+ <rootfile full-path="OEBPS/package.opf" media-type="application/oebps-package+xml" />
247
+ </rootfiles>
248
+ </container>
249
+ `, fileOptions);
250
+ archive.file("OEBPS/styles/book.css", bookStyles, fileOptions);
251
+ if (cover) {
252
+ archive.file(`OEBPS/images/cover.${cover.extension}`, cover.content, fileOptions);
253
+ archive.file("OEBPS/text/cover.xhtml", xhtmlPage({
254
+ language,
255
+ title: `${title}封面`,
256
+ body: ` <div class="cover-page"><img src="../images/cover.${cover.extension}" alt="${xml(title)}封面" /></div>`,
257
+ bodyType: "cover"
258
+ }), fileOptions);
259
+ }
260
+ const titleBody = ` <section class="title-page" epub:type="titlepage">
261
+ <h1>${xml(title)}</h1>${author ? `\n <p class="book-author">${xml(author)}</p>` : ""}${description ? `\n <p class="book-description">${xml(description)}</p>` : ""}
262
+ </section>`;
263
+ const titleDocument = {
264
+ id: "title-page",
265
+ href: "text/title.xhtml",
266
+ title,
267
+ content: xhtmlPage({ language, title, body: titleBody, bodyType: "frontmatter" })
268
+ };
269
+ archive.file(`OEBPS/${titleDocument.href}`, titleDocument.content, fileOptions);
270
+ const volumeDocuments = input.volumes.map((volume, volumeIndex) => {
271
+ const volumeNumber = String(volumeIndex + 1).padStart(3, "0");
272
+ const volumeTitle = String(volume.title ?? "");
273
+ const volumeDocument = {
274
+ id: `volume-${volumeNumber}`,
275
+ href: `text/volume-${volumeNumber}.xhtml`,
276
+ title: volumeTitle,
277
+ content: xhtmlPage({
278
+ language,
279
+ title: volumeTitle,
280
+ body: ` <section class="volume-page" epub:type="part"><h1>${xml(volumeTitle)}</h1></section>`,
281
+ bodyType: "bodymatter"
282
+ })
283
+ };
284
+ archive.file(`OEBPS/${volumeDocument.href}`, volumeDocument.content, fileOptions);
285
+ const chapters = volume.chapters.map((chapter, chapterIndex) => {
286
+ const chapterNumber = String(chapterIndex + 1).padStart(3, "0");
287
+ const chapterTitle = String(chapter.title ?? "");
288
+ const chapterDocument = {
289
+ id: `chapter-${volumeNumber}-${chapterNumber}`,
290
+ href: `text/chapter-${volumeNumber}-${chapterNumber}.xhtml`,
291
+ title: chapterTitle,
292
+ content: xhtmlPage({
293
+ language,
294
+ title: chapterTitle,
295
+ body: ` <article epub:type="chapter">\n <p class="volume-label">${xml(volumeTitle)}</p>\n <h1>${xml(chapterTitle)}</h1>\n${renderChapterBody(chapter.content)}\n </article>`,
296
+ bodyType: "bodymatter"
297
+ })
298
+ };
299
+ archive.file(`OEBPS/${chapterDocument.href}`, chapterDocument.content, fileOptions);
300
+ return chapterDocument;
301
+ });
302
+ return { document: volumeDocument, chapters };
303
+ });
304
+ const documents = [titleDocument, ...volumeDocuments.flatMap((volume) => [volume.document, ...volume.chapters])];
305
+ archive.file("OEBPS/nav.xhtml", navigationDocument({ title, language, volumes: volumeDocuments, hasCover: Boolean(cover) }), fileOptions);
306
+ archive.file("OEBPS/toc.ncx", ncxDocument({ title, identifier, volumes: volumeDocuments }), fileOptions);
307
+ archive.file("OEBPS/package.opf", packageDocument({
308
+ title,
309
+ author,
310
+ description,
311
+ language,
312
+ identifier,
313
+ modifiedAt: modified.value,
314
+ documents,
315
+ cover
316
+ }), fileOptions);
317
+ return archive;
318
+ }
319
+ //# sourceMappingURL=epub-export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epub-export.js","sourceRoot":"","sources":["../src/epub-export.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,14 @@ export const HYBRID_SEARCH_TYPES = [
12
12
  "review",
13
13
  "agent-history"
14
14
  ];
15
+ export const MAXIMUM_WORK_SEARCH_QUERY_LENGTH = 100;
16
+ export function normalizeWorkSearchQuery(value) {
17
+ return value
18
+ .normalize("NFKC")
19
+ .toLocaleLowerCase("zh-CN")
20
+ .trim()
21
+ .slice(0, MAXIMUM_WORK_SEARCH_QUERY_LENGTH);
22
+ }
15
23
  const matchKindOrder = ["metadata", "exact", "phonetic"];
16
24
  const reciprocalRankConstant = 60;
17
25
  export function fuseHybridSearchChannels(channels, limit = 50) {
@@ -1 +1 @@
1
- {"version":3,"file":"hybrid-search.js","sourceRoot":"","sources":["../src/hybrid-search.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hybrid-search.js","sourceRoot":"","sources":["../src/hybrid-search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export type ConnectivityToastType = "info" | "warning" | "error";
2
+ export type ConnectivityToast = { message: string; type: ConnectivityToastType };
3
+ export type ConnectivityObjectType = "provider" | "model";
4
+
5
+ export function connectivityTestResultToast(result: unknown, objectType: ConnectivityObjectType): ConnectivityToast;
6
+ export function connectivityTestErrorToast(error: unknown, objectType: ConnectivityObjectType): ConnectivityToast;
7
+ export function connectivityConfigurationSavedToast(objectType: ConnectivityObjectType): string;
@@ -0,0 +1,82 @@
1
+ const objectLabels = Object.freeze({ provider: "供应商", model: "模型" });
2
+
3
+ function record(value) {
4
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
5
+ }
6
+
7
+ function objectLabel(objectType) {
8
+ return objectLabels[objectType] ?? "AI 配置";
9
+ }
10
+
11
+ function retryTimeText(retryAt) {
12
+ if (typeof retryAt !== "string" || !retryAt) return "";
13
+ const date = new Date(retryAt);
14
+ if (!Number.isFinite(date.getTime())) return "";
15
+ return `,可于 ${date.toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false })} 再次测试`;
16
+ }
17
+
18
+ function remainingSeconds(value, fallback) {
19
+ const seconds = Number(value);
20
+ return Number.isFinite(seconds) && seconds > 0 ? Math.ceil(seconds) : fallback;
21
+ }
22
+
23
+ export function connectivityTestResultToast(result, objectType) {
24
+ const source = record(result);
25
+ const cooldown = record(source.cooldown);
26
+ const label = objectLabel(objectType);
27
+ if (cooldown.reason === "configuration_changed") {
28
+ const outcome = source.ok === false && typeof source.error === "string"
29
+ ? `旧配置测试失败:${source.error};`
30
+ : "旧配置测试已完成;";
31
+ return {
32
+ message: `${label}${outcome}配置已在测试期间更新,旧结果不会锁定新配置,现在可以重新测试`,
33
+ type: "warning"
34
+ };
35
+ }
36
+ if (source.ok === true) {
37
+ const imageNotice = objectType === "model" && source.multimodalTested === true ? ",图片请求已验证" : "";
38
+ return {
39
+ message: `${label}连接测试成功${imageNotice};接下来 2 分钟内不能再次测试${retryTimeText(cooldown.retryAt)}`,
40
+ type: "info"
41
+ };
42
+ }
43
+ const failure = typeof source.error === "string" && source.error ? source.error : "未知错误";
44
+ return {
45
+ message: `${label}连接测试失败:${failure};10 秒后可以重试${retryTimeText(cooldown.retryAt)}`,
46
+ type: "error"
47
+ };
48
+ }
49
+
50
+ export function connectivityTestErrorToast(error, objectType) {
51
+ const source = record(error);
52
+ const details = record(source.details);
53
+ const label = objectLabel(objectType);
54
+ if (details.reason === "in_progress") {
55
+ const seconds = remainingSeconds(details.retryAfterSeconds, 1);
56
+ return {
57
+ message: `${label}已有连接测试正在进行,请等待约 ${seconds} 秒${retryTimeText(details.retryAt)}`,
58
+ type: "warning"
59
+ };
60
+ }
61
+ if (details.reason === "success_cooldown") {
62
+ const seconds = remainingSeconds(details.retryAfterSeconds, 120);
63
+ return {
64
+ message: `${label}仍在成功冷却中,剩余 ${seconds} 秒${retryTimeText(details.retryAt)}`,
65
+ type: "warning"
66
+ };
67
+ }
68
+ if (details.reason === "failure_cooldown") {
69
+ const seconds = remainingSeconds(details.retryAfterSeconds, 10);
70
+ return {
71
+ message: `${label}仍在失败冷却中,剩余 ${seconds} 秒${retryTimeText(details.retryAt)}`,
72
+ type: "warning"
73
+ };
74
+ }
75
+ const message = typeof source.message === "string" && source.message ? source.message : "请求失败";
76
+ return { message: `${label}连接测试失败:${message}`, type: "error" };
77
+ }
78
+
79
+ export function connectivityConfigurationSavedToast(objectType) {
80
+ const label = objectLabel(objectType);
81
+ return `${label}配置已保存,旧连接测试冷却已清除,现在可以重新测试`;
82
+ }
@@ -0,0 +1,99 @@
1
+ function normalizedId(value) {
2
+ const normalized = String(value ?? "").trim();
3
+ return normalized || null;
4
+ }
5
+
6
+ export function createAiRequestAbortError(message = "AI 请求已取消") {
7
+ const error = new Error(message);
8
+ error.name = "AbortError";
9
+ error.code = "AI_REQUEST_CANCELLED";
10
+ return error;
11
+ }
12
+
13
+ export function isAiRequestCancellation(error, request = null) {
14
+ if (request?.signal?.aborted) return true;
15
+ return error?.name === "AbortError" || error?.code === "AI_REQUEST_CANCELLED";
16
+ }
17
+
18
+ export function aiRequestTargetsState(request, current) {
19
+ if (!request || normalizedId(current?.workId) !== request.workId) return false;
20
+ return request.conversationId === null
21
+ || normalizedId(current?.conversationId) === request.conversationId;
22
+ }
23
+
24
+ export function createAiRequestManager() {
25
+ let generation = 0;
26
+ let active = null;
27
+
28
+ const snapshot = (input, controller, requestGeneration) => Object.freeze({
29
+ generation: requestGeneration,
30
+ workId: normalizedId(input.workId),
31
+ conversationId: normalizedId(input.conversationId),
32
+ userMessageId: normalizedId(input.userMessageId),
33
+ signal: controller.signal
34
+ });
35
+
36
+ const isCurrent = (request) => Boolean(
37
+ request
38
+ && active
39
+ && !active.controller.signal.aborted
40
+ && active.snapshot.generation === request.generation
41
+ && active.controller.signal === request.signal
42
+ );
43
+
44
+ const cancel = (reason = "AI 请求已取消") => {
45
+ if (!active) return false;
46
+ const current = active;
47
+ active = null;
48
+ current.controller.abort(createAiRequestAbortError(reason));
49
+ return true;
50
+ };
51
+
52
+ const begin = (input) => {
53
+ cancel("新的 AI 请求已开始");
54
+ const controller = new AbortController();
55
+ generation += 1;
56
+ const request = snapshot(input, controller, generation);
57
+ if (!request.workId) throw new Error("AI 请求必须绑定作品");
58
+ active = { controller, snapshot: request };
59
+ return request;
60
+ };
61
+
62
+ const bind = (request, patch) => {
63
+ if (!isCurrent(request)) throw createAiRequestAbortError("AI 请求已失效");
64
+ const conversationId = Object.hasOwn(patch, "conversationId")
65
+ ? normalizedId(patch.conversationId)
66
+ : request.conversationId;
67
+ const userMessageId = Object.hasOwn(patch, "userMessageId")
68
+ ? normalizedId(patch.userMessageId)
69
+ : request.userMessageId;
70
+ if (request.conversationId && conversationId !== request.conversationId) {
71
+ throw new Error("AI 请求不能改绑到其他对话");
72
+ }
73
+ if (request.userMessageId && userMessageId !== request.userMessageId) {
74
+ throw new Error("AI 请求不能改绑到其他用户消息");
75
+ }
76
+ const next = snapshot({
77
+ workId: request.workId,
78
+ conversationId,
79
+ userMessageId
80
+ }, active.controller, request.generation);
81
+ active.snapshot = next;
82
+ return next;
83
+ };
84
+
85
+ const finish = (request) => {
86
+ if (!isCurrent(request)) return false;
87
+ active = null;
88
+ return true;
89
+ };
90
+
91
+ return {
92
+ begin,
93
+ bind,
94
+ cancel,
95
+ finish,
96
+ hasActive: () => active !== null,
97
+ isCurrent
98
+ };
99
+ }
@@ -0,0 +1,51 @@
1
+ function streamTransportError(code, message) {
2
+ const error = new Error(message);
3
+ error.code = code;
4
+ error.status = 502;
5
+ return error;
6
+ }
7
+
8
+ export function assertAiStreamCompleted(completed) {
9
+ if (completed) return;
10
+ throw streamTransportError(
11
+ "AI_STREAM_UPSTREAM_CLOSED",
12
+ "AI 流在收到完成事件前已关闭,已保留已生成内容"
13
+ );
14
+ }
15
+
16
+ export async function readAiEventStream(body, onEvent) {
17
+ const reader = body.getReader();
18
+ const decoder = new TextDecoder();
19
+ let buffer = "";
20
+ let completed = false;
21
+ const consume = async (eventText) => {
22
+ let eventName = "message";
23
+ const dataLines = [];
24
+ for (const line of eventText.split(/\r?\n/)) {
25
+ if (line.startsWith("event:")) eventName = line.slice(6).trim();
26
+ if (line.startsWith("data:")) dataLines.push(line.slice(5).trimStart());
27
+ }
28
+ if (!dataLines.length) return;
29
+ const payload = JSON.parse(dataLines.join("\n"));
30
+ await onEvent(eventName, payload);
31
+ if (eventName === "complete") completed = true;
32
+ };
33
+ while (true) {
34
+ let chunk;
35
+ try {
36
+ chunk = await reader.read();
37
+ } catch {
38
+ throw streamTransportError(
39
+ "AI_STREAM_NETWORK_ERROR",
40
+ "AI 流连接中断,已保留已生成内容"
41
+ );
42
+ }
43
+ buffer += decoder.decode(chunk.value, { stream: !chunk.done });
44
+ const events = buffer.split(/\r?\n\r?\n/);
45
+ buffer = events.pop() ?? "";
46
+ for (const eventText of events) await consume(eventText);
47
+ if (chunk.done) break;
48
+ }
49
+ if (buffer.trim()) await consume(buffer);
50
+ return { completed };
51
+ }