import type { JsonObject } from './common'; export const SAVE_SNAPSHOT_VERSION = 2; export const DEFAULT_MUSIC_VOLUME = 0.42; export const DEFAULT_PLATFORM_THEME = 'light'; export const PLATFORM_THEMES = ['light', 'dark'] as const; export type PlatformTheme = (typeof PLATFORM_THEMES)[number]; export type SavedGameSnapshot< TGameState = unknown, TBottomTab extends string = string, TCurrentStory = unknown, > = { version: number; savedAt: string; gameState: TGameState; bottomTab: TBottomTab; currentStory: TCurrentStory | null; }; export type SavedGameSnapshotInput< TGameState = unknown, TBottomTab extends string = string, TCurrentStory = unknown, > = Omit< SavedGameSnapshot, 'savedAt' | 'version' > & { savedAt?: string; }; export type RuntimeSaveCheckpointInput = { sessionId: string; bottomTab: TBottomTab; savedAt?: string; }; export type RuntimeSettings = { musicVolume: number; platformTheme: PlatformTheme; }; export type BasicOkResult = { ok: true; }; export type ProfileDashboardCardKey = 'wallet' | 'playTime' | 'playedWorks'; export type ProfileDashboardSummary = { walletBalance: number; totalPlayTimeMs: number; playedWorldCount: number; updatedAt: string | null; }; export type ProfileWalletLedgerEntry = { id: string; amountDelta: number; balanceAfter: number; sourceType: | 'snapshot_sync' | 'invite_inviter_reward' | 'invite_invitee_reward' | 'points_recharge' | 'asset_generation_consume' | 'asset_generation_refund'; createdAt: string; }; export type ProfileWalletLedgerResponse = { entries: ProfileWalletLedgerEntry[]; }; export type ProfileRechargeProductKind = 'points' | 'membership'; export type ProfileMembershipStatus = 'normal' | 'active'; export type ProfileMembershipTier = 'normal' | 'month' | 'season' | 'year'; export type ProfileRechargeOrderStatus = 'paid'; export type ProfileRechargeProduct = { productId: string; title: string; priceCents: number; kind: ProfileRechargeProductKind; pointsAmount: number; bonusPoints: number; durationDays: number; badgeLabel: string; description: string; tier: ProfileMembershipTier; }; export type ProfileMembershipBenefit = { benefitName: string; normalValue: string; monthValue: string; seasonValue: string; yearValue: string; }; export type ProfileMembership = { status: ProfileMembershipStatus; tier: ProfileMembershipTier; startedAt: string | null; expiresAt: string | null; updatedAt: string | null; }; export type ProfileRechargeOrder = { orderId: string; productId: string; productTitle: string; kind: ProfileRechargeProductKind; amountCents: number; status: ProfileRechargeOrderStatus; paymentChannel: string; paidAt: string; createdAt: string; pointsDelta: number; membershipExpiresAt: string | null; }; export type ProfileRechargeCenterResponse = { walletBalance: number; membership: ProfileMembership; pointProducts: ProfileRechargeProduct[]; membershipProducts: ProfileRechargeProduct[]; benefits: ProfileMembershipBenefit[]; latestOrder: ProfileRechargeOrder | null; hasPointsRecharged: boolean; }; export type CreateProfileRechargeOrderRequest = { productId: string; paymentChannel?: string; }; export type CreateProfileRechargeOrderResponse = { order: ProfileRechargeOrder; center: ProfileRechargeCenterResponse; }; export type ProfileReferralInviteCenterResponse = { inviteCode: string; inviteLinkPath: string; invitedCount: number; rewardedInviteCount: number; todayInviterRewardCount: number; todayInviterRewardRemaining: number; rewardPoints: number; hasRedeemedCode: boolean; boundInviterUserId: string | null; boundAt: string | null; updatedAt: string; }; export type RedeemProfileReferralInviteCodeRequest = { inviteCode: string; }; export type RedeemProfileReferralInviteCodeResponse = { center: ProfileReferralInviteCenterResponse; inviteeRewardGranted: boolean; inviterRewardGranted: boolean; inviteeBalanceAfter: number; inviterBalanceAfter: number; }; export type ProfilePlayedWorkSummary = { worldKey: string; ownerUserId: string | null; profileId: string | null; worldType: string | null; worldTitle: string; worldSubtitle: string; firstPlayedAt: string; lastPlayedAt: string; lastObservedPlayTimeMs: number; }; export type ProfilePlayStatsResponse = { totalPlayTimeMs: number; playedWorks: ProfilePlayedWorkSummary[]; updatedAt: string | null; }; export type ProfileSaveArchiveSummary = { worldKey: string; ownerUserId: string | null; profileId: string | null; worldType: string | null; worldName: string; subtitle: string; summaryText: string; coverImageSrc: string | null; lastPlayedAt: string; }; export type ProfileSaveArchiveListResponse = { entries: ProfileSaveArchiveSummary[]; }; export type ProfileSaveArchiveResumeResponse< TGameState = unknown, TBottomTab extends string = string, TCurrentStory = unknown, > = { entry: ProfileSaveArchiveSummary; snapshot: SavedGameSnapshot; }; export type CustomWorldPublicationStatus = 'draft' | 'published'; export type CustomWorldThemeMode = | 'martial' | 'arcane' | 'machina' | 'tide' | 'rift' | 'mythic'; export type CustomWorldProfileRecord = JsonObject & { id?: string; }; export type CustomWorldLibraryEntry = { ownerUserId: string; profileId: string; publicWorkCode: string | null; authorPublicUserCode: string | null; profile: TProfile; visibility: CustomWorldPublicationStatus; publishedAt: string | null; updatedAt: string; authorDisplayName: string; worldName: string; subtitle: string; summaryText: string; coverImageSrc: string | null; themeMode: CustomWorldThemeMode; playableNpcCount: number; landmarkCount: number; }; export type CustomWorldGalleryCard = Omit< CustomWorldLibraryEntry, 'profile' >; export type CustomWorldLibraryResponse = { entries: CustomWorldLibraryEntry[]; }; export type CustomWorldLibraryMutationResponse< TProfile = CustomWorldProfileRecord, > = { entry: CustomWorldLibraryEntry; entries: CustomWorldLibraryEntry[]; }; export type CustomWorldGalleryResponse = { entries: CustomWorldGalleryCard[]; }; export type CustomWorldGalleryDetailResponse< TProfile = CustomWorldProfileRecord, > = { entry: CustomWorldLibraryEntry; }; export type PlatformBrowseHistoryEntry = { ownerUserId: string; profileId: string; worldName: string; subtitle: string; summaryText: string; coverImageSrc: string | null; themeMode: CustomWorldThemeMode; authorDisplayName: string; visitedAt: string; }; export type PlatformBrowseHistoryWriteEntry = Omit< PlatformBrowseHistoryEntry, 'visitedAt' > & { visitedAt?: string; }; export type PlatformBrowseHistoryResponse = { entries: PlatformBrowseHistoryEntry[]; }; export type PlatformBrowseHistoryBatchSyncRequest = { entries: PlatformBrowseHistoryWriteEntry[]; }; export const CUSTOM_WORLD_GENERATION_MODES = ['fast', 'full'] as const; export type CustomWorldGenerationMode = (typeof CUSTOM_WORLD_GENERATION_MODES)[number]; export const CUSTOM_WORLD_SESSION_STATUSES = [ 'clarifying', 'ready_to_generate', 'generating', 'completed', 'generation_error', ] as const; export type CustomWorldSessionStatus = (typeof CUSTOM_WORLD_SESSION_STATUSES)[number]; export type CustomWorldQuestion = { id: string; label: string; question: string; answer?: string; }; export type CustomWorldGenerationStep = { id: string; label: string; detail: string; completed: number; total: number; status: 'pending' | 'active' | 'completed'; }; export type CustomWorldGenerationProgress = { phaseId: string; phaseLabel: string; phaseDetail: string; batchLabel?: string; overallProgress: number; completedWeight: number; totalWeight: number; elapsedMs: number; estimatedRemainingMs: number | null; activeStepIndex: number; steps: CustomWorldGenerationStep[]; }; export type GenerateCustomWorldProfileOptions = { onProgress?: (progress: CustomWorldGenerationProgress) => void; signal?: AbortSignal; }; export type GenerateCustomWorldProfileInput = { settingText: string; creatorIntent?: JsonObject | null; generationMode?: CustomWorldGenerationMode; }; export type CreateCustomWorldSessionRequest = { settingText: string; creatorIntent?: JsonObject | null; generationMode: CustomWorldGenerationMode; }; export type AnswerCustomWorldSessionQuestionRequest = { questionId: string; answer: string; }; export type CustomWorldSessionSummary = { sessionId: string; status: CustomWorldSessionStatus; questions: CustomWorldQuestion[]; createdAt: string; updatedAt: string; }; export type CustomWorldSessionRecord = CustomWorldSessionSummary & { settingText: string; creatorIntent?: JsonObject | null; generationMode: CustomWorldGenerationMode; result?: JsonObject; lastError?: string; };