fix(share): harden story share and relocate import button

- Add Content-Length pre-check to story-pack and story-unpack routes
  to reject oversized payloads before buffering the body
- Suppress internal error details in story-unpack catch (was leaking
  e.message to the client)
- Strengthen sceneIndex validation: require non-negative integer
- Guard against undefined storyState when replaying shared stories
- Fix prefetch regression: remove currentBeat?.id from useEffect deps
  that was re-triggering all change-scene prefetches on every beat
- Fix double detach: use else-if so the second replay detach guard
  doesn't fire redundantly after the first already detached
- Align client file-size limit by format (.json 12MB, .infiplot 13MB)
- Move "载入剧情" import button next to "开始" with hover tooltip

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
yuanzonghao
2026-06-08 08:46:05 +08:00
parent 0abd5f1525
commit 39a7269494
5 changed files with 40 additions and 19 deletions
+6 -4
View File
@@ -1173,6 +1173,9 @@ function PlayInner() {
const blobUrl = await getOrCreateBlobUrl(first.scene.imageUrl);
lastImageOriginalUrlRef.current = first.scene.imageUrl;
const initialStoryState = first.storyStateAfter ?? imported.storyState;
if (!initialStoryState) throw new Error("剧情分享文件缺少初始剧情记忆,无法载入。");
const initial: Session = {
...imported,
history: [
@@ -1182,7 +1185,7 @@ function PlayInner() {
exit: undefined,
},
],
storyState: first.storyStateAfter ?? imported.storyState,
storyState: initialStoryState,
orientation: sessionOrientation,
};
replaySourceRef.current = imported;
@@ -1375,7 +1378,7 @@ function PlayInner() {
!!byoTtsRef.current,
);
}
}, [currentScene?.id, currentBeat?.id, session?.id]);
}, [currentScene?.id, session?.id]);
// Abort all in-flight speculative prefetches when the page unmounts, so we
// stop paying for background scene/image generation. Empty deps → fires only
@@ -1635,8 +1638,7 @@ function PlayInner() {
if (recordedNext && recordedNext !== choice.effect.targetBeatId) {
detachRecordedReplay();
}
}
if (
} else if (
replaySourceRef.current &&
!isRecordedReplayLockedAt(currentBeatRef.current)
) {