@musnows/scriverse 0.5.4 → 0.5.5
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 +831 -90
- package/dist/ai.js.map +1 -1
- package/dist/app.js +124 -58
- package/dist/app.js.map +1 -1
- package/dist/collaboration-presence.js +18 -7
- package/dist/collaboration-presence.js.map +1 -1
- package/dist/database.js +67 -0
- package/dist/database.js.map +1 -1
- package/dist/public/ai-usage.d.ts +20 -0
- package/dist/public/ai-usage.js +75 -0
- package/dist/public/app.js +1089 -111
- package/dist/public/background-task-center.d.ts +28 -0
- package/dist/public/background-task-center.js +30 -0
- package/dist/public/index.html +41 -4
- package/dist/public/page-route.js +2 -2
- package/dist/public/race-hierarchy.js +35 -0
- package/dist/public/styles.css +230 -10
- package/dist/public/theme-init.js +2 -2
- package/dist/relationship-search.js +8 -1
- package/dist/relationship-search.js.map +1 -1
- package/dist/store.js +135 -75
- package/dist/store.js.map +1 -1
- package/dist/user-auth.js +7 -2
- package/dist/user-auth.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/app.js
CHANGED
|
@@ -27,7 +27,7 @@ import { accountReference, logger, sanitizeError } from "./logger.js";
|
|
|
27
27
|
import { currentRequestActor, runWithRequestActor } from "./request-context.js";
|
|
28
28
|
import { APP_VERSION } from "./version.js";
|
|
29
29
|
import { fullWorkModulePermissions, proseReplacementPermissionModules } from "./work-permissions.js";
|
|
30
|
-
import { CollaborationPresence,
|
|
30
|
+
import { CollaborationPresence, entityEditorPageKey, presencePageKinds } from "./collaboration-presence.js";
|
|
31
31
|
import { clearSessionCookie, createCliApiScopeMiddleware, createUserSessionMiddleware, createWorkAuthorizationMiddleware, relationshipAnalysisReadModules, setSessionCookie, UserAuthService } from "./user-auth.js";
|
|
32
32
|
const nonEmpty = z.string().trim().min(1);
|
|
33
33
|
const identifier = z.string().trim().min(1).max(200);
|
|
@@ -95,7 +95,7 @@ const presenceHeartbeatSchema = z.object({
|
|
|
95
95
|
z.object({ kind: z.literal(presencePageKinds[0]) }).strict(),
|
|
96
96
|
z.object({ kind: z.literal(presencePageKinds[1]), resourceId: identifier }).strict(),
|
|
97
97
|
z.object({ kind: z.literal(presencePageKinds[2]), module: z.enum(["settings", "characters", "races", "organizations", "timeline", "relationships", "outlines", "reviews", "tasks", "ai-settings"]) }).strict(),
|
|
98
|
-
z.object({ kind: z.literal(presencePageKinds[3]), module: z.enum(["setting", "character", "race", "organization"]), resourceId: identifier.optional() }).strict(),
|
|
98
|
+
z.object({ kind: z.literal(presencePageKinds[3]), module: z.enum(["setting", "character", "race", "organization", "relationship"]), resourceId: identifier.optional() }).strict(),
|
|
99
99
|
z.object({ kind: z.literal(presencePageKinds[4]) }).strict()
|
|
100
100
|
])
|
|
101
101
|
}).strict();
|
|
@@ -296,8 +296,18 @@ const modelSchema = z.object({
|
|
|
296
296
|
const aiPromptSchema = z.object({
|
|
297
297
|
systemPrompt: z.string().max(100_000).optional()
|
|
298
298
|
});
|
|
299
|
+
const aiUsageQuerySchema = z.object({
|
|
300
|
+
timezoneOffset: z.coerce.number().int().min(-840).max(840).default(0)
|
|
301
|
+
}).strict();
|
|
299
302
|
const platformPageSizesSchema = z.object({
|
|
303
|
+
settings: z.number().int().min(10).max(100).optional(),
|
|
300
304
|
characters: z.number().int().min(10).max(100).optional(),
|
|
305
|
+
races: z.number().int().min(10).max(100).optional(),
|
|
306
|
+
organizations: z.number().int().min(10).max(100).optional(),
|
|
307
|
+
timeline: z.number().int().min(10).max(100).optional(),
|
|
308
|
+
outlines: z.number().int().min(10).max(100).optional(),
|
|
309
|
+
relationships: z.number().int().min(10).max(100).optional(),
|
|
310
|
+
reviews: z.number().int().min(10).max(100).optional(),
|
|
301
311
|
analysisTasks: z.number().int().min(10).max(100).optional(),
|
|
302
312
|
fileVersions: z.number().int().min(10).max(100).optional()
|
|
303
313
|
}).strict();
|
|
@@ -358,12 +368,20 @@ const contextSchema = z.object({
|
|
|
358
368
|
includeBookSummary: z.boolean().optional()
|
|
359
369
|
});
|
|
360
370
|
const analysisTaskTypeSchema = z.enum(["structure", "chapter-analysis", "character-extraction", "character-summary", "character-identity-audit", "timeline-analysis", "worldview-analysis", "setting-extraction", "consistency-check", "report-update", "book-analysis"]);
|
|
371
|
+
const relationshipSourceRefSchema = z.object({
|
|
372
|
+
sourceType: z.string().trim().min(1).max(50).regex(/^[a-z][a-z-]*$/u),
|
|
373
|
+
sourceId: identifier,
|
|
374
|
+
sourceVersion: z.string().trim().min(1).max(200)
|
|
375
|
+
}).strict();
|
|
361
376
|
const relationshipAnalysisScopeSchema = z.object({
|
|
362
377
|
type: z.enum(["chapter", "book", "settings"]),
|
|
363
378
|
chapterId: identifier.optional(),
|
|
364
379
|
includeAllSettings: z.boolean().optional(),
|
|
365
380
|
additionalPrompt: z.string().trim().max(10_000).optional(),
|
|
366
381
|
characterIds: z.array(identifier).max(20).optional(),
|
|
382
|
+
preFilterRelationshipSources: z.boolean().optional(),
|
|
383
|
+
previewRelationshipChanges: z.boolean().optional(),
|
|
384
|
+
relationshipSourceRefs: z.array(relationshipSourceRefSchema).max(5_000).optional(),
|
|
367
385
|
replaceExistingRelationships: z.boolean().optional()
|
|
368
386
|
}).strict().superRefine((scope, context) => {
|
|
369
387
|
if (scope.type === "chapter" && !scope.chapterId) {
|
|
@@ -378,6 +396,18 @@ const relationshipAnalysisScopeSchema = z.object({
|
|
|
378
396
|
if (scope.replaceExistingRelationships && !scope.characterIds?.length) {
|
|
379
397
|
context.addIssue({ code: z.ZodIssueCode.custom, path: ["replaceExistingRelationships"], message: "覆盖已有关系前必须选择被分析角色" });
|
|
380
398
|
}
|
|
399
|
+
if (scope.preFilterRelationshipSources !== undefined && !scope.characterIds?.length) {
|
|
400
|
+
context.addIssue({ code: z.ZodIssueCode.custom, path: ["preFilterRelationshipSources"], message: "来源前置过滤仅支持定向人物关系分析" });
|
|
401
|
+
}
|
|
402
|
+
if (scope.relationshipSourceRefs !== undefined && !scope.characterIds?.length) {
|
|
403
|
+
context.addIssue({ code: z.ZodIssueCode.custom, path: ["relationshipSourceRefs"], message: "预检来源仅支持定向人物关系分析" });
|
|
404
|
+
}
|
|
405
|
+
if (scope.relationshipSourceRefs) {
|
|
406
|
+
const keys = scope.relationshipSourceRefs.map((ref) => `${ref.sourceType}:${ref.sourceId}`);
|
|
407
|
+
if (new Set(keys).size !== keys.length) {
|
|
408
|
+
context.addIssue({ code: z.ZodIssueCode.custom, path: ["relationshipSourceRefs"], message: "预检来源不能重复" });
|
|
409
|
+
}
|
|
410
|
+
}
|
|
381
411
|
});
|
|
382
412
|
const analysisTaskSchema = z.union([
|
|
383
413
|
z.object({ taskType: z.literal("relationship-analysis"), scope: relationshipAnalysisScopeSchema.optional(), modelId: identifier.optional() }).strict(),
|
|
@@ -388,6 +418,15 @@ const analysisTaskSchema = z.union([
|
|
|
388
418
|
if (input.scope?.additionalPrompt !== undefined) {
|
|
389
419
|
context.addIssue({ code: z.ZodIssueCode.custom, path: ["scope", "additionalPrompt"], message: "额外分析提示仅支持人物关系分析" });
|
|
390
420
|
}
|
|
421
|
+
if (input.scope?.preFilterRelationshipSources !== undefined) {
|
|
422
|
+
context.addIssue({ code: z.ZodIssueCode.custom, path: ["scope", "preFilterRelationshipSources"], message: "来源前置过滤仅支持人物关系分析" });
|
|
423
|
+
}
|
|
424
|
+
if (input.scope?.previewRelationshipChanges !== undefined) {
|
|
425
|
+
context.addIssue({ code: z.ZodIssueCode.custom, path: ["scope", "previewRelationshipChanges"], message: "变更预览仅支持人物关系分析" });
|
|
426
|
+
}
|
|
427
|
+
if (input.scope?.relationshipSourceRefs !== undefined) {
|
|
428
|
+
context.addIssue({ code: z.ZodIssueCode.custom, path: ["scope", "relationshipSourceRefs"], message: "预检来源仅支持人物关系分析" });
|
|
429
|
+
}
|
|
391
430
|
if (input.scope?.characterIds !== undefined || input.scope?.replaceExistingRelationships !== undefined) {
|
|
392
431
|
context.addIssue({ code: z.ZodIssueCode.custom, path: ["scope", "characterIds"], message: "被分析角色仅支持人物关系分析" });
|
|
393
432
|
}
|
|
@@ -492,6 +531,11 @@ function redactTaskCharacterNames(record, permissions) {
|
|
|
492
531
|
return redactedRelationship;
|
|
493
532
|
});
|
|
494
533
|
}
|
|
534
|
+
const changePreview = recordValue(taskResult.relationshipChangePreview);
|
|
535
|
+
if (changePreview) {
|
|
536
|
+
const { operations: _operations, ...redactedChangePreview } = changePreview;
|
|
537
|
+
redactedTaskResult.relationshipChangePreview = redactedChangePreview;
|
|
538
|
+
}
|
|
495
539
|
const analysisTarget = recordValue(taskResult.analysisTarget);
|
|
496
540
|
if (analysisTarget) {
|
|
497
541
|
const { characterNames: _characterNames, ...redactedAnalysisTarget } = analysisTarget;
|
|
@@ -500,6 +544,14 @@ function redactTaskCharacterNames(record, permissions) {
|
|
|
500
544
|
result.result = redactedTaskResult;
|
|
501
545
|
}
|
|
502
546
|
}
|
|
547
|
+
if (permissions.relationships === "none") {
|
|
548
|
+
const taskResult = recordValue(result.result);
|
|
549
|
+
const changePreview = recordValue(taskResult?.relationshipChangePreview);
|
|
550
|
+
if (taskResult && changePreview) {
|
|
551
|
+
const { operations: _operations, ...redactedChangePreview } = changePreview;
|
|
552
|
+
result.result = { ...taskResult, relationshipChangePreview: redactedChangePreview };
|
|
553
|
+
}
|
|
554
|
+
}
|
|
503
555
|
const resultSummary = recordValue(result.resultSummary);
|
|
504
556
|
const characterSensitiveTask = ["character-extraction", "character-summary", "character-identity-audit", "relationship-analysis"]
|
|
505
557
|
.includes(String(result.taskType));
|
|
@@ -549,14 +601,14 @@ export function createRuntime(options) {
|
|
|
549
601
|
mkdirSync(attachmentStorage.temporaryDirectory, { recursive: true, mode: 0o700 });
|
|
550
602
|
const auth = new UserAuthService(database);
|
|
551
603
|
const collaborationPresence = new CollaborationPresence();
|
|
552
|
-
const
|
|
604
|
+
const publishRelationshipChange = (workId, relationshipId) => {
|
|
553
605
|
const actor = currentRequestActor();
|
|
554
|
-
if (!actor || !workId || !
|
|
606
|
+
if (!actor || !workId || !relationshipId)
|
|
555
607
|
return;
|
|
556
|
-
collaborationPresence.publishChange(workId,
|
|
608
|
+
collaborationPresence.publishChange(workId, entityEditorPageKey("relationship", relationshipId), {
|
|
557
609
|
userId: actor.userId,
|
|
558
610
|
displayName: actor.displayName
|
|
559
|
-
}
|
|
611
|
+
});
|
|
560
612
|
};
|
|
561
613
|
const getDevelopmentUser = () => options.devAuthBypass
|
|
562
614
|
? auth.listUsers().find((user) => user.status === "active") ?? null
|
|
@@ -946,14 +998,11 @@ export function createRuntime(options) {
|
|
|
946
998
|
const input = parse(z.object({ title: nonEmpty.max(300).optional(), content: z.string().max(2_000_000).optional(), excludedFromAnalysis: z.boolean().optional(), chapterType: chapterTypeSchema.optional(), source: z.enum(["manual", "auto"]).optional(), changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
947
999
|
const { source, changeNote, expectedVersionNo, ...chapterInput } = input;
|
|
948
1000
|
const chapter = store.saveChapter(request.params.chapterId, chapterInput, source ?? "manual", null, changeNote, expectedVersionNo);
|
|
949
|
-
publishCollaborativeChange(String(chapter.workId), editorPageKey(String(chapter.id)));
|
|
950
1001
|
data(response, chapter);
|
|
951
1002
|
});
|
|
952
1003
|
app.delete("/api/chapters/:chapterId", (request, response) => {
|
|
953
1004
|
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
954
|
-
const chapter = store.getChapter(request.params.chapterId);
|
|
955
1005
|
store.deleteChapter(request.params.chapterId, input.expectedVersionNo);
|
|
956
|
-
publishCollaborativeChange(String(chapter.workId), editorPageKey(String(chapter.id)));
|
|
957
1006
|
noContent(response);
|
|
958
1007
|
});
|
|
959
1008
|
app.get("/api/chapters/:chapterId/versions", (request, response) => {
|
|
@@ -967,7 +1016,6 @@ export function createRuntime(options) {
|
|
|
967
1016
|
app.post("/api/chapters/:chapterId/restore", (request, response) => {
|
|
968
1017
|
const input = parse(z.object({ versionNo: z.number().int().positive(), expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
969
1018
|
const chapter = store.restoreChapter(request.params.chapterId, input.versionNo, input.expectedVersionNo);
|
|
970
|
-
publishCollaborativeChange(String(chapter.workId), editorPageKey(String(chapter.id)));
|
|
971
1019
|
data(response, chapter);
|
|
972
1020
|
});
|
|
973
1021
|
app.post("/api/chapters/:chapterId/move", (request, response) => {
|
|
@@ -983,14 +1031,11 @@ export function createRuntime(options) {
|
|
|
983
1031
|
app.put("/api/chapters/:chapterId/outline", (request, response) => {
|
|
984
1032
|
const { changeNote, expectedVersionNo, ...input } = parse(chapterOutlineSchema.extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
985
1033
|
const outline = store.upsertChapterOutline(request.params.chapterId, input, "manual", null, changeNote, expectedVersionNo);
|
|
986
|
-
publishCollaborativeChange(String(outline.workId), modulePageKey("outlines"));
|
|
987
1034
|
data(response, outline);
|
|
988
1035
|
});
|
|
989
1036
|
app.delete("/api/chapters/:chapterId/outline", (request, response) => {
|
|
990
1037
|
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
991
|
-
const chapter = store.getChapter(request.params.chapterId);
|
|
992
1038
|
store.deleteChapterOutline(request.params.chapterId, input.expectedVersionNo);
|
|
993
|
-
publishCollaborativeChange(String(chapter.workId), modulePageKey("outlines"));
|
|
994
1039
|
noContent(response);
|
|
995
1040
|
});
|
|
996
1041
|
app.get("/api/works/:workId/foreshadows", (request, response) => {
|
|
@@ -1005,42 +1050,34 @@ export function createRuntime(options) {
|
|
|
1005
1050
|
});
|
|
1006
1051
|
app.post("/api/works/:workId/foreshadows", (request, response) => {
|
|
1007
1052
|
const foreshadow = store.createForeshadow(request.params.workId, parse(foreshadowSchema, request.body));
|
|
1008
|
-
publishCollaborativeChange(request.params.workId, modulePageKey("outlines"));
|
|
1009
1053
|
data(response, foreshadow, 201);
|
|
1010
1054
|
});
|
|
1011
1055
|
app.get("/api/foreshadows/:foreshadowId", (request, response) => data(response, store.getForeshadow(request.params.foreshadowId)));
|
|
1012
1056
|
app.patch("/api/foreshadows/:foreshadowId", (request, response) => {
|
|
1013
1057
|
const { changeNote, expectedVersionNo, ...input } = parse(foreshadowSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
1014
1058
|
const foreshadow = store.updateForeshadow(request.params.foreshadowId, input, "manual", null, changeNote, expectedVersionNo);
|
|
1015
|
-
publishCollaborativeChange(String(foreshadow.workId), modulePageKey("outlines"));
|
|
1016
1059
|
data(response, foreshadow);
|
|
1017
1060
|
});
|
|
1018
1061
|
app.delete("/api/foreshadows/:foreshadowId", (request, response) => {
|
|
1019
1062
|
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
1020
|
-
const foreshadow = store.getForeshadow(request.params.foreshadowId);
|
|
1021
1063
|
store.deleteForeshadow(request.params.foreshadowId, input.expectedVersionNo);
|
|
1022
|
-
publishCollaborativeChange(String(foreshadow.workId), modulePageKey("outlines"));
|
|
1023
1064
|
noContent(response);
|
|
1024
1065
|
});
|
|
1025
1066
|
app.post("/api/foreshadows/:foreshadowId/occurrences", (request, response) => {
|
|
1026
1067
|
const input = parse(foreshadowOccurrenceSchema.extend({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
1027
1068
|
const { expectedVersionNo, ...occurrenceInput } = input;
|
|
1028
1069
|
const occurrence = store.createForeshadowOccurrence(request.params.foreshadowId, occurrenceInput, expectedVersionNo);
|
|
1029
|
-
publishCollaborativeChange(String(occurrence.workId), modulePageKey("outlines"));
|
|
1030
1070
|
data(response, occurrence, 201);
|
|
1031
1071
|
});
|
|
1032
1072
|
app.patch("/api/foreshadow-occurrences/:occurrenceId", (request, response) => {
|
|
1033
1073
|
const input = parse(foreshadowOccurrenceSchema.partial().extend({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
1034
1074
|
const { expectedVersionNo, ...occurrenceInput } = input;
|
|
1035
1075
|
const occurrence = store.updateForeshadowOccurrence(request.params.occurrenceId, occurrenceInput, expectedVersionNo);
|
|
1036
|
-
publishCollaborativeChange(String(occurrence.workId), modulePageKey("outlines"));
|
|
1037
1076
|
data(response, occurrence);
|
|
1038
1077
|
});
|
|
1039
1078
|
app.delete("/api/foreshadow-occurrences/:occurrenceId", (request, response) => {
|
|
1040
1079
|
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
1041
|
-
const occurrence = store.getForeshadowOccurrence(request.params.occurrenceId);
|
|
1042
1080
|
store.deleteForeshadowOccurrence(request.params.occurrenceId, input.expectedVersionNo);
|
|
1043
|
-
publishCollaborativeChange(String(occurrence.workId), modulePageKey("outlines"));
|
|
1044
1081
|
noContent(response);
|
|
1045
1082
|
});
|
|
1046
1083
|
app.get("/api/works/:workId/settings", (request, response) => {
|
|
@@ -1050,7 +1087,6 @@ export function createRuntime(options) {
|
|
|
1050
1087
|
});
|
|
1051
1088
|
app.post("/api/works/:workId/settings", (request, response) => {
|
|
1052
1089
|
const setting = store.createSetting(request.params.workId, parse(settingSchema, request.body));
|
|
1053
|
-
publishCollaborativeChange(request.params.workId, modulePageKey("settings"));
|
|
1054
1090
|
data(response, setting, 201);
|
|
1055
1091
|
});
|
|
1056
1092
|
app.get("/api/works/:workId/settings/context", (request, response) => data(response, store.listSettings(request.params.workId, true)));
|
|
@@ -1058,14 +1094,11 @@ export function createRuntime(options) {
|
|
|
1058
1094
|
app.patch("/api/settings/:settingId", (request, response) => {
|
|
1059
1095
|
const { changeNote, expectedVersionNo, ...input } = parse(settingSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
1060
1096
|
const setting = store.updateSetting(request.params.settingId, input, "manual", null, changeNote, expectedVersionNo);
|
|
1061
|
-
publishCollaborativeChange(String(setting.workId), entityEditorPageKey("setting", String(setting.id)));
|
|
1062
1097
|
data(response, setting);
|
|
1063
1098
|
});
|
|
1064
1099
|
app.delete("/api/settings/:settingId", (request, response) => {
|
|
1065
1100
|
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
1066
|
-
const setting = store.getSetting(request.params.settingId);
|
|
1067
1101
|
store.deleteSetting(request.params.settingId, input.expectedVersionNo);
|
|
1068
|
-
publishCollaborativeChange(String(setting.workId), entityEditorPageKey("setting", String(setting.id)));
|
|
1069
1102
|
noContent(response);
|
|
1070
1103
|
});
|
|
1071
1104
|
app.get("/api/works/:workId/characters", (request, response) => {
|
|
@@ -1083,7 +1116,6 @@ export function createRuntime(options) {
|
|
|
1083
1116
|
});
|
|
1084
1117
|
app.post("/api/works/:workId/characters", (request, response) => {
|
|
1085
1118
|
const character = store.createCharacter(request.params.workId, parse(characterSchema, request.body));
|
|
1086
|
-
publishCollaborativeChange(request.params.workId, modulePageKey("characters"));
|
|
1087
1119
|
data(response, redactCharacterLinks(character, requestPermissions(request, request.params.workId)), 201);
|
|
1088
1120
|
});
|
|
1089
1121
|
app.get("/api/characters/:characterId", (request, response) => {
|
|
@@ -1092,7 +1124,6 @@ export function createRuntime(options) {
|
|
|
1092
1124
|
app.patch("/api/characters/:characterId", (request, response) => {
|
|
1093
1125
|
const { changeNote, expectedVersionNo, ...input } = parse(characterUpdateSchema.extend({ expectedVersionNo: expectedVersionNoSchema }), request.body);
|
|
1094
1126
|
const character = store.updateCharacter(request.params.characterId, input, "manual", null, changeNote, expectedVersionNo);
|
|
1095
|
-
publishCollaborativeChange(String(character.workId), entityEditorPageKey("character", String(character.id)));
|
|
1096
1127
|
data(response, redactCharacterLinks(character, requestPermissions(request)));
|
|
1097
1128
|
});
|
|
1098
1129
|
app.get("/api/characters/:characterId/versions", (request, response) => {
|
|
@@ -1104,14 +1135,11 @@ export function createRuntime(options) {
|
|
|
1104
1135
|
app.post("/api/characters/:characterId/restore", (request, response) => {
|
|
1105
1136
|
const input = parse(z.object({ versionNo: z.number().int().positive(), expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
1106
1137
|
const character = store.restoreCharacter(request.params.characterId, input.versionNo, input.expectedVersionNo);
|
|
1107
|
-
publishCollaborativeChange(String(character.workId), entityEditorPageKey("character", String(character.id)));
|
|
1108
1138
|
data(response, redactCharacterLinks(character, requestPermissions(request)));
|
|
1109
1139
|
});
|
|
1110
1140
|
app.delete("/api/characters/:characterId", (request, response) => {
|
|
1111
1141
|
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
1112
|
-
const character = store.getCharacter(request.params.characterId);
|
|
1113
1142
|
store.deleteCharacter(request.params.characterId, input.expectedVersionNo);
|
|
1114
|
-
publishCollaborativeChange(String(character.workId), entityEditorPageKey("character", String(character.id)));
|
|
1115
1143
|
noContent(response);
|
|
1116
1144
|
});
|
|
1117
1145
|
app.post("/api/characters/:characterId/merge", (request, response) => {
|
|
@@ -1136,7 +1164,6 @@ export function createRuntime(options) {
|
|
|
1136
1164
|
});
|
|
1137
1165
|
app.post("/api/characters/:characterId/sections", (request, response) => {
|
|
1138
1166
|
const section = store.createCharacterProfileSection(request.params.characterId, parse(characterProfileSectionSchema, request.body));
|
|
1139
|
-
publishCollaborativeChange(String(section.workId), entityEditorPageKey("character", String(section.characterId)));
|
|
1140
1167
|
data(response, section, 201);
|
|
1141
1168
|
});
|
|
1142
1169
|
app.get("/api/character-sections/:sectionId", (request, response) => {
|
|
@@ -1145,14 +1172,11 @@ export function createRuntime(options) {
|
|
|
1145
1172
|
app.patch("/api/character-sections/:sectionId", (request, response) => {
|
|
1146
1173
|
const { changeNote, expectedVersionNo, ...input } = parse(characterProfileSectionSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
1147
1174
|
const section = store.updateCharacterProfileSection(request.params.sectionId, input, "manual", null, changeNote, expectedVersionNo);
|
|
1148
|
-
publishCollaborativeChange(String(section.workId), entityEditorPageKey("character", String(section.characterId)));
|
|
1149
1175
|
data(response, section);
|
|
1150
1176
|
});
|
|
1151
1177
|
app.delete("/api/character-sections/:sectionId", (request, response) => {
|
|
1152
1178
|
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
1153
|
-
const section = store.getCharacterProfileSection(request.params.sectionId);
|
|
1154
1179
|
store.deleteCharacterProfileSection(request.params.sectionId, input.expectedVersionNo);
|
|
1155
|
-
publishCollaborativeChange(String(section.workId), entityEditorPageKey("character", String(section.characterId)));
|
|
1156
1180
|
noContent(response);
|
|
1157
1181
|
});
|
|
1158
1182
|
app.get("/api/character-sections/:sectionId/versions", (request, response) => {
|
|
@@ -1164,7 +1188,6 @@ export function createRuntime(options) {
|
|
|
1164
1188
|
app.post("/api/character-sections/:sectionId/restore", (request, response) => {
|
|
1165
1189
|
const input = parse(z.object({ versionNo: z.number().int().positive(), expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
1166
1190
|
const section = store.restoreCharacterProfileSection(request.params.sectionId, input.versionNo, input.expectedVersionNo);
|
|
1167
|
-
publishCollaborativeChange(String(section.workId), entityEditorPageKey("character", String(section.characterId)));
|
|
1168
1191
|
data(response, section);
|
|
1169
1192
|
});
|
|
1170
1193
|
app.get("/api/works/:workId/attachments", (request, response) => {
|
|
@@ -1221,7 +1244,6 @@ export function createRuntime(options) {
|
|
|
1221
1244
|
});
|
|
1222
1245
|
app.post("/api/works/:workId/races", (request, response) => {
|
|
1223
1246
|
const race = store.createRace(request.params.workId, parse(raceSchema, request.body));
|
|
1224
|
-
publishCollaborativeChange(request.params.workId, modulePageKey("races"));
|
|
1225
1247
|
data(response, redactRaceMembers(race, requestPermissions(request, request.params.workId)), 201);
|
|
1226
1248
|
});
|
|
1227
1249
|
app.get("/api/races/:raceId", (request, response) => {
|
|
@@ -1230,14 +1252,11 @@ export function createRuntime(options) {
|
|
|
1230
1252
|
app.patch("/api/races/:raceId", (request, response) => {
|
|
1231
1253
|
const { changeNote, expectedVersionNo, ...input } = parse(raceSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
1232
1254
|
const race = store.updateRace(request.params.raceId, input, "manual", null, changeNote, expectedVersionNo);
|
|
1233
|
-
publishCollaborativeChange(String(race.workId), entityEditorPageKey("race", String(race.id)));
|
|
1234
1255
|
data(response, redactRaceMembers(race, requestPermissions(request)));
|
|
1235
1256
|
});
|
|
1236
1257
|
app.delete("/api/races/:raceId", (request, response) => {
|
|
1237
1258
|
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
1238
|
-
const race = store.getRace(request.params.raceId);
|
|
1239
1259
|
store.deleteRace(request.params.raceId, input.expectedVersionNo);
|
|
1240
|
-
publishCollaborativeChange(String(race.workId), entityEditorPageKey("race", String(race.id)));
|
|
1241
1260
|
noContent(response);
|
|
1242
1261
|
});
|
|
1243
1262
|
app.post("/api/races/:raceId/merge", (request, response) => {
|
|
@@ -1255,7 +1274,6 @@ export function createRuntime(options) {
|
|
|
1255
1274
|
});
|
|
1256
1275
|
app.post("/api/works/:workId/organizations", (request, response) => {
|
|
1257
1276
|
const organization = store.createOrganization(request.params.workId, parse(organizationSchema, request.body));
|
|
1258
|
-
publishCollaborativeChange(request.params.workId, modulePageKey("organizations"));
|
|
1259
1277
|
data(response, redactOrganizationMembers(organization, requestPermissions(request, request.params.workId)), 201);
|
|
1260
1278
|
});
|
|
1261
1279
|
app.get("/api/organizations/:organizationId", (request, response) => {
|
|
@@ -1264,14 +1282,11 @@ export function createRuntime(options) {
|
|
|
1264
1282
|
app.patch("/api/organizations/:organizationId", (request, response) => {
|
|
1265
1283
|
const { changeNote, expectedVersionNo, ...input } = parse(organizationSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
1266
1284
|
const organization = store.updateOrganization(request.params.organizationId, input, "manual", null, changeNote, expectedVersionNo);
|
|
1267
|
-
publishCollaborativeChange(String(organization.workId), entityEditorPageKey("organization", String(organization.id)));
|
|
1268
1285
|
data(response, redactOrganizationMembers(organization, requestPermissions(request)));
|
|
1269
1286
|
});
|
|
1270
1287
|
app.delete("/api/organizations/:organizationId", (request, response) => {
|
|
1271
1288
|
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
1272
|
-
const organization = store.getOrganization(request.params.organizationId);
|
|
1273
1289
|
store.deleteOrganization(request.params.organizationId, input.expectedVersionNo);
|
|
1274
|
-
publishCollaborativeChange(String(organization.workId), entityEditorPageKey("organization", String(organization.id)));
|
|
1275
1290
|
noContent(response);
|
|
1276
1291
|
});
|
|
1277
1292
|
app.post("/api/organizations/:organizationId/merge", (request, response) => {
|
|
@@ -1286,21 +1301,17 @@ export function createRuntime(options) {
|
|
|
1286
1301
|
});
|
|
1287
1302
|
app.post("/api/works/:workId/timeline-tracks", (request, response) => {
|
|
1288
1303
|
const track = store.createTimelineTrack(request.params.workId, parse(timelineTrackSchema, request.body));
|
|
1289
|
-
publishCollaborativeChange(request.params.workId, modulePageKey("timeline"));
|
|
1290
1304
|
data(response, track, 201);
|
|
1291
1305
|
});
|
|
1292
1306
|
app.get("/api/timeline-tracks/:trackId", (request, response) => data(response, store.getTimelineTrack(request.params.trackId)));
|
|
1293
1307
|
app.patch("/api/timeline-tracks/:trackId", (request, response) => {
|
|
1294
1308
|
const { changeNote, expectedVersionNo, ...input } = parse(timelineTrackSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
1295
1309
|
const track = store.updateTimelineTrack(request.params.trackId, input, "manual", null, changeNote, expectedVersionNo);
|
|
1296
|
-
publishCollaborativeChange(String(track.workId), modulePageKey("timeline"));
|
|
1297
1310
|
data(response, track);
|
|
1298
1311
|
});
|
|
1299
1312
|
app.delete("/api/timeline-tracks/:trackId", (request, response) => {
|
|
1300
1313
|
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
1301
|
-
const track = store.getTimelineTrack(request.params.trackId);
|
|
1302
1314
|
store.deleteTimelineTrack(request.params.trackId, input.expectedVersionNo);
|
|
1303
|
-
publishCollaborativeChange(String(track.workId), modulePageKey("timeline"));
|
|
1304
1315
|
noContent(response);
|
|
1305
1316
|
});
|
|
1306
1317
|
app.get("/api/works/:workId/timeline", (request, response) => {
|
|
@@ -1309,7 +1320,6 @@ export function createRuntime(options) {
|
|
|
1309
1320
|
});
|
|
1310
1321
|
app.post("/api/works/:workId/timeline", (request, response) => {
|
|
1311
1322
|
const event = store.createTimelineEvent(request.params.workId, parse(timelineSchema, request.body));
|
|
1312
|
-
publishCollaborativeChange(request.params.workId, modulePageKey("timeline"));
|
|
1313
1323
|
data(response, event, 201);
|
|
1314
1324
|
});
|
|
1315
1325
|
app.post("/api/works/:workId/timeline/merge", (request, response) => {
|
|
@@ -1323,14 +1333,12 @@ export function createRuntime(options) {
|
|
|
1323
1333
|
}).strict(), request.body);
|
|
1324
1334
|
const { expectedVersionNos, ...mergeInput } = input;
|
|
1325
1335
|
const merged = store.mergeTimelineEvents(request.params.workId, input.eventIds, mergeInput, expectedVersionNos);
|
|
1326
|
-
publishCollaborativeChange(request.params.workId, modulePageKey("timeline"));
|
|
1327
1336
|
data(response, merged, 201);
|
|
1328
1337
|
});
|
|
1329
1338
|
app.get("/api/timeline/:eventId", (request, response) => data(response, store.getTimelineEvent(request.params.eventId)));
|
|
1330
1339
|
app.patch("/api/timeline/:eventId", (request, response) => {
|
|
1331
1340
|
const { changeNote, expectedVersionNo, ...input } = parse(timelineSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
1332
1341
|
const event = store.updateTimelineEvent(request.params.eventId, input, "manual", null, changeNote, expectedVersionNo);
|
|
1333
|
-
publishCollaborativeChange(String(event.workId), modulePageKey("timeline"));
|
|
1334
1342
|
data(response, event);
|
|
1335
1343
|
});
|
|
1336
1344
|
app.post("/api/timeline/:eventId/split", (request, response) => {
|
|
@@ -1344,16 +1352,11 @@ export function createRuntime(options) {
|
|
|
1344
1352
|
expectedVersionNo: expectedVersionNoSchema
|
|
1345
1353
|
}).strict(), request.body);
|
|
1346
1354
|
const split = store.splitTimelineEvent(request.params.eventId, input.parts, input.expectedVersionNo);
|
|
1347
|
-
const first = split[0];
|
|
1348
|
-
if (first)
|
|
1349
|
-
publishCollaborativeChange(String(first.workId), modulePageKey("timeline"));
|
|
1350
1355
|
data(response, split, 201);
|
|
1351
1356
|
});
|
|
1352
1357
|
app.delete("/api/timeline/:eventId", (request, response) => {
|
|
1353
1358
|
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
1354
|
-
const event = store.getTimelineEvent(request.params.eventId);
|
|
1355
1359
|
store.deleteTimelineEvent(request.params.eventId, input.expectedVersionNo);
|
|
1356
|
-
publishCollaborativeChange(String(event.workId), modulePageKey("timeline"));
|
|
1357
1360
|
noContent(response);
|
|
1358
1361
|
});
|
|
1359
1362
|
app.get("/api/works/:workId/relationships", (request, response) => {
|
|
@@ -1367,21 +1370,20 @@ export function createRuntime(options) {
|
|
|
1367
1370
|
});
|
|
1368
1371
|
app.post("/api/works/:workId/relationships", (request, response) => {
|
|
1369
1372
|
const relationship = store.createRelationship(request.params.workId, parse(relationshipSchema, request.body));
|
|
1370
|
-
publishCollaborativeChange(request.params.workId, modulePageKey("relationships"));
|
|
1371
1373
|
data(response, relationship, 201);
|
|
1372
1374
|
});
|
|
1373
1375
|
app.get("/api/relationships/:relationshipId", (request, response) => data(response, store.getRelationship(request.params.relationshipId)));
|
|
1374
1376
|
app.patch("/api/relationships/:relationshipId", (request, response) => {
|
|
1375
1377
|
const { changeNote, expectedVersionNo, ...input } = parse(relationshipSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
1376
1378
|
const relationship = store.updateRelationship(request.params.relationshipId, input, "manual", null, changeNote, expectedVersionNo);
|
|
1377
|
-
|
|
1379
|
+
publishRelationshipChange(String(relationship.workId), String(relationship.id));
|
|
1378
1380
|
data(response, relationship);
|
|
1379
1381
|
});
|
|
1380
1382
|
app.delete("/api/relationships/:relationshipId", (request, response) => {
|
|
1381
1383
|
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
1382
1384
|
const relationship = store.getRelationship(request.params.relationshipId);
|
|
1383
1385
|
store.deleteRelationship(request.params.relationshipId, input.expectedVersionNo);
|
|
1384
|
-
|
|
1386
|
+
publishRelationshipChange(String(relationship.workId), String(relationship.id));
|
|
1385
1387
|
noContent(response);
|
|
1386
1388
|
});
|
|
1387
1389
|
app.get("/api/entity-versions/:entityType/:entityId", (request, response) => {
|
|
@@ -1434,6 +1436,20 @@ export function createRuntime(options) {
|
|
|
1434
1436
|
const permissions = requestPermissions(request, request.params.workId);
|
|
1435
1437
|
data(response, mapRecords(store.listTaskSummariesPage(request.params.workId, parsePagination(request.query) ?? { page: 1, limit: 30, offset: 0 }), (task) => redactTaskCharacterNames(task, permissions)));
|
|
1436
1438
|
});
|
|
1439
|
+
app.post("/api/works/:workId/tasks/relationship-source-preview", async (request, response) => {
|
|
1440
|
+
const input = parse(z.object({
|
|
1441
|
+
scope: relationshipAnalysisScopeSchema,
|
|
1442
|
+
modelId: identifier.optional()
|
|
1443
|
+
}).strict(), request.body);
|
|
1444
|
+
const permissions = requestPermissions(request, request.params.workId);
|
|
1445
|
+
const deniedModules = relationshipAnalysisReadModules(input.scope).filter((module) => permissions[module] === "none");
|
|
1446
|
+
if (deniedModules.length > 0) {
|
|
1447
|
+
throw new AppError(403, "WORK_MODULE_READ_DENIED", "你没有读取人物关系来源预检所需资料模块的权限", {
|
|
1448
|
+
modules: deniedModules
|
|
1449
|
+
});
|
|
1450
|
+
}
|
|
1451
|
+
data(response, await ai.previewRelationshipSources(request.params.workId, input.scope, input.modelId));
|
|
1452
|
+
});
|
|
1437
1453
|
app.post("/api/works/:workId/tasks", (request, response) => {
|
|
1438
1454
|
const input = parse(analysisTaskSchema, request.body);
|
|
1439
1455
|
data(response, redactTaskCharacterNames(ai.createTask(request.params.workId, input), requestPermissions(request, request.params.workId)), 201);
|
|
@@ -1485,7 +1501,30 @@ export function createRuntime(options) {
|
|
|
1485
1501
|
allowAdminAccess: request.authMethod !== "api-key"
|
|
1486
1502
|
} : undefined), requestPermissions(request)));
|
|
1487
1503
|
});
|
|
1504
|
+
app.post("/api/tasks/:taskId/rerun", (request, response) => {
|
|
1505
|
+
parse(z.object({}).strict(), request.body ?? {});
|
|
1506
|
+
const task = store.getTask(request.params.taskId);
|
|
1507
|
+
if (task.taskType === "relationship-analysis") {
|
|
1508
|
+
const permissions = requestPermissions(request, String(task.workId));
|
|
1509
|
+
const deniedModules = relationshipAnalysisReadModules(task.scope).filter((module) => permissions[module] === "none");
|
|
1510
|
+
if (deniedModules.length > 0) {
|
|
1511
|
+
throw new AppError(403, "WORK_MODULE_READ_DENIED", "你没有读取本次定向人物关系分析所需资料模块的权限", {
|
|
1512
|
+
modules: deniedModules
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
data(response, redactTaskCharacterNames(ai.rerunTask(request.params.taskId), requestPermissions(request)), 201);
|
|
1517
|
+
});
|
|
1488
1518
|
app.post("/api/tasks/:taskId/cancel", (request, response) => data(response, redactTaskCharacterNames(ai.cancelTask(request.params.taskId), requestPermissions(request))));
|
|
1519
|
+
app.post("/api/tasks/:taskId/relationship-changes/apply", (request, response) => {
|
|
1520
|
+
parse(z.object({}).strict(), request.body ?? {});
|
|
1521
|
+
const applied = ai.applyRelationshipChangePreview(request.params.taskId);
|
|
1522
|
+
data(response, redactTaskCharacterNames(applied, requestPermissions(request)));
|
|
1523
|
+
});
|
|
1524
|
+
app.post("/api/tasks/:taskId/relationship-changes/discard", (request, response) => {
|
|
1525
|
+
parse(z.object({}).strict(), request.body ?? {});
|
|
1526
|
+
data(response, redactTaskCharacterNames(ai.discardRelationshipChangePreview(request.params.taskId), requestPermissions(request)));
|
|
1527
|
+
});
|
|
1489
1528
|
app.get("/api/platform/ai/providers", (request, response) => {
|
|
1490
1529
|
const pagination = parsePagination(request.query);
|
|
1491
1530
|
data(response, pagination ? ai.listProvidersPage(pagination) : ai.listProviders());
|
|
@@ -1497,12 +1536,39 @@ export function createRuntime(options) {
|
|
|
1497
1536
|
});
|
|
1498
1537
|
app.get("/api/platform/ai/settings", (_request, response) => data(response, store.getPlatformAiSettings()));
|
|
1499
1538
|
app.patch("/api/platform/ai/settings", (request, response) => data(response, store.updatePlatformAiSettings(parse(aiPromptSchema, request.body))));
|
|
1539
|
+
app.get("/api/platform/ai/usage", (request, response) => {
|
|
1540
|
+
const query = parse(aiUsageQuerySchema, request.query);
|
|
1541
|
+
data(response, ai.getPlatformTokenUsage(query.timezoneOffset));
|
|
1542
|
+
});
|
|
1500
1543
|
app.get("/api/ui-settings", (_request, response) => data(response, store.getPlatformUiSettings()));
|
|
1501
1544
|
app.get("/api/platform/ui-settings", (_request, response) => data(response, store.getPlatformUiSettings()));
|
|
1502
1545
|
app.patch("/api/platform/ui-settings", (request, response) => {
|
|
1503
1546
|
data(response, store.updatePlatformUiSettings(parse(platformUiSettingsSchema, request.body)));
|
|
1504
1547
|
});
|
|
1505
1548
|
app.get("/api/works/:workId/ai-settings", (request, response) => data(response, store.getWorkAiSettings(request.params.workId)));
|
|
1549
|
+
app.get("/api/works/:workId/ai-settings/usage", (request, response) => {
|
|
1550
|
+
const query = parse(aiUsageQuerySchema, request.query);
|
|
1551
|
+
data(response, ai.getWorkTokenUsage(request.params.workId, query.timezoneOffset));
|
|
1552
|
+
});
|
|
1553
|
+
app.get("/api/works/:workId/ai-settings/relationship-search-index", (request, response) => {
|
|
1554
|
+
data(response, ai.getRelationshipSearchIndexStatus(request.params.workId));
|
|
1555
|
+
});
|
|
1556
|
+
app.post("/api/works/:workId/ai-settings/relationship-search-index/sync", (request, response) => {
|
|
1557
|
+
const workId = request.params.workId;
|
|
1558
|
+
const result = ai.syncRelationshipSearchIndex(workId);
|
|
1559
|
+
store.audit(workId, "relationship.search-index.incremental-sync-queued", "work-ai-settings", workId, {
|
|
1560
|
+
queuedSourceCount: result.queuedSourceCount
|
|
1561
|
+
});
|
|
1562
|
+
data(response, result, 202);
|
|
1563
|
+
});
|
|
1564
|
+
app.post("/api/works/:workId/ai-settings/relationship-search-index/rebuild", (request, response) => {
|
|
1565
|
+
const workId = request.params.workId;
|
|
1566
|
+
const result = ai.rebuildRelationshipSearchIndex(workId);
|
|
1567
|
+
store.audit(workId, "relationship.search-index.rebuild-queued", "work-ai-settings", workId, {
|
|
1568
|
+
queuedSourceCount: result.queuedSourceCount
|
|
1569
|
+
});
|
|
1570
|
+
data(response, result, 202);
|
|
1571
|
+
});
|
|
1506
1572
|
app.patch("/api/works/:workId/ai-settings", (request, response) => {
|
|
1507
1573
|
const workId = request.params.workId;
|
|
1508
1574
|
const before = store.getWorkAiSettings(workId);
|