@musnows/scriverse 0.3.8 → 0.3.9
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/app.js +117 -65
- package/dist/app.js.map +1 -1
- package/dist/cli-contract.js +4 -4
- package/dist/cli-contract.js.map +1 -1
- package/dist/cli-core.js +37 -6
- package/dist/cli-core.js.map +1 -1
- package/dist/database.js +41 -0
- package/dist/database.js.map +1 -1
- package/dist/public/app.js +257 -39
- package/dist/public/index.html +26 -3
- package/dist/public/styles.css +34 -0
- package/dist/store.js +417 -109
- package/dist/store.js.map +1 -1
- package/dist/user-auth.js +47 -13
- package/dist/user-auth.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/app.js
CHANGED
|
@@ -55,11 +55,12 @@ const loginSchema = z.object({
|
|
|
55
55
|
...captchaFields
|
|
56
56
|
}).strict();
|
|
57
57
|
const userUpdateSchema = z.object({ role: z.enum(["admin", "user"]).optional(), status: z.enum(["active", "disabled"]).optional() }).strict();
|
|
58
|
-
const memberSchema = z.object({ userId: identifier, role: z.enum(["editor", "viewer"]) }).strict();
|
|
59
|
-
const memberRoleSchema = z.object({ role: z.enum(["editor", "viewer"]) }).strict();
|
|
58
|
+
const memberSchema = z.object({ userId: identifier, role: z.enum(["editor", "settings-editor", "viewer"]) }).strict();
|
|
59
|
+
const memberRoleSchema = z.object({ role: z.enum(["editor", "settings-editor", "viewer"]) }).strict();
|
|
60
60
|
const profileSchema = z.object({ displayName: z.string().trim().min(1).max(80) }).strict();
|
|
61
61
|
const passwordChangeSchema = z.object({ currentPassword: z.string().max(200), newPassword: passwordSchema }).strict();
|
|
62
62
|
const changeNoteSchema = z.string().trim().max(500).optional();
|
|
63
|
+
const expectedVersionNoSchema = z.coerce.number().int().positive().optional();
|
|
63
64
|
function validateImportedText(text) {
|
|
64
65
|
if (text.length > maximumImportedTextLength)
|
|
65
66
|
throw new AppError(413, "IMPORT_TEXT_TOO_LARGE", "导入文件解压后的文本超过 2000 万字符限制");
|
|
@@ -174,7 +175,7 @@ const organizationSchema = z.object({
|
|
|
174
175
|
description: z.string().max(100_000).optional(),
|
|
175
176
|
settings: z.array(z.string().trim().min(1).max(20_000)).max(200).optional(),
|
|
176
177
|
memberIds: z.array(identifier).max(1000).optional()
|
|
177
|
-
});
|
|
178
|
+
}).strict();
|
|
178
179
|
const raceSchema = z.object({
|
|
179
180
|
name: nonEmpty.max(200),
|
|
180
181
|
parentRaceId: identifier.nullable().optional(),
|
|
@@ -550,9 +551,13 @@ export function createRuntime(options) {
|
|
|
550
551
|
store.audit(request.params.workId, "work.member-removed", "user", request.params.userId);
|
|
551
552
|
data(response, members);
|
|
552
553
|
});
|
|
553
|
-
app.patch("/api/works/:workId", (request, response) =>
|
|
554
|
+
app.patch("/api/works/:workId", (request, response) => {
|
|
555
|
+
const { expectedVersionNo, changeNote, ...input } = parse(workSchema.partial().extend({ expectedVersionNo: expectedVersionNoSchema, changeNote: changeNoteSchema }).strict(), request.body);
|
|
556
|
+
data(response, store.updateWork(request.params.workId, input, expectedVersionNo, "manual", null, changeNote));
|
|
557
|
+
});
|
|
554
558
|
app.delete("/api/works/:workId", async (request, response) => {
|
|
555
|
-
const
|
|
559
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
560
|
+
const removableStorageKeys = store.deleteWork(request.params.workId, input.expectedVersionNo);
|
|
556
561
|
await Promise.all(removableStorageKeys.map((storageKey) => attachmentStorage.remove(storageKey)));
|
|
557
562
|
noContent(response);
|
|
558
563
|
});
|
|
@@ -574,10 +579,12 @@ export function createRuntime(options) {
|
|
|
574
579
|
const mimeType = isPng ? "image/png" : isJpeg ? "image/jpeg" : isWebp ? "image/webp" : null;
|
|
575
580
|
if (!mimeType)
|
|
576
581
|
throw new AppError(415, "INVALID_COVER", "封面文件内容不是有效的 PNG、JPEG 或 WebP 图片");
|
|
577
|
-
|
|
582
|
+
const expectedVersionNo = parse(expectedVersionNoSchema, request.body.expectedVersionNo);
|
|
583
|
+
data(response, store.setWorkCover(String(request.params.workId), mimeType, bytes, expectedVersionNo));
|
|
578
584
|
});
|
|
579
585
|
app.delete("/api/works/:workId/cover", (request, response) => {
|
|
580
|
-
|
|
586
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
587
|
+
store.deleteWorkCover(request.params.workId, input.expectedVersionNo);
|
|
581
588
|
noContent(response);
|
|
582
589
|
});
|
|
583
590
|
app.get("/api/works/:workId/file-versions", (request, response) => {
|
|
@@ -585,7 +592,8 @@ export function createRuntime(options) {
|
|
|
585
592
|
data(response, pagination ? store.listFileVersionsPage(request.params.workId, pagination) : store.listFileVersions(request.params.workId));
|
|
586
593
|
});
|
|
587
594
|
app.post("/api/works/:workId/file-versions/:fileVersionId/restore", (request, response) => {
|
|
588
|
-
|
|
595
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
596
|
+
data(response, store.restoreFileVersion(request.params.workId, request.params.fileVersionId, input.expectedVersionNo));
|
|
589
597
|
});
|
|
590
598
|
app.post("/api/works/:workId/import", upload.single("file"), async (request, response) => {
|
|
591
599
|
if (!request.file)
|
|
@@ -599,19 +607,23 @@ export function createRuntime(options) {
|
|
|
599
607
|
? await extractDocxText(request.file.buffer)
|
|
600
608
|
: decodeUtf8ImportedText(request.file.buffer));
|
|
601
609
|
const parsed = applyImportFileHints(parseNovelText(text), originalFileName);
|
|
602
|
-
|
|
610
|
+
const mode = parse(z.enum(["append", "overwrite"]), request.body.mode ?? "overwrite");
|
|
611
|
+
const expectedVersionNo = parse(expectedVersionNoSchema, request.body.expectedVersionNo);
|
|
612
|
+
data(response, store.importNovel(String(request.params.workId), originalFileName, extension.slice(1), parsed, mode, expectedVersionNo), 201);
|
|
603
613
|
});
|
|
604
614
|
app.post("/api/works/:workId/volumes", (request, response) => {
|
|
605
615
|
const input = parse(z.object({ title: nonEmpty.max(200), kind: z.enum(["main", "prequel", "extra", "epilogue", "appendix"]).optional(), description: z.string().max(5_000).optional(), keywords: z.array(nonEmpty.max(100)).max(100).optional() }), request.body);
|
|
606
616
|
data(response, store.createVolume(request.params.workId, input), 201);
|
|
607
617
|
});
|
|
608
618
|
app.patch("/api/volumes/:volumeId", (request, response) => {
|
|
609
|
-
const input = parse(z.object({ title: nonEmpty.max(200).optional(), kind: z.enum(["main", "prequel", "extra", "epilogue", "appendix"]).optional(), description: z.string().max(5_000).optional(), keywords: z.array(nonEmpty.max(100)).max(100).optional(), sortOrder: z.number().int().min(0).optional() }), request.body);
|
|
610
|
-
|
|
619
|
+
const input = parse(z.object({ title: nonEmpty.max(200).optional(), kind: z.enum(["main", "prequel", "extra", "epilogue", "appendix"]).optional(), description: z.string().max(5_000).optional(), keywords: z.array(nonEmpty.max(100)).max(100).optional(), sortOrder: z.number().int().min(0).optional(), expectedVersionNo: expectedVersionNoSchema, changeNote: changeNoteSchema }).strict(), request.body);
|
|
620
|
+
const { expectedVersionNo, changeNote, ...volumeInput } = input;
|
|
621
|
+
data(response, store.updateVolume(request.params.volumeId, volumeInput, expectedVersionNo, "manual", null, changeNote));
|
|
611
622
|
});
|
|
612
623
|
app.get("/api/volumes/:volumeId", (request, response) => data(response, store.getVolume(request.params.volumeId)));
|
|
613
624
|
app.delete("/api/volumes/:volumeId", (request, response) => {
|
|
614
|
-
|
|
625
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
626
|
+
store.deleteVolume(request.params.volumeId, input.expectedVersionNo);
|
|
615
627
|
noContent(response);
|
|
616
628
|
});
|
|
617
629
|
app.post("/api/works/:workId/chapters", (request, response) => {
|
|
@@ -620,12 +632,13 @@ export function createRuntime(options) {
|
|
|
620
632
|
});
|
|
621
633
|
app.get("/api/chapters/:chapterId", (request, response) => data(response, store.getChapter(request.params.chapterId)));
|
|
622
634
|
app.patch("/api/chapters/:chapterId", (request, response) => {
|
|
623
|
-
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 }).strict(), request.body);
|
|
624
|
-
const { source, changeNote, ...chapterInput } = input;
|
|
625
|
-
data(response, store.saveChapter(request.params.chapterId, chapterInput, source ?? "manual", null, changeNote));
|
|
635
|
+
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);
|
|
636
|
+
const { source, changeNote, expectedVersionNo, ...chapterInput } = input;
|
|
637
|
+
data(response, store.saveChapter(request.params.chapterId, chapterInput, source ?? "manual", null, changeNote, expectedVersionNo));
|
|
626
638
|
});
|
|
627
639
|
app.delete("/api/chapters/:chapterId", (request, response) => {
|
|
628
|
-
|
|
640
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
641
|
+
store.deleteChapter(request.params.chapterId, input.expectedVersionNo);
|
|
629
642
|
noContent(response);
|
|
630
643
|
});
|
|
631
644
|
app.get("/api/chapters/:chapterId/versions", (request, response) => {
|
|
@@ -637,12 +650,13 @@ export function createRuntime(options) {
|
|
|
637
650
|
data(response, pagination ? store.listChapterInsightsPage(request.params.chapterId, pagination) : store.listChapterInsights(request.params.chapterId));
|
|
638
651
|
});
|
|
639
652
|
app.post("/api/chapters/:chapterId/restore", (request, response) => {
|
|
640
|
-
const input = parse(z.object({ versionNo: z.number().int().positive() }), request.body);
|
|
641
|
-
data(response, store.restoreChapter(request.params.chapterId, input.versionNo));
|
|
653
|
+
const input = parse(z.object({ versionNo: z.number().int().positive(), expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
654
|
+
data(response, store.restoreChapter(request.params.chapterId, input.versionNo, input.expectedVersionNo));
|
|
642
655
|
});
|
|
643
656
|
app.post("/api/chapters/:chapterId/move", (request, response) => {
|
|
644
|
-
const input = parse(z.object({ volumeId: identifier, sortOrder: z.number().int().min(0) }), request.body);
|
|
645
|
-
|
|
657
|
+
const input = parse(z.object({ volumeId: identifier, sortOrder: z.number().int().min(0), expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
658
|
+
const { expectedVersionNo, ...moveInput } = input;
|
|
659
|
+
data(response, store.moveChapter(request.params.chapterId, moveInput, expectedVersionNo));
|
|
646
660
|
});
|
|
647
661
|
app.get("/api/works/:workId/outlines", (request, response) => {
|
|
648
662
|
const pagination = parsePagination(request.query);
|
|
@@ -650,11 +664,12 @@ export function createRuntime(options) {
|
|
|
650
664
|
});
|
|
651
665
|
app.get("/api/chapters/:chapterId/outline", (request, response) => data(response, store.getChapterOutline(request.params.chapterId)));
|
|
652
666
|
app.put("/api/chapters/:chapterId/outline", (request, response) => {
|
|
653
|
-
const { changeNote, ...input } = parse(chapterOutlineSchema.extend({ changeNote: changeNoteSchema }), request.body);
|
|
654
|
-
data(response, store.upsertChapterOutline(request.params.chapterId, input, "manual", null, changeNote));
|
|
667
|
+
const { changeNote, expectedVersionNo, ...input } = parse(chapterOutlineSchema.extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
668
|
+
data(response, store.upsertChapterOutline(request.params.chapterId, input, "manual", null, changeNote, expectedVersionNo));
|
|
655
669
|
});
|
|
656
670
|
app.delete("/api/chapters/:chapterId/outline", (request, response) => {
|
|
657
|
-
|
|
671
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
672
|
+
store.deleteChapterOutline(request.params.chapterId, input.expectedVersionNo);
|
|
658
673
|
noContent(response);
|
|
659
674
|
});
|
|
660
675
|
app.get("/api/works/:workId/foreshadows", (request, response) => {
|
|
@@ -672,21 +687,27 @@ export function createRuntime(options) {
|
|
|
672
687
|
});
|
|
673
688
|
app.get("/api/foreshadows/:foreshadowId", (request, response) => data(response, store.getForeshadow(request.params.foreshadowId)));
|
|
674
689
|
app.patch("/api/foreshadows/:foreshadowId", (request, response) => {
|
|
675
|
-
const { changeNote, ...input } = parse(foreshadowSchema.partial().extend({ changeNote: changeNoteSchema }), request.body);
|
|
676
|
-
data(response, store.updateForeshadow(request.params.foreshadowId, input, "manual", null, changeNote));
|
|
690
|
+
const { changeNote, expectedVersionNo, ...input } = parse(foreshadowSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
691
|
+
data(response, store.updateForeshadow(request.params.foreshadowId, input, "manual", null, changeNote, expectedVersionNo));
|
|
677
692
|
});
|
|
678
693
|
app.delete("/api/foreshadows/:foreshadowId", (request, response) => {
|
|
679
|
-
|
|
694
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
695
|
+
store.deleteForeshadow(request.params.foreshadowId, input.expectedVersionNo);
|
|
680
696
|
noContent(response);
|
|
681
697
|
});
|
|
682
698
|
app.post("/api/foreshadows/:foreshadowId/occurrences", (request, response) => {
|
|
683
|
-
|
|
699
|
+
const input = parse(foreshadowOccurrenceSchema.extend({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
700
|
+
const { expectedVersionNo, ...occurrenceInput } = input;
|
|
701
|
+
data(response, store.createForeshadowOccurrence(request.params.foreshadowId, occurrenceInput, expectedVersionNo), 201);
|
|
684
702
|
});
|
|
685
703
|
app.patch("/api/foreshadow-occurrences/:occurrenceId", (request, response) => {
|
|
686
|
-
|
|
704
|
+
const input = parse(foreshadowOccurrenceSchema.partial().extend({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
705
|
+
const { expectedVersionNo, ...occurrenceInput } = input;
|
|
706
|
+
data(response, store.updateForeshadowOccurrence(request.params.occurrenceId, occurrenceInput, expectedVersionNo));
|
|
687
707
|
});
|
|
688
708
|
app.delete("/api/foreshadow-occurrences/:occurrenceId", (request, response) => {
|
|
689
|
-
|
|
709
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
710
|
+
store.deleteForeshadowOccurrence(request.params.occurrenceId, input.expectedVersionNo);
|
|
690
711
|
noContent(response);
|
|
691
712
|
});
|
|
692
713
|
app.get("/api/works/:workId/settings", (request, response) => {
|
|
@@ -696,11 +717,12 @@ export function createRuntime(options) {
|
|
|
696
717
|
app.post("/api/works/:workId/settings", (request, response) => data(response, store.createSetting(request.params.workId, parse(settingSchema, request.body)), 201));
|
|
697
718
|
app.get("/api/settings/:settingId", (request, response) => data(response, store.getSetting(request.params.settingId)));
|
|
698
719
|
app.patch("/api/settings/:settingId", (request, response) => {
|
|
699
|
-
const { changeNote, ...input } = parse(settingSchema.partial().extend({ changeNote: changeNoteSchema }), request.body);
|
|
700
|
-
data(response, store.updateSetting(request.params.settingId, input, "manual", null, changeNote));
|
|
720
|
+
const { changeNote, expectedVersionNo, ...input } = parse(settingSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
721
|
+
data(response, store.updateSetting(request.params.settingId, input, "manual", null, changeNote, expectedVersionNo));
|
|
701
722
|
});
|
|
702
723
|
app.delete("/api/settings/:settingId", (request, response) => {
|
|
703
|
-
|
|
724
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
725
|
+
store.deleteSetting(request.params.settingId, input.expectedVersionNo);
|
|
704
726
|
noContent(response);
|
|
705
727
|
});
|
|
706
728
|
app.get("/api/works/:workId/characters", (request, response) => {
|
|
@@ -716,21 +738,34 @@ export function createRuntime(options) {
|
|
|
716
738
|
app.post("/api/works/:workId/characters", (request, response) => data(response, store.createCharacter(request.params.workId, parse(characterSchema, request.body)), 201));
|
|
717
739
|
app.get("/api/characters/:characterId", (request, response) => data(response, store.getCharacter(request.params.characterId)));
|
|
718
740
|
app.patch("/api/characters/:characterId", (request, response) => {
|
|
719
|
-
const { changeNote, ...input } = parse(characterUpdateSchema, request.body);
|
|
720
|
-
data(response, store.updateCharacter(request.params.characterId, input, "manual", null, changeNote));
|
|
741
|
+
const { changeNote, expectedVersionNo, ...input } = parse(characterUpdateSchema.extend({ expectedVersionNo: expectedVersionNoSchema }), request.body);
|
|
742
|
+
data(response, store.updateCharacter(request.params.characterId, input, "manual", null, changeNote, expectedVersionNo));
|
|
721
743
|
});
|
|
722
744
|
app.get("/api/characters/:characterId/versions", (request, response) => {
|
|
723
745
|
const pagination = parsePagination(request.query);
|
|
724
746
|
data(response, pagination ? store.listCharacterVersionsPage(request.params.characterId, pagination) : store.listCharacterVersions(request.params.characterId));
|
|
725
747
|
});
|
|
726
748
|
app.post("/api/characters/:characterId/restore", (request, response) => {
|
|
727
|
-
const input = parse(z.object({ versionNo: z.number().int().positive() }), request.body);
|
|
728
|
-
data(response, store.restoreCharacter(request.params.characterId, input.versionNo));
|
|
749
|
+
const input = parse(z.object({ versionNo: z.number().int().positive(), expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
750
|
+
data(response, store.restoreCharacter(request.params.characterId, input.versionNo, input.expectedVersionNo));
|
|
729
751
|
});
|
|
730
752
|
app.delete("/api/characters/:characterId", (request, response) => {
|
|
731
|
-
|
|
753
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
754
|
+
store.deleteCharacter(request.params.characterId, input.expectedVersionNo);
|
|
732
755
|
noContent(response);
|
|
733
756
|
});
|
|
757
|
+
app.post("/api/characters/:characterId/merge", (request, response) => {
|
|
758
|
+
const input = parse(z.object({
|
|
759
|
+
targetCharacterId: identifier,
|
|
760
|
+
expectedTargetVersionNo: z.number().int().positive(),
|
|
761
|
+
expectedSourceVersionNo: z.number().int().positive()
|
|
762
|
+
}).strict(), request.body);
|
|
763
|
+
data(response, store.mergeCharacters({
|
|
764
|
+
reviewId: null,
|
|
765
|
+
sourceCharacterId: request.params.characterId,
|
|
766
|
+
...input
|
|
767
|
+
}));
|
|
768
|
+
});
|
|
734
769
|
app.get("/api/characters/:characterId/sections", (request, response) => {
|
|
735
770
|
const pagination = parsePagination(request.query);
|
|
736
771
|
data(response, pagination
|
|
@@ -744,11 +779,12 @@ export function createRuntime(options) {
|
|
|
744
779
|
data(response, store.getCharacterProfileSection(request.params.sectionId));
|
|
745
780
|
});
|
|
746
781
|
app.patch("/api/character-sections/:sectionId", (request, response) => {
|
|
747
|
-
const { changeNote, ...input } = parse(characterProfileSectionSchema.partial().extend({ changeNote: changeNoteSchema }).strict(), request.body);
|
|
748
|
-
data(response, store.updateCharacterProfileSection(request.params.sectionId, input, "manual", null, changeNote));
|
|
782
|
+
const { changeNote, expectedVersionNo, ...input } = parse(characterProfileSectionSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
783
|
+
data(response, store.updateCharacterProfileSection(request.params.sectionId, input, "manual", null, changeNote, expectedVersionNo));
|
|
749
784
|
});
|
|
750
785
|
app.delete("/api/character-sections/:sectionId", (request, response) => {
|
|
751
|
-
|
|
786
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
787
|
+
store.deleteCharacterProfileSection(request.params.sectionId, input.expectedVersionNo);
|
|
752
788
|
noContent(response);
|
|
753
789
|
});
|
|
754
790
|
app.get("/api/character-sections/:sectionId/versions", (request, response) => {
|
|
@@ -758,8 +794,8 @@ export function createRuntime(options) {
|
|
|
758
794
|
: store.listCharacterProfileSectionVersions(request.params.sectionId));
|
|
759
795
|
});
|
|
760
796
|
app.post("/api/character-sections/:sectionId/restore", (request, response) => {
|
|
761
|
-
const input = parse(z.object({ versionNo: z.number().int().positive() }).strict(), request.body);
|
|
762
|
-
data(response, store.restoreCharacterProfileSection(request.params.sectionId, input.versionNo));
|
|
797
|
+
const input = parse(z.object({ versionNo: z.number().int().positive(), expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
798
|
+
data(response, store.restoreCharacterProfileSection(request.params.sectionId, input.versionNo, input.expectedVersionNo));
|
|
763
799
|
});
|
|
764
800
|
app.get("/api/works/:workId/attachments", (request, response) => {
|
|
765
801
|
const pagination = parsePagination(request.query);
|
|
@@ -815,13 +851,18 @@ export function createRuntime(options) {
|
|
|
815
851
|
});
|
|
816
852
|
app.get("/api/races/:raceId", (request, response) => data(response, store.getRace(request.params.raceId)));
|
|
817
853
|
app.patch("/api/races/:raceId", (request, response) => {
|
|
818
|
-
const { changeNote, ...input } = parse(raceSchema.partial().extend({ changeNote: changeNoteSchema }), request.body);
|
|
819
|
-
data(response, store.updateRace(request.params.raceId, input, "manual", null, changeNote));
|
|
854
|
+
const { changeNote, expectedVersionNo, ...input } = parse(raceSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
855
|
+
data(response, store.updateRace(request.params.raceId, input, "manual", null, changeNote, expectedVersionNo));
|
|
820
856
|
});
|
|
821
857
|
app.delete("/api/races/:raceId", (request, response) => {
|
|
822
|
-
|
|
858
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
859
|
+
store.deleteRace(request.params.raceId, input.expectedVersionNo);
|
|
823
860
|
noContent(response);
|
|
824
861
|
});
|
|
862
|
+
app.post("/api/races/:raceId/merge", (request, response) => {
|
|
863
|
+
const input = parse(z.object({ targetRaceId: identifier }).strict(), request.body);
|
|
864
|
+
data(response, store.mergeRaces(request.params.raceId, input.targetRaceId));
|
|
865
|
+
});
|
|
825
866
|
app.get("/api/works/:workId/organizations", (request, response) => {
|
|
826
867
|
const pagination = parsePagination(request.query);
|
|
827
868
|
data(response, pagination ? store.listOrganizationsPage(request.params.workId, pagination) : store.listOrganizations(request.params.workId));
|
|
@@ -831,13 +872,18 @@ export function createRuntime(options) {
|
|
|
831
872
|
});
|
|
832
873
|
app.get("/api/organizations/:organizationId", (request, response) => data(response, store.getOrganization(request.params.organizationId)));
|
|
833
874
|
app.patch("/api/organizations/:organizationId", (request, response) => {
|
|
834
|
-
const { changeNote, ...input } = parse(organizationSchema.partial().extend({ changeNote: changeNoteSchema }), request.body);
|
|
835
|
-
data(response, store.updateOrganization(request.params.organizationId, input, "manual", null, changeNote));
|
|
875
|
+
const { changeNote, expectedVersionNo, ...input } = parse(organizationSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
876
|
+
data(response, store.updateOrganization(request.params.organizationId, input, "manual", null, changeNote, expectedVersionNo));
|
|
836
877
|
});
|
|
837
878
|
app.delete("/api/organizations/:organizationId", (request, response) => {
|
|
838
|
-
|
|
879
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
880
|
+
store.deleteOrganization(request.params.organizationId, input.expectedVersionNo);
|
|
839
881
|
noContent(response);
|
|
840
882
|
});
|
|
883
|
+
app.post("/api/organizations/:organizationId/merge", (request, response) => {
|
|
884
|
+
const input = parse(z.object({ targetOrganizationId: identifier }).strict(), request.body);
|
|
885
|
+
data(response, store.mergeOrganizations(request.params.organizationId, input.targetOrganizationId));
|
|
886
|
+
});
|
|
841
887
|
app.get("/api/works/:workId/timeline-tracks", (request, response) => {
|
|
842
888
|
const pagination = parsePagination(request.query);
|
|
843
889
|
data(response, pagination ? store.listTimelineTracksPage(request.params.workId, pagination) : store.listTimelineTracks(request.params.workId));
|
|
@@ -845,11 +891,12 @@ export function createRuntime(options) {
|
|
|
845
891
|
app.post("/api/works/:workId/timeline-tracks", (request, response) => data(response, store.createTimelineTrack(request.params.workId, parse(timelineTrackSchema, request.body)), 201));
|
|
846
892
|
app.get("/api/timeline-tracks/:trackId", (request, response) => data(response, store.getTimelineTrack(request.params.trackId)));
|
|
847
893
|
app.patch("/api/timeline-tracks/:trackId", (request, response) => {
|
|
848
|
-
const { changeNote, ...input } = parse(timelineTrackSchema.partial().extend({ changeNote: changeNoteSchema }), request.body);
|
|
849
|
-
data(response, store.updateTimelineTrack(request.params.trackId, input, "manual", null, changeNote));
|
|
894
|
+
const { changeNote, expectedVersionNo, ...input } = parse(timelineTrackSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
895
|
+
data(response, store.updateTimelineTrack(request.params.trackId, input, "manual", null, changeNote, expectedVersionNo));
|
|
850
896
|
});
|
|
851
897
|
app.delete("/api/timeline-tracks/:trackId", (request, response) => {
|
|
852
|
-
|
|
898
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
899
|
+
store.deleteTimelineTrack(request.params.trackId, input.expectedVersionNo);
|
|
853
900
|
noContent(response);
|
|
854
901
|
});
|
|
855
902
|
app.get("/api/works/:workId/timeline", (request, response) => {
|
|
@@ -863,14 +910,16 @@ export function createRuntime(options) {
|
|
|
863
910
|
name: nonEmpty.max(300),
|
|
864
911
|
description: z.string().max(100_000).optional(),
|
|
865
912
|
timeLabel: z.string().max(300).optional(),
|
|
866
|
-
timeSort: z.number().finite().nullable().optional()
|
|
867
|
-
|
|
868
|
-
|
|
913
|
+
timeSort: z.number().finite().nullable().optional(),
|
|
914
|
+
expectedVersionNos: z.record(identifier, z.number().int().positive()).optional()
|
|
915
|
+
}).strict(), request.body);
|
|
916
|
+
const { expectedVersionNos, ...mergeInput } = input;
|
|
917
|
+
data(response, store.mergeTimelineEvents(request.params.workId, input.eventIds, mergeInput, expectedVersionNos), 201);
|
|
869
918
|
});
|
|
870
919
|
app.get("/api/timeline/:eventId", (request, response) => data(response, store.getTimelineEvent(request.params.eventId)));
|
|
871
920
|
app.patch("/api/timeline/:eventId", (request, response) => {
|
|
872
|
-
const { changeNote, ...input } = parse(timelineSchema.partial().extend({ changeNote: changeNoteSchema }), request.body);
|
|
873
|
-
data(response, store.updateTimelineEvent(request.params.eventId, input, "manual", null, changeNote));
|
|
921
|
+
const { changeNote, expectedVersionNo, ...input } = parse(timelineSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
922
|
+
data(response, store.updateTimelineEvent(request.params.eventId, input, "manual", null, changeNote, expectedVersionNo));
|
|
874
923
|
});
|
|
875
924
|
app.post("/api/timeline/:eventId/split", (request, response) => {
|
|
876
925
|
const input = parse(z.object({
|
|
@@ -879,12 +928,14 @@ export function createRuntime(options) {
|
|
|
879
928
|
description: z.string().max(100_000).optional(),
|
|
880
929
|
timeLabel: z.string().max(300).optional(),
|
|
881
930
|
timeSort: z.number().finite().nullable().optional()
|
|
882
|
-
})).min(2)
|
|
883
|
-
|
|
884
|
-
|
|
931
|
+
})).min(2),
|
|
932
|
+
expectedVersionNo: expectedVersionNoSchema
|
|
933
|
+
}).strict(), request.body);
|
|
934
|
+
data(response, store.splitTimelineEvent(request.params.eventId, input.parts, input.expectedVersionNo), 201);
|
|
885
935
|
});
|
|
886
936
|
app.delete("/api/timeline/:eventId", (request, response) => {
|
|
887
|
-
|
|
937
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
938
|
+
store.deleteTimelineEvent(request.params.eventId, input.expectedVersionNo);
|
|
888
939
|
noContent(response);
|
|
889
940
|
});
|
|
890
941
|
app.get("/api/works/:workId/relationships", (request, response) => {
|
|
@@ -899,11 +950,12 @@ export function createRuntime(options) {
|
|
|
899
950
|
app.post("/api/works/:workId/relationships", (request, response) => data(response, store.createRelationship(request.params.workId, parse(relationshipSchema, request.body)), 201));
|
|
900
951
|
app.get("/api/relationships/:relationshipId", (request, response) => data(response, store.getRelationship(request.params.relationshipId)));
|
|
901
952
|
app.patch("/api/relationships/:relationshipId", (request, response) => {
|
|
902
|
-
const { changeNote, ...input } = parse(relationshipSchema.partial().extend({ changeNote: changeNoteSchema }), request.body);
|
|
903
|
-
data(response, store.updateRelationship(request.params.relationshipId, input, "manual", null, changeNote));
|
|
953
|
+
const { changeNote, expectedVersionNo, ...input } = parse(relationshipSchema.partial().extend({ changeNote: changeNoteSchema, expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
954
|
+
data(response, store.updateRelationship(request.params.relationshipId, input, "manual", null, changeNote, expectedVersionNo));
|
|
904
955
|
});
|
|
905
956
|
app.delete("/api/relationships/:relationshipId", (request, response) => {
|
|
906
|
-
|
|
957
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
958
|
+
store.deleteRelationship(request.params.relationshipId, input.expectedVersionNo);
|
|
907
959
|
noContent(response);
|
|
908
960
|
});
|
|
909
961
|
app.get("/api/entity-versions/:entityType/:entityId", (request, response) => {
|
|
@@ -915,8 +967,8 @@ export function createRuntime(options) {
|
|
|
915
967
|
});
|
|
916
968
|
app.post("/api/entity-versions/:entityType/:entityId/restore", (request, response) => {
|
|
917
969
|
const params = parse(z.object({ entityType: versionedEntityTypeSchema, entityId: identifier }), request.params);
|
|
918
|
-
const input = parse(z.object({ versionNo: z.number().int().positive() }), request.body);
|
|
919
|
-
data(response, store.restoreEntityVersion(params.entityType, params.entityId, input.versionNo));
|
|
970
|
+
const input = parse(z.object({ versionNo: z.number().int().positive(), expectedVersionNo: expectedVersionNoSchema }).strict(), request.body);
|
|
971
|
+
data(response, store.restoreEntityVersion(params.entityType, params.entityId, input.versionNo, input.expectedVersionNo));
|
|
920
972
|
});
|
|
921
973
|
app.get("/api/works/:workId/reviews", (request, response) => {
|
|
922
974
|
const status = typeof request.query.status === "string" ? request.query.status : undefined;
|