refactor(models): migrate 28 data models to Zod schema-driven pattern

This commit is contained in:
2026-06-08 14:50:20 +08:00
parent 700ad0bc1a
commit d7943f5f06
36 changed files with 1204 additions and 1358 deletions
+24 -25
View File
@@ -2,36 +2,35 @@
* Apple 登录请求
* 原始 Dart: AppleLoginRequest (lib/data/models/auth/auth_request.dart)
*/
export class AppleLoginRequest {
readonly identityToken: string;
readonly platform: string;
import { z } from "zod";
constructor(params: { identityToken: string; platform: string }) {
this.identityToken = params.identityToken;
this.platform = params.platform;
export const AppleLoginRequestSchema = z.object({
identityToken: z.string(),
platform: z.string(),
});
export type AppleLoginRequestInput = z.input<typeof AppleLoginRequestSchema>;
export type AppleLoginRequestData = z.output<typeof AppleLoginRequestSchema>;
export class AppleLoginRequest {
declare readonly identityToken: string;
declare readonly platform: string;
private constructor(input: AppleLoginRequestInput) {
const data = AppleLoginRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
identityToken: this.identityToken,
platform: this.platform,
};
static from(input: AppleLoginRequestInput): AppleLoginRequest {
return new AppleLoginRequest(input);
}
static fromJson(json: Record<string, unknown>): AppleLoginRequest {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`AppleLoginRequest.${key} is required and must be a string`
);
}
return v;
};
return new AppleLoginRequest({
identityToken: requireString("identityToken"),
platform: requireString("platform"),
});
static fromJson(json: unknown): AppleLoginRequest {
return AppleLoginRequest.from(json as AppleLoginRequestInput);
}
toJson(): AppleLoginRequestData {
return AppleLoginRequestSchema.parse(this);
}
}
+26 -35
View File
@@ -1,47 +1,38 @@
/**
* Facebook 登录请求
* 原始 Dart: FacebookLoginRequest (lib/data/models/auth/auth_request.dart)
*
* 注:原始 Dart 中 `guestId` 为 `String?`,按"全部非空"约定统一兜底为空串。
*/
export class FacebookLoginRequest {
readonly accessToken: string;
readonly platform: string;
readonly guestId: string;
import { z } from "zod";
constructor(params: {
accessToken: string;
platform: string;
guestId?: string;
}) {
this.accessToken = params.accessToken;
this.platform = params.platform;
this.guestId = params.guestId ?? "";
export const FacebookLoginRequestSchema = z.object({
accessToken: z.string(),
platform: z.string(),
guestId: z.string().default(""),
});
export type FacebookLoginRequestInput = z.input<typeof FacebookLoginRequestSchema>;
export type FacebookLoginRequestData = z.output<typeof FacebookLoginRequestSchema>;
export class FacebookLoginRequest {
declare readonly accessToken: string;
declare readonly platform: string;
declare readonly guestId: string;
private constructor(input: FacebookLoginRequestInput) {
const data = FacebookLoginRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
accessToken: this.accessToken,
platform: this.platform,
guestId: this.guestId,
};
static from(input: FacebookLoginRequestInput): FacebookLoginRequest {
return new FacebookLoginRequest(input);
}
static fromJson(json: Record<string, unknown>): FacebookLoginRequest {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`FacebookLoginRequest.${key} is required and must be a string`
);
}
return v;
};
return new FacebookLoginRequest({
accessToken: requireString("accessToken"),
platform: requireString("platform"),
guestId: typeof json.guestId === "string" ? json.guestId : undefined,
});
static fromJson(json: unknown): FacebookLoginRequest {
return FacebookLoginRequest.from(json as FacebookLoginRequestInput);
}
toJson(): FacebookLoginRequestData {
return FacebookLoginRequestSchema.parse(this);
}
}
+24 -25
View File
@@ -1,37 +1,36 @@
/**
* Facebook ID 登录请求
* 原始 Dart: FbIdLoginRequest (lib/data/models/auth/auth_request.dart)
*
* 注:原始 Dart 中 `avatarUrl` 为 `String?`,按"全部非空"约定统一兜底为空串。
*/
export class FbIdLoginRequest {
readonly fbId: string;
readonly avatarUrl: string;
import { z } from "zod";
constructor(params: { fbId: string; avatarUrl?: string }) {
this.fbId = params.fbId;
this.avatarUrl = params.avatarUrl ?? "";
export const FbIdLoginRequestSchema = z.object({
fbId: z.string(),
avatarUrl: z.string().default(""),
});
export type FbIdLoginRequestInput = z.input<typeof FbIdLoginRequestSchema>;
export type FbIdLoginRequestData = z.output<typeof FbIdLoginRequestSchema>;
export class FbIdLoginRequest {
declare readonly fbId: string;
declare readonly avatarUrl: string;
private constructor(input: FbIdLoginRequestInput) {
const data = FbIdLoginRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
fbId: this.fbId,
avatarUrl: this.avatarUrl,
};
static from(input: FbIdLoginRequestInput): FbIdLoginRequest {
return new FbIdLoginRequest(input);
}
static fromJson(json: Record<string, unknown>): FbIdLoginRequest {
const fbId = json.fbId;
if (typeof fbId !== "string") {
throw new Error(
"FbIdLoginRequest.fbId is required and must be a string"
);
}
return new FbIdLoginRequest({
fbId,
avatarUrl:
typeof json.avatarUrl === "string" ? json.avatarUrl : undefined,
});
static fromJson(json: unknown): FbIdLoginRequest {
return FbIdLoginRequest.from(json as FbIdLoginRequestInput);
}
toJson(): FbIdLoginRequestData {
return FbIdLoginRequestSchema.parse(this);
}
}
+26 -35
View File
@@ -1,47 +1,38 @@
/**
* Google 登录请求
* 原始 Dart: GoogleLoginRequest (lib/data/models/auth/auth_request.dart)
*
* 注:原始 Dart 中 `guestId` 为 `String?`,按"全部非空"约定统一兜底为空串。
*/
export class GoogleLoginRequest {
readonly idToken: string;
readonly platform: string;
readonly guestId: string;
import { z } from "zod";
constructor(params: {
idToken: string;
platform: string;
guestId?: string;
}) {
this.idToken = params.idToken;
this.platform = params.platform;
this.guestId = params.guestId ?? "";
export const GoogleLoginRequestSchema = z.object({
idToken: z.string(),
platform: z.string(),
guestId: z.string().default(""),
});
export type GoogleLoginRequestInput = z.input<typeof GoogleLoginRequestSchema>;
export type GoogleLoginRequestData = z.output<typeof GoogleLoginRequestSchema>;
export class GoogleLoginRequest {
declare readonly idToken: string;
declare readonly platform: string;
declare readonly guestId: string;
private constructor(input: GoogleLoginRequestInput) {
const data = GoogleLoginRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
idToken: this.idToken,
platform: this.platform,
guestId: this.guestId,
};
static from(input: GoogleLoginRequestInput): GoogleLoginRequest {
return new GoogleLoginRequest(input);
}
static fromJson(json: Record<string, unknown>): GoogleLoginRequest {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`GoogleLoginRequest.${key} is required and must be a string`
);
}
return v;
};
return new GoogleLoginRequest({
idToken: requireString("idToken"),
platform: requireString("platform"),
guestId: typeof json.guestId === "string" ? json.guestId : undefined,
});
static fromJson(json: unknown): GoogleLoginRequest {
return GoogleLoginRequest.from(json as GoogleLoginRequestInput);
}
toJson(): GoogleLoginRequestData {
return GoogleLoginRequestSchema.parse(this);
}
}
+22 -14
View File
@@ -2,25 +2,33 @@
* 游客登录请求
* 原始 Dart: GuestLoginRequest (lib/data/models/auth/auth_request.dart)
*/
export class GuestLoginRequest {
readonly deviceId: string;
import { z } from "zod";
constructor(params: { deviceId: string }) {
this.deviceId = params.deviceId;
export const GuestLoginRequestSchema = z.object({
deviceId: z.string(),
});
export type GuestLoginRequestInput = z.input<typeof GuestLoginRequestSchema>;
export type GuestLoginRequestData = z.output<typeof GuestLoginRequestSchema>;
export class GuestLoginRequest {
declare readonly deviceId: string;
private constructor(input: GuestLoginRequestInput) {
const data = GuestLoginRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return { deviceId: this.deviceId };
static from(input: GuestLoginRequestInput): GuestLoginRequest {
return new GuestLoginRequest(input);
}
static fromJson(json: Record<string, unknown>): GuestLoginRequest {
const deviceId = json.deviceId;
if (typeof deviceId !== "string") {
throw new Error(
"GuestLoginRequest.deviceId is required and must be a string"
);
}
return new GuestLoginRequest({ deviceId });
static fromJson(json: unknown): GuestLoginRequest {
return GuestLoginRequest.from(json as GuestLoginRequestInput);
}
toJson(): GuestLoginRequestData {
return GuestLoginRequestSchema.parse(this);
}
}
+37 -58
View File
@@ -1,73 +1,52 @@
/**
* 游客登录响应
* 原始 Dart: GuestLoginResponse (lib/data/models/auth/auth_response.dart)
*
* 注:原始 Dart 中 `user` 为 `User?`,按"全部非空"约定兜底为默认 User 实例
* id/username 为空串,使用方可通过 user.id === "" 判定无用户数据)。
*/
import { User } from "../user/user";
import { z } from "zod";
import { User, UserSchema } from "../user/user";
export const GuestLoginResponseSchema = z.object({
token: z.string(),
deviceId: z.string(),
userId: z.string(),
isDeviceUser: z.boolean().default(true),
expiresIn: z.number().default(2592000),
user: UserSchema.optional(),
});
export type GuestLoginResponseInput = z.input<typeof GuestLoginResponseSchema>;
export type GuestLoginResponseData = z.output<typeof GuestLoginResponseSchema>;
export class GuestLoginResponse {
readonly token: string;
readonly deviceId: string;
readonly userId: string;
readonly isDeviceUser: boolean;
readonly expiresIn: number;
readonly user: User;
declare readonly token: string;
declare readonly deviceId: string;
declare readonly userId: string;
declare readonly isDeviceUser: boolean;
declare readonly expiresIn: number;
declare readonly user: User;
constructor(params: {
token: string;
deviceId: string;
userId: string;
isDeviceUser?: boolean;
expiresIn?: number;
user?: User;
}) {
this.token = params.token;
this.deviceId = params.deviceId;
this.userId = params.userId;
this.isDeviceUser = params.isDeviceUser ?? true;
this.expiresIn = params.expiresIn ?? 2592000;
this.user = params.user ?? new User({ id: "", username: "" });
private constructor(data: GuestLoginResponseData) {
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
token: this.token,
deviceId: this.deviceId,
userId: this.userId,
isDeviceUser: this.isDeviceUser,
expiresIn: this.expiresIn,
user: this.user.toJson(),
};
static from(input: GuestLoginResponseInput): GuestLoginResponse {
const parsed = GuestLoginResponseSchema.parse(input);
return new GuestLoginResponse({
...parsed,
user: parsed.user ?? User.empty(),
});
}
static fromJson(json: Record<string, unknown>): GuestLoginResponse {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`GuestLoginResponse.${key} is required and must be a string`
);
}
return v;
};
const userJson = json.user;
const user: User =
typeof userJson === "object" && userJson !== null
? User.fromJson(userJson as Record<string, unknown>)
: new User({ id: "", username: "" });
return new GuestLoginResponse({
token: requireString("token"),
deviceId: requireString("deviceId"),
userId: requireString("userId"),
isDeviceUser:
typeof json.isDeviceUser === "boolean"
? json.isDeviceUser
: undefined,
expiresIn: typeof json.expiresIn === "number" ? json.expiresIn : undefined,
user,
static fromJson(json: unknown): GuestLoginResponse {
return GuestLoginResponse.from(json as GuestLoginResponseInput);
}
toJson(): GuestLoginResponseData {
const { user, ...rest } = this;
return GuestLoginResponseSchema.parse({
...rest,
...(user.id !== "" ? { user } : {}),
});
}
}
+30 -46
View File
@@ -1,58 +1,42 @@
/**
* 登录请求 - 支持用户名或邮箱登录
* 原始 Dart: LoginRequest (lib/data/models/auth/auth_request.dart)
*
* 注:原始 Dart 中 `email`/`username`/`guestId` 为 `String?`,按"全部非空"约定统一兜底为空串。
* 后端校验 email 与 username 至少传入一个。
*/
export class LoginRequest {
readonly email: string;
readonly username: string;
readonly password: string;
readonly platform: string;
readonly guestId: string;
import { z } from "zod";
constructor(params: {
email?: string;
username?: string;
password: string;
platform: string;
guestId?: string;
}) {
this.email = params.email ?? "";
this.username = params.username ?? "";
this.password = params.password;
this.platform = params.platform;
this.guestId = params.guestId ?? "";
export const LoginRequestSchema = z.object({
email: z.string().default(""),
username: z.string().default(""),
password: z.string(),
platform: z.string(),
guestId: z.string().default(""),
});
export type LoginRequestInput = z.input<typeof LoginRequestSchema>;
export type LoginRequestData = z.output<typeof LoginRequestSchema>;
export class LoginRequest {
declare readonly email: string;
declare readonly username: string;
declare readonly password: string;
declare readonly platform: string;
declare readonly guestId: string;
private constructor(input: LoginRequestInput) {
const data = LoginRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
email: this.email,
username: this.username,
password: this.password,
platform: this.platform,
guestId: this.guestId,
};
static from(input: LoginRequestInput): LoginRequest {
return new LoginRequest(input);
}
static fromJson(json: Record<string, unknown>): LoginRequest {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`LoginRequest.${key} is required and must be a string`
);
}
return v;
};
return new LoginRequest({
email: typeof json.email === "string" ? json.email : undefined,
username: typeof json.username === "string" ? json.username : undefined,
password: requireString("password"),
platform: requireString("platform"),
guestId: typeof json.guestId === "string" ? json.guestId : undefined,
});
static fromJson(json: unknown): LoginRequest {
return LoginRequest.from(json as LoginRequestInput);
}
toJson(): LoginRequestData {
return LoginRequestSchema.parse(this);
}
}
+25 -29
View File
@@ -2,42 +2,38 @@
* 登录响应
* 原始 Dart: LoginResponse (lib/data/models/auth/auth_response.dart)
*/
import { User } from "../user/user";
import { z } from "zod";
import { User, UserSchema } from "../user/user";
export const LoginResponseSchema = z.object({
user: UserSchema,
token: z.string(),
refreshToken: z.string().default(""),
});
export type LoginResponseInput = z.input<typeof LoginResponseSchema>;
export type LoginResponseData = z.output<typeof LoginResponseSchema>;
export class LoginResponse {
readonly user: User;
readonly token: string;
readonly refreshToken: string;
declare readonly user: User;
declare readonly token: string;
declare readonly refreshToken: string;
constructor(params: { user: User; token: string; refreshToken?: string }) {
this.user = params.user;
this.token = params.token;
this.refreshToken = params.refreshToken ?? "";
private constructor(input: LoginResponseInput) {
const data = LoginResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
user: this.user.toJson(),
token: this.token,
refreshToken: this.refreshToken,
};
static from(input: LoginResponseInput): LoginResponse {
return new LoginResponse(input);
}
static fromJson(json: Record<string, unknown>): LoginResponse {
const token = json.token;
if (typeof token !== "string") {
throw new Error("LoginResponse.token is required and must be a string");
}
const userJson = json.user;
if (typeof userJson !== "object" || userJson === null) {
throw new Error("LoginResponse.user is required and must be an object");
}
return new LoginResponse({
user: User.fromJson(userJson as Record<string, unknown>),
token,
refreshToken:
typeof json.refreshToken === "string" ? json.refreshToken : undefined,
});
static fromJson(json: unknown): LoginResponse {
return LoginResponse.from(json as LoginResponseInput);
}
toJson(): LoginResponseData {
return LoginResponseSchema.parse(this);
}
}
+22 -10
View File
@@ -2,21 +2,33 @@
* 退出登录响应
* 原始 Dart: LogoutResponse (lib/data/models/auth/auth_response.dart)
*/
export class LogoutResponse {
readonly success: boolean;
import { z } from "zod";
constructor(params: { success?: boolean }) {
this.success = params.success ?? true;
export const LogoutResponseSchema = z.object({
success: z.boolean().default(true),
});
export type LogoutResponseInput = z.input<typeof LogoutResponseSchema>;
export type LogoutResponseData = z.output<typeof LogoutResponseSchema>;
export class LogoutResponse {
declare readonly success: boolean;
private constructor(input: LogoutResponseInput) {
const data = LogoutResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return { success: this.success };
static from(input: LogoutResponseInput): LogoutResponse {
return new LogoutResponse(input);
}
static fromJson(json: Record<string, unknown>): LogoutResponse {
return new LogoutResponse({
success: typeof json.success === "boolean" ? json.success : undefined,
});
static fromJson(json: unknown): LogoutResponse {
return LogoutResponse.from(json as LogoutResponseInput);
}
toJson(): LogoutResponseData {
return LogoutResponseSchema.parse(this);
}
}
+22 -14
View File
@@ -2,25 +2,33 @@
* 刷新 Token 请求
* 原始 Dart: RefreshTokenRequest (lib/data/models/auth/auth_request.dart)
*/
export class RefreshTokenRequest {
readonly refreshToken: string;
import { z } from "zod";
constructor(params: { refreshToken: string }) {
this.refreshToken = params.refreshToken;
export const RefreshTokenRequestSchema = z.object({
refreshToken: z.string(),
});
export type RefreshTokenRequestInput = z.input<typeof RefreshTokenRequestSchema>;
export type RefreshTokenRequestData = z.output<typeof RefreshTokenRequestSchema>;
export class RefreshTokenRequest {
declare readonly refreshToken: string;
private constructor(input: RefreshTokenRequestInput) {
const data = RefreshTokenRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return { refreshToken: this.refreshToken };
static from(input: RefreshTokenRequestInput): RefreshTokenRequest {
return new RefreshTokenRequest(input);
}
static fromJson(json: Record<string, unknown>): RefreshTokenRequest {
const refreshToken = json.refreshToken;
if (typeof refreshToken !== "string") {
throw new Error(
"RefreshTokenRequest.refreshToken is required and must be a string"
);
}
return new RefreshTokenRequest({ refreshToken });
static fromJson(json: unknown): RefreshTokenRequest {
return RefreshTokenRequest.from(json as RefreshTokenRequestInput);
}
toJson(): RefreshTokenRequestData {
return RefreshTokenRequestSchema.parse(this);
}
}
+26 -33
View File
@@ -2,44 +2,37 @@
* 刷新 Token 响应
* 原始 Dart: RefreshTokenResponse (lib/data/models/auth/auth_response.dart)
*/
export class RefreshTokenResponse {
readonly token: string;
readonly refreshToken: string;
readonly userId: string;
import { z } from "zod";
constructor(params: {
token: string;
refreshToken: string;
userId: string;
}) {
this.token = params.token;
this.refreshToken = params.refreshToken;
this.userId = params.userId;
export const RefreshTokenResponseSchema = z.object({
token: z.string(),
refreshToken: z.string(),
userId: z.string(),
});
export type RefreshTokenResponseInput = z.input<typeof RefreshTokenResponseSchema>;
export type RefreshTokenResponseData = z.output<typeof RefreshTokenResponseSchema>;
export class RefreshTokenResponse {
declare readonly token: string;
declare readonly refreshToken: string;
declare readonly userId: string;
private constructor(input: RefreshTokenResponseInput) {
const data = RefreshTokenResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
token: this.token,
refreshToken: this.refreshToken,
userId: this.userId,
};
static from(input: RefreshTokenResponseInput): RefreshTokenResponse {
return new RefreshTokenResponse(input);
}
static fromJson(json: Record<string, unknown>): RefreshTokenResponse {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`RefreshTokenResponse.${key} is required and must be a string`
);
}
return v;
};
return new RefreshTokenResponse({
token: requireString("token"),
refreshToken: requireString("refreshToken"),
userId: requireString("userId"),
});
static fromJson(json: unknown): RefreshTokenResponse {
return RefreshTokenResponse.from(json as RefreshTokenResponseInput);
}
toJson(): RefreshTokenResponseData {
return RefreshTokenResponseSchema.parse(this);
}
}
+30 -45
View File
@@ -1,57 +1,42 @@
/**
* 注册请求
* 原始 Dart: RegisterRequest (lib/data/models/auth/auth_request.dart)
*
* 注:原始 Dart 中 `guestId` 为 `String?`,按"全部非空"约定统一兜底为空串。
*/
export class RegisterRequest {
readonly username: string;
readonly email: string;
readonly password: string;
readonly platform: string;
readonly guestId: string;
import { z } from "zod";
constructor(params: {
username: string;
email: string;
password: string;
platform: string;
guestId?: string;
}) {
this.username = params.username;
this.email = params.email;
this.password = params.password;
this.platform = params.platform;
this.guestId = params.guestId ?? "";
export const RegisterRequestSchema = z.object({
username: z.string(),
email: z.string(),
password: z.string(),
platform: z.string(),
guestId: z.string().default(""),
});
export type RegisterRequestInput = z.input<typeof RegisterRequestSchema>;
export type RegisterRequestData = z.output<typeof RegisterRequestSchema>;
export class RegisterRequest {
declare readonly username: string;
declare readonly email: string;
declare readonly password: string;
declare readonly platform: string;
declare readonly guestId: string;
private constructor(input: RegisterRequestInput) {
const data = RegisterRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
username: this.username,
email: this.email,
password: this.password,
platform: this.platform,
guestId: this.guestId,
};
static from(input: RegisterRequestInput): RegisterRequest {
return new RegisterRequest(input);
}
static fromJson(json: Record<string, unknown>): RegisterRequest {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`RegisterRequest.${key} is required and must be a string`
);
}
return v;
};
return new RegisterRequest({
username: requireString("username"),
email: requireString("email"),
password: requireString("password"),
platform: requireString("platform"),
guestId: typeof json.guestId === "string" ? json.guestId : undefined,
});
static fromJson(json: unknown): RegisterRequest {
return RegisterRequest.from(json as RegisterRequestInput);
}
toJson(): RegisterRequestData {
return RegisterRequestSchema.parse(this);
}
}
+22 -14
View File
@@ -2,25 +2,33 @@
* 发送验证码请求
* 原始 Dart: SendCodeRequest (lib/data/models/auth/auth_request.dart)
*/
export class SendCodeRequest {
readonly email: string;
import { z } from "zod";
constructor(params: { email: string }) {
this.email = params.email;
export const SendCodeRequestSchema = z.object({
email: z.string(),
});
export type SendCodeRequestInput = z.input<typeof SendCodeRequestSchema>;
export type SendCodeRequestData = z.output<typeof SendCodeRequestSchema>;
export class SendCodeRequest {
declare readonly email: string;
private constructor(input: SendCodeRequestInput) {
const data = SendCodeRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return { email: this.email };
static from(input: SendCodeRequestInput): SendCodeRequest {
return new SendCodeRequest(input);
}
static fromJson(json: Record<string, unknown>): SendCodeRequest {
const email = json.email;
if (typeof email !== "string") {
throw new Error(
"SendCodeRequest.email is required and must be a string"
);
}
return new SendCodeRequest({ email });
static fromJson(json: unknown): SendCodeRequest {
return SendCodeRequest.from(json as SendCodeRequestInput);
}
toJson(): SendCodeRequestData {
return SendCodeRequestSchema.parse(this);
}
}
+27 -46
View File
@@ -1,60 +1,41 @@
/**
* 聊天历史响应
* 原始 Dart: ChatHistoryResponse (lib/data/models/chat/chat_response.dart)
*
* 注:原始 Dart 中 `total` 为 `int?`,按"全部非空"约定兜底为 0。
*/
import { ChatMessage } from "./chat_message";
import { z } from "zod";
import { ChatMessage, ChatMessageSchema } from "./chat_message";
export const ChatHistoryResponseSchema = z.object({
messages: z.array(ChatMessageSchema),
total: z.number().default(0),
limit: z.number(),
offset: z.number(),
});
export type ChatHistoryResponseInput = z.input<typeof ChatHistoryResponseSchema>;
export type ChatHistoryResponseData = z.output<typeof ChatHistoryResponseSchema>;
export class ChatHistoryResponse {
readonly messages: ChatMessage[];
readonly total: number;
readonly limit: number;
readonly offset: number;
declare readonly messages: ChatMessage[];
declare readonly total: number;
declare readonly limit: number;
declare readonly offset: number;
constructor(params: {
messages: ChatMessage[];
total?: number;
limit: number;
offset: number;
}) {
this.messages = params.messages;
this.total = params.total ?? 0;
this.limit = params.limit;
this.offset = params.offset;
private constructor(input: ChatHistoryResponseInput) {
const data = ChatHistoryResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
messages: this.messages.map((m) => m.toJson()),
total: this.total,
limit: this.limit,
offset: this.offset,
};
static from(input: ChatHistoryResponseInput): ChatHistoryResponse {
return new ChatHistoryResponse(input);
}
static fromJson(json: Record<string, unknown>): ChatHistoryResponse {
const requireNumber = (key: string): number => {
const v = json[key];
if (typeof v !== "number") {
throw new Error(
`ChatHistoryResponse.${key} is required and must be a number`
);
}
return v;
};
const rawMessages = json.messages;
const messages: ChatMessage[] = Array.isArray(rawMessages)
? (rawMessages as Record<string, unknown>[]).map((m) =>
ChatMessage.fromJson(m)
)
: [];
return new ChatHistoryResponse({
messages,
total: typeof json.total === "number" ? json.total : undefined,
limit: requireNumber("limit"),
offset: requireNumber("offset"),
});
static fromJson(json: unknown): ChatHistoryResponse {
return ChatHistoryResponse.from(json as ChatHistoryResponseInput);
}
toJson(): ChatHistoryResponseData {
return ChatHistoryResponseSchema.parse(this);
}
}
+28 -41
View File
@@ -1,53 +1,40 @@
/**
* 聊天历史中的单条消息
* 原始 Dart: ChatMessage (lib/data/models/chat/chat_response.dart)
*
* 注:原始 Dart 中 `id`/`createdAt` 为 `String?`,按"全部非空"约定兜底为空串。
*/
export class ChatMessage {
readonly role: string;
readonly content: string;
readonly id: string;
readonly createdAt: string;
import { z } from "zod";
constructor(params: {
role: string;
content: string;
id?: string;
createdAt?: string;
}) {
this.role = params.role;
this.content = params.content;
this.id = params.id ?? "";
this.createdAt = params.createdAt ?? "";
export const ChatMessageSchema = z.object({
role: z.string(),
content: z.string(),
id: z.string().default(""),
createdAt: z.string().default(""),
});
export type ChatMessageInput = z.input<typeof ChatMessageSchema>;
export type ChatMessageData = z.output<typeof ChatMessageSchema>;
export class ChatMessage {
declare readonly role: string;
declare readonly content: string;
declare readonly id: string;
declare readonly createdAt: string;
private constructor(input: ChatMessageInput) {
const data = ChatMessageSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
role: this.role,
content: this.content,
id: this.id,
createdAt: this.createdAt,
};
static from(input: ChatMessageInput): ChatMessage {
return new ChatMessage(input);
}
static fromJson(json: Record<string, unknown>): ChatMessage {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`ChatMessage.${key} is required and must be a string`
);
}
return v;
};
return new ChatMessage({
role: requireString("role"),
content: requireString("content"),
id: typeof json.id === "string" ? json.id : undefined,
createdAt:
typeof json.createdAt === "string" ? json.createdAt : undefined,
});
static fromJson(json: unknown): ChatMessage {
return ChatMessage.from(json as ChatMessageInput);
}
toJson(): ChatMessageData {
return ChatMessageSchema.parse(this);
}
}
+42 -86
View File
@@ -1,98 +1,54 @@
/**
* 发送消息响应
* 原始 Dart: ChatSendResponse (lib/data/models/chat/chat_response.dart)
*
* 注:原始 Dart 中 `mode`/`currentMood`/`isGuest` 为可空字段,按"全部非空"约定兜底:
* - 字符串 → ""
* - bool → false
* - int → 0
*/
export class ChatSendResponse {
readonly mode: string;
readonly reply: string;
readonly voiceUrl: string;
readonly audioUrl: string;
readonly intimacyChange: number;
readonly newIntimacy: number;
readonly relationshipStage: string;
readonly currentMood: string;
readonly messageId: string;
readonly isGuest: boolean;
readonly timestamp: number;
import { z } from "zod";
constructor(params: {
mode?: string;
reply: string;
voiceUrl?: string;
audioUrl?: string;
intimacyChange?: number;
newIntimacy?: number;
relationshipStage: string;
currentMood?: string;
messageId: string;
isGuest?: boolean;
timestamp?: number;
}) {
this.mode = params.mode ?? "";
this.reply = params.reply;
this.voiceUrl = params.voiceUrl ?? "";
this.audioUrl = params.audioUrl ?? "";
this.intimacyChange = params.intimacyChange ?? 0;
this.newIntimacy = params.newIntimacy ?? 0;
this.relationshipStage = params.relationshipStage;
this.currentMood = params.currentMood ?? "";
this.messageId = params.messageId;
this.isGuest = params.isGuest ?? false;
this.timestamp = params.timestamp ?? 0;
export const ChatSendResponseSchema = z.object({
mode: z.string().default(""),
reply: z.string(),
voiceUrl: z.string().default(""),
audioUrl: z.string().default(""),
intimacyChange: z.number().default(0),
newIntimacy: z.number().default(0),
relationshipStage: z.string(),
currentMood: z.string().default(""),
messageId: z.string(),
isGuest: z.boolean().default(false),
timestamp: z.number().default(0),
});
export type ChatSendResponseInput = z.input<typeof ChatSendResponseSchema>;
export type ChatSendResponseData = z.output<typeof ChatSendResponseSchema>;
export class ChatSendResponse {
declare readonly mode: string;
declare readonly reply: string;
declare readonly voiceUrl: string;
declare readonly audioUrl: string;
declare readonly intimacyChange: number;
declare readonly newIntimacy: number;
declare readonly relationshipStage: string;
declare readonly currentMood: string;
declare readonly messageId: string;
declare readonly isGuest: boolean;
declare readonly timestamp: number;
private constructor(input: ChatSendResponseInput) {
const data = ChatSendResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
mode: this.mode,
reply: this.reply,
voiceUrl: this.voiceUrl,
audioUrl: this.audioUrl,
intimacyChange: this.intimacyChange,
newIntimacy: this.newIntimacy,
relationshipStage: this.relationshipStage,
currentMood: this.currentMood,
messageId: this.messageId,
isGuest: this.isGuest,
timestamp: this.timestamp,
};
static from(input: ChatSendResponseInput): ChatSendResponse {
return new ChatSendResponse(input);
}
static fromJson(json: Record<string, unknown>): ChatSendResponse {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`ChatSendResponse.${key} is required and must be a string`
);
}
return v;
};
return new ChatSendResponse({
mode: typeof json.mode === "string" ? json.mode : undefined,
reply: requireString("reply"),
voiceUrl:
typeof json.voiceUrl === "string" ? json.voiceUrl : undefined,
audioUrl:
typeof json.audioUrl === "string" ? json.audioUrl : undefined,
intimacyChange:
typeof json.intimacyChange === "number"
? json.intimacyChange
: undefined,
newIntimacy:
typeof json.newIntimacy === "number" ? json.newIntimacy : undefined,
relationshipStage: requireString("relationshipStage"),
currentMood:
typeof json.currentMood === "string" ? json.currentMood : undefined,
messageId: requireString("messageId"),
isGuest: typeof json.isGuest === "boolean" ? json.isGuest : undefined,
timestamp:
typeof json.timestamp === "number" ? json.timestamp : undefined,
});
static fromJson(json: unknown): ChatSendResponse {
return ChatSendResponse.from(json as ChatSendResponseInput);
}
toJson(): ChatSendResponseData {
return ChatSendResponseSchema.parse(this);
}
}
+24 -25
View File
@@ -2,36 +2,35 @@
* 消息同步响应
* 原始 Dart: ChatSyncData (lib/data/models/chat/chat_sync.dart)
*/
export class ChatSyncData {
readonly syncedCount: number;
readonly totalHistory: number;
import { z } from "zod";
constructor(params: { syncedCount: number; totalHistory: number }) {
this.syncedCount = params.syncedCount;
this.totalHistory = params.totalHistory;
export const ChatSyncDataSchema = z.object({
syncedCount: z.number(),
totalHistory: z.number(),
});
export type ChatSyncDataInput = z.input<typeof ChatSyncDataSchema>;
export type ChatSyncDataData = z.output<typeof ChatSyncDataSchema>;
export class ChatSyncData {
declare readonly syncedCount: number;
declare readonly totalHistory: number;
private constructor(input: ChatSyncDataInput) {
const data = ChatSyncDataSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
syncedCount: this.syncedCount,
totalHistory: this.totalHistory,
};
static from(input: ChatSyncDataInput): ChatSyncData {
return new ChatSyncData(input);
}
static fromJson(json: Record<string, unknown>): ChatSyncData {
const requireNumber = (key: string): number => {
const v = json[key];
if (typeof v !== "number") {
throw new Error(
`ChatSyncData.${key} is required and must be a number`
);
}
return v;
};
return new ChatSyncData({
syncedCount: requireNumber("syncedCount"),
totalHistory: requireNumber("totalHistory"),
});
static fromJson(json: unknown): ChatSyncData {
return ChatSyncData.from(json as ChatSyncDataInput);
}
toJson(): ChatSyncDataData {
return ChatSyncDataSchema.parse(this);
}
}
+21 -14
View File
@@ -2,27 +2,34 @@
* 消息同步请求
* 原始 Dart: ChatSyncRequest (lib/data/models/chat/chat_sync.dart)
*/
import { SyncMessage } from "./sync_message";
import { z } from "zod";
import { SyncMessage, SyncMessageSchema } from "./sync_message";
export const ChatSyncRequestSchema = z.object({
messages: z.array(SyncMessageSchema),
});
export type ChatSyncRequestInput = z.input<typeof ChatSyncRequestSchema>;
export type ChatSyncRequestData = z.output<typeof ChatSyncRequestSchema>;
export class ChatSyncRequest {
readonly messages: SyncMessage[];
declare readonly messages: SyncMessage[];
constructor(params: { messages: SyncMessage[] }) {
this.messages = params.messages;
private constructor(input: ChatSyncRequestInput) {
const data = ChatSyncRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return { messages: this.messages.map((m) => m.toJson()) };
static from(input: ChatSyncRequestInput): ChatSyncRequest {
return new ChatSyncRequest(input);
}
static fromJson(json: Record<string, unknown>): ChatSyncRequest {
const rawMessages = json.messages;
const messages: SyncMessage[] = Array.isArray(rawMessages)
? (rawMessages as Record<string, unknown>[]).map((m) =>
SyncMessage.fromJson(m)
)
: [];
return new ChatSyncRequest({ messages });
static fromJson(json: unknown): ChatSyncRequest {
return ChatSyncRequest.from(json as ChatSyncRequestInput);
}
toJson(): ChatSyncRequestData {
return ChatSyncRequestSchema.parse(this);
}
}
+30 -33
View File
@@ -2,17 +2,23 @@
* 游客每日聊天配额数据
* 原始 Dart: GuestChatQuota (lib/data/models/chat/guest_chat_quota.dart)
*
* 注:原始 Dart 中的静态常量与运行时环境判断方法isDevelopment)已迁移为
* 静态成员。环境检测逻辑(threshold / totalQuotaDefault 等)保留为方法,
* 内部使用 `process.env.NODE_ENV` 替代 Dart 中的 `AppEnvUtil.isDevelopment`
* `initial()` 工厂方法已迁移为静态方法;`needReset` getter 保留为实例方法。
*
* Dart 中 `initial()` 依赖 `app_date.DateUtils.todayString()`
* 在 TS 中由调用方通过 `date` 字段传入。
* 注:保留原始 Dart 中的静态常量与运行时环境判断方法
* `process.env.NODE_ENV` 替代 Dart 的 `AppEnvUtil.isDevelopment`。
* `initial()` 工厂方法与 `needReset` 实例方法保留
*/
import { z } from "zod";
export const GuestChatQuotaSchema = z.object({
remaining: z.number(),
date: z.string(),
});
export type GuestChatQuotaInput = z.input<typeof GuestChatQuotaSchema>;
export type GuestChatQuotaData = z.output<typeof GuestChatQuotaSchema>;
export class GuestChatQuota {
readonly remaining: number;
readonly date: string;
declare readonly remaining: number;
declare readonly date: string;
// 静态常量
static readonly maxQuotaPerDay = 40;
@@ -23,12 +29,24 @@ export class GuestChatQuota {
static readonly defaultTotalQuotaDev = 5;
static readonly quotaExhausted = 0;
constructor(params: { remaining: number; date: string }) {
this.remaining = params.remaining;
this.date = params.date;
private constructor(input: GuestChatQuotaInput) {
const data = GuestChatQuotaSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: GuestChatQuotaInput): GuestChatQuota {
return new GuestChatQuota(input);
}
static fromJson(json: unknown): GuestChatQuota {
return GuestChatQuota.from(json as GuestChatQuotaInput);
}
toJson(): GuestChatQuotaData {
return GuestChatQuotaSchema.parse(this);
}
/**
* 配额耗尽状态值(便捷引用)
*/
@@ -89,25 +107,4 @@ export class GuestChatQuota {
needsReset(todayString: string): boolean {
return this.date !== todayString;
}
toJson(): Record<string, unknown> {
return {
remaining: this.remaining,
date: this.date,
};
}
static fromJson(json: Record<string, unknown>): GuestChatQuota {
const remaining = json.remaining;
const date = json.date;
if (typeof remaining !== "number") {
throw new Error(
"GuestChatQuota.remaining is required and must be a number"
);
}
if (typeof date !== "string") {
throw new Error("GuestChatQuota.date is required and must be a string");
}
return new GuestChatQuota({ remaining, date });
}
}
+36 -67
View File
@@ -2,78 +2,47 @@
* 图片上传响应
* 原始 Dart: ImageUploadResponse (lib/data/models/chat/image_upload_response.dart)
*/
export class ImageUploadResponse {
readonly success: boolean;
readonly imageId: string;
readonly thumbUrl: string;
readonly mediumUrl: string;
readonly originalUrl: string;
readonly width: number;
readonly height: number;
readonly bytes: number;
import { z } from "zod";
constructor(params: {
success?: boolean;
imageId: string;
thumbUrl: string;
mediumUrl: string;
originalUrl: string;
width: number;
height: number;
bytes: number;
}) {
this.success = params.success ?? true;
this.imageId = params.imageId;
this.thumbUrl = params.thumbUrl;
this.mediumUrl = params.mediumUrl;
this.originalUrl = params.originalUrl;
this.width = params.width;
this.height = params.height;
this.bytes = params.bytes;
export const ImageUploadResponseSchema = z.object({
success: z.boolean().default(true),
imageId: z.string(),
thumbUrl: z.string(),
mediumUrl: z.string(),
originalUrl: z.string(),
width: z.number(),
height: z.number(),
bytes: z.number(),
});
export type ImageUploadResponseInput = z.input<typeof ImageUploadResponseSchema>;
export type ImageUploadResponseData = z.output<typeof ImageUploadResponseSchema>;
export class ImageUploadResponse {
declare readonly success: boolean;
declare readonly imageId: string;
declare readonly thumbUrl: string;
declare readonly mediumUrl: string;
declare readonly originalUrl: string;
declare readonly width: number;
declare readonly height: number;
declare readonly bytes: number;
private constructor(input: ImageUploadResponseInput) {
const data = ImageUploadResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
success: this.success,
imageId: this.imageId,
thumbUrl: this.thumbUrl,
mediumUrl: this.mediumUrl,
originalUrl: this.originalUrl,
width: this.width,
height: this.height,
bytes: this.bytes,
};
static from(input: ImageUploadResponseInput): ImageUploadResponse {
return new ImageUploadResponse(input);
}
static fromJson(json: Record<string, unknown>): ImageUploadResponse {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`ImageUploadResponse.${key} is required and must be a string`
);
}
return v;
};
const requireNumber = (key: string): number => {
const v = json[key];
if (typeof v !== "number") {
throw new Error(
`ImageUploadResponse.${key} is required and must be a number`
);
}
return v;
};
return new ImageUploadResponse({
success: typeof json.success === "boolean" ? json.success : undefined,
imageId: requireString("imageId"),
thumbUrl: requireString("thumbUrl"),
mediumUrl: requireString("mediumUrl"),
originalUrl: requireString("originalUrl"),
width: requireNumber("width"),
height: requireNumber("height"),
bytes: requireNumber("bytes"),
});
static fromJson(json: unknown): ImageUploadResponse {
return ImageUploadResponse.from(json as ImageUploadResponseInput);
}
toJson(): ImageUploadResponseData {
return ImageUploadResponseSchema.parse(this);
}
}
+38 -70
View File
@@ -1,82 +1,50 @@
/**
* 发送消息请求 - 用于 /api/chat/send 接口
* 原始 Dart: SendMessageRequest (lib/data/models/chat/send_message_request.dart)
*
* 注:原始 Dart 中所有图片相关字段为可空,按"全部非空"约定兜底:
* - 字符串 → ""
* - 数字 → 0
*/
export class SendMessageRequest {
readonly message: string;
readonly image: string;
readonly imageId: string;
readonly imageThumbUrl: string;
readonly imageMediumUrl: string;
readonly imageOriginalUrl: string;
readonly imageWidth: number;
readonly imageHeight: number;
readonly useWebSocket: boolean;
import { z } from "zod";
constructor(params: {
message?: string;
image?: string;
imageId?: string;
imageThumbUrl?: string;
imageMediumUrl?: string;
imageOriginalUrl?: string;
imageWidth?: number;
imageHeight?: number;
useWebSocket?: boolean;
}) {
this.message = params.message ?? "";
this.image = params.image ?? "";
this.imageId = params.imageId ?? "";
this.imageThumbUrl = params.imageThumbUrl ?? "";
this.imageMediumUrl = params.imageMediumUrl ?? "";
this.imageOriginalUrl = params.imageOriginalUrl ?? "";
this.imageWidth = params.imageWidth ?? 0;
this.imageHeight = params.imageHeight ?? 0;
this.useWebSocket = params.useWebSocket ?? false;
export const SendMessageRequestSchema = z.object({
message: z.string().default(""),
image: z.string().default(""),
imageId: z.string().default(""),
imageThumbUrl: z.string().default(""),
imageMediumUrl: z.string().default(""),
imageOriginalUrl: z.string().default(""),
imageWidth: z.number().default(0),
imageHeight: z.number().default(0),
useWebSocket: z.boolean().default(false),
});
export type SendMessageRequestInput = z.input<typeof SendMessageRequestSchema>;
export type SendMessageRequestData = z.output<typeof SendMessageRequestSchema>;
export class SendMessageRequest {
declare readonly message: string;
declare readonly image: string;
declare readonly imageId: string;
declare readonly imageThumbUrl: string;
declare readonly imageMediumUrl: string;
declare readonly imageOriginalUrl: string;
declare readonly imageWidth: number;
declare readonly imageHeight: number;
declare readonly useWebSocket: boolean;
private constructor(input: SendMessageRequestInput) {
const data = SendMessageRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
message: this.message,
image: this.image,
imageId: this.imageId,
imageThumbUrl: this.imageThumbUrl,
imageMediumUrl: this.imageMediumUrl,
imageOriginalUrl: this.imageOriginalUrl,
imageWidth: this.imageWidth,
imageHeight: this.imageHeight,
useWebSocket: this.useWebSocket,
};
static from(input: SendMessageRequestInput): SendMessageRequest {
return new SendMessageRequest(input);
}
static fromJson(json: Record<string, unknown>): SendMessageRequest {
return new SendMessageRequest({
message: typeof json.message === "string" ? json.message : undefined,
image: typeof json.image === "string" ? json.image : undefined,
imageId: typeof json.imageId === "string" ? json.imageId : undefined,
imageThumbUrl:
typeof json.imageThumbUrl === "string"
? json.imageThumbUrl
: undefined,
imageMediumUrl:
typeof json.imageMediumUrl === "string"
? json.imageMediumUrl
: undefined,
imageOriginalUrl:
typeof json.imageOriginalUrl === "string"
? json.imageOriginalUrl
: undefined,
imageWidth:
typeof json.imageWidth === "number" ? json.imageWidth : undefined,
imageHeight:
typeof json.imageHeight === "number" ? json.imageHeight : undefined,
useWebSocket:
typeof json.useWebSocket === "boolean" ? json.useWebSocket : undefined,
});
static fromJson(json: unknown): SendMessageRequest {
return SendMessageRequest.from(json as SendMessageRequestInput);
}
toJson(): SendMessageRequestData {
return SendMessageRequestSchema.parse(this);
}
}
+22 -12
View File
@@ -2,23 +2,33 @@
* STT(语音转文字)响应
* 原始 Dart: SttData (lib/data/models/chat/stt_response.dart)
*/
export class SttData {
readonly text: string;
import { z } from "zod";
constructor(params: { text: string }) {
this.text = params.text;
export const SttDataSchema = z.object({
text: z.string(),
});
export type SttDataInput = z.input<typeof SttDataSchema>;
export type SttDataData = z.output<typeof SttDataSchema>;
export class SttData {
declare readonly text: string;
private constructor(input: SttDataInput) {
const data = SttDataSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return { text: this.text };
static from(input: SttDataInput): SttData {
return new SttData(input);
}
static fromJson(json: Record<string, unknown>): SttData {
const text = json.text;
if (typeof text !== "string") {
throw new Error("SttData.text is required and must be a string");
}
return new SttData({ text });
static fromJson(json: unknown): SttData {
return SttData.from(json as SttDataInput);
}
toJson(): SttDataData {
return SttDataSchema.parse(this);
}
}
+26 -29
View File
@@ -2,40 +2,37 @@
* 待同步的单条消息
* 原始 Dart: SyncMessage (lib/data/models/chat/chat_sync.dart)
*/
export class SyncMessage {
readonly role: string;
readonly content: string;
readonly timestamp: string;
import { z } from "zod";
constructor(params: { role: string; content: string; timestamp: string }) {
this.role = params.role;
this.content = params.content;
this.timestamp = params.timestamp;
export const SyncMessageSchema = z.object({
role: z.string(),
content: z.string(),
timestamp: z.string(),
});
export type SyncMessageInput = z.input<typeof SyncMessageSchema>;
export type SyncMessageData = z.output<typeof SyncMessageSchema>;
export class SyncMessage {
declare readonly role: string;
declare readonly content: string;
declare readonly timestamp: string;
private constructor(input: SyncMessageInput) {
const data = SyncMessageSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
role: this.role,
content: this.content,
timestamp: this.timestamp,
};
static from(input: SyncMessageInput): SyncMessage {
return new SyncMessage(input);
}
static fromJson(json: Record<string, unknown>): SyncMessage {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`SyncMessage.${key} is required and must be a string`
);
}
return v;
};
return new SyncMessage({
role: requireString("role"),
content: requireString("content"),
timestamp: requireString("timestamp"),
});
static fromJson(json: unknown): SyncMessage {
return SyncMessage.from(json as SyncMessageInput);
}
toJson(): SyncMessageData {
return SyncMessageSchema.parse(this);
}
}
+26 -29
View File
@@ -2,40 +2,37 @@
* 应用事件上报请求 - 用于 /api/data/report-user-info 接口
* 原始 Dart: AppEvent (lib/data/models/metrics/app_event.dart)
*/
export class AppEvent {
readonly userId: string;
readonly browser: string;
readonly userAgent: string;
import { z } from "zod";
constructor(params: { userId: string; browser: string; userAgent: string }) {
this.userId = params.userId;
this.browser = params.browser;
this.userAgent = params.userAgent;
export const AppEventSchema = z.object({
userId: z.string(),
browser: z.string(),
userAgent: z.string(),
});
export type AppEventInput = z.input<typeof AppEventSchema>;
export type AppEventData = z.output<typeof AppEventSchema>;
export class AppEvent {
declare readonly userId: string;
declare readonly browser: string;
declare readonly userAgent: string;
private constructor(input: AppEventInput) {
const data = AppEventSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
userId: this.userId,
browser: this.browser,
userAgent: this.userAgent,
};
static from(input: AppEventInput): AppEvent {
return new AppEvent(input);
}
static fromJson(json: Record<string, unknown>): AppEvent {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`AppEvent.${key} is required and must be a string`
);
}
return v;
};
return new AppEvent({
userId: requireString("userId"),
browser: requireString("browser"),
userAgent: requireString("userAgent"),
});
static fromJson(json: unknown): AppEvent {
return AppEvent.from(json as AppEventInput);
}
toJson(): AppEventData {
return AppEventSchema.parse(this);
}
}
+30 -56
View File
@@ -2,67 +2,41 @@
* PWA 事件上报请求 - 用于 /api/metrics/pwa/event 接口
* 原始 Dart: PwaEvent (lib/data/models/metrics/pwa_event.dart)
*/
export class PwaEvent {
readonly deviceId: string;
readonly deviceType: string;
readonly timestamp: number;
readonly pwaInstalled: boolean;
readonly pwaSupported: boolean;
import { z } from "zod";
constructor(params: {
deviceId: string;
deviceType: string;
timestamp: number;
pwaInstalled?: boolean;
pwaSupported?: boolean;
}) {
this.deviceId = params.deviceId;
this.deviceType = params.deviceType;
this.timestamp = params.timestamp;
this.pwaInstalled = params.pwaInstalled ?? false;
this.pwaSupported = params.pwaSupported ?? false;
export const PwaEventSchema = z.object({
deviceId: z.string(),
deviceType: z.string(),
timestamp: z.number(),
pwaInstalled: z.boolean().default(false),
pwaSupported: z.boolean().default(false),
});
export type PwaEventInput = z.input<typeof PwaEventSchema>;
export type PwaEventData = z.output<typeof PwaEventSchema>;
export class PwaEvent {
declare readonly deviceId: string;
declare readonly deviceType: string;
declare readonly timestamp: number;
declare readonly pwaInstalled: boolean;
declare readonly pwaSupported: boolean;
private constructor(input: PwaEventInput) {
const data = PwaEventSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
deviceId: this.deviceId,
deviceType: this.deviceType,
timestamp: this.timestamp,
pwaInstalled: this.pwaInstalled,
pwaSupported: this.pwaSupported,
};
static from(input: PwaEventInput): PwaEvent {
return new PwaEvent(input);
}
static fromJson(json: Record<string, unknown>): PwaEvent {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`PwaEvent.${key} is required and must be a string`
);
}
return v;
};
const requireNumber = (key: string): number => {
const v = json[key];
if (typeof v !== "number") {
throw new Error(`PwaEvent.${key} is required and must be a number`);
}
return v;
};
return new PwaEvent({
deviceId: requireString("deviceId"),
deviceType: requireString("deviceType"),
timestamp: requireNumber("timestamp"),
pwaInstalled:
typeof json.pwaInstalled === "boolean"
? json.pwaInstalled
: undefined,
pwaSupported:
typeof json.pwaSupported === "boolean"
? json.pwaSupported
: undefined,
});
static fromJson(json: unknown): PwaEvent {
return PwaEvent.from(json as PwaEventInput);
}
toJson(): PwaEventData {
return PwaEventSchema.parse(this);
}
}
+23 -23
View File
@@ -1,35 +1,35 @@
/**
* 头像数据模型 - 对应后端 AvatarData schema
* 原始 Dart: AvatarData (lib/data/models/user/user.dart)
*
* 注:原始 Dart 中 `avatarUrl` 为 `String?`,按"全部非空"约定兜底为空串。
*/
export class AvatarData {
readonly avatarUrl: string;
readonly userId: string;
import { z } from "zod";
constructor(params: { avatarUrl?: string; userId: string }) {
this.avatarUrl = params.avatarUrl ?? "";
this.userId = params.userId;
export const AvatarDataSchema = z.object({
avatarUrl: z.string().default(""),
userId: z.string(),
});
export type AvatarDataInput = z.input<typeof AvatarDataSchema>;
export type AvatarDataData = z.output<typeof AvatarDataSchema>;
export class AvatarData {
declare readonly avatarUrl: string;
declare readonly userId: string;
private constructor(data: AvatarDataData) {
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
avatarUrl: this.avatarUrl,
userId: this.userId,
};
static from(input: AvatarDataInput): AvatarData {
return new AvatarData(AvatarDataSchema.parse(input));
}
static fromJson(json: Record<string, unknown>): AvatarData {
const userId = json.userId;
if (typeof userId !== "string") {
throw new Error("AvatarData.userId is required and must be a string");
}
return new AvatarData({
userId,
avatarUrl:
typeof json.avatarUrl === "string" ? json.avatarUrl : undefined,
});
static fromJson(json: unknown): AvatarData {
return AvatarData.from(json as AvatarDataInput);
}
toJson(): AvatarDataData {
return AvatarDataSchema.parse(this);
}
}
+23 -23
View File
@@ -2,34 +2,34 @@
* 积分数据模型 - 对应后端 CreditsData schema
* 原始 Dart: CreditsData (lib/data/models/user/user.dart)
*/
export class CreditsData {
readonly userId: string;
readonly dolBalance: number;
import { z } from "zod";
constructor(params: { userId: string; dolBalance: number }) {
this.userId = params.userId;
this.dolBalance = params.dolBalance;
export const CreditsDataSchema = z.object({
userId: z.string(),
dolBalance: z.number(),
});
export type CreditsDataInput = z.input<typeof CreditsDataSchema>;
export type CreditsDataData = z.output<typeof CreditsDataSchema>;
export class CreditsData {
declare readonly userId: string;
declare readonly dolBalance: number;
private constructor(data: CreditsDataData) {
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
userId: this.userId,
dolBalance: this.dolBalance,
};
static from(input: CreditsDataInput): CreditsData {
return new CreditsData(CreditsDataSchema.parse(input));
}
static fromJson(json: Record<string, unknown>): CreditsData {
const userId = json.userId;
const dolBalance = json.dolBalance;
if (typeof userId !== "string") {
throw new Error("CreditsData.userId is required and must be a string");
}
if (typeof dolBalance !== "number") {
throw new Error(
"CreditsData.dolBalance is required and must be a number"
);
}
return new CreditsData({ userId, dolBalance });
static fromJson(json: unknown): CreditsData {
return CreditsData.from(json as CreditsDataInput);
}
toJson(): CreditsDataData {
return CreditsDataSchema.parse(this);
}
}
+27 -45
View File
@@ -1,57 +1,39 @@
/**
* 积分历史记录模型 - 对应后端 CreditsHistoryData schema
* 原始 Dart: CreditsHistoryData (lib/data/models/user/user.dart)
*
* 注:原始 Dart 中 `records` 为 `List<Map<String, dynamic>>`
* 迁移为 `Record<string, unknown>[]`。
*/
export class CreditsHistoryData {
readonly records: Record<string, unknown>[];
readonly total: number;
readonly limit: number;
readonly offset: number;
import { z } from "zod";
constructor(params: {
records: Record<string, unknown>[];
total: number;
limit: number;
offset: number;
}) {
this.records = params.records;
this.total = params.total;
this.limit = params.limit;
this.offset = params.offset;
export const CreditsHistoryDataSchema = z.object({
records: z.array(z.record(z.string(), z.unknown())),
total: z.number(),
limit: z.number(),
offset: z.number(),
});
export type CreditsHistoryDataInput = z.input<typeof CreditsHistoryDataSchema>;
export type CreditsHistoryDataData = z.output<typeof CreditsHistoryDataSchema>;
export class CreditsHistoryData {
declare readonly records: Record<string, unknown>[];
declare readonly total: number;
declare readonly limit: number;
declare readonly offset: number;
private constructor(data: CreditsHistoryDataData) {
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
records: this.records,
total: this.total,
limit: this.limit,
offset: this.offset,
};
static from(input: CreditsHistoryDataInput): CreditsHistoryData {
return new CreditsHistoryData(CreditsHistoryDataSchema.parse(input));
}
static fromJson(json: Record<string, unknown>): CreditsHistoryData {
const requireNumber = (key: string): number => {
const v = json[key];
if (typeof v !== "number") {
throw new Error(
`CreditsHistoryData.${key} is required and must be a number`
);
}
return v;
};
const rawRecords = json.records;
const records: Record<string, unknown>[] = Array.isArray(rawRecords)
? (rawRecords as Record<string, unknown>[])
: [];
return new CreditsHistoryData({
records,
total: requireNumber("total"),
limit: requireNumber("limit"),
offset: requireNumber("offset"),
});
static fromJson(json: unknown): CreditsHistoryData {
return CreditsHistoryData.from(json as CreditsHistoryDataInput);
}
toJson(): CreditsHistoryDataData {
return CreditsHistoryDataSchema.parse(this);
}
}
+37 -36
View File
@@ -1,48 +1,49 @@
/**
* 个性特征模型
* 原始 Dart: PersonalityTraits (lib/data/models/user/user.dart)
*
* 注:所有 double 字段在 Dart 中使用 @Default(0.5)。
*/
export class PersonalityTraits {
readonly cheerful: number;
readonly caring: number;
readonly playful: number;
readonly serious: number;
readonly romantic: number;
import { z } from "zod";
constructor(params: {
cheerful?: number;
caring?: number;
playful?: number;
serious?: number;
romantic?: number;
}) {
this.cheerful = params.cheerful ?? 0.5;
this.caring = params.caring ?? 0.5;
this.playful = params.playful ?? 0.5;
this.serious = params.serious ?? 0.5;
this.romantic = params.romantic ?? 0.5;
export const PERSONALITY_TRAITS_DEFAULTS: PersonalityTraitsData = {
cheerful: 0.5,
caring: 0.5,
playful: 0.5,
serious: 0.5,
romantic: 0.5,
};
export const PersonalityTraitsSchema = z.object({
cheerful: z.number().default(0.5),
caring: z.number().default(0.5),
playful: z.number().default(0.5),
serious: z.number().default(0.5),
romantic: z.number().default(0.5),
});
export type PersonalityTraitsInput = z.input<typeof PersonalityTraitsSchema>;
export type PersonalityTraitsData = z.output<typeof PersonalityTraitsSchema>;
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(data: PersonalityTraitsData) {
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
cheerful: this.cheerful,
caring: this.caring,
playful: this.playful,
serious: this.serious,
romantic: this.romantic,
};
static from(input: PersonalityTraitsInput): PersonalityTraits {
return new PersonalityTraits(PersonalityTraitsSchema.parse(input));
}
static fromJson(json: Record<string, unknown>): PersonalityTraits {
return new PersonalityTraits({
cheerful: typeof json.cheerful === "number" ? json.cheerful : undefined,
caring: typeof json.caring === "number" ? json.caring : undefined,
playful: typeof json.playful === "number" ? json.playful : undefined,
serious: typeof json.serious === "number" ? json.serious : undefined,
romantic: typeof json.romantic === "number" ? json.romantic : undefined,
});
static fromJson(json: unknown): PersonalityTraits {
return PersonalityTraits.from(json as PersonalityTraitsInput);
}
toJson(): PersonalityTraitsData {
return PersonalityTraitsSchema.parse(this);
}
}
+27 -47
View File
@@ -1,59 +1,39 @@
/**
* 最近记忆模型
* 原始 Dart: RecentMemory (lib/data/models/user/recent_memory.dart)
*
* 注:原始 Dart 中 `createdAt` 为 `String?`,按"全部非空"约定兜底为空串。
*/
export class RecentMemory {
readonly type: string;
readonly content: string;
readonly importance: number;
readonly createdAt: string;
import { z } from "zod";
constructor(params: {
type: string;
content: string;
importance: number;
createdAt?: string;
}) {
this.type = params.type;
this.content = params.content;
this.importance = params.importance;
this.createdAt = params.createdAt ?? "";
export const RecentMemorySchema = z.object({
type: z.string(),
content: z.string(),
importance: z.number(),
createdAt: z.string().default(""),
});
export type RecentMemoryInput = z.input<typeof RecentMemorySchema>;
export type RecentMemoryData = z.output<typeof RecentMemorySchema>;
export class RecentMemory {
declare readonly type: string;
declare readonly content: string;
declare readonly importance: number;
declare readonly createdAt: string;
private constructor(data: RecentMemoryData) {
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
type: this.type,
content: this.content,
importance: this.importance,
createdAt: this.createdAt,
};
static from(input: RecentMemoryInput): RecentMemory {
return new RecentMemory(RecentMemorySchema.parse(input));
}
static fromJson(json: Record<string, unknown>): RecentMemory {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`RecentMemory.${key} is required and must be a string`
);
}
return v;
};
const importance = json.importance;
if (typeof importance !== "number") {
throw new Error(
"RecentMemory.importance is required and must be a number"
);
}
return new RecentMemory({
type: requireString("type"),
content: requireString("content"),
importance,
createdAt:
typeof json.createdAt === "string" ? json.createdAt : undefined,
});
static fromJson(json: unknown): RecentMemory {
return RecentMemory.from(json as RecentMemoryInput);
}
toJson(): RecentMemoryData {
return RecentMemorySchema.parse(this);
}
}
+27 -35
View File
@@ -1,47 +1,39 @@
/**
* 更新个人资料请求
* 原始 Dart: UpdateProfileRequest (lib/data/models/user/user.dart)
*
* 注:原始 Dart 中所有字段为 `String?`,按"全部非空"约定兜底为空串。
*/
export class UpdateProfileRequest {
readonly username: string;
readonly nickname: string;
readonly preferredLanguage: string;
readonly currentMood: string;
import { z } from "zod";
constructor(params: {
username?: string;
nickname?: string;
preferredLanguage?: string;
currentMood?: string;
}) {
this.username = params.username ?? "";
this.nickname = params.nickname ?? "";
this.preferredLanguage = params.preferredLanguage ?? "";
this.currentMood = params.currentMood ?? "";
export const UpdateProfileRequestSchema = z.object({
username: z.string().default(""),
nickname: z.string().default(""),
preferredLanguage: z.string().default(""),
currentMood: z.string().default(""),
});
export type UpdateProfileRequestInput = z.input<typeof UpdateProfileRequestSchema>;
export type UpdateProfileRequestData = z.output<typeof UpdateProfileRequestSchema>;
export class UpdateProfileRequest {
declare readonly username: string;
declare readonly nickname: string;
declare readonly preferredLanguage: string;
declare readonly currentMood: string;
private constructor(data: UpdateProfileRequestData) {
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
username: this.username,
nickname: this.nickname,
preferredLanguage: this.preferredLanguage,
currentMood: this.currentMood,
};
static from(input: UpdateProfileRequestInput): UpdateProfileRequest {
return new UpdateProfileRequest(UpdateProfileRequestSchema.parse(input));
}
static fromJson(json: Record<string, unknown>): UpdateProfileRequest {
return new UpdateProfileRequest({
username: typeof json.username === "string" ? json.username : undefined,
nickname: typeof json.nickname === "string" ? json.nickname : undefined,
preferredLanguage:
typeof json.preferredLanguage === "string"
? json.preferredLanguage
: undefined,
currentMood:
typeof json.currentMood === "string" ? json.currentMood : undefined,
});
static fromJson(json: unknown): UpdateProfileRequest {
return UpdateProfileRequest.from(json as UpdateProfileRequestInput);
}
toJson(): UpdateProfileRequestData {
return UpdateProfileRequestSchema.parse(this);
}
}
+63 -114
View File
@@ -1,128 +1,77 @@
/**
* 用户模型 - 对应后端 UserData schema
* 原始 Dart: User (lib/data/models/user/user.dart)
*
* 注:原始 Dart 中 `email`/`personalityTraits`/`preferredLanguage`/`createdAt`/
* `lastMessageAt`/`avatarUrl` 为可空字段,按"全部非空"约定统一兜底:
* - 字符串字段 → 空串 ""
* - PersonalityTraits → 默认实例(全 0.5
*/
import { PersonalityTraits } from "./personality_traits";
import { z } from "zod";
import {
PersonalityTraits,
PersonalityTraitsSchema,
PERSONALITY_TRAITS_DEFAULTS,
} from "./personality_traits";
export const UserSchema = z.object({
id: z.string(),
username: z.string(),
email: z.string().default(""),
platform: z.string().default("web"),
intimacy: z.number().default(0),
dolBalance: z.number().default(0),
relationshipStage: z.string().default("密友"),
currentMood: z.string().default("happy"),
personalityTraits: PersonalityTraitsSchema.default(
PERSONALITY_TRAITS_DEFAULTS
),
preferredLanguage: z.string().default(""),
createdAt: z.string().default(""),
lastMessageAt: z.string().default(""),
avatarUrl: z.string().default(""),
loginProvider: z.string().default("email"),
isGuest: z.boolean().default(false),
});
export type UserInput = z.input<typeof UserSchema>;
export type UserData = z.output<typeof UserSchema>;
export class User {
readonly id: string;
readonly username: string;
readonly email: string;
readonly platform: string;
readonly intimacy: number;
readonly dolBalance: number;
readonly relationshipStage: string;
readonly currentMood: string;
readonly personalityTraits: PersonalityTraits;
readonly preferredLanguage: string;
readonly createdAt: string;
readonly lastMessageAt: string;
readonly avatarUrl: string;
readonly loginProvider: string;
readonly isGuest: boolean;
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;
constructor(params: {
id: string;
username: string;
email?: string;
platform?: string;
intimacy?: number;
dolBalance?: number;
relationshipStage?: string;
currentMood?: string;
personalityTraits?: PersonalityTraits;
preferredLanguage?: string;
createdAt?: string;
lastMessageAt?: string;
avatarUrl?: string;
loginProvider?: string;
isGuest?: boolean;
}) {
this.id = params.id;
this.username = params.username;
this.email = params.email ?? "";
this.platform = params.platform ?? "web";
this.intimacy = params.intimacy ?? 0;
this.dolBalance = params.dolBalance ?? 0;
this.relationshipStage = params.relationshipStage ?? "密友";
this.currentMood = params.currentMood ?? "happy";
this.personalityTraits = params.personalityTraits ?? new PersonalityTraits({});
this.preferredLanguage = params.preferredLanguage ?? "";
this.createdAt = params.createdAt ?? "";
this.lastMessageAt = params.lastMessageAt ?? "";
this.avatarUrl = params.avatarUrl ?? "";
this.loginProvider = params.loginProvider ?? "email";
this.isGuest = params.isGuest ?? false;
private constructor(input: UserInput) {
const data = UserSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
id: this.id,
username: this.username,
email: this.email,
platform: this.platform,
intimacy: this.intimacy,
dolBalance: this.dolBalance,
relationshipStage: this.relationshipStage,
currentMood: this.currentMood,
personalityTraits: this.personalityTraits.toJson(),
preferredLanguage: this.preferredLanguage,
createdAt: this.createdAt,
lastMessageAt: this.lastMessageAt,
avatarUrl: this.avatarUrl,
loginProvider: this.loginProvider,
isGuest: this.isGuest,
};
static from(input: UserInput): User {
return new User(input);
}
static fromJson(json: Record<string, unknown>): User {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(`User.${key} is required and must be a string`);
}
return v;
};
return new User({
id: requireString("id"),
username: requireString("username"),
email: typeof json.email === "string" ? json.email : undefined,
platform: typeof json.platform === "string" ? json.platform : undefined,
intimacy: typeof json.intimacy === "number" ? json.intimacy : undefined,
dolBalance:
typeof json.dolBalance === "number" ? json.dolBalance : undefined,
relationshipStage:
typeof json.relationshipStage === "string"
? json.relationshipStage
: undefined,
currentMood:
typeof json.currentMood === "string" ? json.currentMood : undefined,
personalityTraits: json.personalityTraits
? PersonalityTraits.fromJson(
json.personalityTraits as Record<string, unknown>
)
: undefined,
preferredLanguage:
typeof json.preferredLanguage === "string"
? json.preferredLanguage
: undefined,
createdAt:
typeof json.createdAt === "string" ? json.createdAt : undefined,
lastMessageAt:
typeof json.lastMessageAt === "string" ? json.lastMessageAt : undefined,
avatarUrl:
typeof json.avatarUrl === "string" ? json.avatarUrl : undefined,
loginProvider:
typeof json.loginProvider === "string"
? json.loginProvider
: undefined,
isGuest: typeof json.isGuest === "boolean" ? json.isGuest : undefined,
});
static fromJson(json: unknown): User {
return User.from(json as UserInput);
}
/**
* 创建一个具有空 id/username 的 User 实例,用于可选 user 字段的默认占位。
* 调用方可通过 `user.id === ""` 判定"无用户数据"。
*/
static empty(): User {
return new User({ id: "", username: "" });
}
toJson(): UserData {
return UserSchema.parse(this);
}
}
+57 -142
View File
@@ -1,156 +1,71 @@
/**
* 用户统计响应
* 原始 Dart: UserStatsResponse (lib/data/models/user/user_stats_response.dart)
*
* 注:原始 Dart 中 `lastMessageAt`/`accountCreatedAt`/`currentMood` 为 `String?`
* `personalityTraits` 为 `PersonalityTraits?`,按"全部非空"约定兜底:
* - 字符串 → ""
* - PersonalityTraits → 默认实例
* - recentMemories 缺失或 null 时使用 []
*/
import { PersonalityTraits } from "./personality_traits";
import { RecentMemory } from "./recent_memory";
import { z } from "zod";
import {
PersonalityTraits,
PERSONALITY_TRAITS_DEFAULTS,
PersonalityTraitsSchema,
} from "./personality_traits";
import { RecentMemory, RecentMemorySchema } from "./recent_memory";
export const UserStatsResponseSchema = z.object({
userId: z.string(),
username: z.string(),
platform: z.string(),
intimacy: z.number(),
relationshipStage: z.string(),
dolBalance: z.number(),
totalMessages: z.number(),
lastMessageAt: z.string().default(""),
accountCreatedAt: z.string().default(""),
currentMood: z.string().default(""),
personalityTraits: PersonalityTraitsSchema.default(
PERSONALITY_TRAITS_DEFAULTS
),
recentMemories: z.array(RecentMemorySchema).default([]),
promptTokensTotal: z.number().default(0),
completionTokensTotal: z.number().default(0),
cacheHitTokensTotal: z.number().default(0),
tokensTotal: z.number().default(0),
});
export type UserStatsResponseInput = z.input<typeof UserStatsResponseSchema>;
export type UserStatsResponseData = z.output<typeof UserStatsResponseSchema>;
export class UserStatsResponse {
readonly userId: string;
readonly username: string;
readonly platform: string;
readonly intimacy: number;
readonly relationshipStage: string;
readonly dolBalance: number;
readonly totalMessages: number;
readonly lastMessageAt: string;
readonly accountCreatedAt: string;
readonly currentMood: string;
readonly personalityTraits: PersonalityTraits;
readonly recentMemories: RecentMemory[];
readonly promptTokensTotal: number;
readonly completionTokensTotal: number;
readonly cacheHitTokensTotal: number;
readonly tokensTotal: number;
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;
constructor(params: {
userId: string;
username: string;
platform: string;
intimacy: number;
relationshipStage: string;
dolBalance: number;
totalMessages: number;
lastMessageAt?: string;
accountCreatedAt?: string;
currentMood?: string;
personalityTraits?: PersonalityTraits;
recentMemories?: RecentMemory[];
promptTokensTotal?: number;
completionTokensTotal?: number;
cacheHitTokensTotal?: number;
tokensTotal?: number;
}) {
this.userId = params.userId;
this.username = params.username;
this.platform = params.platform;
this.intimacy = params.intimacy;
this.relationshipStage = params.relationshipStage;
this.dolBalance = params.dolBalance;
this.totalMessages = params.totalMessages;
this.lastMessageAt = params.lastMessageAt ?? "";
this.accountCreatedAt = params.accountCreatedAt ?? "";
this.currentMood = params.currentMood ?? "";
this.personalityTraits =
params.personalityTraits ?? new PersonalityTraits({});
this.recentMemories = params.recentMemories ?? [];
this.promptTokensTotal = params.promptTokensTotal ?? 0;
this.completionTokensTotal = params.completionTokensTotal ?? 0;
this.cacheHitTokensTotal = params.cacheHitTokensTotal ?? 0;
this.tokensTotal = params.tokensTotal ?? 0;
private constructor(data: UserStatsResponseData) {
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
userId: this.userId,
username: this.username,
platform: this.platform,
intimacy: this.intimacy,
relationshipStage: this.relationshipStage,
dolBalance: this.dolBalance,
totalMessages: this.totalMessages,
lastMessageAt: this.lastMessageAt,
accountCreatedAt: this.accountCreatedAt,
currentMood: this.currentMood,
personalityTraits: this.personalityTraits.toJson(),
recentMemories: this.recentMemories.map((m) => m.toJson()),
promptTokensTotal: this.promptTokensTotal,
completionTokensTotal: this.completionTokensTotal,
cacheHitTokensTotal: this.cacheHitTokensTotal,
tokensTotal: this.tokensTotal,
};
static from(input: UserStatsResponseInput): UserStatsResponse {
return new UserStatsResponse(UserStatsResponseSchema.parse(input));
}
static fromJson(json: Record<string, unknown>): UserStatsResponse {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`UserStatsResponse.${key} is required and must be a string`
);
}
return v;
};
const requireNumber = (key: string): number => {
const v = json[key];
if (typeof v !== "number") {
throw new Error(
`UserStatsResponse.${key} is required and must be a number`
);
}
return v;
};
const rawMemories = json.recentMemories;
const recentMemories: RecentMemory[] = Array.isArray(rawMemories)
? (rawMemories as Record<string, unknown>[]).map((m) =>
RecentMemory.fromJson(m)
)
: [];
return new UserStatsResponse({
userId: requireString("userId"),
username: requireString("username"),
platform: requireString("platform"),
intimacy: requireNumber("intimacy"),
relationshipStage: requireString("relationshipStage"),
dolBalance: requireNumber("dolBalance"),
totalMessages: requireNumber("totalMessages"),
lastMessageAt:
typeof json.lastMessageAt === "string"
? json.lastMessageAt
: undefined,
accountCreatedAt:
typeof json.accountCreatedAt === "string"
? json.accountCreatedAt
: undefined,
currentMood:
typeof json.currentMood === "string" ? json.currentMood : undefined,
personalityTraits: json.personalityTraits
? PersonalityTraits.fromJson(
json.personalityTraits as Record<string, unknown>
)
: undefined,
recentMemories,
promptTokensTotal:
typeof json.promptTokensTotal === "number"
? json.promptTokensTotal
: undefined,
completionTokensTotal:
typeof json.completionTokensTotal === "number"
? json.completionTokensTotal
: undefined,
cacheHitTokensTotal:
typeof json.cacheHitTokensTotal === "number"
? json.cacheHitTokensTotal
: undefined,
tokensTotal:
typeof json.tokensTotal === "number" ? json.tokensTotal : undefined,
});
static fromJson(json: unknown): UserStatsResponse {
return UserStatsResponse.from(json as UserStatsResponseInput);
}
toJson(): UserStatsResponseData {
return UserStatsResponseSchema.parse(this);
}
}