refactor: 收口视觉小说详情 session 映射
This commit is contained in:
@@ -1405,9 +1405,9 @@
|
|||||||
|
|
||||||
## 2026-06-04 Platform Mini Game Session Mapping Model 收口
|
## 2026-06-04 Platform Mini Game Session Mapping Model 收口
|
||||||
|
|
||||||
- 背景:`PlatformEntryFlowShellImpl.tsx` 顶部仍保留拼图 runtime 恢复、方洞 session draft 转 profile、跳一跳 pending session、敲木鱼 detail 恢复和敲木鱼 pending session 等纯 DTO 映射,壳层需要理解 sessionId 优先级、拼图稳定 ID、方洞草稿 profile 默认值和 pending draft 默认值。
|
- 背景:`PlatformEntryFlowShellImpl.tsx` 顶部仍保留拼图 runtime 恢复、方洞 session draft 转 profile、视觉小说 work detail 转 Agent session、跳一跳 pending session、敲木鱼 detail 恢复和敲木鱼 pending session 等纯 DTO 映射,壳层需要理解 sessionId 优先级、拼图稳定 ID、方洞草稿 profile 默认值、视觉小说 work/session fallback 和 pending draft 默认值。
|
||||||
- 决策:新增 `src/components/platform-entry/platformMiniGameSessionMappingModel.ts`,收口 `buildPuzzleRuntimeWorkFromSession`、`buildSquareHoleProfileFromSession`、`buildJumpHopPendingSession`、`buildWoodenFishSessionFromWorkDetail` 与 `buildWoodenFishPendingSession`。Module 复用 `normalizeCreationUrlValue` 与 `platformPuzzleIdentityModel`;壳层只保留网络读取、React state、URL 写入和 stage 切换副作用。
|
- 决策:新增 `src/components/platform-entry/platformMiniGameSessionMappingModel.ts`,收口 `buildPuzzleRuntimeWorkFromSession`、`buildSquareHoleProfileFromSession`、`buildVisualNovelSessionFromWorkDetail`、`buildJumpHopPendingSession`、`buildWoodenFishSessionFromWorkDetail` 与 `buildWoodenFishPendingSession`。Module 复用 `normalizeCreationUrlValue` 与 `platformPuzzleIdentityModel`;壳层只保留网络读取、React state、URL 写入和 stage 切换副作用。
|
||||||
- 影响范围:拼图 runtime URL 恢复、方洞挑战草稿 profile 构造、跳一跳生成中作品架打开、敲木鱼生成中作品架打开和敲木鱼草稿 detail 恢复。
|
- 影响范围:拼图 runtime URL 恢复、方洞挑战草稿 profile 构造、视觉小说草稿作品架恢复、跳一跳生成中作品架打开、敲木鱼生成中作品架打开和敲木鱼草稿 detail 恢复。
|
||||||
- 验证方式:`npm run test -- src/components/platform-entry/platformMiniGameSessionMappingModel.test.ts`、针对新 Module 和 `PlatformEntryFlowShellImpl.tsx` 执行 ESLint、`npm run typecheck`、`npm run check:encoding`。
|
- 验证方式:`npm run test -- src/components/platform-entry/platformMiniGameSessionMappingModel.test.ts`、针对新 Module 和 `PlatformEntryFlowShellImpl.tsx` 执行 ESLint、`npm run typecheck`、`npm run check:encoding`。
|
||||||
- 关联文档:`docs/technical/【前端架构】PlatformMiniGameSessionMappingModel收口计划-2026-06-04.md`、`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`。
|
- 关联文档:`docs/technical/【前端架构】PlatformMiniGameSessionMappingModel收口计划-2026-06-04.md`、`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`。
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ AI 文字游戏模板接入以 [AI_NATIVE_TEXT_GAME_TEMPLATE_MOKU_REFERENCE_PRD_
|
|||||||
|
|
||||||
平台入口生成页进度 tick 的 stage 到生成状态映射、终态判定和视觉小说轻量生成特例收口到 `src/components/platform-entry/platformGenerationProgressTickModel.ts`,壳层只保留 `Date.now()`、`setInterval` 和 cleanup 副作用,规则见 [【前端架构】PlatformGenerationProgressTickModel收口计划-2026-06-04.md](./technical/【前端架构】PlatformGenerationProgressTickModel收口计划-2026-06-04.md)。
|
平台入口生成页进度 tick 的 stage 到生成状态映射、终态判定和视觉小说轻量生成特例收口到 `src/components/platform-entry/platformGenerationProgressTickModel.ts`,壳层只保留 `Date.now()`、`setInterval` 和 cleanup 副作用,规则见 [【前端架构】PlatformGenerationProgressTickModel收口计划-2026-06-04.md](./technical/【前端架构】PlatformGenerationProgressTickModel收口计划-2026-06-04.md)。
|
||||||
|
|
||||||
平台壳的拼图 runtime 恢复 work、方洞 session draft 转 profile、跳一跳 pending session、敲木鱼 detail 恢复 session 和敲木鱼 pending session DTO 映射收口到 `src/components/platform-entry/platformMiniGameSessionMappingModel.ts`,壳层只保留网络、状态、URL 与 stage 副作用,规则见 [【前端架构】PlatformMiniGameSessionMappingModel收口计划-2026-06-04.md](./technical/【前端架构】PlatformMiniGameSessionMappingModel收口计划-2026-06-04.md)。
|
平台壳的拼图 runtime 恢复 work、方洞 session draft 转 profile、视觉小说 work detail 转 Agent session、跳一跳 pending session、敲木鱼 detail 恢复 session 和敲木鱼 pending session DTO 映射收口到 `src/components/platform-entry/platformMiniGameSessionMappingModel.ts`,壳层只保留网络、状态、URL 与 stage 副作用,规则见 [【前端架构】PlatformMiniGameSessionMappingModel收口计划-2026-06-04.md](./technical/【前端架构】PlatformMiniGameSessionMappingModel收口计划-2026-06-04.md)。
|
||||||
|
|
||||||
平台小游戏生成状态的恢复、失败 / 完成收尾、展示 rebase、拼图后端进度合并、抓大鹅生成资产旁路进度合并和 ready / generating 判定收口到 `src/components/platform-entry/platformMiniGameDraftGenerationStateModel.ts`,壳层只保留 API、后台任务、React state、URL 与 stage 副作用,规则见 [【前端架构】PlatformMiniGameDraftGenerationStateModel收口计划-2026-06-04.md](./technical/【前端架构】PlatformMiniGameDraftGenerationStateModel收口计划-2026-06-04.md)。
|
平台小游戏生成状态的恢复、失败 / 完成收尾、展示 rebase、拼图后端进度合并、抓大鹅生成资产旁路进度合并和 ready / generating 判定收口到 `src/components/platform-entry/platformMiniGameDraftGenerationStateModel.ts`,壳层只保留 API、后台任务、React state、URL 与 stage 副作用,规则见 [【前端架构】PlatformMiniGameDraftGenerationStateModel收口计划-2026-06-04.md](./technical/【前端架构】PlatformMiniGameDraftGenerationStateModel收口计划-2026-06-04.md)。
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## 背景
|
## 背景
|
||||||
|
|
||||||
`PlatformEntryFlowShellImpl.tsx` 顶部曾保留拼图 runtime 恢复、方洞挑战 session draft 转 profile、跳一跳 pending session、敲木鱼 work detail 恢复和敲木鱼 pending session 多段纯 DTO 映射。它们没有 React state、网络请求、路由、弹窗或计时副作用,却住在大型平台壳内;新增或修正生成中草稿恢复时,需要在壳层里理解 sessionId 优先级、拼图稳定 ID、方洞 profile 默认值、pending draft 默认值和木鱼 fallback 规则。
|
`PlatformEntryFlowShellImpl.tsx` 顶部曾保留拼图 runtime 恢复、方洞挑战 session draft 转 profile、视觉小说 work detail 转 Agent session、跳一跳 pending session、敲木鱼 work detail 恢复和敲木鱼 pending session 多段纯 DTO 映射。它们没有 React state、网络请求、路由、弹窗或计时副作用,却住在大型平台壳内;新增或修正生成中草稿恢复时,需要在壳层里理解 sessionId 优先级、拼图稳定 ID、方洞 profile 默认值、视觉小说 work/session fallback、pending draft 默认值和木鱼 fallback 规则。
|
||||||
|
|
||||||
这些规则属于平台壳 session / work 恢复映射,应成为可测试的 **Module**。壳层只负责调用网络、写 React state、写 URL 和切换 stage。
|
这些规则属于平台壳 session / work 恢复映射,应成为可测试的 **Module**。壳层只负责调用网络、写 React state、写 URL 和切换 stage。
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
- `buildPuzzleRuntimeWorkFromSession(session, owner)`:从拼图 Agent session 构造可进入 runtime 的 draft `PuzzleWorkSummary`,缺草稿、缺 profile 或缺封面时返回 `null`。
|
- `buildPuzzleRuntimeWorkFromSession(session, owner)`:从拼图 Agent session 构造可进入 runtime 的 draft `PuzzleWorkSummary`,缺草稿、缺 profile 或缺封面时返回 `null`。
|
||||||
- `buildSquareHoleProfileFromSession(session)`:从方洞挑战 Agent session draft 构造草稿 `SquareHoleWorkProfile`,缺 session、缺 draft 或缺 profileId 时返回 `null`。
|
- `buildSquareHoleProfileFromSession(session)`:从方洞挑战 Agent session draft 构造草稿 `SquareHoleWorkProfile`,缺 session、缺 draft 或缺 profileId 时返回 `null`。
|
||||||
|
- `buildVisualNovelSessionFromWorkDetail(work)`:从视觉小说 work detail 恢复 `VisualNovelAgentSessionSnapshot`,供草稿作品架回到结果页继续编辑。
|
||||||
- `buildJumpHopPendingSession(item)`:从跳一跳作品架 summary 构造生成中 pending session。
|
- `buildJumpHopPendingSession(item)`:从跳一跳作品架 summary 构造生成中 pending session。
|
||||||
- `buildWoodenFishSessionFromWorkDetail(work, fallbackItem?)`:从敲木鱼 work detail 恢复 session,并按 summary / fallback / profileId 决定 sessionId。
|
- `buildWoodenFishSessionFromWorkDetail(work, fallbackItem?)`:从敲木鱼 work detail 恢复 session,并按 summary / fallback / profileId 决定 sessionId。
|
||||||
- `buildWoodenFishPendingSession(item)`:从敲木鱼作品架 summary 构造生成中 pending session。
|
- `buildWoodenFishPendingSession(item)`:从敲木鱼作品架 summary 构造生成中 pending session。
|
||||||
@@ -25,15 +26,16 @@
|
|||||||
- 拼图 owner 缺省为 `current-user` / `玩家`;`publishReady` 来自 `session.resultPreview?.publishReady`。
|
- 拼图 owner 缺省为 `current-user` / `玩家`;`publishReady` 来自 `session.resultPreview?.publishReady`。
|
||||||
- 方洞 profile 的 `workId` 与 `profileId` 都来自 draft `profileId`;owner 固定为 `current-user`,`sourceSessionId` 来自 sessionId。
|
- 方洞 profile 的 `workId` 与 `profileId` 都来自 draft `profileId`;owner 固定为 `current-user`,`sourceSessionId` 来自 sessionId。
|
||||||
- 方洞 profile 的 `updatedAt` 优先 session `updatedAt`,缺失时使用当前时间;`publicationStatus='draft'`、`playCount=0`、`publishedAt=null`,`publishReady` 来自 draft。
|
- 方洞 profile 的 `updatedAt` 优先 session `updatedAt`,缺失时使用当前时间;`publicationStatus='draft'`、`playCount=0`、`publishedAt=null`,`publishReady` 来自 draft。
|
||||||
|
- 视觉小说恢复 session 的 `sessionId` 优先归一化后的 `sourceSessionId`,为空时回退 `workId`;`status='ready'`,`messages=[]`,`pendingAction=null`,`sourceMode` 来自 draft,`updatedAt` 来自 summary。
|
||||||
- 跳一跳 pending sessionId 优先 `sourceSessionId`,缺失时用 `profileId`;素材、路径和 prompt 维持空值兜底。
|
- 跳一跳 pending sessionId 优先 `sourceSessionId`,缺失时用 `profileId`;素材、路径和 prompt 维持空值兜底。
|
||||||
- 敲木鱼 detail sessionId 优先级固定为 `work.summary.sourceSessionId > fallbackItem.sourceSessionId > profileId`。
|
- 敲木鱼 detail sessionId 优先级固定为 `work.summary.sourceSessionId > fallbackItem.sourceSessionId > profileId`。
|
||||||
- 敲木鱼 pending session 保持 `floatingWords=['功德 +1']`、素材 / 音效 / 背景为空的旧默认。
|
- 敲木鱼 pending session 保持 `floatingWords=['功德 +1']`、素材 / 音效 / 背景为空的旧默认。
|
||||||
|
|
||||||
## Depth / Leverage / Locality
|
## Depth / Leverage / Locality
|
||||||
|
|
||||||
- **Depth**:壳层以少量函数取得恢复用 DTO;ID 优先级、方洞 profile 默认值和 pending draft 字段藏入 Module Implementation。
|
- **Depth**:壳层以少量函数取得恢复用 DTO;ID 优先级、方洞 profile 默认值、视觉小说 session fallback 和 pending draft 字段藏入 Module Implementation。
|
||||||
- **Leverage**:后续新增生成中作品恢复或修改 sessionId 规则时,先改 Module 与单测,再保持壳层 Adapter 副作用不变。
|
- **Leverage**:后续新增生成中作品恢复或修改 sessionId 规则时,先改 Module 与单测,再保持壳层 Adapter 副作用不变。
|
||||||
- **Locality**:拼图、方洞、跳一跳和敲木鱼的恢复映射集中在一个纯测试面,避免在大型壳层顶部继续堆积 DTO 构造。
|
- **Locality**:拼图、方洞、视觉小说、跳一跳和敲木鱼的恢复映射集中在一个纯测试面,避免在大型壳层顶部继续堆积 DTO 构造。
|
||||||
|
|
||||||
## 验收
|
## 验收
|
||||||
|
|
||||||
|
|||||||
@@ -537,6 +537,7 @@ import {
|
|||||||
buildJumpHopPendingSession,
|
buildJumpHopPendingSession,
|
||||||
buildPuzzleRuntimeWorkFromSession,
|
buildPuzzleRuntimeWorkFromSession,
|
||||||
buildSquareHoleProfileFromSession,
|
buildSquareHoleProfileFromSession,
|
||||||
|
buildVisualNovelSessionFromWorkDetail,
|
||||||
buildWoodenFishPendingSession,
|
buildWoodenFishPendingSession,
|
||||||
buildWoodenFishSessionFromWorkDetail,
|
buildWoodenFishSessionFromWorkDetail,
|
||||||
} from './platformMiniGameSessionMappingModel';
|
} from './platformMiniGameSessionMappingModel';
|
||||||
@@ -736,22 +737,6 @@ const PUZZLE_DRAFT_GENERATION_POINT_COST = 2;
|
|||||||
const MATCH3D_DRAFT_GENERATION_POINT_COST = 10;
|
const MATCH3D_DRAFT_GENERATION_POINT_COST = 10;
|
||||||
const BARK_BATTLE_DRAFT_GENERATION_POINT_COST = 3;
|
const BARK_BATTLE_DRAFT_GENERATION_POINT_COST = 3;
|
||||||
|
|
||||||
function mapVisualNovelWorkDetailToSession(
|
|
||||||
work: VisualNovelWorkDetail,
|
|
||||||
): VisualNovelAgentSessionSnapshot {
|
|
||||||
return {
|
|
||||||
sessionId: work.sourceSessionId?.trim() || work.workId,
|
|
||||||
ownerUserId: work.summary.ownerUserId,
|
|
||||||
sourceMode: work.draft.sourceMode,
|
|
||||||
status: 'ready',
|
|
||||||
messages: [],
|
|
||||||
draft: work.draft,
|
|
||||||
pendingAction: null,
|
|
||||||
createdAt: work.createdAt,
|
|
||||||
updatedAt: work.summary.updatedAt,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function mergePuzzleWorkSummary(
|
function mergePuzzleWorkSummary(
|
||||||
current: PuzzleWorkSummary,
|
current: PuzzleWorkSummary,
|
||||||
updated: PuzzleWorkSummary,
|
updated: PuzzleWorkSummary,
|
||||||
@@ -11094,7 +11079,7 @@ export function PlatformEntryFlowShellImpl({
|
|||||||
try {
|
try {
|
||||||
const { work } = await getVisualNovelWorkDetail(item.profileId);
|
const { work } = await getVisualNovelWorkDetail(item.profileId);
|
||||||
setVisualNovelWork(work);
|
setVisualNovelWork(work);
|
||||||
setVisualNovelSession(mapVisualNovelWorkDetailToSession(work));
|
setVisualNovelSession(buildVisualNovelSessionFromWorkDetail(work));
|
||||||
enterCreateTab();
|
enterCreateTab();
|
||||||
setSelectionStage('visual-novel-result');
|
setSelectionStage('visual-novel-result');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ import type {
|
|||||||
SquareHoleResultDraft,
|
SquareHoleResultDraft,
|
||||||
SquareHoleSessionSnapshot,
|
SquareHoleSessionSnapshot,
|
||||||
} from '../../../packages/shared/src/contracts/squareHoleAgent';
|
} from '../../../packages/shared/src/contracts/squareHoleAgent';
|
||||||
|
import type {
|
||||||
|
VisualNovelResultDraft,
|
||||||
|
VisualNovelWorkDetail,
|
||||||
|
} from '../../../packages/shared/src/contracts/visualNovel';
|
||||||
import type {
|
import type {
|
||||||
WoodenFishAudioAsset,
|
WoodenFishAudioAsset,
|
||||||
WoodenFishImageAsset,
|
WoodenFishImageAsset,
|
||||||
@@ -22,6 +26,7 @@ import {
|
|||||||
buildJumpHopPendingSession,
|
buildJumpHopPendingSession,
|
||||||
buildPuzzleRuntimeWorkFromSession,
|
buildPuzzleRuntimeWorkFromSession,
|
||||||
buildSquareHoleProfileFromSession,
|
buildSquareHoleProfileFromSession,
|
||||||
|
buildVisualNovelSessionFromWorkDetail,
|
||||||
buildWoodenFishPendingSession,
|
buildWoodenFishPendingSession,
|
||||||
buildWoodenFishSessionFromWorkDetail,
|
buildWoodenFishSessionFromWorkDetail,
|
||||||
} from './platformMiniGameSessionMappingModel';
|
} from './platformMiniGameSessionMappingModel';
|
||||||
@@ -222,6 +227,126 @@ function buildSquareHoleSession(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildVisualNovelDraft(
|
||||||
|
overrides: Partial<VisualNovelResultDraft> = {},
|
||||||
|
): VisualNovelResultDraft {
|
||||||
|
return {
|
||||||
|
profileId: 'visual-novel-profile-1',
|
||||||
|
workTitle: '雪线电台',
|
||||||
|
workDescription: '旧电台牵出雪夜列车谜案。',
|
||||||
|
workTags: ['雪夜', '电台'],
|
||||||
|
coverImageSrc: '/visual-novel-cover.png',
|
||||||
|
sourceMode: 'idea',
|
||||||
|
sourceAssetIds: ['asset-source-1'],
|
||||||
|
world: {
|
||||||
|
title: '北境终点线',
|
||||||
|
summary: '边境小城与旧电台。',
|
||||||
|
background: '十二年前的雪崩留下夜间广播。',
|
||||||
|
premise: '玩家需要在日出前找出列车停摆的原因。',
|
||||||
|
literaryStyle: '克制冷光感。',
|
||||||
|
playerRole: '临时广播员',
|
||||||
|
defaultTone: '安静紧张',
|
||||||
|
},
|
||||||
|
characters: [
|
||||||
|
{
|
||||||
|
characterId: 'vn-char-1',
|
||||||
|
name: '林遥',
|
||||||
|
gender: '女',
|
||||||
|
role: 'main',
|
||||||
|
appearance: '灰色长外套。',
|
||||||
|
personality: '谨慎敏锐。',
|
||||||
|
tone: '短句多。',
|
||||||
|
background: '旧电台夜班实习生。',
|
||||||
|
relationshipToPlayer: '临时搭档',
|
||||||
|
imageAssets: [],
|
||||||
|
defaultExpression: 'calm',
|
||||||
|
isPlayerVisible: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
scenes: [
|
||||||
|
{
|
||||||
|
sceneId: 'vn-scene-1',
|
||||||
|
name: '风雪站台',
|
||||||
|
description: '站灯忽明忽暗。',
|
||||||
|
backgroundImageSrc: null,
|
||||||
|
musicSrc: null,
|
||||||
|
ambientSoundSrc: null,
|
||||||
|
availability: 'opening',
|
||||||
|
phaseIds: ['vn-phase-1'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
storyPhases: [
|
||||||
|
{
|
||||||
|
phaseId: 'vn-phase-1',
|
||||||
|
title: '重启站台',
|
||||||
|
goal: '确认列车为何停在废弃站台。',
|
||||||
|
summary: '玩家抵达风雪站台。',
|
||||||
|
entryCondition: '开场进入',
|
||||||
|
exitCondition: '找到车长日志',
|
||||||
|
sceneIds: ['vn-scene-1'],
|
||||||
|
characterIds: ['vn-char-1'],
|
||||||
|
suggestedChoices: ['检查广播柜'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
opening: {
|
||||||
|
sceneId: 'vn-scene-1',
|
||||||
|
narration: '雪落得很慢。',
|
||||||
|
speakerCharacterId: 'vn-char-1',
|
||||||
|
firstDialogue: '你听见了吗?',
|
||||||
|
initialChoices: [
|
||||||
|
{
|
||||||
|
choiceId: 'vn-choice-1',
|
||||||
|
text: '靠近广播柜。',
|
||||||
|
actionHint: 'inspect_radio',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
runtimeConfig: {
|
||||||
|
textModeEnabled: true,
|
||||||
|
defaultTextMode: false,
|
||||||
|
maxHistoryEntries: 80,
|
||||||
|
maxAssistantStepCountPerTurn: 8,
|
||||||
|
allowFreeTextAction: true,
|
||||||
|
allowHistoryRegeneration: true,
|
||||||
|
attributePanelMode: 'template_config',
|
||||||
|
saveArchiveEnabled: true,
|
||||||
|
},
|
||||||
|
publishReady: true,
|
||||||
|
validationIssues: [],
|
||||||
|
updatedAt: '2026-06-01T13:00:00.000Z',
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildVisualNovelWorkDetail(
|
||||||
|
overrides: Partial<VisualNovelWorkDetail> = {},
|
||||||
|
): VisualNovelWorkDetail {
|
||||||
|
const draft = buildVisualNovelDraft();
|
||||||
|
return {
|
||||||
|
workId: 'visual-novel-work-1',
|
||||||
|
summary: {
|
||||||
|
runtimeKind: 'visual-novel',
|
||||||
|
profileId: 'visual-novel-profile-1',
|
||||||
|
ownerUserId: 'user-visual-novel-1',
|
||||||
|
title: draft.workTitle,
|
||||||
|
description: draft.workDescription,
|
||||||
|
coverImageSrc: draft.coverImageSrc,
|
||||||
|
tags: draft.workTags,
|
||||||
|
publishStatus: 'draft',
|
||||||
|
publishReady: draft.publishReady,
|
||||||
|
playCount: 0,
|
||||||
|
updatedAt: '2026-06-01T13:30:00.000Z',
|
||||||
|
publishedAt: null,
|
||||||
|
},
|
||||||
|
sourceSessionId: ' visual-novel-session-1 ',
|
||||||
|
authorDisplayName: '视觉小说作者',
|
||||||
|
sourceAssetIds: draft.sourceAssetIds,
|
||||||
|
draft,
|
||||||
|
createdAt: '2026-06-01T12:50:00.000Z',
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const woodenFishImageAsset: WoodenFishImageAsset = {
|
const woodenFishImageAsset: WoodenFishImageAsset = {
|
||||||
assetId: 'asset-hit',
|
assetId: 'asset-hit',
|
||||||
imageSrc: '/hit.png',
|
imageSrc: '/hit.png',
|
||||||
@@ -427,6 +552,33 @@ describe('platformMiniGameSessionMappingModel', () => {
|
|||||||
).toBeNull();
|
).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('builds visual novel recovered session from work detail', () => {
|
||||||
|
const work = buildVisualNovelWorkDetail();
|
||||||
|
|
||||||
|
expect(buildVisualNovelSessionFromWorkDetail(work)).toEqual({
|
||||||
|
sessionId: 'visual-novel-session-1',
|
||||||
|
ownerUserId: 'user-visual-novel-1',
|
||||||
|
sourceMode: 'idea',
|
||||||
|
status: 'ready',
|
||||||
|
messages: [],
|
||||||
|
draft: work.draft,
|
||||||
|
pendingAction: null,
|
||||||
|
createdAt: '2026-06-01T12:50:00.000Z',
|
||||||
|
updatedAt: '2026-06-01T13:30:00.000Z',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('falls back visual novel recovered session id to work id', () => {
|
||||||
|
expect(
|
||||||
|
buildVisualNovelSessionFromWorkDetail(
|
||||||
|
buildVisualNovelWorkDetail({
|
||||||
|
sourceSessionId: ' ',
|
||||||
|
workId: 'visual-novel-work-fallback',
|
||||||
|
}),
|
||||||
|
).sessionId,
|
||||||
|
).toBe('visual-novel-work-fallback');
|
||||||
|
});
|
||||||
|
|
||||||
test('builds wooden fish pending session from work summary', () => {
|
test('builds wooden fish pending session from work summary', () => {
|
||||||
expect(buildWoodenFishPendingSession(buildWoodenFishSummary())).toEqual({
|
expect(buildWoodenFishPendingSession(buildWoodenFishSummary())).toEqual({
|
||||||
sessionId: 'wooden-fish-session-1',
|
sessionId: 'wooden-fish-session-1',
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import type { PuzzleAgentSessionSnapshot } from '../../../packages/shared/src/co
|
|||||||
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
|
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
|
||||||
import type { SquareHoleSessionSnapshot } from '../../../packages/shared/src/contracts/squareHoleAgent';
|
import type { SquareHoleSessionSnapshot } from '../../../packages/shared/src/contracts/squareHoleAgent';
|
||||||
import type { SquareHoleWorkProfile } from '../../../packages/shared/src/contracts/squareHoleWorks';
|
import type { SquareHoleWorkProfile } from '../../../packages/shared/src/contracts/squareHoleWorks';
|
||||||
|
import type {
|
||||||
|
VisualNovelAgentSessionSnapshot,
|
||||||
|
VisualNovelWorkDetail,
|
||||||
|
} from '../../../packages/shared/src/contracts/visualNovel';
|
||||||
import type {
|
import type {
|
||||||
WoodenFishSessionSnapshotResponse,
|
WoodenFishSessionSnapshotResponse,
|
||||||
WoodenFishWorkProfileResponse,
|
WoodenFishWorkProfileResponse,
|
||||||
@@ -88,6 +92,22 @@ export function buildSquareHoleProfileFromSession(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildVisualNovelSessionFromWorkDetail(
|
||||||
|
work: VisualNovelWorkDetail,
|
||||||
|
): VisualNovelAgentSessionSnapshot {
|
||||||
|
return {
|
||||||
|
sessionId: normalizeCreationUrlValue(work.sourceSessionId) ?? work.workId,
|
||||||
|
ownerUserId: work.summary.ownerUserId,
|
||||||
|
sourceMode: work.draft.sourceMode,
|
||||||
|
status: 'ready',
|
||||||
|
messages: [],
|
||||||
|
draft: work.draft,
|
||||||
|
pendingAction: null,
|
||||||
|
createdAt: work.createdAt,
|
||||||
|
updatedAt: work.summary.updatedAt,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function buildJumpHopPendingSession(
|
export function buildJumpHopPendingSession(
|
||||||
item: JumpHopWorkSummaryResponse,
|
item: JumpHopWorkSummaryResponse,
|
||||||
): JumpHopSessionSnapshotResponse {
|
): JumpHopSessionSnapshotResponse {
|
||||||
|
|||||||
Reference in New Issue
Block a user