@musnows/scriverse 0.3.6 → 0.3.8
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/dist/ai.js +59 -0
- package/dist/ai.js.map +1 -1
- package/dist/app.js +136 -35
- package/dist/app.js.map +1 -1
- package/dist/http-logging.js +2 -2
- package/dist/http-logging.js.map +1 -1
- package/dist/logger.js +2 -2
- package/dist/logger.js.map +1 -1
- package/dist/pagination.js +42 -0
- package/dist/pagination.js.map +1 -0
- package/dist/public/analysis-types.d.ts +8 -0
- package/dist/public/analysis-types.js +53 -0
- package/dist/public/app.js +235 -77
- package/dist/public/index.html +37 -8
- package/dist/public/markdown.js +35 -1
- package/dist/public/page-route.js +12 -0
- package/dist/public/styles.css +65 -22
- package/dist/security.js +41 -4
- package/dist/security.js.map +1 -1
- package/dist/store.js +303 -0
- package/dist/store.js.map +1 -1
- package/dist/user-auth.js +30 -0
- package/dist/user-auth.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -1
package/dist/store.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { PLATFORM_AI_WORK_ID } from "./database.js";
|
|
3
3
|
import { AppError, notFound } from "./errors.js";
|
|
4
4
|
import { accountReference, logger } from "./logger.js";
|
|
5
|
+
import { paginated, paginationSql } from "./pagination.js";
|
|
5
6
|
import { currentRequestActor } from "./request-context.js";
|
|
6
7
|
import { countWords, documentShortSearchTerms, id, json, normalizeDocumentSearchText, normalizeParagraphSpacing, now, splitDocumentParagraphs } from "./utils.js";
|
|
7
8
|
export const versionedEntityTypes = [
|
|
@@ -206,6 +207,27 @@ export class Store {
|
|
|
206
207
|
actor: optionalString(row, "actor_display_name") ?? optionalString(row, "actor_username") ?? "历史数据"
|
|
207
208
|
}));
|
|
208
209
|
}
|
|
210
|
+
listEntityVersionsPage(type, entityId, pagination) {
|
|
211
|
+
const page = paginationSql(pagination);
|
|
212
|
+
const rows = this.db.all(`SELECT version.*, user.display_name AS actor_display_name, user.username AS actor_username
|
|
213
|
+
FROM entity_versions version LEFT JOIN users user ON user.id = version.created_by_user_id
|
|
214
|
+
WHERE version.entity_type = ? AND version.entity_id = ? ORDER BY version.version_no DESC${page.sql}`, type, entityId, ...page.params);
|
|
215
|
+
if (!rows.length && pagination.page === 1)
|
|
216
|
+
this.versionedEntity(type, entityId);
|
|
217
|
+
return paginated(rows.map((row) => ({
|
|
218
|
+
id: requiredString(row, "id"),
|
|
219
|
+
workId: requiredString(row, "work_id"),
|
|
220
|
+
entityType: requiredString(row, "entity_type"),
|
|
221
|
+
entityId: requiredString(row, "entity_id"),
|
|
222
|
+
versionNo: numberValue(row, "version_no"),
|
|
223
|
+
snapshot: json(requiredString(row, "snapshot_json"), {}),
|
|
224
|
+
source: requiredString(row, "source"),
|
|
225
|
+
sourceRef: optionalString(row, "source_ref"),
|
|
226
|
+
changeNote: requiredString(row, "change_note"),
|
|
227
|
+
createdAt: requiredString(row, "created_at"),
|
|
228
|
+
actor: optionalString(row, "actor_display_name") ?? optionalString(row, "actor_username") ?? "历史数据"
|
|
229
|
+
})), pagination);
|
|
230
|
+
}
|
|
209
231
|
restoreEntityVersion(type, entityId, versionNo) {
|
|
210
232
|
const version = this.db.get("SELECT * FROM entity_versions WHERE entity_type = ? AND entity_id = ? AND version_no = ?", type, entityId, versionNo);
|
|
211
233
|
if (!version)
|
|
@@ -301,6 +323,16 @@ export class Store {
|
|
|
301
323
|
WHERE COALESCE(work.is_internal, 0) = 0 AND (work.owner_user_id = ? OR membership.user_id = ?)
|
|
302
324
|
ORDER BY work.updated_at DESC`, actor.userId, actor.userId).map((row) => this.mapWork(row));
|
|
303
325
|
}
|
|
326
|
+
listWorksPage(pagination) {
|
|
327
|
+
const actor = currentRequestActor();
|
|
328
|
+
const page = paginationSql(pagination);
|
|
329
|
+
const rows = !actor || (actor.role === "admin" && actor.authentication !== "api-key")
|
|
330
|
+
? this.db.all(`SELECT * FROM works WHERE COALESCE(is_internal, 0) = 0 ORDER BY updated_at DESC${page.sql}`, ...page.params)
|
|
331
|
+
: this.db.all(`SELECT DISTINCT work.* FROM works work LEFT JOIN work_memberships membership ON membership.work_id = work.id
|
|
332
|
+
WHERE COALESCE(work.is_internal, 0) = 0 AND (work.owner_user_id = ? OR membership.user_id = ?)
|
|
333
|
+
ORDER BY work.updated_at DESC${page.sql}`, actor.userId, actor.userId, ...page.params);
|
|
334
|
+
return paginated(rows.map((row) => this.mapWork(row)), pagination);
|
|
335
|
+
}
|
|
304
336
|
getWork(workId) {
|
|
305
337
|
const row = this.db.get("SELECT * FROM works WHERE id = ?", workId);
|
|
306
338
|
if (!row)
|
|
@@ -486,6 +518,27 @@ export class Store {
|
|
|
486
518
|
}));
|
|
487
519
|
return { ...work, volumes };
|
|
488
520
|
}
|
|
521
|
+
getWorkDirectoryPage(workId, pagination) {
|
|
522
|
+
const work = this.getWork(workId);
|
|
523
|
+
const volumeRows = this.db.all("SELECT * FROM volumes WHERE work_id = ? ORDER BY sort_order, created_at", workId);
|
|
524
|
+
const page = paginationSql(pagination);
|
|
525
|
+
const chapterRows = this.db.all(`SELECT id, work_id, volume_id, title, chapter_type, sort_order, word_count, version_no,
|
|
526
|
+
analysis_status, excluded_from_analysis, created_at, updated_at
|
|
527
|
+
FROM chapters WHERE work_id = ? ORDER BY sort_order, created_at${page.sql}`, workId, ...page.params);
|
|
528
|
+
const chapters = chapterRows.map((row) => this.mapChapterDirectoryEntry(row));
|
|
529
|
+
const chaptersByVolume = new Map();
|
|
530
|
+
for (const chapter of chapters) {
|
|
531
|
+
const volumeId = String(chapter.volumeId);
|
|
532
|
+
const list = chaptersByVolume.get(volumeId) ?? [];
|
|
533
|
+
list.push(chapter);
|
|
534
|
+
chaptersByVolume.set(volumeId, list);
|
|
535
|
+
}
|
|
536
|
+
const volumes = volumeRows.map((row) => ({
|
|
537
|
+
...this.mapVolume(row),
|
|
538
|
+
chapters: chaptersByVolume.get(requiredString(row, "id")) ?? []
|
|
539
|
+
}));
|
|
540
|
+
return { ...work, volumes, directoryPage: paginated(chapters, pagination) };
|
|
541
|
+
}
|
|
489
542
|
listFileVersions(workId) {
|
|
490
543
|
this.getWork(workId);
|
|
491
544
|
return this.db
|
|
@@ -505,6 +558,25 @@ export class Store {
|
|
|
505
558
|
actor: optionalString(row, "actor_display_name") ?? optionalString(row, "actor_username") ?? "历史数据"
|
|
506
559
|
}));
|
|
507
560
|
}
|
|
561
|
+
listFileVersionsPage(workId, pagination) {
|
|
562
|
+
this.getWork(workId);
|
|
563
|
+
const page = paginationSql(pagination);
|
|
564
|
+
const rows = this.db.all(`SELECT version.id, version.work_id, version.file_name, version.file_type, version.word_count, version.paragraph_count,
|
|
565
|
+
version.warnings_json, version.created_at, user.display_name AS actor_display_name, user.username AS actor_username
|
|
566
|
+
FROM file_versions version LEFT JOIN users user ON user.id = version.created_by_user_id
|
|
567
|
+
WHERE version.work_id = ? ORDER BY version.created_at DESC${page.sql}`, workId, ...page.params);
|
|
568
|
+
return paginated(rows.map((row) => ({
|
|
569
|
+
id: requiredString(row, "id"),
|
|
570
|
+
workId: requiredString(row, "work_id"),
|
|
571
|
+
fileName: requiredString(row, "file_name"),
|
|
572
|
+
fileType: requiredString(row, "file_type"),
|
|
573
|
+
wordCount: numberValue(row, "word_count"),
|
|
574
|
+
paragraphCount: numberValue(row, "paragraph_count"),
|
|
575
|
+
warnings: json(requiredString(row, "warnings_json"), []),
|
|
576
|
+
createdAt: requiredString(row, "created_at"),
|
|
577
|
+
actor: optionalString(row, "actor_display_name") ?? optionalString(row, "actor_username") ?? "历史数据"
|
|
578
|
+
})), pagination);
|
|
579
|
+
}
|
|
508
580
|
restoreFileVersion(workId, fileVersionId) {
|
|
509
581
|
this.getWork(workId);
|
|
510
582
|
const version = this.db.get("SELECT * FROM file_versions WHERE id = ? AND work_id = ?", fileVersionId, workId);
|
|
@@ -671,6 +743,17 @@ export class Store {
|
|
|
671
743
|
}
|
|
672
744
|
return rows.map((row) => this.mapChapterVersionRow(row));
|
|
673
745
|
}
|
|
746
|
+
listChapterVersionsPage(chapterId, pagination) {
|
|
747
|
+
const page = paginationSql(pagination);
|
|
748
|
+
const rows = this.db.all(`SELECT version.*, user.display_name AS actor_display_name, user.username AS actor_username
|
|
749
|
+
FROM chapter_versions version LEFT JOIN users user ON user.id = version.created_by_user_id
|
|
750
|
+
WHERE version.chapter_id = ? ORDER BY version.version_no DESC${page.sql}`, chapterId, ...page.params);
|
|
751
|
+
if (!rows.length) {
|
|
752
|
+
this.getChapter(chapterId);
|
|
753
|
+
return paginated([], pagination);
|
|
754
|
+
}
|
|
755
|
+
return paginated(rows.slice(pagination.offset, pagination.offset + pagination.limit + 1).map((row) => this.mapChapterVersionRow(row)), pagination);
|
|
756
|
+
}
|
|
674
757
|
listChapterInsights(chapterId) {
|
|
675
758
|
this.getChapter(chapterId);
|
|
676
759
|
return this.db
|
|
@@ -689,6 +772,24 @@ export class Store {
|
|
|
689
772
|
createdAt: requiredString(row, "created_at")
|
|
690
773
|
}));
|
|
691
774
|
}
|
|
775
|
+
listChapterInsightsPage(chapterId, pagination) {
|
|
776
|
+
this.getChapter(chapterId);
|
|
777
|
+
const page = paginationSql(pagination);
|
|
778
|
+
const rows = this.db.all(`SELECT * FROM chapter_insights WHERE chapter_id = ? ORDER BY chapter_version DESC, created_at DESC${page.sql}`, chapterId, ...page.params);
|
|
779
|
+
return paginated(rows.map((row) => ({
|
|
780
|
+
id: requiredString(row, "id"),
|
|
781
|
+
chapterId: requiredString(row, "chapter_id"),
|
|
782
|
+
chapterVersion: numberValue(row, "chapter_version"),
|
|
783
|
+
summary: requiredString(row, "summary"),
|
|
784
|
+
events: json(requiredString(row, "events_json"), []),
|
|
785
|
+
characters: json(requiredString(row, "characters_json"), []),
|
|
786
|
+
settings: json(requiredString(row, "settings_json"), []),
|
|
787
|
+
evidence: json(requiredString(row, "evidence_json"), []),
|
|
788
|
+
uncertainties: json(requiredString(row, "uncertainties_json"), []),
|
|
789
|
+
status: requiredString(row, "status"),
|
|
790
|
+
createdAt: requiredString(row, "created_at")
|
|
791
|
+
})), pagination);
|
|
792
|
+
}
|
|
692
793
|
listCurrentChapterInsights(workId) {
|
|
693
794
|
this.getWork(workId);
|
|
694
795
|
return this.db.all(`SELECT insight.id, insight.chapter_id, insight.summary, chapter.title AS chapter_title,
|
|
@@ -1027,6 +1128,35 @@ export class Store {
|
|
|
1027
1128
|
updatedAt: optionalString(row, "updated_at")
|
|
1028
1129
|
}));
|
|
1029
1130
|
}
|
|
1131
|
+
listChapterOutlinesPage(workId, pagination) {
|
|
1132
|
+
this.getWork(workId);
|
|
1133
|
+
const page = paginationSql(pagination);
|
|
1134
|
+
const rows = this.db.all(`SELECT c.id AS chapter_id, c.title AS chapter_title, c.volume_id, c.sort_order AS chapter_order,
|
|
1135
|
+
v.title AS volume_title, v.sort_order AS volume_order,
|
|
1136
|
+
o.goal, o.conflict, o.turning_point, o.notes, o.status, o.created_at, o.updated_at,
|
|
1137
|
+
(SELECT COUNT(DISTINCT fo.foreshadow_id) FROM foreshadow_occurrences fo
|
|
1138
|
+
JOIN foreshadows f ON f.id = fo.foreshadow_id
|
|
1139
|
+
WHERE fo.chapter_id = c.id AND f.status IN ('planned', 'planted')) AS unresolved_count
|
|
1140
|
+
FROM chapters c
|
|
1141
|
+
JOIN volumes v ON v.id = c.volume_id
|
|
1142
|
+
LEFT JOIN chapter_outlines o ON o.chapter_id = c.id
|
|
1143
|
+
WHERE c.work_id = ?
|
|
1144
|
+
ORDER BY v.sort_order, c.sort_order, c.created_at${page.sql}`, workId, ...page.params);
|
|
1145
|
+
return paginated(rows.map((row) => ({
|
|
1146
|
+
chapterId: requiredString(row, "chapter_id"),
|
|
1147
|
+
chapterTitle: requiredString(row, "chapter_title"),
|
|
1148
|
+
volumeId: requiredString(row, "volume_id"),
|
|
1149
|
+
volumeTitle: requiredString(row, "volume_title"),
|
|
1150
|
+
goal: optionalString(row, "goal") ?? "",
|
|
1151
|
+
conflict: optionalString(row, "conflict") ?? "",
|
|
1152
|
+
turningPoint: optionalString(row, "turning_point") ?? "",
|
|
1153
|
+
notes: optionalString(row, "notes") ?? "",
|
|
1154
|
+
status: optionalString(row, "status") ?? "draft",
|
|
1155
|
+
unresolvedForeshadowCount: numberValue(row, "unresolved_count"),
|
|
1156
|
+
createdAt: optionalString(row, "created_at"),
|
|
1157
|
+
updatedAt: optionalString(row, "updated_at")
|
|
1158
|
+
})), pagination);
|
|
1159
|
+
}
|
|
1030
1160
|
upsertChapterOutline(chapterId, input, source = "manual", sourceRef = null, changeNote = "") {
|
|
1031
1161
|
const chapter = this.getChapter(chapterId);
|
|
1032
1162
|
const current = this.getChapterOutline(chapterId);
|
|
@@ -1131,6 +1261,18 @@ export class Store {
|
|
|
1131
1261
|
return this.db.all(`SELECT id FROM foreshadows WHERE work_id = ? ${where}
|
|
1132
1262
|
ORDER BY CASE importance WHEN 'high' THEN 0 WHEN 'medium' THEN 1 ELSE 2 END, created_at`, workId).map((row) => this.getForeshadow(requiredString(row, "id"), currentChapterId));
|
|
1133
1263
|
}
|
|
1264
|
+
listForeshadowsPage(workId, pagination, status = "all", currentChapterId) {
|
|
1265
|
+
this.getWork(workId);
|
|
1266
|
+
if (currentChapterId)
|
|
1267
|
+
this.assertChapterInWork(currentChapterId, workId);
|
|
1268
|
+
const where = status === "unresolved"
|
|
1269
|
+
? "AND status IN ('planned', 'planted')"
|
|
1270
|
+
: status === "resolved" ? "AND status IN ('resolved', 'abandoned')" : "";
|
|
1271
|
+
const page = paginationSql(pagination);
|
|
1272
|
+
const rows = this.db.all(`SELECT id FROM foreshadows WHERE work_id = ? ${where}
|
|
1273
|
+
ORDER BY CASE importance WHEN 'high' THEN 0 WHEN 'medium' THEN 1 ELSE 2 END, created_at${page.sql}`, workId, ...page.params);
|
|
1274
|
+
return paginated(rows.map((row) => this.getForeshadow(requiredString(row, "id"), currentChapterId)), pagination);
|
|
1275
|
+
}
|
|
1134
1276
|
updateForeshadow(foreshadowId, input, source = "manual", sourceRef = null, changeNote = "") {
|
|
1135
1277
|
const current = this.getForeshadow(foreshadowId);
|
|
1136
1278
|
const workId = String(current.workId);
|
|
@@ -1248,6 +1390,12 @@ export class Store {
|
|
|
1248
1390
|
this.getWork(workId);
|
|
1249
1391
|
return this.db.all("SELECT * FROM settings WHERE work_id = ? ORDER BY locked DESC, category, title", workId).map((row) => this.mapSetting(row));
|
|
1250
1392
|
}
|
|
1393
|
+
listSettingsPage(workId, pagination) {
|
|
1394
|
+
this.getWork(workId);
|
|
1395
|
+
const page = paginationSql(pagination);
|
|
1396
|
+
const rows = this.db.all(`SELECT * FROM settings WHERE work_id = ? ORDER BY locked DESC, category, title${page.sql}`, workId, ...page.params);
|
|
1397
|
+
return paginated(rows.map((row) => this.mapSetting(row)), pagination);
|
|
1398
|
+
}
|
|
1251
1399
|
getSetting(settingId) {
|
|
1252
1400
|
const row = this.db.get("SELECT * FROM settings WHERE id = ?", settingId);
|
|
1253
1401
|
if (!row)
|
|
@@ -1319,6 +1467,12 @@ export class Store {
|
|
|
1319
1467
|
this.getWork(workId);
|
|
1320
1468
|
return this.db.all("SELECT * FROM races WHERE work_id = ? ORDER BY name", workId).map((row) => this.mapRace(row));
|
|
1321
1469
|
}
|
|
1470
|
+
listRacesPage(workId, pagination) {
|
|
1471
|
+
this.getWork(workId);
|
|
1472
|
+
const page = paginationSql(pagination);
|
|
1473
|
+
const rows = this.db.all(`SELECT * FROM races WHERE work_id = ? ORDER BY name${page.sql}`, workId, ...page.params);
|
|
1474
|
+
return paginated(rows.map((row) => this.mapRace(row)), pagination);
|
|
1475
|
+
}
|
|
1322
1476
|
getRace(raceId) {
|
|
1323
1477
|
const row = this.db.get("SELECT * FROM races WHERE id = ?", raceId);
|
|
1324
1478
|
if (!row)
|
|
@@ -1493,6 +1647,12 @@ export class Store {
|
|
|
1493
1647
|
this.getWork(workId);
|
|
1494
1648
|
return this.db.all("SELECT * FROM organizations WHERE work_id = ? ORDER BY name", workId).map((row) => this.mapOrganization(row));
|
|
1495
1649
|
}
|
|
1650
|
+
listOrganizationsPage(workId, pagination) {
|
|
1651
|
+
this.getWork(workId);
|
|
1652
|
+
const page = paginationSql(pagination);
|
|
1653
|
+
const rows = this.db.all(`SELECT * FROM organizations WHERE work_id = ? ORDER BY name${page.sql}`, workId, ...page.params);
|
|
1654
|
+
return paginated(rows.map((row) => this.mapOrganization(row)), pagination);
|
|
1655
|
+
}
|
|
1496
1656
|
getOrganization(organizationId) {
|
|
1497
1657
|
const row = this.db.get("SELECT * FROM organizations WHERE id = ?", organizationId);
|
|
1498
1658
|
if (!row)
|
|
@@ -1666,6 +1826,12 @@ export class Store {
|
|
|
1666
1826
|
return this.db.all(`SELECT * FROM characters WHERE work_id = ?${includeMerged ? "" : " AND merged_into_character_id IS NULL"} ORDER BY name`, workId)
|
|
1667
1827
|
.map((row) => this.mapCharacter(row, includeProfileSections));
|
|
1668
1828
|
}
|
|
1829
|
+
listCharactersPage(workId, pagination, includeProfileSections = false, includeMerged = false) {
|
|
1830
|
+
this.getWork(workId);
|
|
1831
|
+
const page = paginationSql(pagination);
|
|
1832
|
+
const rows = this.db.all(`SELECT * FROM characters WHERE work_id = ?${includeMerged ? "" : " AND merged_into_character_id IS NULL"} ORDER BY name${page.sql}`, workId, ...page.params);
|
|
1833
|
+
return paginated(rows.map((row) => this.mapCharacter(row, includeProfileSections)), pagination);
|
|
1834
|
+
}
|
|
1669
1835
|
mapCharacterProfileSection(row) {
|
|
1670
1836
|
return {
|
|
1671
1837
|
id: requiredString(row, "id"),
|
|
@@ -1687,6 +1853,12 @@ export class Store {
|
|
|
1687
1853
|
this.getCharacter(characterId);
|
|
1688
1854
|
return this.db.all("SELECT * FROM character_profile_sections WHERE character_id = ? ORDER BY sort_order, created_at", characterId).map((row) => this.mapCharacterProfileSection(row));
|
|
1689
1855
|
}
|
|
1856
|
+
listCharacterProfileSectionsPage(characterId, pagination) {
|
|
1857
|
+
this.getCharacter(characterId);
|
|
1858
|
+
const page = paginationSql(pagination);
|
|
1859
|
+
const rows = this.db.all(`SELECT * FROM character_profile_sections WHERE character_id = ? ORDER BY sort_order, created_at${page.sql}`, characterId, ...page.params);
|
|
1860
|
+
return paginated(rows.map((row) => this.mapCharacterProfileSection(row)), pagination);
|
|
1861
|
+
}
|
|
1690
1862
|
listCharacterProfileSectionCatalog(characterId) {
|
|
1691
1863
|
this.getCharacter(characterId);
|
|
1692
1864
|
return this.db.all(`SELECT id, character_id, section_type, title, summary, sort_order, version_no
|
|
@@ -1813,6 +1985,27 @@ export class Store {
|
|
|
1813
1985
|
actor: optionalString(row, "actor_display_name") ?? optionalString(row, "actor_username") ?? "历史数据"
|
|
1814
1986
|
}));
|
|
1815
1987
|
}
|
|
1988
|
+
listCharacterProfileSectionVersionsPage(sectionId, pagination) {
|
|
1989
|
+
const page = paginationSql(pagination);
|
|
1990
|
+
const rows = this.db.all(`SELECT version.*, user.display_name AS actor_display_name, user.username AS actor_username
|
|
1991
|
+
FROM character_profile_section_versions version LEFT JOIN users user ON user.id = version.created_by_user_id
|
|
1992
|
+
WHERE version.section_id = ? ORDER BY version.version_no DESC${page.sql}`, sectionId, ...page.params);
|
|
1993
|
+
if (!rows.length && pagination.page === 1)
|
|
1994
|
+
this.getCharacterProfileSection(sectionId);
|
|
1995
|
+
return paginated(rows.map((row) => ({
|
|
1996
|
+
id: requiredString(row, "id"),
|
|
1997
|
+
workId: requiredString(row, "work_id"),
|
|
1998
|
+
characterId: requiredString(row, "character_id"),
|
|
1999
|
+
sectionId: requiredString(row, "section_id"),
|
|
2000
|
+
versionNo: numberValue(row, "version_no"),
|
|
2001
|
+
snapshot: json(requiredString(row, "snapshot_json"), {}),
|
|
2002
|
+
source: requiredString(row, "source"),
|
|
2003
|
+
sourceRef: optionalString(row, "source_ref"),
|
|
2004
|
+
changeNote: requiredString(row, "change_note"),
|
|
2005
|
+
createdAt: requiredString(row, "created_at"),
|
|
2006
|
+
actor: optionalString(row, "actor_display_name") ?? optionalString(row, "actor_username") ?? "历史数据"
|
|
2007
|
+
})), pagination);
|
|
2008
|
+
}
|
|
1816
2009
|
restoreCharacterProfileSection(sectionId, versionNo) {
|
|
1817
2010
|
const version = this.db.get("SELECT * FROM character_profile_section_versions WHERE section_id = ? AND version_no = ?", sectionId, versionNo);
|
|
1818
2011
|
if (!version)
|
|
@@ -1900,6 +2093,12 @@ export class Store {
|
|
|
1900
2093
|
this.getWork(workId);
|
|
1901
2094
|
return this.db.all("SELECT * FROM attachments WHERE work_id = ? ORDER BY created_at DESC", workId).map((row) => this.mapAttachment(row));
|
|
1902
2095
|
}
|
|
2096
|
+
listAttachmentsPage(workId, pagination) {
|
|
2097
|
+
this.getWork(workId);
|
|
2098
|
+
const page = paginationSql(pagination);
|
|
2099
|
+
const rows = this.db.all(`SELECT * FROM attachments WHERE work_id = ? ORDER BY created_at DESC${page.sql}`, workId, ...page.params);
|
|
2100
|
+
return paginated(rows.map((row) => this.mapAttachment(row)), pagination);
|
|
2101
|
+
}
|
|
1903
2102
|
getAttachment(attachmentId) {
|
|
1904
2103
|
const row = this.db.get("SELECT * FROM attachments WHERE id = ?", attachmentId);
|
|
1905
2104
|
if (!row)
|
|
@@ -1985,6 +2184,26 @@ export class Store {
|
|
|
1985
2184
|
actor: optionalString(row, "actor_display_name") ?? optionalString(row, "actor_username") ?? "历史数据"
|
|
1986
2185
|
}));
|
|
1987
2186
|
}
|
|
2187
|
+
listCharacterVersionsPage(characterId, pagination) {
|
|
2188
|
+
const page = paginationSql(pagination);
|
|
2189
|
+
const rows = this.db.all(`SELECT version.*, user.display_name AS actor_display_name, user.username AS actor_username
|
|
2190
|
+
FROM character_versions version LEFT JOIN users user ON user.id = version.created_by_user_id
|
|
2191
|
+
WHERE version.character_id = ? ORDER BY version.version_no DESC${page.sql}`, characterId, ...page.params);
|
|
2192
|
+
if (!rows.length && pagination.page === 1)
|
|
2193
|
+
this.getCharacter(characterId);
|
|
2194
|
+
return paginated(rows.map((row) => ({
|
|
2195
|
+
id: requiredString(row, "id"),
|
|
2196
|
+
workId: optionalString(row, "work_id"),
|
|
2197
|
+
characterId: requiredString(row, "character_id"),
|
|
2198
|
+
versionNo: numberValue(row, "version_no"),
|
|
2199
|
+
snapshot: json(requiredString(row, "snapshot_json"), {}),
|
|
2200
|
+
source: requiredString(row, "source"),
|
|
2201
|
+
sourceRef: optionalString(row, "source_ref"),
|
|
2202
|
+
changeNote: requiredString(row, "change_note"),
|
|
2203
|
+
createdAt: requiredString(row, "created_at"),
|
|
2204
|
+
actor: optionalString(row, "actor_display_name") ?? optionalString(row, "actor_username") ?? "历史数据"
|
|
2205
|
+
})), pagination);
|
|
2206
|
+
}
|
|
1988
2207
|
restoreCharacter(characterId, versionNo) {
|
|
1989
2208
|
const version = this.db.get("SELECT * FROM character_versions WHERE character_id = ? AND version_no = ?", characterId, versionNo);
|
|
1990
2209
|
if (!version)
|
|
@@ -2291,6 +2510,12 @@ export class Store {
|
|
|
2291
2510
|
this.getWork(workId);
|
|
2292
2511
|
return this.db.all("SELECT * FROM timeline_tracks WHERE work_id = ? ORDER BY sort_order, created_at", workId).map((row) => this.mapTimelineTrack(row));
|
|
2293
2512
|
}
|
|
2513
|
+
listTimelineTracksPage(workId, pagination) {
|
|
2514
|
+
this.getWork(workId);
|
|
2515
|
+
const page = paginationSql(pagination);
|
|
2516
|
+
const rows = this.db.all(`SELECT * FROM timeline_tracks WHERE work_id = ? ORDER BY sort_order, created_at${page.sql}`, workId, ...page.params);
|
|
2517
|
+
return paginated(rows.map((row) => this.mapTimelineTrack(row)), pagination);
|
|
2518
|
+
}
|
|
2294
2519
|
getTimelineTrack(trackId) {
|
|
2295
2520
|
const row = this.db.get("SELECT * FROM timeline_tracks WHERE id = ?", trackId);
|
|
2296
2521
|
if (!row)
|
|
@@ -2345,6 +2570,12 @@ export class Store {
|
|
|
2345
2570
|
.all("SELECT * FROM timeline_events WHERE work_id = ? ORDER BY time_sort IS NULL, time_sort, created_at", workId)
|
|
2346
2571
|
.map((row) => this.mapTimelineEvent(row));
|
|
2347
2572
|
}
|
|
2573
|
+
listTimelineEventsPage(workId, pagination) {
|
|
2574
|
+
this.getWork(workId);
|
|
2575
|
+
const page = paginationSql(pagination);
|
|
2576
|
+
const rows = this.db.all(`SELECT * FROM timeline_events WHERE work_id = ? ORDER BY time_sort IS NULL, time_sort, created_at${page.sql}`, workId, ...page.params);
|
|
2577
|
+
return paginated(rows.map((row) => this.mapTimelineEvent(row)), pagination);
|
|
2578
|
+
}
|
|
2348
2579
|
getTimelineEvent(eventId) {
|
|
2349
2580
|
const row = this.db.get("SELECT * FROM timeline_events WHERE id = ?", eventId);
|
|
2350
2581
|
if (!row)
|
|
@@ -2507,6 +2738,12 @@ export class Store {
|
|
|
2507
2738
|
.all("SELECT * FROM relationships WHERE work_id = ? AND confidence >= ? ORDER BY confidence DESC, created_at", workId, minimumConfidence)
|
|
2508
2739
|
.map((row) => this.mapRelationship(row));
|
|
2509
2740
|
}
|
|
2741
|
+
listRelationshipsPage(workId, pagination, minimumConfidence = 0) {
|
|
2742
|
+
this.getWork(workId);
|
|
2743
|
+
const page = paginationSql(pagination);
|
|
2744
|
+
const rows = this.db.all(`SELECT * FROM relationships WHERE work_id = ? AND confidence >= ? ORDER BY confidence DESC, created_at${page.sql}`, workId, minimumConfidence, ...page.params);
|
|
2745
|
+
return paginated(rows.map((row) => this.mapRelationship(row)), pagination);
|
|
2746
|
+
}
|
|
2510
2747
|
getRelationship(relationshipId) {
|
|
2511
2748
|
const row = this.db.get("SELECT * FROM relationships WHERE id = ?", relationshipId);
|
|
2512
2749
|
if (!row)
|
|
@@ -2602,6 +2839,14 @@ export class Store {
|
|
|
2602
2839
|
: this.db.all("SELECT * FROM review_items WHERE work_id = ? ORDER BY created_at DESC", workId);
|
|
2603
2840
|
return rows.map((row) => this.mapReviewItem(row));
|
|
2604
2841
|
}
|
|
2842
|
+
listReviewItemsPage(workId, pagination, status) {
|
|
2843
|
+
this.getWork(workId);
|
|
2844
|
+
const page = paginationSql(pagination);
|
|
2845
|
+
const rows = status
|
|
2846
|
+
? this.db.all(`SELECT * FROM review_items WHERE work_id = ? AND status = ? ORDER BY created_at DESC${page.sql}`, workId, status, ...page.params)
|
|
2847
|
+
: this.db.all(`SELECT * FROM review_items WHERE work_id = ? ORDER BY created_at DESC${page.sql}`, workId, ...page.params);
|
|
2848
|
+
return paginated(rows.map((row) => this.mapReviewItem(row)), pagination);
|
|
2849
|
+
}
|
|
2605
2850
|
getReviewItem(reviewId) {
|
|
2606
2851
|
const row = this.db.get("SELECT * FROM review_items WHERE id = ?", reviewId);
|
|
2607
2852
|
if (!row)
|
|
@@ -2659,6 +2904,14 @@ export class Store {
|
|
|
2659
2904
|
throw notFound("AI 建议");
|
|
2660
2905
|
return this.db.all("SELECT * FROM continuation_guard_runs WHERE suggestion_id = ? ORDER BY created_at DESC", suggestionId).map((row) => this.mapContinuationGuard(row));
|
|
2661
2906
|
}
|
|
2907
|
+
listContinuationGuardsPage(suggestionId, pagination) {
|
|
2908
|
+
const suggestion = this.db.get("SELECT id FROM ai_suggestions WHERE id = ?", suggestionId);
|
|
2909
|
+
if (!suggestion)
|
|
2910
|
+
throw notFound("AI 建议");
|
|
2911
|
+
const page = paginationSql(pagination);
|
|
2912
|
+
const rows = this.db.all(`SELECT * FROM continuation_guard_runs WHERE suggestion_id = ? ORDER BY created_at DESC${page.sql}`, suggestionId, ...page.params);
|
|
2913
|
+
return paginated(rows.map((row) => this.mapContinuationGuard(row)), pagination);
|
|
2914
|
+
}
|
|
2662
2915
|
getLatestContinuationGuard(suggestionId) {
|
|
2663
2916
|
const row = this.db.get("SELECT * FROM continuation_guard_runs WHERE suggestion_id = ? ORDER BY created_at DESC LIMIT 1", suggestionId);
|
|
2664
2917
|
return row ? this.mapContinuationGuard(row) : null;
|
|
@@ -2680,6 +2933,17 @@ export class Store {
|
|
|
2680
2933
|
ORDER BY conversation.updated_at DESC, conversation.created_at DESC
|
|
2681
2934
|
LIMIT 100`, workId).map((row) => this.mapAiConversation(row));
|
|
2682
2935
|
}
|
|
2936
|
+
listAiConversationsPage(workId, pagination) {
|
|
2937
|
+
this.getWork(workId);
|
|
2938
|
+
const page = paginationSql(pagination);
|
|
2939
|
+
const rows = this.db.all(`SELECT conversation.*,
|
|
2940
|
+
(SELECT COUNT(*) FROM ai_conversation_messages message WHERE message.conversation_id = conversation.id) AS message_count,
|
|
2941
|
+
COALESCE((SELECT content FROM ai_conversation_messages message WHERE message.conversation_id = conversation.id ORDER BY message.created_at DESC, message.rowid DESC LIMIT 1), '') AS preview
|
|
2942
|
+
FROM ai_conversations conversation
|
|
2943
|
+
WHERE conversation.work_id = ?
|
|
2944
|
+
ORDER BY conversation.updated_at DESC, conversation.created_at DESC${page.sql}`, workId, ...page.params);
|
|
2945
|
+
return paginated(rows.map((row) => this.mapAiConversation(row)), pagination);
|
|
2946
|
+
}
|
|
2683
2947
|
getAiConversation(conversationId) {
|
|
2684
2948
|
const row = this.db.get("SELECT * FROM ai_conversations WHERE id = ?", conversationId);
|
|
2685
2949
|
if (!row)
|
|
@@ -2687,6 +2951,22 @@ export class Store {
|
|
|
2687
2951
|
const messages = this.db.all("SELECT * FROM ai_conversation_messages WHERE conversation_id = ? ORDER BY created_at, rowid", conversationId).map((message) => this.mapAiConversationMessage(message));
|
|
2688
2952
|
return { ...this.mapAiConversation(row), messageCount: messages.length, messages };
|
|
2689
2953
|
}
|
|
2954
|
+
getAiConversationPage(conversationId, pagination) {
|
|
2955
|
+
const row = this.db.get("SELECT * FROM ai_conversations WHERE id = ?", conversationId);
|
|
2956
|
+
if (!row)
|
|
2957
|
+
throw notFound("AI 对话");
|
|
2958
|
+
const countRow = this.db.get("SELECT COUNT(*) AS count FROM ai_conversation_messages WHERE conversation_id = ?", conversationId);
|
|
2959
|
+
const page = paginationSql(pagination);
|
|
2960
|
+
const rows = this.db.all(`SELECT * FROM ai_conversation_messages WHERE conversation_id = ? ORDER BY created_at DESC, rowid DESC${page.sql}`, conversationId, ...page.params);
|
|
2961
|
+
const messagesPage = paginated(rows.map((message) => this.mapAiConversationMessage(message)), pagination);
|
|
2962
|
+
messagesPage.items.reverse();
|
|
2963
|
+
return {
|
|
2964
|
+
...this.mapAiConversation(row),
|
|
2965
|
+
messageCount: Number(countRow?.count ?? 0),
|
|
2966
|
+
messages: messagesPage.items,
|
|
2967
|
+
messagesPage
|
|
2968
|
+
};
|
|
2969
|
+
}
|
|
2690
2970
|
getAiConversationContext(conversationId, workId, excludeMessageId) {
|
|
2691
2971
|
const conversation = this.db.get("SELECT * FROM ai_conversations WHERE id = ?", conversationId);
|
|
2692
2972
|
if (!conversation)
|
|
@@ -2840,6 +3120,12 @@ export class Store {
|
|
|
2840
3120
|
this.getWork(workId);
|
|
2841
3121
|
return this.db.all("SELECT * FROM analysis_tasks WHERE work_id = ? ORDER BY created_at DESC", workId).map((row) => this.mapTask(row));
|
|
2842
3122
|
}
|
|
3123
|
+
listTasksPage(workId, pagination) {
|
|
3124
|
+
this.getWork(workId);
|
|
3125
|
+
const page = paginationSql(pagination);
|
|
3126
|
+
const rows = this.db.all(`SELECT * FROM analysis_tasks WHERE work_id = ? ORDER BY created_at DESC${page.sql}`, workId, ...page.params);
|
|
3127
|
+
return paginated(rows.map((row) => this.mapTask(row)), pagination);
|
|
3128
|
+
}
|
|
2843
3129
|
getTask(taskId) {
|
|
2844
3130
|
const row = this.db.get("SELECT * FROM analysis_tasks WHERE id = ?", taskId);
|
|
2845
3131
|
if (!row)
|
|
@@ -3107,5 +3393,22 @@ export class Store {
|
|
|
3107
3393
|
createdAt: requiredString(row, "created_at")
|
|
3108
3394
|
}));
|
|
3109
3395
|
}
|
|
3396
|
+
listAuditLogsPage(workId, pagination) {
|
|
3397
|
+
this.getWork(workId);
|
|
3398
|
+
const page = paginationSql(pagination);
|
|
3399
|
+
const rows = this.db.all(`SELECT log.*, user.display_name AS actor_display_name, user.username AS actor_username
|
|
3400
|
+
FROM audit_logs log LEFT JOIN users user ON user.id = log.user_id
|
|
3401
|
+
WHERE log.work_id = ? ORDER BY log.created_at DESC${page.sql}`, workId, ...page.params);
|
|
3402
|
+
return paginated(rows.map((row) => ({
|
|
3403
|
+
id: requiredString(row, "id"),
|
|
3404
|
+
action: requiredString(row, "action"),
|
|
3405
|
+
entityType: requiredString(row, "entity_type"),
|
|
3406
|
+
entityId: optionalString(row, "entity_id"),
|
|
3407
|
+
actor: optionalString(row, "actor_display_name") ?? optionalString(row, "actor_username") ?? requiredString(row, "actor"),
|
|
3408
|
+
userId: optionalString(row, "user_id"),
|
|
3409
|
+
detail: json(requiredString(row, "detail_json"), {}),
|
|
3410
|
+
createdAt: requiredString(row, "created_at")
|
|
3411
|
+
})), pagination);
|
|
3412
|
+
}
|
|
3110
3413
|
}
|
|
3111
3414
|
//# sourceMappingURL=store.js.map
|