refactor(data): split models into separate dto and schema modules
Reorganize the data layer by separating DTOs (Data Transfer Objects) from Zod validation schemas into distinct directory structures. Previously, all model types were imported from a single `@/data/models` barrel file, mixing request/response classes with validation schemas. Changes: - Update API files (auth, chat, metrics, user) to import DTOs from specific paths under `@/data/dto/*` instead of the models barrel - Move user schema to `@/data/schemas/user/user` for type-only imports - Create dedicated Zod schema files under `@/data/schemas/*` for auth and chat domain models (e.g., AppleLoginRequestSchema, SendMessageRequestSchema, SyncMessageSchema, SttDataSchema) - Improve discoverability and tree-shaking by co-locating schemas with their respective domain areas This is a non-functional refactor that lays the groundwork for clearer separation between transport-layer types and runtime validation.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 头像数据 DTO
|
||||
*/
|
||||
import {
|
||||
AvatarDataSchema,
|
||||
type AvatarDataInput,
|
||||
type AvatarDataData,
|
||||
} from "@/data/schemas/user/avatar_data";
|
||||
|
||||
export class AvatarData {
|
||||
declare readonly avatarUrl: string;
|
||||
declare readonly userId: string;
|
||||
|
||||
private constructor(input: AvatarDataInput) {
|
||||
const data = AvatarDataSchema.parse(input);
|
||||
Object.assign(this, data);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: AvatarDataInput): AvatarData {
|
||||
return new AvatarData(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): AvatarData {
|
||||
return AvatarData.from(json as AvatarDataInput);
|
||||
}
|
||||
|
||||
toJson(): AvatarDataData {
|
||||
return AvatarDataSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 积分数据 DTO
|
||||
*/
|
||||
import {
|
||||
CreditsDataSchema,
|
||||
type CreditsDataInput,
|
||||
type CreditsDataData,
|
||||
} from "@/data/schemas/user/credits_data";
|
||||
|
||||
export class CreditsData {
|
||||
declare readonly userId: string;
|
||||
declare readonly dolBalance: number;
|
||||
|
||||
private constructor(input: CreditsDataInput) {
|
||||
const data = CreditsDataSchema.parse(input);
|
||||
Object.assign(this, data);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: CreditsDataInput): CreditsData {
|
||||
return new CreditsData(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): CreditsData {
|
||||
return CreditsData.from(json as CreditsDataInput);
|
||||
}
|
||||
|
||||
toJson(): CreditsDataData {
|
||||
return CreditsDataSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 积分历史记录 DTO
|
||||
*/
|
||||
import {
|
||||
CreditsHistoryDataSchema,
|
||||
type CreditsHistoryDataInput,
|
||||
type CreditsHistoryDataData,
|
||||
} from "@/data/schemas/user/credits_history_data";
|
||||
|
||||
export class CreditsHistoryData {
|
||||
declare readonly records: Record<string, unknown>[];
|
||||
declare readonly total: number;
|
||||
declare readonly limit: number;
|
||||
declare readonly offset: number;
|
||||
|
||||
private constructor(input: CreditsHistoryDataInput) {
|
||||
const data = CreditsHistoryDataSchema.parse(input);
|
||||
Object.assign(this, data);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: CreditsHistoryDataInput): CreditsHistoryData {
|
||||
return new CreditsHistoryData(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): CreditsHistoryData {
|
||||
return CreditsHistoryData.from(json as CreditsHistoryDataInput);
|
||||
}
|
||||
|
||||
toJson(): CreditsHistoryDataData {
|
||||
return CreditsHistoryDataSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 个性特征 DTO
|
||||
*/
|
||||
import {
|
||||
PersonalityTraitsSchema,
|
||||
type PersonalityTraitsInput,
|
||||
type PersonalityTraitsData,
|
||||
} from "@/data/schemas/user/personality_traits";
|
||||
|
||||
export class PersonalityTraits {
|
||||
declare readonly cheerful: number;
|
||||
declare readonly caring: number;
|
||||
declare readonly playful: number;
|
||||
declare readonly serious: number;
|
||||
declare readonly romantic: number;
|
||||
|
||||
private constructor(input: PersonalityTraitsInput) {
|
||||
const data = PersonalityTraitsSchema.parse(input);
|
||||
Object.assign(this, data);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: PersonalityTraitsInput): PersonalityTraits {
|
||||
return new PersonalityTraits(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): PersonalityTraits {
|
||||
return PersonalityTraits.from(json as PersonalityTraitsInput);
|
||||
}
|
||||
|
||||
toJson(): PersonalityTraitsData {
|
||||
return PersonalityTraitsSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 最近记忆 DTO
|
||||
*/
|
||||
import {
|
||||
RecentMemorySchema,
|
||||
type RecentMemoryInput,
|
||||
type RecentMemoryData,
|
||||
} from "@/data/schemas/user/recent_memory";
|
||||
|
||||
export class RecentMemory {
|
||||
declare readonly type: string;
|
||||
declare readonly content: string;
|
||||
declare readonly importance: number;
|
||||
declare readonly createdAt: string;
|
||||
|
||||
private constructor(input: RecentMemoryInput) {
|
||||
const data = RecentMemorySchema.parse(input);
|
||||
Object.assign(this, data);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: RecentMemoryInput): RecentMemory {
|
||||
return new RecentMemory(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): RecentMemory {
|
||||
return RecentMemory.from(json as RecentMemoryInput);
|
||||
}
|
||||
|
||||
toJson(): RecentMemoryData {
|
||||
return RecentMemorySchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 更新个人资料请求 DTO
|
||||
*/
|
||||
import {
|
||||
UpdateProfileRequestSchema,
|
||||
type UpdateProfileRequestInput,
|
||||
type UpdateProfileRequestData,
|
||||
} from "@/data/schemas/user/update_profile_request";
|
||||
|
||||
export class UpdateProfileRequest {
|
||||
declare readonly username: string;
|
||||
declare readonly nickname: string;
|
||||
declare readonly preferredLanguage: string;
|
||||
declare readonly currentMood: string;
|
||||
|
||||
private constructor(input: UpdateProfileRequestInput) {
|
||||
const data = UpdateProfileRequestSchema.parse(input);
|
||||
Object.assign(this, data);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: UpdateProfileRequestInput): UpdateProfileRequest {
|
||||
return new UpdateProfileRequest(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): UpdateProfileRequest {
|
||||
return UpdateProfileRequest.from(json as UpdateProfileRequestInput);
|
||||
}
|
||||
|
||||
toJson(): UpdateProfileRequestData {
|
||||
return UpdateProfileRequestSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 用户 DTO
|
||||
*/
|
||||
import {
|
||||
UserSchema,
|
||||
type UserInput,
|
||||
type UserData,
|
||||
} from "@/data/schemas/user/user";
|
||||
import { PersonalityTraits } from "./personality_traits";
|
||||
|
||||
export class User {
|
||||
declare readonly id: string;
|
||||
declare readonly username: string;
|
||||
declare readonly email: string;
|
||||
declare readonly platform: string;
|
||||
declare readonly intimacy: number;
|
||||
declare readonly dolBalance: number;
|
||||
declare readonly relationshipStage: string;
|
||||
declare readonly currentMood: string;
|
||||
declare readonly personalityTraits: PersonalityTraits;
|
||||
declare readonly preferredLanguage: string;
|
||||
declare readonly createdAt: string;
|
||||
declare readonly lastMessageAt: string;
|
||||
declare readonly avatarUrl: string;
|
||||
declare readonly loginProvider: string;
|
||||
declare readonly isGuest: boolean;
|
||||
|
||||
private constructor(input: UserInput) {
|
||||
const data = UserSchema.parse(input);
|
||||
Object.assign(this, {
|
||||
...data,
|
||||
personalityTraits: PersonalityTraits.from(data.personalityTraits),
|
||||
});
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: UserInput): User {
|
||||
return new User(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): User {
|
||||
return User.from(json as UserInput);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个具有空 id/username 的 User 实例(用于可选 user 字段的默认占位)
|
||||
*/
|
||||
static empty(): User {
|
||||
return new User({ id: "", username: "" });
|
||||
}
|
||||
|
||||
toJson(): UserData {
|
||||
const { personalityTraits, ...rest } = this;
|
||||
return {
|
||||
...rest,
|
||||
personalityTraits: personalityTraits.toJson(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 用户统计响应 DTO
|
||||
*/
|
||||
import {
|
||||
UserStatsResponseSchema,
|
||||
type UserStatsResponseInput,
|
||||
type UserStatsResponseData,
|
||||
} from "@/data/schemas/user/user_stats_response";
|
||||
import { PersonalityTraits } from "./personality_traits";
|
||||
import { RecentMemory } from "./recent_memory";
|
||||
|
||||
export class UserStatsResponse {
|
||||
declare readonly userId: string;
|
||||
declare readonly username: string;
|
||||
declare readonly platform: string;
|
||||
declare readonly intimacy: number;
|
||||
declare readonly relationshipStage: string;
|
||||
declare readonly dolBalance: number;
|
||||
declare readonly totalMessages: number;
|
||||
declare readonly lastMessageAt: string;
|
||||
declare readonly accountCreatedAt: string;
|
||||
declare readonly currentMood: string;
|
||||
declare readonly personalityTraits: PersonalityTraits;
|
||||
declare readonly recentMemories: RecentMemory[];
|
||||
declare readonly promptTokensTotal: number;
|
||||
declare readonly completionTokensTotal: number;
|
||||
declare readonly cacheHitTokensTotal: number;
|
||||
declare readonly tokensTotal: number;
|
||||
|
||||
private constructor(input: UserStatsResponseInput) {
|
||||
const data = UserStatsResponseSchema.parse(input);
|
||||
Object.assign(this, {
|
||||
...data,
|
||||
personalityTraits: PersonalityTraits.from(data.personalityTraits),
|
||||
recentMemories: data.recentMemories.map((m) => RecentMemory.from(m)),
|
||||
});
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: UserStatsResponseInput): UserStatsResponse {
|
||||
return new UserStatsResponse(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): UserStatsResponse {
|
||||
return UserStatsResponse.from(json as UserStatsResponseInput);
|
||||
}
|
||||
|
||||
toJson(): UserStatsResponseData {
|
||||
return UserStatsResponseSchema.parse(this);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user