import type { BarkBattleWorkSummary } from '../../../packages/shared/src/contracts/barkBattle'; import type { BigFishWorkSummary } from '../../../packages/shared/src/contracts/bigFishWorkSummary'; import type { BabyObjectMatchDraft } from '../../../packages/shared/src/contracts/edutainmentBabyObject'; import type { JumpHopGalleryCardResponse } from '../../../packages/shared/src/contracts/jumpHop'; import type { Match3DWorkSummary } from '../../../packages/shared/src/contracts/match3dWorks'; import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary'; import type { CustomWorldGalleryCard, CustomWorldLibraryEntry, } from '../../../packages/shared/src/contracts/runtime'; import type { SquareHoleWorkSummary } from '../../../packages/shared/src/contracts/squareHoleWorks'; import type { VisualNovelWorkSummary } from '../../../packages/shared/src/contracts/visualNovel'; import type { WoodenFishGalleryCardResponse } from '../../../packages/shared/src/contracts/woodenFish'; import { isSameBabyObjectMatchPublicWorkCode, isSameBarkBattlePublicWorkCode, isSameBigFishPublicWorkCode, isSameJumpHopPublicWorkCode, isSameMatch3DPublicWorkCode, isSamePuzzlePublicWorkCode, isSameSquareHolePublicWorkCode, isSameVisualNovelPublicWorkCode, isSameWoodenFishPublicWorkCode, } from '../../services/publicWorkCode'; import type { CustomWorldProfile } from '../../types'; import type { PlatformPublicGalleryCard } from '../rpg-entry/rpgEntryWorldPresentation'; import { mapBabyObjectMatchDraftToPlatformGalleryCard } from '../rpg-entry/rpgEntryWorldPresentation'; import { canExposePublicWork } from './platformEdutainmentVisibility'; import { mapMatch3DWorkToPublicWorkDetail } from './platformMatch3DRuntimeProfile'; import { mapBarkBattleWorkToPublicWorkDetail, mapBigFishWorkToPublicWorkDetail, mapJumpHopWorkToPublicWorkDetail, mapPuzzleWorkToPublicWorkDetail, mapSquareHoleWorkToPublicWorkDetail, mapVisualNovelWorkToPublicWorkDetail, mapWoodenFishWorkToPublicWorkDetail, } from './platformPublicWorkDetailFlow'; export type PlatformPublicCodeSearchStep = | 'user-id' | 'public-user-code' | 'rpg-work' | 'puzzle-work' | 'big-fish-work' | 'jump-hop-work' | 'wooden-fish-work' | 'baby-object-match-work' | 'match3d-work' | 'square-hole-work' | 'visual-novel-work' | 'bark-battle-work'; export type PlatformPublicCodeSearchPlan = { normalizedKeyword: string; steps: readonly PlatformPublicCodeSearchStep[]; }; export type PlatformPublicCodeSearchMatch = { item: TItem; detail: PlatformPublicGalleryCard; }; type PlatformPublicCodeSearchMatcherInput = { keyword: string; entries: readonly TItem[]; mapEntry: (item: TItem) => PlatformPublicGalleryCard; matchesEntry: (keyword: string, item: TItem) => boolean; canExposeEntry?: (entry: PlatformPublicGalleryCard) => boolean; }; const PLATFORM_PUBLIC_USER_ID_PATTERN = /^user[_-][a-z0-9_-]+$/iu; const PLATFORM_RPG_WORK_NUMERIC_CODE_PATTERN = /^\d{1,8}$/u; const DIRECT_WORK_PREFIX_STEPS: ReadonlyArray< readonly [prefix: string, step: PlatformPublicCodeSearchStep] > = [ ['PZ', 'puzzle-work'], ['BF', 'big-fish-work'], ['JH', 'jump-hop-work'], ['WF', 'wooden-fish-work'], ['BO', 'baby-object-match-work'], ['M3', 'match3d-work'], ['SH', 'square-hole-work'], ['VN', 'visual-novel-work'], ['BB', 'bark-battle-work'], ]; /** 收口公开码搜索顺序,壳层只按步骤执行网络读取与打开副作用。 */ export function resolvePlatformPublicCodeSearchPlan( keyword: string, ): PlatformPublicCodeSearchPlan | null { const normalizedKeyword = keyword.trim(); if (!normalizedKeyword) { return null; } if (PLATFORM_PUBLIC_USER_ID_PATTERN.test(normalizedKeyword)) { return { normalizedKeyword, steps: ['user-id'], }; } const upperKeyword = normalizedKeyword.toUpperCase(); const directWorkStep = DIRECT_WORK_PREFIX_STEPS.find(([prefix]) => upperKeyword.startsWith(prefix), )?.[1]; if (directWorkStep) { return { normalizedKeyword, steps: [directWorkStep], }; } if ( upperKeyword.startsWith('CW') || PLATFORM_RPG_WORK_NUMERIC_CODE_PATTERN.test(normalizedKeyword) ) { return { normalizedKeyword, steps: ['rpg-work', 'public-user-code'], }; } return { normalizedKeyword, steps: [ 'public-user-code', 'rpg-work', 'bark-battle-work', 'public-user-code', ], }; } export function mapRpgPublicCodeSearchDetailToGalleryCard( entry: CustomWorldLibraryEntry, ): CustomWorldGalleryCard { return { ownerUserId: entry.ownerUserId, profileId: entry.profileId, publicWorkCode: entry.publicWorkCode, authorPublicUserCode: entry.authorPublicUserCode, visibility: 'published', publishedAt: entry.publishedAt, updatedAt: entry.updatedAt, authorDisplayName: entry.authorDisplayName, worldName: entry.worldName, subtitle: entry.subtitle, summaryText: entry.summaryText, coverImageSrc: entry.coverImageSrc, themeMode: entry.themeMode, playableNpcCount: entry.playableNpcCount, landmarkCount: entry.landmarkCount, playCount: entry.playCount ?? 0, remixCount: entry.remixCount ?? 0, likeCount: entry.likeCount ?? 0, }; } export function resolvePuzzlePublicCodeSearchMatch( entries: readonly PuzzleWorkSummary[], keyword: string, canExposeEntry = canExposePublicWork, ) { return resolveMappedPublicCodeSearchMatch({ keyword, entries, mapEntry: mapPuzzleWorkToPublicWorkDetail, matchesEntry: (searchKeyword, item) => isSamePuzzlePublicWorkCode(searchKeyword, item.profileId), canExposeEntry, }); } export function resolveBigFishPublicCodeSearchMatch( entries: readonly BigFishWorkSummary[], keyword: string, canExposeEntry = canExposePublicWork, ) { return resolveMappedPublicCodeSearchMatch({ keyword, entries, mapEntry: mapBigFishWorkToPublicWorkDetail, matchesEntry: (searchKeyword, item) => isSameBigFishPublicWorkCode(searchKeyword, item.sourceSessionId), canExposeEntry, }); } export function resolveJumpHopPublicCodeSearchMatch( entries: readonly JumpHopGalleryCardResponse[], keyword: string, canExposeEntry = canExposePublicWork, ) { return resolveMappedPublicCodeSearchMatch({ keyword, entries, mapEntry: mapJumpHopWorkToPublicWorkDetail, matchesEntry: (searchKeyword, item) => isSameJumpHopPublicWorkCode(searchKeyword, item.profileId), canExposeEntry, }); } export function resolveWoodenFishPublicCodeSearchMatch( entries: readonly WoodenFishGalleryCardResponse[], keyword: string, canExposeEntry = canExposePublicWork, ) { return resolveMappedPublicCodeSearchMatch({ keyword, entries, mapEntry: mapWoodenFishWorkToPublicWorkDetail, matchesEntry: (searchKeyword, item) => isSameWoodenFishPublicWorkCode(searchKeyword, item.profileId), canExposeEntry, }); } export function resolveBabyObjectMatchPublicCodeSearchMatch( entries: readonly BabyObjectMatchDraft[], keyword: string, canExposeEntry = canExposePublicWork, ) { return resolveMappedPublicCodeSearchMatch({ keyword, entries, mapEntry: mapBabyObjectMatchDraftToPlatformGalleryCard, matchesEntry: (searchKeyword, item) => isSameBabyObjectMatchPublicWorkCode(searchKeyword, item.profileId), canExposeEntry, }); } export function resolveMatch3DPublicCodeSearchMatch( entries: readonly Match3DWorkSummary[], keyword: string, canExposeEntry = canExposePublicWork, ) { return resolveMappedPublicCodeSearchMatch({ keyword, entries, mapEntry: mapMatch3DWorkToPublicWorkDetail, matchesEntry: (searchKeyword, item) => isSameMatch3DPublicWorkCode(searchKeyword, item.profileId), canExposeEntry, }); } export function resolveSquareHolePublicCodeSearchMatch( entries: readonly SquareHoleWorkSummary[], keyword: string, canExposeEntry = canExposePublicWork, ) { return resolveMappedPublicCodeSearchMatch({ keyword, entries, mapEntry: mapSquareHoleWorkToPublicWorkDetail, matchesEntry: (searchKeyword, item) => isSameSquareHolePublicWorkCode(searchKeyword, item.profileId), canExposeEntry, }); } export function resolveVisualNovelPublicCodeSearchMatch( entries: readonly VisualNovelWorkSummary[], keyword: string, canExposeEntry = canExposePublicWork, ) { return resolveMappedPublicCodeSearchMatch({ keyword, entries, mapEntry: mapVisualNovelWorkToPublicWorkDetail, matchesEntry: (searchKeyword, item) => isSameVisualNovelPublicWorkCode(searchKeyword, item.profileId), canExposeEntry, }); } export function resolveBarkBattlePublicCodeSearchMatch( entries: readonly BarkBattleWorkSummary[], keyword: string, canExposeEntry = canExposePublicWork, ) { return resolveMappedPublicCodeSearchMatch({ keyword, entries, mapEntry: mapBarkBattleWorkToPublicWorkDetail, matchesEntry: (searchKeyword, item) => isSameBarkBattlePublicWorkCode(searchKeyword, item.workId), canExposeEntry, }); } function resolveMappedPublicCodeSearchMatch({ keyword, entries, mapEntry, matchesEntry, canExposeEntry = canExposePublicWork, }: PlatformPublicCodeSearchMatcherInput): | PlatformPublicCodeSearchMatch | null { for (const item of entries) { const detail = mapEntry(item); if (canExposeEntry(detail) && matchesEntry(keyword, item)) { return { item, detail }; } } return null; }