import type { JumpHopActionRequest, JumpHopActionResponse, JumpHopDraftResponse, JumpHopGalleryCardResponse, JumpHopGalleryDetailResponse, JumpHopGalleryResponse, JumpHopRunResponse, JumpHopRuntimeRunSnapshotResponse, JumpHopSessionResponse, JumpHopSessionSnapshotResponse, JumpHopWorkDetailResponse, JumpHopWorkMutationResponse, JumpHopWorkProfileResponse, JumpHopWorksResponse, JumpHopWorkspaceCreateRequest, JumpHopWorkSummaryResponse, } from '../../../packages/shared/src/contracts/jumpHop'; import { type ApiRetryOptions, requestJson, } from '../apiClient'; import { createCreationAgentClient } from '../creation-agent'; import { buildRuntimeGuestAuthOptions, buildRuntimeGuestHeaders, type RuntimeGuestRequestOptions, } from '../runtimeGuestAuth'; const JUMP_HOP_API_BASE = '/api/creation/jump-hop/sessions'; const JUMP_HOP_WORKS_API_BASE = '/api/creation/jump-hop/works'; const JUMP_HOP_RUNTIME_API_BASE = '/api/runtime/jump-hop'; const JUMP_HOP_RUNTIME_READ_RETRY: ApiRetryOptions = { maxRetries: 1, baseDelayMs: 120, maxDelayMs: 360, }; type JumpHopRuntimeRequestOptions = RuntimeGuestRequestOptions; export type { JumpHopActionRequest, JumpHopActionResponse, JumpHopDraftResponse, JumpHopGalleryCardResponse, JumpHopGalleryDetailResponse, JumpHopGalleryResponse, JumpHopRunResponse, JumpHopRuntimeRunSnapshotResponse, JumpHopSessionResponse, JumpHopSessionSnapshotResponse, JumpHopWorkDetailResponse, JumpHopWorkMutationResponse, JumpHopWorkProfileResponse, JumpHopWorksResponse, JumpHopWorkspaceCreateRequest, }; export type CreateJumpHopSessionRequest = { themeText: string; characterDescription: string; tileStyle: string; difficulty: string; rhythmPreference: string; }; export type ExecuteJumpHopActionRequest = JumpHopActionRequest; export type JumpHopSessionSnapshot = JumpHopSessionSnapshotResponse; const jumpHopCreationClient = createCreationAgentClient< JumpHopWorkspaceCreateRequest, JumpHopSessionResponse, JumpHopSessionResponse, JumpHopSessionSnapshotResponse, never, never, JumpHopActionRequest, JumpHopActionResponse >({ apiBase: JUMP_HOP_API_BASE, messages: { createSession: '创建跳一跳共创会话失败', getSession: '读取跳一跳共创会话失败', sendMessage: '发送跳一跳共创消息失败', streamIncomplete: '跳一跳共创消息流式结果不完整', executeAction: '执行跳一跳共创操作失败', }, }); type FlattenedJumpHopWorkProfileResponse = Omit< JumpHopWorkProfileResponse, 'summary' > & JumpHopWorkSummaryResponse; function normalizeJumpHopWorkProfile( work: JumpHopWorkProfileResponse | FlattenedJumpHopWorkProfileResponse, ): JumpHopWorkProfileResponse { if ('summary' in work && work.summary) { return work; } const flattened = work as FlattenedJumpHopWorkProfileResponse; const summary: JumpHopWorkProfileResponse['summary'] = { runtimeKind: flattened.runtimeKind, workId: flattened.workId, profileId: flattened.profileId, ownerUserId: flattened.ownerUserId, sourceSessionId: flattened.sourceSessionId ?? null, workTitle: flattened.workTitle, workDescription: flattened.workDescription, themeTags: flattened.themeTags, difficulty: flattened.difficulty, stylePreset: flattened.stylePreset, coverImageSrc: flattened.coverImageSrc ?? null, publicationStatus: flattened.publicationStatus, playCount: flattened.playCount, updatedAt: flattened.updatedAt, publishedAt: flattened.publishedAt ?? null, publishReady: flattened.publishReady, generationStatus: flattened.generationStatus, }; return { summary, draft: flattened.draft, path: flattened.path, characterAsset: flattened.characterAsset, tileAtlasAsset: flattened.tileAtlasAsset, tileAssets: flattened.tileAssets, }; } function normalizeJumpHopActionResponse( response: JumpHopActionResponse, ): JumpHopActionResponse { return { ...response, work: response.work ? normalizeJumpHopWorkProfile(response.work) : null, }; } function normalizeJumpHopWorkDetailResponse( response: JumpHopWorkDetailResponse, ): JumpHopWorkDetailResponse { return { ...response, item: normalizeJumpHopWorkProfile(response.item), }; } function normalizeJumpHopWorkMutationResponse( response: JumpHopWorkMutationResponse, ): JumpHopWorkMutationResponse { return { ...response, item: normalizeJumpHopWorkProfile(response.item), }; } export function createJumpHopCreationSession( payload: JumpHopWorkspaceCreateRequest, ) { return jumpHopCreationClient.createSession(payload); } export function getJumpHopCreationSession(sessionId: string) { return jumpHopCreationClient.getSession(sessionId); } export function executeJumpHopCreationAction( sessionId: string, payload: JumpHopActionRequest, ) { return jumpHopCreationClient .executeAction(sessionId, payload) .then(normalizeJumpHopActionResponse); } export async function getJumpHopWorkDetail(profileId: string) { const response = await requestJson( `${JUMP_HOP_RUNTIME_API_BASE}/works/${encodeURIComponent(profileId)}`, { method: 'GET' }, '读取跳一跳作品详情失败', ); return normalizeJumpHopWorkDetailResponse(response); } export async function listJumpHopGallery() { return requestJson( `${JUMP_HOP_RUNTIME_API_BASE}/gallery`, { method: 'GET' }, '读取跳一跳广场失败', { retry: JUMP_HOP_RUNTIME_READ_RETRY, skipAuth: true, skipRefresh: true, }, ); } export async function getJumpHopGalleryDetail(publicWorkCode: string) { const response = await requestJson( `${JUMP_HOP_RUNTIME_API_BASE}/gallery/${encodeURIComponent(publicWorkCode)}`, { method: 'GET' }, '读取跳一跳广场详情失败', { retry: JUMP_HOP_RUNTIME_READ_RETRY, skipAuth: true, skipRefresh: true, }, ); return normalizeJumpHopWorkDetailResponse(response); } export async function listJumpHopWorks() { return requestJson( JUMP_HOP_WORKS_API_BASE, { method: 'GET' }, '读取跳一跳作品列表失败', { retry: JUMP_HOP_RUNTIME_READ_RETRY, }, ); } export async function publishJumpHopWork(profileId: string) { const response = await requestJson( `${JUMP_HOP_WORKS_API_BASE}/${encodeURIComponent(profileId)}/publish`, { method: 'POST' }, '发布跳一跳作品失败', ); return normalizeJumpHopWorkMutationResponse(response); } export async function startJumpHopRuntimeRun( profileId: string, options: JumpHopRuntimeRequestOptions = {}, ) { const requestOptions = buildRuntimeGuestAuthOptions(options); return requestJson( `${JUMP_HOP_RUNTIME_API_BASE}/runs`, { method: 'POST', headers: { 'content-type': 'application/json', ...buildRuntimeGuestHeaders(options), }, body: JSON.stringify({ profileId }), }, '启动跳一跳运行态失败', { ...requestOptions, }, ); } export async function submitJumpHopJump( runId: string, payload: { chargeMs: number }, options: JumpHopRuntimeRequestOptions = {}, ) { const requestOptions = buildRuntimeGuestAuthOptions(options); const requestPayload = { chargeMs: payload.chargeMs, clientEventId: `jump-${runId}-${Date.now()}`, }; return requestJson( `${JUMP_HOP_RUNTIME_API_BASE}/runs/${encodeURIComponent(runId)}/jump`, { method: 'POST', headers: { 'content-type': 'application/json', ...buildRuntimeGuestHeaders(options), }, body: JSON.stringify(requestPayload), }, '提交跳一跳起跳失败', requestOptions, ); } export async function restartJumpHopRuntimeRun( runId: string, options: JumpHopRuntimeRequestOptions = {}, ) { const requestOptions = buildRuntimeGuestAuthOptions(options); return requestJson( `${JUMP_HOP_RUNTIME_API_BASE}/runs/${encodeURIComponent(runId)}/restart`, { method: 'POST', headers: { 'content-type': 'application/json', ...buildRuntimeGuestHeaders(options), }, body: JSON.stringify({ clientActionId: `restart-${runId}-${Date.now()}`, }), }, '重新开始跳一跳失败', requestOptions, ); } export const jumpHopClient = { createSession: createJumpHopCreationSession, getSession: getJumpHopCreationSession, executeAction: executeJumpHopCreationAction, getGalleryDetail: getJumpHopGalleryDetail, getWorkDetail: getJumpHopWorkDetail, listGallery: listJumpHopGallery, listWorks: listJumpHopWorks, publishWork: publishJumpHopWork, restartRun: restartJumpHopRuntimeRun, startRun: startJumpHopRuntimeRun, submitJump: submitJumpHopJump, };