refactor: 收口方洞 session profile 映射
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 恢复、跳一跳 pending session、敲木鱼 detail 恢复和敲木鱼 pending session 四段纯 DTO 映射,壳层需要理解 sessionId 优先级、拼图稳定 ID 和 pending draft 默认值。
|
- 背景:`PlatformEntryFlowShellImpl.tsx` 顶部仍保留拼图 runtime 恢复、方洞 session draft 转 profile、跳一跳 pending session、敲木鱼 detail 恢复和敲木鱼 pending session 等纯 DTO 映射,壳层需要理解 sessionId 优先级、拼图稳定 ID、方洞草稿 profile 默认值和 pending draft 默认值。
|
||||||
- 决策:新增 `src/components/platform-entry/platformMiniGameSessionMappingModel.ts`,收口 `buildPuzzleRuntimeWorkFromSession`、`buildJumpHopPendingSession`、`buildWoodenFishSessionFromWorkDetail` 与 `buildWoodenFishPendingSession`。Module 复用 `normalizeCreationUrlValue` 与 `platformPuzzleIdentityModel`;壳层只保留网络读取、React state、URL 写入和 stage 切换副作用。
|
- 决策:新增 `src/components/platform-entry/platformMiniGameSessionMappingModel.ts`,收口 `buildPuzzleRuntimeWorkFromSession`、`buildSquareHoleProfileFromSession`、`buildJumpHopPendingSession`、`buildWoodenFishSessionFromWorkDetail` 与 `buildWoodenFishPendingSession`。Module 复用 `normalizeCreationUrlValue` 与 `platformPuzzleIdentityModel`;壳层只保留网络读取、React state、URL 写入和 stage 切换副作用。
|
||||||
- 影响范围:拼图 runtime URL 恢复、跳一跳生成中作品架打开、敲木鱼生成中作品架打开和敲木鱼草稿 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、跳一跳 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、跳一跳 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 恢复、跳一跳 pending session、敲木鱼 work detail 恢复和敲木鱼 pending session 四段纯 DTO 映射。它们没有 React state、网络请求、路由、弹窗或计时副作用,却住在大型平台壳内;新增或修正生成中草稿恢复时,需要在壳层里理解 sessionId 优先级、拼图稳定 ID、pending draft 默认值和木鱼 fallback 规则。
|
`PlatformEntryFlowShellImpl.tsx` 顶部曾保留拼图 runtime 恢复、方洞挑战 session draft 转 profile、跳一跳 pending session、敲木鱼 work detail 恢复和敲木鱼 pending session 多段纯 DTO 映射。它们没有 React state、网络请求、路由、弹窗或计时副作用,却住在大型平台壳内;新增或修正生成中草稿恢复时,需要在壳层里理解 sessionId 优先级、拼图稳定 ID、方洞 profile 默认值、pending draft 默认值和木鱼 fallback 规则。
|
||||||
|
|
||||||
这些规则属于平台壳 session / work 恢复映射,应成为可测试的 **Module**。壳层只负责调用网络、写 React state、写 URL 和切换 stage。
|
这些规则属于平台壳 session / work 恢复映射,应成为可测试的 **Module**。壳层只负责调用网络、写 React state、写 URL 和切换 stage。
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
新增 `src/components/platform-entry/platformMiniGameSessionMappingModel.ts` 作为 Platform Mini Game Session Mapping **Module**。其公开 **Interface** 为:
|
新增 `src/components/platform-entry/platformMiniGameSessionMappingModel.ts` 作为 Platform Mini Game Session Mapping **Module**。其公开 **Interface** 为:
|
||||||
|
|
||||||
- `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`。
|
||||||
- `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。
|
||||||
@@ -22,15 +23,17 @@
|
|||||||
- 拼图 runtime work 必须保留 `draft.coverImageSrc` 非空门槛,避免启动缺封面的草稿运行态。
|
- 拼图 runtime work 必须保留 `draft.coverImageSrc` 非空门槛,避免启动缺封面的草稿运行态。
|
||||||
- 拼图 profileId 优先 `publishedProfileId`,否则用 `buildPuzzleResultProfileId(sessionId)`;workId 使用 `buildPuzzleResultWorkId(sessionId)`,缺失时回退 profileId。
|
- 拼图 profileId 优先 `publishedProfileId`,否则用 `buildPuzzleResultProfileId(sessionId)`;workId 使用 `buildPuzzleResultWorkId(sessionId)`,缺失时回退 profileId。
|
||||||
- 拼图 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 的 `updatedAt` 优先 session `updatedAt`,缺失时使用当前时间;`publicationStatus='draft'`、`playCount=0`、`publishedAt=null`,`publishReady` 来自 draft。
|
||||||
- 跳一跳 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 优先级和默认 draft 字段藏入 Module Implementation。
|
- **Depth**:壳层以少量函数取得恢复用 DTO;ID 优先级、方洞 profile 默认值和 pending draft 字段藏入 Module Implementation。
|
||||||
- **Leverage**:后续新增生成中作品恢复或修改 sessionId 规则时,先改 Module 与单测,再保持壳层 Adapter 副作用不变。
|
- **Leverage**:后续新增生成中作品恢复或修改 sessionId 规则时,先改 Module 与单测,再保持壳层 Adapter 副作用不变。
|
||||||
- **Locality**:拼图、跳一跳和敲木鱼的恢复映射集中在一个纯测试面,避免在大型壳层顶部继续堆积 DTO 构造。
|
- **Locality**:拼图、方洞、跳一跳和敲木鱼的恢复映射集中在一个纯测试面,避免在大型壳层顶部继续堆积 DTO 构造。
|
||||||
|
|
||||||
## 验收
|
## 验收
|
||||||
|
|
||||||
|
|||||||
@@ -536,6 +536,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
buildJumpHopPendingSession,
|
buildJumpHopPendingSession,
|
||||||
buildPuzzleRuntimeWorkFromSession,
|
buildPuzzleRuntimeWorkFromSession,
|
||||||
|
buildSquareHoleProfileFromSession,
|
||||||
buildWoodenFishPendingSession,
|
buildWoodenFishPendingSession,
|
||||||
buildWoodenFishSessionFromWorkDetail,
|
buildWoodenFishSessionFromWorkDetail,
|
||||||
} from './platformMiniGameSessionMappingModel';
|
} from './platformMiniGameSessionMappingModel';
|
||||||
@@ -751,40 +752,6 @@ function mapVisualNovelWorkDetailToSession(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildSquareHoleProfileFromSession(
|
|
||||||
session: SquareHoleSessionSnapshot | null,
|
|
||||||
): SquareHoleWorkProfile | null {
|
|
||||||
const draft = session?.draft;
|
|
||||||
if (!session || !draft?.profileId) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const now = session.updatedAt || new Date().toISOString();
|
|
||||||
return {
|
|
||||||
workId: draft.profileId,
|
|
||||||
profileId: draft.profileId,
|
|
||||||
ownerUserId: 'current-user',
|
|
||||||
sourceSessionId: session.sessionId,
|
|
||||||
gameName: draft.gameName,
|
|
||||||
themeText: draft.themeText,
|
|
||||||
twistRule: draft.twistRule,
|
|
||||||
summary: draft.summary,
|
|
||||||
tags: draft.tags,
|
|
||||||
coverImageSrc: draft.coverImageSrc ?? null,
|
|
||||||
backgroundPrompt: draft.backgroundPrompt,
|
|
||||||
backgroundImageSrc: draft.backgroundImageSrc ?? null,
|
|
||||||
shapeOptions: draft.shapeOptions,
|
|
||||||
holeOptions: draft.holeOptions,
|
|
||||||
shapeCount: draft.shapeCount,
|
|
||||||
difficulty: draft.difficulty,
|
|
||||||
publicationStatus: 'draft',
|
|
||||||
playCount: 0,
|
|
||||||
updatedAt: now,
|
|
||||||
publishedAt: null,
|
|
||||||
publishReady: Boolean(draft.publishReady),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function mergePuzzleWorkSummary(
|
function mergePuzzleWorkSummary(
|
||||||
current: PuzzleWorkSummary,
|
current: PuzzleWorkSummary,
|
||||||
updated: PuzzleWorkSummary,
|
updated: PuzzleWorkSummary,
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ import type {
|
|||||||
PuzzleResultDraft,
|
PuzzleResultDraft,
|
||||||
} from '../../../packages/shared/src/contracts/puzzleAgentDraft';
|
} from '../../../packages/shared/src/contracts/puzzleAgentDraft';
|
||||||
import type { PuzzleAgentSessionSnapshot } from '../../../packages/shared/src/contracts/puzzleAgentSession';
|
import type { PuzzleAgentSessionSnapshot } from '../../../packages/shared/src/contracts/puzzleAgentSession';
|
||||||
|
import type {
|
||||||
|
SquareHoleResultDraft,
|
||||||
|
SquareHoleSessionSnapshot,
|
||||||
|
} from '../../../packages/shared/src/contracts/squareHoleAgent';
|
||||||
import type {
|
import type {
|
||||||
WoodenFishAudioAsset,
|
WoodenFishAudioAsset,
|
||||||
WoodenFishImageAsset,
|
WoodenFishImageAsset,
|
||||||
@@ -17,6 +21,7 @@ import type {
|
|||||||
import {
|
import {
|
||||||
buildJumpHopPendingSession,
|
buildJumpHopPendingSession,
|
||||||
buildPuzzleRuntimeWorkFromSession,
|
buildPuzzleRuntimeWorkFromSession,
|
||||||
|
buildSquareHoleProfileFromSession,
|
||||||
buildWoodenFishPendingSession,
|
buildWoodenFishPendingSession,
|
||||||
buildWoodenFishSessionFromWorkDetail,
|
buildWoodenFishSessionFromWorkDetail,
|
||||||
} from './platformMiniGameSessionMappingModel';
|
} from './platformMiniGameSessionMappingModel';
|
||||||
@@ -123,6 +128,100 @@ function buildJumpHopSummary(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildSquareHoleDraft(
|
||||||
|
overrides: Partial<SquareHoleResultDraft> = {},
|
||||||
|
): SquareHoleResultDraft {
|
||||||
|
return {
|
||||||
|
profileId: 'square-hole-profile-1',
|
||||||
|
gameName: '星桥方洞',
|
||||||
|
themeText: '星桥机关',
|
||||||
|
twistRule: '只允许相同颜色形状入洞',
|
||||||
|
summary: '把星桥机关里的形状送入正确孔洞。',
|
||||||
|
tags: ['星桥', '机关'],
|
||||||
|
coverImageSrc: '/square-hole-cover.png',
|
||||||
|
backgroundPrompt: '星桥机关背景',
|
||||||
|
backgroundImageSrc: '/square-hole-background.png',
|
||||||
|
shapeOptions: [
|
||||||
|
{
|
||||||
|
optionId: 'shape-1',
|
||||||
|
shapeKind: 'star',
|
||||||
|
label: '星形',
|
||||||
|
targetHoleId: 'hole-1',
|
||||||
|
imagePrompt: '星形积木',
|
||||||
|
imageSrc: '/shape-star.png',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
holeOptions: [
|
||||||
|
{
|
||||||
|
holeId: 'hole-1',
|
||||||
|
holeKind: 'star-hole',
|
||||||
|
label: '星形洞',
|
||||||
|
imagePrompt: '星形洞口',
|
||||||
|
imageSrc: '/hole-star.png',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
shapeCount: 6,
|
||||||
|
difficulty: 3,
|
||||||
|
publishReady: true,
|
||||||
|
blockers: [],
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSquareHoleSession(
|
||||||
|
overrides: Partial<SquareHoleSessionSnapshot> = {},
|
||||||
|
): SquareHoleSessionSnapshot {
|
||||||
|
return {
|
||||||
|
sessionId: 'square-hole-session-1',
|
||||||
|
currentTurn: 2,
|
||||||
|
progressPercent: 100,
|
||||||
|
stage: 'draft_ready',
|
||||||
|
anchorPack: {
|
||||||
|
theme: {
|
||||||
|
key: 'theme',
|
||||||
|
label: '主题',
|
||||||
|
value: '星桥机关',
|
||||||
|
status: 'confirmed',
|
||||||
|
},
|
||||||
|
twistRule: {
|
||||||
|
key: 'twistRule',
|
||||||
|
label: '扭转规则',
|
||||||
|
value: '只允许相同颜色形状入洞',
|
||||||
|
status: 'confirmed',
|
||||||
|
},
|
||||||
|
shapeCount: {
|
||||||
|
key: 'shapeCount',
|
||||||
|
label: '形状数量',
|
||||||
|
value: '6',
|
||||||
|
status: 'confirmed',
|
||||||
|
},
|
||||||
|
difficulty: {
|
||||||
|
key: 'difficulty',
|
||||||
|
label: '难度',
|
||||||
|
value: '3',
|
||||||
|
status: 'confirmed',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
themeText: '星桥机关',
|
||||||
|
twistRule: '只允许相同颜色形状入洞',
|
||||||
|
shapeCount: 6,
|
||||||
|
difficulty: 3,
|
||||||
|
shapeOptions: [],
|
||||||
|
holeOptions: [],
|
||||||
|
backgroundPrompt: '星桥机关背景',
|
||||||
|
coverImageSrc: null,
|
||||||
|
backgroundImageSrc: null,
|
||||||
|
},
|
||||||
|
draft: buildSquareHoleDraft(),
|
||||||
|
messages: [],
|
||||||
|
lastAssistantReply: null,
|
||||||
|
publishedProfileId: null,
|
||||||
|
updatedAt: '2026-06-01T12:30:00.000Z',
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const woodenFishImageAsset: WoodenFishImageAsset = {
|
const woodenFishImageAsset: WoodenFishImageAsset = {
|
||||||
assetId: 'asset-hit',
|
assetId: 'asset-hit',
|
||||||
imageSrc: '/hit.png',
|
imageSrc: '/hit.png',
|
||||||
@@ -284,6 +383,50 @@ describe('platformMiniGameSessionMappingModel', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('builds square hole draft profile from session', () => {
|
||||||
|
expect(buildSquareHoleProfileFromSession(buildSquareHoleSession())).toEqual({
|
||||||
|
workId: 'square-hole-profile-1',
|
||||||
|
profileId: 'square-hole-profile-1',
|
||||||
|
ownerUserId: 'current-user',
|
||||||
|
sourceSessionId: 'square-hole-session-1',
|
||||||
|
gameName: '星桥方洞',
|
||||||
|
themeText: '星桥机关',
|
||||||
|
twistRule: '只允许相同颜色形状入洞',
|
||||||
|
summary: '把星桥机关里的形状送入正确孔洞。',
|
||||||
|
tags: ['星桥', '机关'],
|
||||||
|
coverImageSrc: '/square-hole-cover.png',
|
||||||
|
backgroundPrompt: '星桥机关背景',
|
||||||
|
backgroundImageSrc: '/square-hole-background.png',
|
||||||
|
shapeOptions: buildSquareHoleDraft().shapeOptions,
|
||||||
|
holeOptions: buildSquareHoleDraft().holeOptions,
|
||||||
|
shapeCount: 6,
|
||||||
|
difficulty: 3,
|
||||||
|
publicationStatus: 'draft',
|
||||||
|
playCount: 0,
|
||||||
|
updatedAt: '2026-06-01T12:30:00.000Z',
|
||||||
|
publishedAt: null,
|
||||||
|
publishReady: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('returns null for square hole profile without session draft or profile id', () => {
|
||||||
|
expect(buildSquareHoleProfileFromSession(null)).toBeNull();
|
||||||
|
expect(
|
||||||
|
buildSquareHoleProfileFromSession(
|
||||||
|
buildSquareHoleSession({
|
||||||
|
draft: null,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
).toBeNull();
|
||||||
|
expect(
|
||||||
|
buildSquareHoleProfileFromSession(
|
||||||
|
buildSquareHoleSession({
|
||||||
|
draft: buildSquareHoleDraft({ profileId: '' }),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
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',
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import type { JumpHopSessionSnapshotResponse, JumpHopWorkSummaryResponse } from '../../../packages/shared/src/contracts/jumpHop';
|
import type { JumpHopSessionSnapshotResponse, JumpHopWorkSummaryResponse } from '../../../packages/shared/src/contracts/jumpHop';
|
||||||
import type { PuzzleAgentSessionSnapshot } from '../../../packages/shared/src/contracts/puzzleAgentSession';
|
import type { PuzzleAgentSessionSnapshot } from '../../../packages/shared/src/contracts/puzzleAgentSession';
|
||||||
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 { SquareHoleWorkProfile } from '../../../packages/shared/src/contracts/squareHoleWorks';
|
||||||
import type {
|
import type {
|
||||||
WoodenFishSessionSnapshotResponse,
|
WoodenFishSessionSnapshotResponse,
|
||||||
WoodenFishWorkProfileResponse,
|
WoodenFishWorkProfileResponse,
|
||||||
@@ -52,6 +54,40 @@ export function buildPuzzleRuntimeWorkFromSession(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildSquareHoleProfileFromSession(
|
||||||
|
session: SquareHoleSessionSnapshot | null,
|
||||||
|
): SquareHoleWorkProfile | null {
|
||||||
|
const draft = session?.draft;
|
||||||
|
if (!session || !draft?.profileId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = session.updatedAt || new Date().toISOString();
|
||||||
|
return {
|
||||||
|
workId: draft.profileId,
|
||||||
|
profileId: draft.profileId,
|
||||||
|
ownerUserId: 'current-user',
|
||||||
|
sourceSessionId: session.sessionId,
|
||||||
|
gameName: draft.gameName,
|
||||||
|
themeText: draft.themeText,
|
||||||
|
twistRule: draft.twistRule,
|
||||||
|
summary: draft.summary,
|
||||||
|
tags: draft.tags,
|
||||||
|
coverImageSrc: draft.coverImageSrc ?? null,
|
||||||
|
backgroundPrompt: draft.backgroundPrompt,
|
||||||
|
backgroundImageSrc: draft.backgroundImageSrc ?? null,
|
||||||
|
shapeOptions: draft.shapeOptions,
|
||||||
|
holeOptions: draft.holeOptions,
|
||||||
|
shapeCount: draft.shapeCount,
|
||||||
|
difficulty: draft.difficulty,
|
||||||
|
publicationStatus: 'draft',
|
||||||
|
playCount: 0,
|
||||||
|
updatedAt: now,
|
||||||
|
publishedAt: null,
|
||||||
|
publishReady: Boolean(draft.publishReady),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function buildJumpHopPendingSession(
|
export function buildJumpHopPendingSession(
|
||||||
item: JumpHopWorkSummaryResponse,
|
item: JumpHopWorkSummaryResponse,
|
||||||
): JumpHopSessionSnapshotResponse {
|
): JumpHopSessionSnapshotResponse {
|
||||||
|
|||||||
Reference in New Issue
Block a user