f0cad9dddc
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m28s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m26s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m41s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m56s
Project CI / Backend tests (pull_request) Successful in 9m4s
Project CI / Repository checks (pull_request) Successful in 7m13s
Project CI / Native shell tests (pull_request) Successful in 10m16s
Project CI / Frontend tests (pull_request) Successful in 2m26s
- 同步 master 侧 248 个提交:会员与泥点计费(PR #588 / #603)、创作者主页与关注粉丝(PR #638)、运行页刷新真重载(PR #640)、AGC 模板 templateVersion 递增(PR #643)等;确认 master 未触碰发行网关与 `api-server/src/modules/game_distribution.rs`。 - 冲突 1(server-rs/crates/module-runtime/src/domain.rs:1157-1162)`RuntimeProfileWalletLedgerSourceType` 两侧各自在末尾追加变体:保留 master 的 `MembershipUpgradeGrant` 为索引 16(线上已落库口径),本分支 `GamePurchase` 顺延为索引 17,并保留其「每账号每游戏一次扣费」注释。 - 冲突 2(server-rs/crates/module-runtime/src/domain.rs:1184-1188)`as_str()` 同时保留 `membership_upgrade_grant` 与 `game_purchase` 两个分支。 - 冲突 3(server-rs/crates/spacetime-client/src/active/mapper/runtime_profile.rs:95-101)bindings→领域枚举映射同时保留 `MembershipUpgradeGrant` 与 `GamePurchase` 两支,按新索引顺序排列。 - 冲突 4(server-rs/crates/spacetime-client/src/module_bindings/runtime_profile_wallet_ledger_source_type_type.rs:43-47)生成枚举按模块源码顺序合并为 …`MembershipUpgradeGrant`、`GamePurchase`;随后 `npm run spacetime:generate` 复核该文件与生成结果逐字节一致。 - 冲突 5(server-rs/crates/api-server/src/admin.rs:4849-4853)sats 索引映射改为 `16 => membership_upgrade_grant` 与 `17 => game_purchase` 两条并存。 - 冲突 6(server-rs/crates/api-server/src/admin.rs:6368-6461)索引断言并入 master 的 `[16] => membership_upgrade_grant`,并把 master 的「17 尚未映射」占位断言替换为 `[17] => game_purchase`;本分支的后台消耗统计两个用例原样保留。 - 冲突 7(server-rs/crates/api-server/src/runtime_profile.rs:219-226)来源文案格式化同时保留 `MembershipUpgradeGrant` 与 `GamePurchase` 两支,注释随 `GamePurchase` 保留。 - 冲突 8(docs/project-memory/shared-memory/decision-log.md:3-24)两条决策记录并列保留:本分支 2026-10-05「播放会话前缀在三处入口清空 Cookie」在前,master 2026-10-03「每日免费发放额为 0 时前端隐藏该池」在后。 - 保住 master 侧:发行响应 ETag/304/gzip(`release_asset_response_with_cache` 五参形态与 `release_asset_etag` / `if_none_match_matches` / `accepts_gzip_encoding` / `gzip_release_asset` / `release_asset_not_modified_response`)、共享加载面 `PlatformGameLoadingSurface` 及其使用方、三池钱包与会员档位目录改造。 - 保住本分支侧:付费作品 404 守卫(`price_mud_points > 0` 且位于 `load_package` 之前)、购买与播放会话网关路由、nginx×3 / Pingora / Vite 的播放会话 Cookie 清空与 `nginx-route-parity.matrix.json` 登记、viewer 感知公开详情、后台审核价格、`PlatformGamePricingField` 共享定价组件与两端接入、AGC 项目版本只读 + 平台派发下一版本号、schema 与迁移白名单、钱包来源 `game_purchase`。 - 验证:`git merge-base --is-ancestor origin/master HEAD` 返回 0;`check:encoding`、`check:doc-index`、`check:spacetime-schema`、`check:server-rs-ddd`、`check:rustfmt`、`check:npm-workspaces`、`check:game-distribution-dto-parity`、`check:game-distribution-price-limit-parity`、`check:pingora-route-parity`、`check:nginx-spa-routes`、根/admin-web/AGC typecheck、`git diff --check` 全绿。 - 测试:`cargo test -p module-game-distribution` 30 passed,`cargo test -p api-server game_distribution` 61 passed,`cargo test -p spacetime-module game_distribution` 7 passed;定向 vitest 28 个文件 252 个用例全通过。 - `npm run spacetime:generate` 除 11 个 procedure 文件的纯空白格式差异外无任何语义改动(`git diff -w` 为空),已保留 master 的生成产物形态,提交内无 schema/绑定语义变化。
748 lines
20 KiB
TypeScript
748 lines
20 KiB
TypeScript
import type { JsonObject } from './common';
|
|
import type { AdminUpsertProfileMembershipPlanRequest } from './generated/AdminUpsertProfileMembershipPlanRequest';
|
|
import type { ProfileDailyFreePointsResponse } from './generated/ProfileDailyFreePointsResponse';
|
|
import type { ProfileMembershipChangeKindToken } from './generated/ProfileMembershipChangeKindToken';
|
|
import type { ProfileMembershipCycleKindToken } from './generated/ProfileMembershipCycleKindToken';
|
|
import type { ProfileMembershipModelAccessToken } from './generated/ProfileMembershipModelAccessToken';
|
|
import type { ProfileMembershipPlanAdminListResponse } from './generated/ProfileMembershipPlanAdminListResponse';
|
|
import type { ProfileMembershipPlanResponse } from './generated/ProfileMembershipPlanResponse';
|
|
import type { ProfileMembershipPlanToken } from './generated/ProfileMembershipPlanToken';
|
|
import type { ProfileMembershipResponse } from './generated/ProfileMembershipResponse';
|
|
import type { ProfileMembershipStatusToken } from './generated/ProfileMembershipStatusToken';
|
|
import type { ProfileMembershipUpgradeQuoteRequest } from './generated/ProfileMembershipUpgradeQuoteRequest';
|
|
import type { ProfileMembershipUpgradeQuoteResponse } from './generated/ProfileMembershipUpgradeQuoteResponse';
|
|
import type { ProfileMudPointBalanceResponse as ProfileMudPointBalance } from './generated/ProfileMudPointBalanceResponse';
|
|
import type { ProfileRechargeCenterResponse as GeneratedProfileRechargeCenterResponse } from './generated/ProfileRechargeCenterResponse';
|
|
import type { ProfileRechargeOrderResponse } from './generated/ProfileRechargeOrderResponse';
|
|
import type { ProfileRechargeProductResponse } from './generated/ProfileRechargeProductResponse';
|
|
|
|
export type {
|
|
AdminUpsertProfileMembershipPlanRequest,
|
|
ProfileDailyFreePointsResponse,
|
|
ProfileMembershipChangeKindToken,
|
|
ProfileMembershipCycleKindToken,
|
|
ProfileMembershipModelAccessToken,
|
|
ProfileMembershipPlanAdminListResponse,
|
|
ProfileMembershipPlanResponse,
|
|
ProfileMembershipPlanToken,
|
|
ProfileMembershipResponse,
|
|
ProfileMembershipStatusToken,
|
|
ProfileMembershipUpgradeQuoteRequest,
|
|
ProfileMembershipUpgradeQuoteResponse,
|
|
ProfileMudPointBalance,
|
|
ProfileRechargeOrderResponse,
|
|
ProfileRechargeProductResponse,
|
|
};
|
|
|
|
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<TGameState, TBottomTab, TCurrentStory>,
|
|
'savedAt' | 'version'
|
|
> & {
|
|
savedAt?: string;
|
|
};
|
|
|
|
export type RuntimeSaveCheckpointInput<TBottomTab extends string = string> = {
|
|
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;
|
|
dailyFreePoints?: ProfileDailyFreePoints;
|
|
};
|
|
|
|
export type ProfileDailyFreePoints = ProfileDailyFreePointsResponse;
|
|
|
|
export type ProfileWalletLedgerEntry = {
|
|
id: string;
|
|
amountDelta: number;
|
|
balanceAfter: number;
|
|
sourceType:
|
|
| 'snapshot_sync'
|
|
| 'new_user_registration_reward'
|
|
| 'invite_inviter_reward'
|
|
| 'invite_invitee_reward'
|
|
| 'points_recharge'
|
|
| 'membership_period_grant'
|
|
| 'membership_period_reset'
|
|
| 'membership_upgrade_grant'
|
|
| 'daily_free_grant'
|
|
| 'daily_free_reset'
|
|
| 'asset_operation_consume'
|
|
| 'llm_router_consume'
|
|
| 'asset_operation_refund'
|
|
| 'recharge_refund_recovery'
|
|
| 'redeem_code_reward'
|
|
| 'puzzle_author_incentive_claim'
|
|
| 'daily_task_reward'
|
|
| 'game_purchase';
|
|
createdAt: string;
|
|
reason?: string;
|
|
};
|
|
|
|
export type ProfileWalletLedgerResponse = {
|
|
entries: ProfileWalletLedgerEntry[];
|
|
};
|
|
|
|
export type ExternalApiKeyProfile = {
|
|
keyId: string;
|
|
name: string;
|
|
keyPrefix: string;
|
|
scopes: string[];
|
|
createdAt: string;
|
|
lastUsedAt: string | null;
|
|
revokedAt: string | null;
|
|
updatedAt: string;
|
|
};
|
|
|
|
export type ExternalApiKeyListResponse = {
|
|
keys: ExternalApiKeyProfile[];
|
|
};
|
|
|
|
export type ExternalApiKeyCreateResponse = {
|
|
apiKey: string;
|
|
key: ExternalApiKeyProfile;
|
|
};
|
|
|
|
export type ExternalApiKeyMutationResponse = {
|
|
key: ExternalApiKeyProfile;
|
|
};
|
|
|
|
export type ProfileRechargeProductKind = 'points' | 'membership';
|
|
/** 会员状态:来源 Rust `ProfileMembershipStatusToken`,禁止手工维护字面量。 */
|
|
export type ProfileMembershipStatus = ProfileMembershipStatusToken;
|
|
/** 会员档位:`normal` 是非会员占位档位,不可购买。 */
|
|
export type ProfileMembershipPlan = ProfileMembershipPlanToken;
|
|
/** 会员周期:有效期内不支持月年互换,到期后重新选择。 */
|
|
export type ProfileMembershipCycleKind = ProfileMembershipCycleKindToken;
|
|
/** 模型权限:`basic` 仅基础模型,`full` 基础及高性能模型。 */
|
|
export type ProfileMembershipModelAccess = ProfileMembershipModelAccessToken;
|
|
export type ProfileRechargeOrderStatus =
|
|
| 'pending'
|
|
| 'paid'
|
|
| 'failed'
|
|
| 'closed'
|
|
| 'refunded'
|
|
| 'expired';
|
|
|
|
/** 充点 / 会员商品;`kind` 是前端收窄的联合类型,其余字段以后端生成为准。 */
|
|
export type ProfileRechargeProduct = Omit<
|
|
ProfileRechargeProductResponse,
|
|
'kind'
|
|
> & {
|
|
kind: ProfileRechargeProductKind;
|
|
};
|
|
|
|
/** 会员档位目录行;价格与权益的唯一真相源是后端 `profile_membership_plan` 表。 */
|
|
export type ProfileMembershipPlanRecord = ProfileMembershipPlanResponse;
|
|
|
|
export type ProfileMembership = ProfileMembershipResponse;
|
|
|
|
/** 补差升级报价;下单时后端会用同一套规则重算,前端展示的数字不是真相源。 */
|
|
export type ProfileMembershipUpgradeQuote =
|
|
ProfileMembershipUpgradeQuoteResponse;
|
|
|
|
/** 充值订单;`kind` / `status` 是前端收窄的联合类型,其余字段以后端生成为准。 */
|
|
export type ProfileRechargeOrder = Omit<
|
|
ProfileRechargeOrderResponse,
|
|
'kind' | 'status'
|
|
> & {
|
|
kind: ProfileRechargeProductKind;
|
|
status: ProfileRechargeOrderStatus;
|
|
};
|
|
|
|
/** 充值中心;结构以后端生成为准,仅把商品 / 订单收窄成带联合类型的本地别名。 */
|
|
export type ProfileRechargeCenterResponse = Omit<
|
|
GeneratedProfileRechargeCenterResponse,
|
|
'pointProducts' | 'latestOrder'
|
|
> & {
|
|
pointProducts: ProfileRechargeProduct[];
|
|
latestOrder: ProfileRechargeOrder | null;
|
|
};
|
|
|
|
export type WechatMiniProgramPayParams = {
|
|
appId?: string;
|
|
timeStamp: string;
|
|
nonceStr: string;
|
|
package: string;
|
|
signType: 'RSA';
|
|
paySign: string;
|
|
};
|
|
|
|
export type WechatMiniProgramVirtualPayParams = {
|
|
mode: 'short_series_coin' | 'short_series_goods';
|
|
signData: string;
|
|
paySig: string;
|
|
signature: string;
|
|
};
|
|
|
|
export type WechatH5Payment = {
|
|
h5Url: string;
|
|
};
|
|
|
|
export type WechatNativePayment = {
|
|
codeUrl: string;
|
|
expiresAt: string;
|
|
};
|
|
|
|
export type CreateProfileRechargeOrderRequest = {
|
|
productId: string;
|
|
paymentChannel?: string;
|
|
};
|
|
|
|
export type CreateProfileRechargeOrderResponse = {
|
|
order: ProfileRechargeOrder;
|
|
center: ProfileRechargeCenterResponse;
|
|
wechatMiniProgramPayParams?:
|
|
| WechatMiniProgramPayParams
|
|
| WechatMiniProgramVirtualPayParams
|
|
| null;
|
|
wechatH5Payment?: WechatH5Payment | null;
|
|
wechatNativePayment?: WechatNativePayment | null;
|
|
};
|
|
|
|
export type ConfirmWechatProfileRechargeOrderResponse = {
|
|
order: ProfileRechargeOrder;
|
|
center: ProfileRechargeCenterResponse;
|
|
};
|
|
|
|
export type WechatProfileRechargeOrderDoneEvent = {
|
|
orderId: string;
|
|
status: ProfileRechargeOrderStatus;
|
|
};
|
|
|
|
export type WechatProfileRechargeOrderErrorEvent = {
|
|
message: string;
|
|
};
|
|
|
|
export type ProfileFeedbackStatus = 'open';
|
|
|
|
export type ProfileFeedbackEvidenceItemInput = {
|
|
fileName: string;
|
|
contentType: string;
|
|
sizeBytes: number;
|
|
dataUrl: string;
|
|
};
|
|
|
|
export type SubmitProfileFeedbackRequest = {
|
|
description: string;
|
|
contactPhone?: string | null;
|
|
evidenceItems: ProfileFeedbackEvidenceItemInput[];
|
|
};
|
|
|
|
export type ProfileFeedbackEvidenceItem = {
|
|
evidenceId: string;
|
|
fileName: string;
|
|
contentType: string;
|
|
sizeBytes: number;
|
|
};
|
|
|
|
export type ProfileFeedbackSubmission = {
|
|
feedbackId: string;
|
|
status: ProfileFeedbackStatus;
|
|
createdAt: string;
|
|
evidenceItems: ProfileFeedbackEvidenceItem[];
|
|
};
|
|
|
|
export type SubmitProfileFeedbackResponse = {
|
|
feedback: ProfileFeedbackSubmission;
|
|
};
|
|
|
|
export type ProfileReferralInviteCenterResponse = {
|
|
inviteCode: string;
|
|
inviteLinkPath: string;
|
|
invitedCount: number;
|
|
rewardedInviteCount: number;
|
|
todayInviterRewardCount: number;
|
|
todayInviterRewardRemaining: number;
|
|
rewardPoints: number;
|
|
invitedUsers: ProfileReferralInvitedUser[];
|
|
hasRedeemedCode: boolean;
|
|
boundInviterUserId: string | null;
|
|
boundAt: string | null;
|
|
updatedAt: string;
|
|
};
|
|
|
|
export type ProfileReferralInvitedUser = {
|
|
userId: string;
|
|
displayName: string;
|
|
avatarUrl: string | null;
|
|
boundAt: string;
|
|
};
|
|
|
|
export type RedeemProfileReferralInviteCodeRequest = {
|
|
inviteCode: string;
|
|
};
|
|
|
|
export type RedeemProfileReferralInviteCodeResponse = {
|
|
center: ProfileReferralInviteCenterResponse;
|
|
inviteeRewardGranted: boolean;
|
|
inviterRewardGranted: boolean;
|
|
inviteeBalanceAfter: number;
|
|
inviterBalanceAfter: number;
|
|
};
|
|
|
|
export type RedeemProfileRewardCodeRequest = {
|
|
code: string;
|
|
};
|
|
|
|
export type RedeemProfileRewardCodeResponse = {
|
|
walletBalance: number;
|
|
amountGranted: number;
|
|
ledgerEntry: ProfileWalletLedgerEntry;
|
|
};
|
|
|
|
export type ProfileTaskCycle = 'daily';
|
|
export type TrackingScopeKind = 'site' | 'work' | 'module' | 'user';
|
|
export type AnalyticsGranularity =
|
|
| 'day'
|
|
| 'week'
|
|
| 'month'
|
|
| 'quarter'
|
|
| 'year';
|
|
export type ProfileTaskStatus =
|
|
| 'incomplete'
|
|
| 'claimable'
|
|
| 'claimed'
|
|
| 'disabled';
|
|
|
|
export type ProfileTaskItem = {
|
|
taskId: string;
|
|
title: string;
|
|
description: string;
|
|
eventKey: string;
|
|
cycle: ProfileTaskCycle;
|
|
threshold: number;
|
|
progressCount: number;
|
|
rewardPoints: number;
|
|
status: ProfileTaskStatus;
|
|
dayKey: number;
|
|
claimedAt: string | null;
|
|
updatedAt: string;
|
|
};
|
|
|
|
export type ProfileTaskCenterResponse = {
|
|
dayKey: number;
|
|
walletBalance: number;
|
|
tasks: ProfileTaskItem[];
|
|
updatedAt: string;
|
|
};
|
|
|
|
export type ClaimProfileTaskRewardResponse = {
|
|
taskId: string;
|
|
dayKey: number;
|
|
rewardPoints: number;
|
|
walletBalance: number;
|
|
ledgerEntry: ProfileWalletLedgerEntry;
|
|
center: ProfileTaskCenterResponse;
|
|
};
|
|
|
|
export type ProfileTaskConfigAdminResponse = {
|
|
taskId: string;
|
|
title: string;
|
|
description: string;
|
|
eventKey: string;
|
|
cycle: ProfileTaskCycle;
|
|
scopeKind: TrackingScopeKind;
|
|
threshold: number;
|
|
rewardPoints: number;
|
|
enabled: boolean;
|
|
sortOrder: number;
|
|
createdBy: string;
|
|
createdAt: string;
|
|
updatedBy: string;
|
|
updatedAt: string;
|
|
};
|
|
|
|
export type ProfileTaskConfigAdminListResponse = {
|
|
entries: ProfileTaskConfigAdminResponse[];
|
|
};
|
|
|
|
export type AnalyticsMetricQueryRequest = {
|
|
eventKey: string;
|
|
scopeKind: TrackingScopeKind;
|
|
scopeId: string;
|
|
granularity: AnalyticsGranularity;
|
|
};
|
|
|
|
export type AnalyticsBucketMetric = {
|
|
bucketKey: string;
|
|
bucketStartDateKey: number;
|
|
bucketEndDateKey: number;
|
|
value: number;
|
|
};
|
|
|
|
export type AnalyticsMetricQueryResponse = {
|
|
buckets: AnalyticsBucketMetric[];
|
|
};
|
|
|
|
export type AdminUpsertProfileTaskConfigRequest = {
|
|
taskId: string;
|
|
title: string;
|
|
description?: string | null;
|
|
eventKey: string;
|
|
cycle: ProfileTaskCycle;
|
|
scopeKind: TrackingScopeKind;
|
|
threshold: number;
|
|
rewardPoints: number;
|
|
enabled?: boolean;
|
|
sortOrder?: number;
|
|
};
|
|
|
|
export type AdminDisableProfileTaskConfigRequest = {
|
|
taskId: string;
|
|
};
|
|
|
|
export type ProfileRedeemCodeMode = 'public' | 'unique' | 'private';
|
|
|
|
export type ProfileRedeemCodeAdminResponse = {
|
|
code: string;
|
|
mode: ProfileRedeemCodeMode;
|
|
rewardPoints: number;
|
|
maxUses: number;
|
|
globalUsedCount: number;
|
|
enabled: boolean;
|
|
allowedUserIds: string[];
|
|
startsAt?: string | null;
|
|
expiresAt?: string | null;
|
|
createdBy: string;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
};
|
|
|
|
export type ProfileCodeOperationAdminResponse = {
|
|
operationId: string;
|
|
codeKind: 'redeem' | 'invite' | string;
|
|
code: string;
|
|
action: 'create' | 'update' | 'disable' | string;
|
|
operatorUserId: string;
|
|
createdAt: string;
|
|
};
|
|
|
|
export type ProfileRedeemCodeAdminListResponse = {
|
|
entries: ProfileRedeemCodeAdminResponse[];
|
|
operations: ProfileCodeOperationAdminResponse[];
|
|
};
|
|
|
|
export type AdminUpsertProfileRedeemCodeRequest = {
|
|
code: string;
|
|
mode: ProfileRedeemCodeMode;
|
|
rewardPoints: number;
|
|
maxUses: number;
|
|
enabled?: boolean;
|
|
allowedUserIds?: string[];
|
|
allowedPublicUserCodes?: string[];
|
|
startsAt?: string | null;
|
|
expiresAt?: string | null;
|
|
};
|
|
|
|
export type AdminDisableProfileRedeemCodeRequest = {
|
|
code: string;
|
|
};
|
|
|
|
export type AdminUpsertProfileInviteCodeRequest = {
|
|
inviteCode: string;
|
|
metadata?: Record<string, unknown> | null;
|
|
startsAt?: string | null;
|
|
expiresAt?: string | null;
|
|
};
|
|
|
|
export type ProfileInviteCodeAdminResponse = {
|
|
userId: string;
|
|
inviteCode: string;
|
|
metadata: Record<string, unknown>;
|
|
startsAt?: string | null;
|
|
expiresAt?: string | null;
|
|
status: 'pending' | 'active' | 'expired';
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
};
|
|
|
|
export type ProfileInviteCodeAdminListResponse = {
|
|
entries: ProfileInviteCodeAdminResponse[];
|
|
operations: ProfileCodeOperationAdminResponse[];
|
|
};
|
|
|
|
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<TGameState, TBottomTab, TCurrentStory>;
|
|
};
|
|
|
|
export type CustomWorldPublicationStatus = 'draft' | 'published';
|
|
export type CustomWorldThemeMode =
|
|
| 'martial'
|
|
| 'arcane'
|
|
| 'machina'
|
|
| 'tide'
|
|
| 'rift'
|
|
| 'mythic';
|
|
|
|
export type CustomWorldProfileRecord = JsonObject & {
|
|
id?: string;
|
|
openingCg?: CustomWorldOpeningCgProfile | null;
|
|
};
|
|
|
|
export type CustomWorldOpeningCgStatus =
|
|
| 'not_started'
|
|
| 'storyboard_generating'
|
|
| 'video_generating'
|
|
| 'ready'
|
|
| 'failed';
|
|
|
|
export type CustomWorldOpeningCgProfile = {
|
|
id: string;
|
|
status: CustomWorldOpeningCgStatus;
|
|
storyboardImageSrc?: string | null;
|
|
storyboardAssetId?: string | null;
|
|
videoSrc?: string | null;
|
|
videoAssetId?: string | null;
|
|
posterImageSrc?: string | null;
|
|
posterAssetId?: string | null;
|
|
storyboardPrompt?: string | null;
|
|
videoPrompt?: string | null;
|
|
imageModel: 'gpt-image-2';
|
|
videoModel: string;
|
|
aspectRatio: '16:9';
|
|
imageSize: '2k';
|
|
videoResolution: '480p';
|
|
durationSeconds: 15;
|
|
pointCost: 80;
|
|
estimatedWaitMinutes: 10;
|
|
generatedAt?: string | null;
|
|
updatedAt: string;
|
|
errorMessage?: string | null;
|
|
};
|
|
|
|
export type CustomWorldLibraryEntry<TProfile = CustomWorldProfileRecord> = {
|
|
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;
|
|
playCount?: number;
|
|
remixCount?: number;
|
|
likeCount?: number;
|
|
recentPlayCount7d?: number;
|
|
};
|
|
|
|
export type CustomWorldGalleryCard = Omit<
|
|
CustomWorldLibraryEntry<never>,
|
|
'profile'
|
|
>;
|
|
|
|
export type CustomWorldLibraryResponse<TProfile = CustomWorldProfileRecord> = {
|
|
entries: CustomWorldLibraryEntry<TProfile>[];
|
|
};
|
|
|
|
export type CustomWorldLibraryMutationResponse<
|
|
TProfile = CustomWorldProfileRecord,
|
|
> = {
|
|
entry: CustomWorldLibraryEntry<TProfile>;
|
|
entries: CustomWorldLibraryEntry<TProfile>[];
|
|
};
|
|
|
|
export type CustomWorldGalleryResponse = {
|
|
entries: CustomWorldGalleryCard[];
|
|
};
|
|
|
|
export type CustomWorldGalleryDetailResponse<
|
|
TProfile = CustomWorldProfileRecord,
|
|
> = {
|
|
entry: CustomWorldLibraryEntry<TProfile>;
|
|
};
|
|
|
|
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;
|
|
};
|