import { RUNTIME_BACKGROUND_AUTH_OPTIONS, type RuntimeRequestOptions, requestPublicRpgRuntimeJson, requestRpgRuntimeJson, } from '../rpg-runtime/rpgRuntimeRequest'; import type { CustomWorldGalleryDetailResponse, CustomWorldGalleryResponse, CustomWorldLibraryEntry, CustomWorldLibraryMutationResponse, CustomWorldLibraryResponse, } from '../../../packages/shared/src/contracts/runtime'; import { normalizeCustomWorldProfileRecord } from '../../data/customWorldLibrary'; import type { CustomWorldProfile } from '../../types'; export type { RuntimeRequestOptions }; type RpgEntryWorldEntry = CustomWorldLibraryEntry; type RpgEntryWorldMutationResponse = CustomWorldLibraryMutationResponse; function normalizeRpgEntryWorldProfile(entry: RpgEntryWorldEntry) { const rawProfile = entry.profile && typeof entry.profile === 'object' ? entry.profile : {}; const fallbackProfile = { id: entry.profileId, name: entry.worldName, subtitle: entry.subtitle, summary: entry.summaryText, settingText: entry.summaryText || entry.worldName, playableNpcs: [], storyNpcs: [], items: [], landmarks: [], }; const normalizedProfile = normalizeCustomWorldProfileRecord({ ...fallbackProfile, ...rawProfile, }) ?? normalizeCustomWorldProfileRecord(fallbackProfile); return { ...entry, profile: normalizedProfile ?? entry.profile, } as RpgEntryWorldEntry; } function normalizeRpgEntryWorldEntries( entries: RpgEntryWorldEntry[] | null | undefined, ) { return Array.isArray(entries) ? entries.map((entry) => normalizeRpgEntryWorldProfile(entry)) : []; } function normalizeRpgEntryWorldMutationResponse( response: RpgEntryWorldMutationResponse, ) { return { entry: normalizeRpgEntryWorldProfile(response.entry), entries: normalizeRpgEntryWorldEntries(response.entries), }; } /** * RPG 入口世界库 client 的真实实现。 * 第三批收口后,平台首页/详情页开始游戏链直接走 rpg-entry 域请求,不再反向穿旧 storageService 兼容层。 */ export async function listRpgEntryWorldLibrary( options: RuntimeRequestOptions = {}, ) { const response = await requestRpgRuntimeJson< CustomWorldLibraryResponse >( '/custom-world-library', { method: 'GET' }, '读取自定义世界库失败', { ...RUNTIME_BACKGROUND_AUTH_OPTIONS, ...options, }, ); return normalizeRpgEntryWorldEntries(response?.entries); } export async function listRpgEntryWorldGallery( options: RuntimeRequestOptions = {}, ) { const response = await requestPublicRpgRuntimeJson( '/custom-world-gallery', { method: 'GET' }, '读取作品广场失败', options, ); return Array.isArray(response?.entries) ? response.entries : []; } export async function getRpgEntryWorldGalleryDetail( ownerUserId: string, profileId: string, options: RuntimeRequestOptions = {}, ) { const response = await requestPublicRpgRuntimeJson< CustomWorldGalleryDetailResponse >( `/custom-world-gallery/${encodeURIComponent(ownerUserId)}/${encodeURIComponent(profileId)}`, { method: 'GET' }, '读取作品详情失败', options, ); return normalizeRpgEntryWorldProfile(response.entry); } export async function getRpgEntryWorldGalleryDetailByCode( code: string, options: RuntimeRequestOptions = {}, ) { const response = await requestPublicRpgRuntimeJson< CustomWorldGalleryDetailResponse >( `/custom-world-gallery/by-code/${encodeURIComponent(code)}`, { method: 'GET' }, '读取作品详情失败', options, ); return normalizeRpgEntryWorldProfile(response.entry); } export async function remixRpgEntryWorldGallery( ownerUserId: string, profileId: string, options: RuntimeRequestOptions = {}, ) { const response = await requestRpgRuntimeJson< CustomWorldLibraryMutationResponse >( `/custom-world-gallery/${encodeURIComponent(ownerUserId)}/${encodeURIComponent(profileId)}/remix`, { method: 'POST' }, 'Remix 作品失败', options, ); return normalizeRpgEntryWorldMutationResponse(response); } export async function recordRpgEntryWorldGalleryPlay( ownerUserId: string, profileId: string, options: RuntimeRequestOptions = {}, ) { const response = await requestRpgRuntimeJson< CustomWorldGalleryDetailResponse >( `/custom-world-gallery/${encodeURIComponent(ownerUserId)}/${encodeURIComponent(profileId)}/play`, { method: 'POST' }, '记录作品游玩失败', options, ); return normalizeRpgEntryWorldProfile(response.entry); } export async function likeRpgEntryWorldGallery( ownerUserId: string, profileId: string, options: RuntimeRequestOptions = {}, ) { const response = await requestRpgRuntimeJson< CustomWorldGalleryDetailResponse >( `/custom-world-gallery/${encodeURIComponent(ownerUserId)}/${encodeURIComponent(profileId)}/like`, { method: 'POST' }, '点赞作品失败', options, ); return normalizeRpgEntryWorldProfile(response.entry); } export async function getRpgEntryWorldLibraryDetail( profileId: string, options: RuntimeRequestOptions = {}, ) { const response = await requestRpgRuntimeJson< CustomWorldGalleryDetailResponse >( `/custom-world-library/${encodeURIComponent(profileId)}`, { method: 'GET' }, '读取作品详情失败', options, ); return normalizeRpgEntryWorldProfile(response.entry); } export async function upsertRpgEntryWorldProfile( profile: CustomWorldProfile, options: RuntimeRequestOptions = {}, ) { const response = await requestRpgRuntimeJson< CustomWorldLibraryMutationResponse >( `/custom-world-library/${encodeURIComponent(profile.id)}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ profile, }), }, '保存自定义世界失败', options, ); return normalizeRpgEntryWorldMutationResponse(response); } export async function deleteRpgEntryWorldProfile( profileId: string, options: RuntimeRequestOptions = {}, ) { const response = await requestRpgRuntimeJson< CustomWorldLibraryResponse >( `/custom-world-library/${encodeURIComponent(profileId)}`, { method: 'DELETE' }, '删除自定义世界失败', options, ); return normalizeRpgEntryWorldEntries(response?.entries); } export async function publishRpgEntryWorldProfile( profileId: string, options: RuntimeRequestOptions = {}, ) { const response = await requestRpgRuntimeJson< CustomWorldLibraryMutationResponse >( `/custom-world-library/${encodeURIComponent(profileId)}/publish`, { method: 'POST' }, '发布自定义世界失败', options, ); return normalizeRpgEntryWorldMutationResponse(response); } export async function unpublishRpgEntryWorldProfile( profileId: string, options: RuntimeRequestOptions = {}, ) { const response = await requestRpgRuntimeJson< CustomWorldLibraryMutationResponse >( `/custom-world-library/${encodeURIComponent(profileId)}/unpublish`, { method: 'POST' }, '下架自定义世界失败', options, ); return normalizeRpgEntryWorldMutationResponse(response); } export const rpgEntryLibraryClient = { listWorldLibrary: listRpgEntryWorldLibrary, listWorldGallery: listRpgEntryWorldGallery, getWorldGalleryDetail: getRpgEntryWorldGalleryDetail, getWorldGalleryDetailByCode: getRpgEntryWorldGalleryDetailByCode, getWorldLibraryDetail: getRpgEntryWorldLibraryDetail, remixWorldGallery: remixRpgEntryWorldGallery, recordWorldGalleryPlay: recordRpgEntryWorldGalleryPlay, likeWorldGallery: likeRpgEntryWorldGallery, upsertWorldProfile: upsertRpgEntryWorldProfile, deleteWorldProfile: deleteRpgEntryWorldProfile, publishWorldProfile: publishRpgEntryWorldProfile, unpublishWorldProfile: unpublishRpgEntryWorldProfile, };