refactor(data): consolidate data layer under services namespace
- Move src/data/{api,dto,schemas} directories to src/data/services/*
- Update all relative imports across the codebase to reference new paths
- Use CSS color tokens for splash button gradient in splash-button.module.css
- Add responsive sizes attribute to splash background image
- Add JSDoc documentation to splash-background component referencing original Dart implementation
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* API 路径管理
|
||||
* 统一管理所有接口路径
|
||||
* 原始 Dart: lib/data/services/api/api_path.dart
|
||||
*/
|
||||
export class ApiPath {
|
||||
private constructor() {}
|
||||
|
||||
// API 基础路径
|
||||
private static readonly _baseUrl = "/api";
|
||||
|
||||
// ============ 功能模块分组 ============
|
||||
private static readonly _auth = `${ApiPath._baseUrl}/auth`;
|
||||
private static readonly _verify = `${ApiPath._baseUrl}/verify`;
|
||||
private static readonly _user = `${ApiPath._baseUrl}/user`;
|
||||
private static readonly _payment = `${ApiPath._baseUrl}/payment`;
|
||||
private static readonly _chat = `${ApiPath._baseUrl}/chat`;
|
||||
|
||||
// ============ 认证相关 ============
|
||||
/** 发送验证码 */
|
||||
static readonly sendCode = `${ApiPath._verify}/send`;
|
||||
|
||||
/** 邮箱密码登录 */
|
||||
static readonly emailLogin = `${ApiPath._auth}/login`;
|
||||
|
||||
/** 注册 */
|
||||
static readonly register = `${ApiPath._auth}/register`;
|
||||
|
||||
/** 设备自动登录 */
|
||||
static readonly guestLogin = `${ApiPath._auth}/guest`;
|
||||
|
||||
/** Apple 登录 */
|
||||
static readonly appleLogin = `${ApiPath._auth}/login/apple`;
|
||||
|
||||
/** Google 登录 */
|
||||
static readonly googleLogin = `${ApiPath._auth}/login/google`;
|
||||
|
||||
/** Facebook 登录 */
|
||||
static readonly facebookLogin = `${ApiPath._auth}/login/facebook`;
|
||||
|
||||
/** Facebook ID 登录(v7.0 新增) */
|
||||
static readonly facebookIdLogin = `${ApiPath._auth}/login/facebook/by-id`;
|
||||
|
||||
/** 刷新 Token */
|
||||
static readonly refresh = `${ApiPath._auth}/refresh`;
|
||||
|
||||
/** 退出登录 */
|
||||
static readonly logout = `${ApiPath._auth}/logout`;
|
||||
|
||||
/** 获取当前用户信息 */
|
||||
static readonly getCurrentUser = `${ApiPath._auth}/me`;
|
||||
|
||||
// ============ 用户相关 ============
|
||||
/** 获取用户统计信息 */
|
||||
static readonly userStats = `${ApiPath._user}/stats`;
|
||||
|
||||
/** 获取个人信息(与 /auth/me 等价) */
|
||||
static readonly userProfile = `${ApiPath._user}/profile`;
|
||||
|
||||
/** 更新个人信息 */
|
||||
static readonly updateProfile = `${ApiPath._user}/profile`;
|
||||
|
||||
/** 上传头像 */
|
||||
static readonly userAvatar = `${ApiPath._user}/avatar`;
|
||||
|
||||
/** 查询积分余额 */
|
||||
static readonly userCredits = `${ApiPath._user}/credits`;
|
||||
|
||||
/** 查询积分操作历史 */
|
||||
static readonly userCreditsHistory = `${ApiPath._user}/credits/history`;
|
||||
|
||||
// ============ 支付相关 ============
|
||||
/** 创建充值订单 */
|
||||
static readonly paymentCreateOrder = `${ApiPath._payment}/order/create`;
|
||||
|
||||
/** 查询订单状态 */
|
||||
static readonly paymentOrderStatus = `${ApiPath._payment}/order/status`;
|
||||
|
||||
/** 获取商品套餐列表 */
|
||||
static readonly paymentProducts = `${ApiPath._payment}/products`;
|
||||
|
||||
/** 申请退款 */
|
||||
static readonly paymentRefund = `${ApiPath._payment}/refund`;
|
||||
|
||||
/** 获取商品详情路径 */
|
||||
static getPaymentProductDetail(productId: string): string {
|
||||
return `${ApiPath.paymentProducts}/${productId}`;
|
||||
}
|
||||
|
||||
// ============ 聊天相关 ============
|
||||
/** 发送消息 */
|
||||
static readonly chatSend = `${ApiPath._chat}/send`;
|
||||
|
||||
/** 获取聊天历史 */
|
||||
static readonly chatHistory = `${ApiPath._chat}/history`;
|
||||
|
||||
/** 语音转文字(STT) */
|
||||
static readonly chatStt = `${ApiPath._chat}/stt`;
|
||||
|
||||
/** 同步游客消息 */
|
||||
static readonly chatSync = `${ApiPath._chat}/sync`;
|
||||
|
||||
/** 上传图片 */
|
||||
static readonly chatUploadImage = `${ApiPath._chat}/upload-image`;
|
||||
|
||||
// ============ 数据看板相关 ============
|
||||
private static readonly _metrics = `${ApiPath._baseUrl}/metrics`;
|
||||
|
||||
/** 上报 PWA 事件 */
|
||||
static readonly metricsPwaEvent = `${ApiPath._metrics}/pwa/event`;
|
||||
|
||||
// ============ 数据上报相关(v7.0 新增) ============
|
||||
private static readonly _data = `${ApiPath._baseUrl}/data`;
|
||||
|
||||
/** 上报用户信息 */
|
||||
static readonly reportUserInfo = `${ApiPath._data}/report-user-info`;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 统一 API 响应包装
|
||||
*
|
||||
* 与 Dart 的 `NetResult<T>` 对应:
|
||||
* - 成功:`{ success: true, data: T }`
|
||||
* - 失败:`{ success: false, error: ApiError }`
|
||||
*/
|
||||
export type ApiResult<T> =
|
||||
| { success: true; data: T }
|
||||
| { success: false; error: ApiError };
|
||||
|
||||
/**
|
||||
* API 错误类
|
||||
*/
|
||||
export class ApiError extends Error {
|
||||
readonly code: string;
|
||||
readonly status?: number;
|
||||
readonly details?: unknown;
|
||||
|
||||
constructor(
|
||||
code: string,
|
||||
message: string,
|
||||
status?: number,
|
||||
details?: unknown
|
||||
) {
|
||||
super(message);
|
||||
this.name = "ApiError";
|
||||
this.code = code;
|
||||
this.status = status;
|
||||
this.details = details;
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为 JSON 字符串
|
||||
*/
|
||||
override toString(): string {
|
||||
const statusStr = this.status !== undefined ? ` [${this.status}]` : "";
|
||||
return `${this.name}${statusStr} ${this.code}: ${this.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误码常量
|
||||
*/
|
||||
export class ErrorCode {
|
||||
private constructor() {}
|
||||
|
||||
static readonly httpUnauthorized = 401;
|
||||
static readonly httpForbidden = 403;
|
||||
static readonly httpNotFound = 404;
|
||||
static readonly httpServerError = 500;
|
||||
static readonly httpBadRequest = 400;
|
||||
|
||||
static readonly networkError = "NETWORK_ERROR";
|
||||
static readonly timeoutError = "TIMEOUT_ERROR";
|
||||
static readonly parseError = "PARSE_ERROR";
|
||||
static readonly unknownError = "UNKNOWN_ERROR";
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Auth API
|
||||
*
|
||||
* 认证相关接口
|
||||
* 原始 Dart: lib/data/services/api/auth_api_client.dart
|
||||
*/
|
||||
import { httpClient } from "./http_client";
|
||||
import { ApiPath } from "./api_path";
|
||||
import { ApiEnvelope, unwrap } from "./response_helper";
|
||||
import { AppleLoginRequest } from "@/data/dto/auth/apple_login_request";
|
||||
import { FacebookLoginRequest } from "@/data/dto/auth/facebook_login_request";
|
||||
import { FbIdLoginRequest } from "@/data/dto/auth/fb_id_login_request";
|
||||
import { GoogleLoginRequest } from "@/data/dto/auth/google_login_request";
|
||||
import { GuestLoginRequest } from "@/data/dto/auth/guest_login_request";
|
||||
import { GuestLoginResponse } from "@/data/dto/auth/guest_login_response";
|
||||
import { LoginRequest } from "@/data/dto/auth/login_request";
|
||||
import { LoginResponse } from "@/data/dto/auth/login_response";
|
||||
import { LogoutResponse } from "@/data/dto/auth/logout_response";
|
||||
import { RefreshTokenRequest } from "@/data/dto/auth/refresh_token_request";
|
||||
import { RefreshTokenResponse } from "@/data/dto/auth/refresh_token_response";
|
||||
import { RegisterRequest } from "@/data/dto/auth/register_request";
|
||||
import { SendCodeRequest } from "@/data/dto/auth/send_code_request";
|
||||
import { User } from "@/data/dto/user/user";
|
||||
import type { UserData } from "@/data/services/schemas/user/user";
|
||||
|
||||
export class AuthApi {
|
||||
/**
|
||||
* 发送验证码
|
||||
*/
|
||||
async sendCode(body: SendCodeRequest): Promise<void> {
|
||||
await httpClient<ApiEnvelope<unknown>>(ApiPath.sendCode, {
|
||||
method: "POST",
|
||||
body: body.toJson(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱密码登录
|
||||
*/
|
||||
async emailLogin(body: LoginRequest): Promise<LoginResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(
|
||||
ApiPath.emailLogin,
|
||||
{ method: "POST", body: body.toJson() }
|
||||
);
|
||||
return LoginResponse.fromJson(unwrap(env) as Record<string, unknown>);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
async register(body: RegisterRequest): Promise<void> {
|
||||
await httpClient<ApiEnvelope<unknown>>(ApiPath.register, {
|
||||
method: "POST",
|
||||
body: body.toJson(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Apple 登录
|
||||
*/
|
||||
async appleLogin(body: AppleLoginRequest): Promise<LoginResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.appleLogin, {
|
||||
method: "POST",
|
||||
body: body.toJson(),
|
||||
});
|
||||
return LoginResponse.fromJson(unwrap(env) as Record<string, unknown>);
|
||||
}
|
||||
|
||||
/**
|
||||
* Google 登录
|
||||
*/
|
||||
async googleLogin(body: GoogleLoginRequest): Promise<LoginResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.googleLogin, {
|
||||
method: "POST",
|
||||
body: body.toJson(),
|
||||
});
|
||||
return LoginResponse.fromJson(unwrap(env) as Record<string, unknown>);
|
||||
}
|
||||
|
||||
/**
|
||||
* Facebook 登录
|
||||
*/
|
||||
async facebookLogin(body: FacebookLoginRequest): Promise<LoginResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(
|
||||
ApiPath.facebookLogin,
|
||||
{ method: "POST", body: body.toJson() }
|
||||
);
|
||||
return LoginResponse.fromJson(unwrap(env) as Record<string, unknown>);
|
||||
}
|
||||
|
||||
/**
|
||||
* Facebook ID 登录(v7.0 新增)
|
||||
*/
|
||||
async facebookIdLogin(body: FbIdLoginRequest): Promise<LoginResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(
|
||||
ApiPath.facebookIdLogin,
|
||||
{ method: "POST", body: body.toJson() }
|
||||
);
|
||||
return LoginResponse.fromJson(unwrap(env) as Record<string, unknown>);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
async logout(): Promise<LogoutResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.logout, {
|
||||
method: "POST",
|
||||
});
|
||||
return LogoutResponse.fromJson(unwrap(env) as Record<string, unknown>);
|
||||
}
|
||||
|
||||
/**
|
||||
* 游客登录
|
||||
*/
|
||||
async guestLogin(body: GuestLoginRequest): Promise<GuestLoginResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.guestLogin, {
|
||||
method: "POST",
|
||||
body: body.toJson(),
|
||||
});
|
||||
return GuestLoginResponse.fromJson(unwrap(env) as Record<string, unknown>);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新 Token
|
||||
*/
|
||||
async refreshToken(
|
||||
body: RefreshTokenRequest
|
||||
): Promise<RefreshTokenResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.refresh, {
|
||||
method: "POST",
|
||||
body: body.toJson(),
|
||||
});
|
||||
return RefreshTokenResponse.fromJson(
|
||||
unwrap(env) as Record<string, unknown>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户信息
|
||||
*/
|
||||
async getCurrentUser(): Promise<User> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(
|
||||
ApiPath.getCurrentUser
|
||||
);
|
||||
return User.fromJson(unwrap(env) as UserData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局单例
|
||||
*/
|
||||
export const authApi = new AuthApi();
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Chat API
|
||||
*
|
||||
* 聊天相关接口
|
||||
* 原始 Dart: lib/data/services/api/chat_api_client.dart
|
||||
*/
|
||||
import { httpClient } from "./http_client";
|
||||
import { ApiPath } from "./api_path";
|
||||
import { ApiEnvelope, unwrap } from "./response_helper";
|
||||
import { ChatHistoryResponse } from "@/data/dto/chat/chat_history_response";
|
||||
import { ChatSendResponse } from "@/data/dto/chat/chat_send_response";
|
||||
import { ChatSyncData } from "@/data/dto/chat/chat_sync_data";
|
||||
import { ChatSyncRequest } from "@/data/dto/chat/chat_sync_request";
|
||||
import { ImageUploadResponse } from "@/data/dto/chat/image_upload_response";
|
||||
import { SendMessageRequest } from "@/data/dto/chat/send_message_request";
|
||||
import { SttData } from "@/data/dto/chat/stt_data";
|
||||
import { SyncMessage } from "@/data/dto/chat/sync_message";
|
||||
|
||||
export class ChatApi {
|
||||
/**
|
||||
* 发送消息
|
||||
*/
|
||||
async sendMessage(body: SendMessageRequest): Promise<ChatSendResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.chatSend, {
|
||||
method: "POST",
|
||||
body: body.toJson(),
|
||||
});
|
||||
return ChatSendResponse.fromJson(unwrap(env) as Record<string, unknown>);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取聊天历史
|
||||
*/
|
||||
async getHistory(limit = 50, offset = 0): Promise<ChatHistoryResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.chatHistory, {
|
||||
query: { limit, offset },
|
||||
});
|
||||
return ChatHistoryResponse.fromJson(
|
||||
unwrap(env) as Record<string, unknown>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 语音转文字(multipart 上传)
|
||||
*/
|
||||
async speechToText(audio: Blob | File): Promise<SttData> {
|
||||
const formData = new FormData();
|
||||
formData.append("audio", audio);
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.chatStt, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
return SttData.fromJson(unwrap(env) as Record<string, unknown>);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步游客消息
|
||||
*/
|
||||
async syncMessages(messages: SyncMessage[]): Promise<ChatSyncData> {
|
||||
const body = ChatSyncRequest.from({ messages });
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.chatSync, {
|
||||
method: "POST",
|
||||
body: body.toJson(),
|
||||
});
|
||||
return ChatSyncData.fromJson(unwrap(env) as Record<string, unknown>);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传图片
|
||||
*/
|
||||
async uploadImage(image: Blob | File): Promise<ImageUploadResponse> {
|
||||
const formData = new FormData();
|
||||
formData.append("image", image);
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(
|
||||
ApiPath.chatUploadImage,
|
||||
{ method: "POST", body: formData }
|
||||
);
|
||||
return ImageUploadResponse.fromJson(
|
||||
unwrap(env) as Record<string, unknown>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局单例
|
||||
*/
|
||||
export const chatApi = new ChatApi();
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* API 配置管理
|
||||
*
|
||||
* 通过环境变量配置后端服务地址与超时时间。
|
||||
* 原始 Dart: lib/core/net/service_manager.dart
|
||||
*/
|
||||
|
||||
export type AppEnv = "development" | "test" | "production";
|
||||
|
||||
export interface ApiConfig {
|
||||
/** 后端 API 基础 URL(含协议) */
|
||||
baseUrl: string;
|
||||
/** WebSocket 基础 URL */
|
||||
wsUrl: string;
|
||||
/** 连接超时(ms) */
|
||||
connectTimeout: number;
|
||||
/** 接收超时(ms) */
|
||||
receiveTimeout: number;
|
||||
/** 发送超时(ms) */
|
||||
sendTimeout: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 超时常量
|
||||
*/
|
||||
export class TimeoutConstants {
|
||||
private constructor() {}
|
||||
static readonly shortTimeout = 30000;
|
||||
static readonly longTimeout = 60000;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析当前环境
|
||||
*/
|
||||
export function getAppEnv(): AppEnv {
|
||||
const env = process.env.NEXT_PUBLIC_APP_ENV;
|
||||
if (env === "production" || env === "test") return env;
|
||||
return "development";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前 API 配置
|
||||
*/
|
||||
export function getApiConfig(): ApiConfig {
|
||||
const baseUrl =
|
||||
process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://172.16.48.49:3002";
|
||||
const wsUrl =
|
||||
process.env.NEXT_PUBLIC_WS_BASE_URL ?? "ws://172.16.48.49:3002";
|
||||
const connectTimeout = Number.parseInt(
|
||||
process.env.NEXT_PUBLIC_API_CONNECT_TIMEOUT ?? "30000",
|
||||
10
|
||||
);
|
||||
const receiveTimeout = Number.parseInt(
|
||||
process.env.NEXT_PUBLIC_API_RECEIVE_TIMEOUT ?? "60000",
|
||||
10
|
||||
);
|
||||
const sendTimeout = Number.parseInt(
|
||||
process.env.NEXT_PUBLIC_API_SEND_TIMEOUT ?? "30000",
|
||||
10
|
||||
);
|
||||
|
||||
return {
|
||||
baseUrl,
|
||||
wsUrl,
|
||||
connectTimeout,
|
||||
receiveTimeout,
|
||||
sendTimeout,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* HTTP 客户端工厂
|
||||
*
|
||||
* 创建配置好拦截器的 ofetch 实例。
|
||||
* 原始 Dart: lib/core/net/backend_service.dart
|
||||
*/
|
||||
import { ofetch, type $Fetch, type FetchHook } from "ofetch";
|
||||
import { ApiError, ErrorCode } from "./api_result";
|
||||
import { getApiConfig } from "./config/api_config";
|
||||
import { authRefreshInterceptor } from "./interceptor/auth_refresh_interceptor";
|
||||
import { loggingInterceptor } from "./interceptor/logging_interceptor";
|
||||
import { tokenInterceptor } from "./interceptor/token_interceptor";
|
||||
|
||||
/**
|
||||
* 合并多个同类型 hook 为单个 hook(按顺序执行)
|
||||
*/
|
||||
function chain(...fns: (FetchHook | undefined)[]): FetchHook {
|
||||
return async (ctx: unknown) => {
|
||||
for (const fn of fns) {
|
||||
if (fn) await (fn as (c: unknown) => Promise<void> | void)(ctx);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 ofetch 实例
|
||||
*/
|
||||
export function createHttpClient(): $Fetch {
|
||||
const config = getApiConfig();
|
||||
|
||||
return ofetch.create({
|
||||
baseURL: config.baseUrl,
|
||||
timeout: config.receiveTimeout,
|
||||
retry: 0, // 401 刷新由 auth_refresh_interceptor 自定义处理
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
onRequest: chain(
|
||||
loggingInterceptor.onRequest,
|
||||
tokenInterceptor.onRequest
|
||||
),
|
||||
onResponse: chain(loggingInterceptor.onResponse),
|
||||
onResponseError: chain(
|
||||
loggingInterceptor.onResponseError,
|
||||
authRefreshInterceptor.onResponseError,
|
||||
((ctx: unknown) => {
|
||||
const c = ctx as {
|
||||
response?: { status?: number; _data?: unknown };
|
||||
error?: Error;
|
||||
};
|
||||
const status = c.response?.status;
|
||||
const code =
|
||||
status === ErrorCode.httpUnauthorized
|
||||
? "HTTP_UNAUTHORIZED"
|
||||
: status === ErrorCode.httpServerError
|
||||
? "HTTP_SERVER_ERROR"
|
||||
: "HTTP_ERROR";
|
||||
const data = c.response?._data;
|
||||
const message =
|
||||
(data as { message?: string; error?: string } | undefined)
|
||||
?.message ??
|
||||
(data as { message?: string; error?: string } | undefined)
|
||||
?.error ??
|
||||
c.error?.message ??
|
||||
"Unknown error";
|
||||
throw new ApiError(code, message, status, data);
|
||||
}) as FetchHook
|
||||
),
|
||||
onRequestError: chain(loggingInterceptor.onResponseError),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认 HTTP 客户端实例
|
||||
*/
|
||||
export const httpClient = createHttpClient();
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./api_path";
|
||||
export * from "./api_result";
|
||||
export * from "./auth_api";
|
||||
export * from "./chat_api";
|
||||
export * from "./http_client";
|
||||
export * from "./metrics_api";
|
||||
export * from "./response_helper";
|
||||
export * from "./user_api";
|
||||
export * from "./config/api_config";
|
||||
export * from "./interceptor/auth_refresh_interceptor";
|
||||
export * from "./interceptor/logging_interceptor";
|
||||
export * from "./interceptor/token_interceptor";
|
||||
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* 认证刷新拦截器
|
||||
*
|
||||
* 处理 401 错误,自动刷新 token 并重试原请求。
|
||||
* 原始 Dart: lib/core/net/interceptor/auth_interceptor.dart
|
||||
*/
|
||||
import type { FetchHook } from "ofetch";
|
||||
import { ApiPath } from "../api_path";
|
||||
import { ApiError, ErrorCode } from "../api_result";
|
||||
import { authStorage } from "../../storage/auth_storage";
|
||||
import { deviceIdentifier } from "@/utils/device_identifier";
|
||||
|
||||
/**
|
||||
* 不需要 auth token 刷新的路径
|
||||
* (这些路径返回 401 时不触发刷新)
|
||||
*/
|
||||
const NO_AUTH_REFRESH_PATHS: readonly string[] = [
|
||||
ApiPath.sendCode,
|
||||
ApiPath.emailLogin,
|
||||
ApiPath.register,
|
||||
ApiPath.guestLogin,
|
||||
ApiPath.refresh,
|
||||
];
|
||||
|
||||
/**
|
||||
* 是否正在刷新 token(防止并发刷新)
|
||||
*/
|
||||
let isRefreshing = false;
|
||||
|
||||
/**
|
||||
* 等待中的刷新 Promise
|
||||
*/
|
||||
let refreshPromise: Promise<void> | null = null;
|
||||
|
||||
/**
|
||||
* 实际刷新 token(被拦截器调用)
|
||||
*/
|
||||
async function refreshToken(
|
||||
isGuestMode: boolean,
|
||||
baseUrl: string
|
||||
): Promise<void> {
|
||||
if (isGuestMode) {
|
||||
await refreshGuestToken(baseUrl);
|
||||
} else {
|
||||
await refreshLoginToken(baseUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新登录 token
|
||||
*/
|
||||
async function refreshLoginToken(baseUrl: string): Promise<void> {
|
||||
const refreshToken = authStorage.getRefreshToken();
|
||||
if (!refreshToken) {
|
||||
throw new Error("No refresh token available");
|
||||
}
|
||||
|
||||
const response = await fetch(`${baseUrl}${ApiPath.refresh}`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ refreshToken }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Refresh failed: ${response.status}`);
|
||||
}
|
||||
|
||||
const json = (await response.json()) as {
|
||||
success?: boolean;
|
||||
data?: { token?: string; refreshToken?: string };
|
||||
};
|
||||
|
||||
if (json.success && json.data) {
|
||||
if (json.data.token) authStorage.setLoginToken(json.data.token);
|
||||
if (json.data.refreshToken)
|
||||
authStorage.setRefreshToken(json.data.refreshToken);
|
||||
} else {
|
||||
throw new Error("Refresh response invalid");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新游客 token
|
||||
*/
|
||||
async function refreshGuestToken(baseUrl: string): Promise<void> {
|
||||
const deviceId = await deviceIdentifier.getDeviceId();
|
||||
|
||||
const response = await fetch(`${baseUrl}${ApiPath.guestLogin}`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ deviceId }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Guest refresh failed: ${response.status}`);
|
||||
}
|
||||
|
||||
const json = (await response.json()) as {
|
||||
success?: boolean;
|
||||
data?: { token?: string; deviceId?: string };
|
||||
};
|
||||
|
||||
if (json.success && json.data) {
|
||||
if (json.data.token) authStorage.setGuestToken(json.data.token);
|
||||
if (json.data.deviceId) authStorage.setDeviceId(json.data.deviceId);
|
||||
} else {
|
||||
throw new Error("Guest refresh response invalid");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 401 → 刷新 token 并重试
|
||||
*/
|
||||
export const onResponseErrorAuthRefresh: FetchHook = async (ctx) => {
|
||||
const status = ctx.response?.status;
|
||||
|
||||
// 只处理 401
|
||||
if (status !== ErrorCode.httpUnauthorized) return;
|
||||
|
||||
// 跳过不需要刷新的路径
|
||||
const requestUrl =
|
||||
ctx.request instanceof Request ? ctx.request.url : ctx.request;
|
||||
const path = new URL(requestUrl).pathname;
|
||||
if (NO_AUTH_REFRESH_PATHS.some((p) => path.includes(p))) return;
|
||||
|
||||
// 已登录则刷新登录 token,否则刷新游客 token
|
||||
const isGuestMode = !authStorage.hasLoginToken();
|
||||
|
||||
// 并发刷新:等待或启动
|
||||
if (isRefreshing && refreshPromise) {
|
||||
await refreshPromise;
|
||||
} else {
|
||||
isRefreshing = true;
|
||||
const baseUrl = new URL(requestUrl).origin;
|
||||
refreshPromise = (async () => {
|
||||
try {
|
||||
await refreshToken(isGuestMode, baseUrl);
|
||||
} finally {
|
||||
isRefreshing = false;
|
||||
refreshPromise = null;
|
||||
}
|
||||
})();
|
||||
await refreshPromise;
|
||||
}
|
||||
|
||||
// 刷新失败 → 清除数据并抛出
|
||||
const newToken = authStorage.getAuthToken();
|
||||
if (!newToken) {
|
||||
authStorage.clearAuthData();
|
||||
throw new ApiError(
|
||||
ErrorCode.unknownError,
|
||||
"Token refresh failed",
|
||||
status
|
||||
);
|
||||
}
|
||||
|
||||
// 刷新成功:更新请求头的 token
|
||||
if (ctx.request instanceof Request) {
|
||||
ctx.request.headers.set("Authorization", `Bearer ${newToken}`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 兼容旧接口的 FetchHooks 形式
|
||||
*/
|
||||
export const authRefreshInterceptor = {
|
||||
onResponseError: onResponseErrorAuthRefresh,
|
||||
};
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 日志拦截器
|
||||
*
|
||||
* 在开发模式下记录请求/响应/错误日志。
|
||||
* 原始 Dart: lib/core/net/interceptor/app_interceptor.dart 中的日志部分。
|
||||
*/
|
||||
import type { FetchHook } from "ofetch";
|
||||
|
||||
const TAG = "[API]";
|
||||
|
||||
function isDev(): boolean {
|
||||
return process.env.NODE_ENV !== "production";
|
||||
}
|
||||
|
||||
function getRequestUrl(request: Request | string): string {
|
||||
return typeof request === "string" ? request : request.url;
|
||||
}
|
||||
|
||||
function getRequestMethod(
|
||||
request: Request | string,
|
||||
options: { method?: string }
|
||||
): string {
|
||||
return request instanceof Request ? request.method : options.method ?? "GET";
|
||||
}
|
||||
|
||||
function formatBody(body: unknown): string {
|
||||
if (body === undefined || body === null) return "";
|
||||
try {
|
||||
if (body instanceof FormData) {
|
||||
const entries: string[] = [];
|
||||
body.forEach((value, key) => {
|
||||
if (value instanceof File) {
|
||||
entries.push(`${key}=File(${value.name})`);
|
||||
} else {
|
||||
entries.push(`${key}=${String(value)}`);
|
||||
}
|
||||
});
|
||||
return `FormData{${entries.join(", ")}}`;
|
||||
}
|
||||
return JSON.stringify(body);
|
||||
} catch {
|
||||
return String(body);
|
||||
}
|
||||
}
|
||||
|
||||
export const onRequestLogging: FetchHook = async (ctx) => {
|
||||
if (!isDev()) return;
|
||||
const method = getRequestMethod(ctx.request, ctx.options);
|
||||
const url = getRequestUrl(ctx.request);
|
||||
console.log(
|
||||
`${TAG} → ${method} ${url}`,
|
||||
ctx.options.body !== undefined ? formatBody(ctx.options.body) : ""
|
||||
);
|
||||
};
|
||||
|
||||
export const onResponseLogging: FetchHook = async (ctx) => {
|
||||
if (!isDev() || !ctx.response) return;
|
||||
const method = getRequestMethod(ctx.request, ctx.options);
|
||||
const url = getRequestUrl(ctx.request);
|
||||
console.log(
|
||||
`${TAG} ← ${ctx.response.status} ${method} ${url}`,
|
||||
formatBody(ctx.response._data)
|
||||
);
|
||||
};
|
||||
|
||||
export const onErrorLogging: FetchHook = async (ctx) => {
|
||||
if (!isDev()) return;
|
||||
const status = ctx.response?.status ?? "N/A";
|
||||
const method = getRequestMethod(ctx.request, ctx.options);
|
||||
const url = getRequestUrl(ctx.request);
|
||||
console.error(
|
||||
`${TAG} ✕ ${status} ${method} ${url}`,
|
||||
ctx.error?.message ?? "Unknown error"
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 兼容旧接口的 FetchHooks 形式(保留以备兼容)
|
||||
*/
|
||||
export const loggingInterceptor = {
|
||||
onRequest: onRequestLogging,
|
||||
onResponse: onResponseLogging,
|
||||
onResponseError: onErrorLogging,
|
||||
onRequestError: onErrorLogging,
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Token 拦截器
|
||||
*
|
||||
* 在请求头中注入 Authorization: Bearer <token>。
|
||||
* 跳过不需要 token 的路径(登录、注册、发送验证码、刷新等)。
|
||||
* 原始 Dart: lib/core/net/interceptor/token_interceptor.dart + token_paths.dart
|
||||
*/
|
||||
import type { FetchHook } from "ofetch";
|
||||
import { ApiPath } from "../api_path";
|
||||
import { authStorage } from "../../storage/auth_storage";
|
||||
|
||||
/**
|
||||
* 不需要 token 的路径
|
||||
*/
|
||||
const NO_TOKEN_PATHS: readonly string[] = [
|
||||
ApiPath.sendCode,
|
||||
ApiPath.emailLogin,
|
||||
ApiPath.register,
|
||||
ApiPath.guestLogin,
|
||||
];
|
||||
|
||||
/**
|
||||
* 获取请求路径
|
||||
*/
|
||||
function getRequestPath(request: Request | string): string {
|
||||
if (typeof request === "string") {
|
||||
try {
|
||||
return new URL(request).pathname;
|
||||
} catch {
|
||||
return request;
|
||||
}
|
||||
}
|
||||
return new URL(request.url).pathname;
|
||||
}
|
||||
|
||||
/**
|
||||
* 路径是否需要 token
|
||||
*/
|
||||
function needsToken(path: string): boolean {
|
||||
return !NO_TOKEN_PATHS.some((noTokenPath) => path.includes(noTokenPath));
|
||||
}
|
||||
|
||||
export const onRequestToken: FetchHook = async (ctx) => {
|
||||
const path = getRequestPath(ctx.request);
|
||||
if (!needsToken(path)) return;
|
||||
|
||||
const token = authStorage.getAuthToken();
|
||||
if (token && ctx.request instanceof Request) {
|
||||
ctx.request.headers.set("Authorization", `Bearer ${token}`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 兼容旧接口的 FetchHooks 形式
|
||||
*/
|
||||
export const tokenInterceptor = {
|
||||
onRequest: onRequestToken,
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Metrics API
|
||||
*
|
||||
* 数据看板/上报相关接口
|
||||
* 原始 Dart: lib/data/services/api/metrics_api_client.dart
|
||||
*/
|
||||
import { httpClient } from "./http_client";
|
||||
import { ApiPath } from "./api_path";
|
||||
import { ApiEnvelope, unwrapOptional } from "./response_helper";
|
||||
import { AppEvent } from "@/data/dto/metrics/app_event";
|
||||
import { PwaEvent } from "@/data/dto/metrics/pwa_event";
|
||||
|
||||
export class MetricsApi {
|
||||
/**
|
||||
* 上报 PWA 事件
|
||||
*/
|
||||
async reportPwaEvent(body: PwaEvent): Promise<void> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(
|
||||
ApiPath.metricsPwaEvent,
|
||||
{ method: "POST", body: body.toJson() }
|
||||
);
|
||||
unwrapOptional(env);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报用户信息
|
||||
*/
|
||||
async reportUserInfo(body: AppEvent): Promise<void> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(
|
||||
ApiPath.reportUserInfo,
|
||||
{ method: "POST", body: body.toJson() }
|
||||
);
|
||||
unwrapOptional(env);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局单例
|
||||
*/
|
||||
export const metricsApi = new MetricsApi();
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 共享的后端 envelope 解析工具
|
||||
*
|
||||
* 4 个 `*_api.ts` 文件中重复的 `interface ApiEnvelope<T>` 与 `function unwrap<T>`
|
||||
* 集中到这里。HTTP 拦截器(`http_client.ts`)已经对非 2xx 响应抛 `ApiError`;
|
||||
* 本工具处理第二种失败:2xx 但 `success: false` 的 envelope。
|
||||
*
|
||||
* 行为升级:失败时抛 `ApiError`(`ApiError extends Error`),而不是裸 `Error`。
|
||||
* 这样调用方在 `Result.err` 内能 `instanceof ApiError` 检查 `.code` / `.status`。
|
||||
*
|
||||
* 原始 Dart: lib/data/services/api/api_client.dart 的 `NetResult<T>` 解析。
|
||||
*/
|
||||
import { ApiError, ErrorCode } from "./api_result";
|
||||
|
||||
/** 后端统一响应包装。 */
|
||||
export interface ApiEnvelope<T> {
|
||||
success: boolean;
|
||||
data?: T;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解包 envelope,失败时抛 `ApiError`。
|
||||
* 用于:data 字段必有(API 一定返回业务数据)的端点。
|
||||
*/
|
||||
export function unwrap<T>(envelope: ApiEnvelope<T>): T {
|
||||
if (!envelope.success || envelope.data === undefined) {
|
||||
throw new ApiError(
|
||||
ErrorCode.unknownError,
|
||||
envelope.message ?? envelope.error ?? "API call failed",
|
||||
);
|
||||
}
|
||||
return envelope.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解包 envelope,但允许 `data` 字段为 `undefined`(用于 fire-and-forget 类端点)。
|
||||
* 失败时仍抛 `ApiError`。
|
||||
*/
|
||||
export function unwrapOptional<T>(envelope: ApiEnvelope<T>): T | undefined {
|
||||
if (!envelope.success) {
|
||||
throw new ApiError(
|
||||
ErrorCode.unknownError,
|
||||
envelope.message ?? envelope.error ?? "API call failed",
|
||||
);
|
||||
}
|
||||
return envelope.data;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* User API
|
||||
*
|
||||
* 用户相关接口
|
||||
* 原始 Dart: lib/data/services/api/user_api_client.dart
|
||||
*/
|
||||
import { httpClient } from "./http_client";
|
||||
import { ApiPath } from "./api_path";
|
||||
import { ApiEnvelope, unwrap } from "./response_helper";
|
||||
import { CreditsData } from "@/data/dto/user/credits_data";
|
||||
import { CreditsHistoryData } from "@/data/dto/user/credits_history_data";
|
||||
import { UpdateProfileRequest } from "@/data/dto/user/update_profile_request";
|
||||
import { User } from "@/data/dto/user/user";
|
||||
import { UserStatsResponse } from "@/data/dto/user/user_stats_response";
|
||||
import type { UserData } from "@/data/services/schemas/user/user";
|
||||
|
||||
export class UserApi {
|
||||
/**
|
||||
* 获取用户统计信息
|
||||
*/
|
||||
async getUserStats(): Promise<UserStatsResponse> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.userStats);
|
||||
return UserStatsResponse.fromJson(
|
||||
unwrap(env) as Record<string, unknown>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取个人信息
|
||||
*/
|
||||
async getCurrentUser(): Promise<User> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.userProfile);
|
||||
return User.fromJson(unwrap(env) as UserData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新个人资料
|
||||
*/
|
||||
async updateProfile(body: UpdateProfileRequest): Promise<User> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.updateProfile, {
|
||||
method: "PUT",
|
||||
body: body.toJson(),
|
||||
});
|
||||
return User.fromJson(unwrap(env) as UserData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询积分余额
|
||||
*/
|
||||
async getCredits(): Promise<CreditsData> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.userCredits);
|
||||
return CreditsData.fromJson(unwrap(env) as Record<string, unknown>);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询积分操作历史
|
||||
*/
|
||||
async getCreditsHistory(
|
||||
limit = 50,
|
||||
offset = 0
|
||||
): Promise<CreditsHistoryData> {
|
||||
const env = await httpClient<ApiEnvelope<unknown>>(
|
||||
ApiPath.userCreditsHistory,
|
||||
{ query: { limit, offset } }
|
||||
);
|
||||
return CreditsHistoryData.fromJson(
|
||||
unwrap(env) as Record<string, unknown>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局单例
|
||||
*/
|
||||
export const userApi = new UserApi();
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Apple 登录请求 DTO
|
||||
*/
|
||||
import {
|
||||
AppleLoginRequestSchema,
|
||||
type AppleLoginRequestInput,
|
||||
type AppleLoginRequestData,
|
||||
} from "@/data/services/schemas/auth/apple_login_request";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: AppleLoginRequestInput): AppleLoginRequest {
|
||||
return new AppleLoginRequest(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): AppleLoginRequest {
|
||||
return AppleLoginRequest.from(json as AppleLoginRequestInput);
|
||||
}
|
||||
|
||||
toJson(): AppleLoginRequestData {
|
||||
return AppleLoginRequestSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Facebook 登录请求 DTO
|
||||
*/
|
||||
import {
|
||||
FacebookLoginRequestSchema,
|
||||
type FacebookLoginRequestInput,
|
||||
type FacebookLoginRequestData,
|
||||
} from "@/data/services/schemas/auth/facebook_login_request";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: FacebookLoginRequestInput): FacebookLoginRequest {
|
||||
return new FacebookLoginRequest(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): FacebookLoginRequest {
|
||||
return FacebookLoginRequest.from(json as FacebookLoginRequestInput);
|
||||
}
|
||||
|
||||
toJson(): FacebookLoginRequestData {
|
||||
return FacebookLoginRequestSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Facebook 用户数据 DTO
|
||||
*
|
||||
* 原始 Dart: FacebookUserData (lib/data/services/auth/auth_platform.dart)
|
||||
*/
|
||||
import {
|
||||
FacebookUserDataSchema,
|
||||
type FacebookUserDataInput,
|
||||
type FacebookUserDataData,
|
||||
} from "@/data/services/schemas/auth/facebook_user_data";
|
||||
|
||||
export class FacebookUserData {
|
||||
declare readonly id: string | null;
|
||||
declare readonly name: string | null;
|
||||
declare readonly email: string | null;
|
||||
declare readonly pictureUrl: string | null;
|
||||
|
||||
private constructor(input: FacebookUserDataInput) {
|
||||
const data = FacebookUserDataSchema.parse(input);
|
||||
Object.assign(this, data);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: FacebookUserDataInput): FacebookUserData {
|
||||
return new FacebookUserData(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): FacebookUserData {
|
||||
return FacebookUserData.from(json as FacebookUserDataInput);
|
||||
}
|
||||
|
||||
toJson(): FacebookUserDataData {
|
||||
return FacebookUserDataSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Facebook ID 登录请求 DTO
|
||||
*/
|
||||
import {
|
||||
FbIdLoginRequestSchema,
|
||||
type FbIdLoginRequestInput,
|
||||
type FbIdLoginRequestData,
|
||||
} from "@/data/services/schemas/auth/fb_id_login_request";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: FbIdLoginRequestInput): FbIdLoginRequest {
|
||||
return new FbIdLoginRequest(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): FbIdLoginRequest {
|
||||
return FbIdLoginRequest.from(json as FbIdLoginRequestInput);
|
||||
}
|
||||
|
||||
toJson(): FbIdLoginRequestData {
|
||||
return FbIdLoginRequestSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Google 登录请求 DTO
|
||||
*/
|
||||
import {
|
||||
GoogleLoginRequestSchema,
|
||||
type GoogleLoginRequestInput,
|
||||
type GoogleLoginRequestData,
|
||||
} from "@/data/services/schemas/auth/google_login_request";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: GoogleLoginRequestInput): GoogleLoginRequest {
|
||||
return new GoogleLoginRequest(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): GoogleLoginRequest {
|
||||
return GoogleLoginRequest.from(json as GoogleLoginRequestInput);
|
||||
}
|
||||
|
||||
toJson(): GoogleLoginRequestData {
|
||||
return GoogleLoginRequestSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 游客登录请求 DTO
|
||||
*/
|
||||
import {
|
||||
GuestLoginRequestSchema,
|
||||
type GuestLoginRequestInput,
|
||||
type GuestLoginRequestData,
|
||||
} from "@/data/services/schemas/auth/guest_login_request";
|
||||
|
||||
export class GuestLoginRequest {
|
||||
declare readonly deviceId: string;
|
||||
|
||||
private constructor(input: GuestLoginRequestInput) {
|
||||
const data = GuestLoginRequestSchema.parse(input);
|
||||
Object.assign(this, data);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: GuestLoginRequestInput): GuestLoginRequest {
|
||||
return new GuestLoginRequest(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): GuestLoginRequest {
|
||||
return GuestLoginRequest.from(json as GuestLoginRequestInput);
|
||||
}
|
||||
|
||||
toJson(): GuestLoginRequestData {
|
||||
return GuestLoginRequestSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 游客登录响应 DTO
|
||||
*/
|
||||
import {
|
||||
GuestLoginResponseSchema,
|
||||
type GuestLoginResponseInput,
|
||||
type GuestLoginResponseData,
|
||||
} from "@/data/services/schemas/auth/guest_login_response";
|
||||
import { User } from "@/data/dto/user/user";
|
||||
|
||||
export class GuestLoginResponse {
|
||||
declare readonly token: string;
|
||||
declare readonly deviceId: string;
|
||||
declare readonly userId: string;
|
||||
declare readonly isDeviceUser: boolean;
|
||||
declare readonly expiresIn: number;
|
||||
declare readonly user: User;
|
||||
|
||||
private constructor(input: GuestLoginResponseInput) {
|
||||
const parsed = GuestLoginResponseSchema.parse(input);
|
||||
Object.assign(this, {
|
||||
...parsed,
|
||||
user: parsed.user ? User.fromJson(parsed.user) : User.empty(),
|
||||
});
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: GuestLoginResponseInput): GuestLoginResponse {
|
||||
return new GuestLoginResponse(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): GuestLoginResponse {
|
||||
return GuestLoginResponse.from(json as GuestLoginResponseInput);
|
||||
}
|
||||
|
||||
toJson(): GuestLoginResponseData {
|
||||
const data = GuestLoginResponseSchema.parse(this);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./apple_login_request";
|
||||
export * from "./facebook_login_request";
|
||||
export * from "./facebook_user_data";
|
||||
export * from "./fb_id_login_request";
|
||||
export * from "./google_login_request";
|
||||
export * from "./guest_login_request";
|
||||
export * from "./guest_login_response";
|
||||
export * from "./login_request";
|
||||
export * from "./login_response";
|
||||
export * from "./logout_response";
|
||||
export * from "./refresh_token_request";
|
||||
export * from "./refresh_token_response";
|
||||
export * from "./register_request";
|
||||
export * from "./send_code_request";
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 登录请求 DTO
|
||||
*/
|
||||
import {
|
||||
LoginRequestSchema,
|
||||
type LoginRequestInput,
|
||||
type LoginRequestData,
|
||||
} from "@/data/services/schemas/auth/login_request";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: LoginRequestInput): LoginRequest {
|
||||
return new LoginRequest(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): LoginRequest {
|
||||
return LoginRequest.from(json as LoginRequestInput);
|
||||
}
|
||||
|
||||
toJson(): LoginRequestData {
|
||||
return LoginRequestSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 登录响应 DTO
|
||||
*/
|
||||
import {
|
||||
LoginResponseSchema,
|
||||
type LoginResponseInput,
|
||||
type LoginResponseData,
|
||||
} from "@/data/services/schemas/auth/login_response";
|
||||
import { User } from "@/data/dto/user/user";
|
||||
|
||||
export class LoginResponse {
|
||||
declare readonly user: User;
|
||||
declare readonly token: string;
|
||||
declare readonly refreshToken: string;
|
||||
|
||||
private constructor(input: LoginResponseInput) {
|
||||
const data = LoginResponseSchema.parse(input);
|
||||
Object.assign(this, {
|
||||
...data,
|
||||
user: User.fromJson(data.user),
|
||||
});
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: LoginResponseInput): LoginResponse {
|
||||
return new LoginResponse(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): LoginResponse {
|
||||
return LoginResponse.from(json as LoginResponseInput);
|
||||
}
|
||||
|
||||
toJson(): LoginResponseData {
|
||||
return LoginResponseSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 退出登录响应 DTO
|
||||
*/
|
||||
import {
|
||||
LogoutResponseSchema,
|
||||
type LogoutResponseInput,
|
||||
type LogoutResponseData,
|
||||
} from "@/data/services/schemas/auth/logout_response";
|
||||
|
||||
export class LogoutResponse {
|
||||
declare readonly success: boolean;
|
||||
|
||||
private constructor(input: LogoutResponseInput) {
|
||||
const data = LogoutResponseSchema.parse(input);
|
||||
Object.assign(this, data);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: LogoutResponseInput): LogoutResponse {
|
||||
return new LogoutResponse(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): LogoutResponse {
|
||||
return LogoutResponse.from(json as LogoutResponseInput);
|
||||
}
|
||||
|
||||
toJson(): LogoutResponseData {
|
||||
return LogoutResponseSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 刷新 Token 请求 DTO
|
||||
*/
|
||||
import {
|
||||
RefreshTokenRequestSchema,
|
||||
type RefreshTokenRequestInput,
|
||||
type RefreshTokenRequestData,
|
||||
} from "@/data/services/schemas/auth/refresh_token_request";
|
||||
|
||||
export class RefreshTokenRequest {
|
||||
declare readonly refreshToken: string;
|
||||
|
||||
private constructor(input: RefreshTokenRequestInput) {
|
||||
const data = RefreshTokenRequestSchema.parse(input);
|
||||
Object.assign(this, data);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: RefreshTokenRequestInput): RefreshTokenRequest {
|
||||
return new RefreshTokenRequest(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): RefreshTokenRequest {
|
||||
return RefreshTokenRequest.from(json as RefreshTokenRequestInput);
|
||||
}
|
||||
|
||||
toJson(): RefreshTokenRequestData {
|
||||
return RefreshTokenRequestSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 刷新 Token 响应 DTO
|
||||
*/
|
||||
import {
|
||||
RefreshTokenResponseSchema,
|
||||
type RefreshTokenResponseInput,
|
||||
type RefreshTokenResponseData,
|
||||
} from "@/data/services/schemas/auth/refresh_token_response";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: RefreshTokenResponseInput): RefreshTokenResponse {
|
||||
return new RefreshTokenResponse(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): RefreshTokenResponse {
|
||||
return RefreshTokenResponse.from(json as RefreshTokenResponseInput);
|
||||
}
|
||||
|
||||
toJson(): RefreshTokenResponseData {
|
||||
return RefreshTokenResponseSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 注册请求 DTO
|
||||
*/
|
||||
import {
|
||||
RegisterRequestSchema,
|
||||
type RegisterRequestInput,
|
||||
type RegisterRequestData,
|
||||
} from "@/data/services/schemas/auth/register_request";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: RegisterRequestInput): RegisterRequest {
|
||||
return new RegisterRequest(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): RegisterRequest {
|
||||
return RegisterRequest.from(json as RegisterRequestInput);
|
||||
}
|
||||
|
||||
toJson(): RegisterRequestData {
|
||||
return RegisterRequestSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 发送验证码请求 DTO
|
||||
*/
|
||||
import {
|
||||
SendCodeRequestSchema,
|
||||
type SendCodeRequestInput,
|
||||
type SendCodeRequestData,
|
||||
} from "@/data/services/schemas/auth/send_code_request";
|
||||
|
||||
export class SendCodeRequest {
|
||||
declare readonly email: string;
|
||||
|
||||
private constructor(input: SendCodeRequestInput) {
|
||||
const data = SendCodeRequestSchema.parse(input);
|
||||
Object.assign(this, data);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: SendCodeRequestInput): SendCodeRequest {
|
||||
return new SendCodeRequest(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): SendCodeRequest {
|
||||
return SendCodeRequest.from(json as SendCodeRequestInput);
|
||||
}
|
||||
|
||||
toJson(): SendCodeRequestData {
|
||||
return SendCodeRequestSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 聊天历史响应 DTO
|
||||
*/
|
||||
import {
|
||||
ChatHistoryResponseSchema,
|
||||
type ChatHistoryResponseInput,
|
||||
type ChatHistoryResponseData,
|
||||
} from "@/data/services/schemas/chat/chat_history_response";
|
||||
import { ChatMessage } from "./chat_message";
|
||||
|
||||
export class ChatHistoryResponse {
|
||||
declare readonly messages: ChatMessage[];
|
||||
declare readonly total: number;
|
||||
declare readonly limit: number;
|
||||
declare readonly offset: number;
|
||||
|
||||
private constructor(input: ChatHistoryResponseInput) {
|
||||
const data = ChatHistoryResponseSchema.parse(input);
|
||||
Object.assign(this, {
|
||||
...data,
|
||||
messages: data.messages.map((m) => ChatMessage.from(m)),
|
||||
});
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: ChatHistoryResponseInput): ChatHistoryResponse {
|
||||
return new ChatHistoryResponse(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): ChatHistoryResponse {
|
||||
return ChatHistoryResponse.from(json as ChatHistoryResponseInput);
|
||||
}
|
||||
|
||||
toJson(): ChatHistoryResponseData {
|
||||
return ChatHistoryResponseSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 聊天历史中的单条消息 DTO
|
||||
*/
|
||||
import {
|
||||
ChatMessageSchema,
|
||||
type ChatMessageInput,
|
||||
type ChatMessageData,
|
||||
} from "@/data/services/schemas/chat/chat_message";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: ChatMessageInput): ChatMessage {
|
||||
return new ChatMessage(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): ChatMessage {
|
||||
return ChatMessage.from(json as ChatMessageInput);
|
||||
}
|
||||
|
||||
toJson(): ChatMessageData {
|
||||
return ChatMessageSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 发送消息响应 DTO
|
||||
*/
|
||||
import {
|
||||
ChatSendResponseSchema,
|
||||
type ChatSendResponseInput,
|
||||
type ChatSendResponseData,
|
||||
} from "@/data/services/schemas/chat/chat_send_response";
|
||||
|
||||
export class ChatSendResponse {
|
||||
declare readonly mode: string;
|
||||
declare readonly reply: string;
|
||||
declare readonly voiceUrl: string;
|
||||
declare readonly audioUrl: string;
|
||||
declare readonly intimidadChange: 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);
|
||||
}
|
||||
|
||||
static from(input: ChatSendResponseInput): ChatSendResponse {
|
||||
return new ChatSendResponse(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): ChatSendResponse {
|
||||
return ChatSendResponse.from(json as ChatSendResponseInput);
|
||||
}
|
||||
|
||||
toJson(): ChatSendResponseData {
|
||||
return ChatSendResponseSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 消息同步响应 DTO
|
||||
*/
|
||||
import {
|
||||
ChatSyncDataSchema,
|
||||
type ChatSyncDataInput,
|
||||
type ChatSyncDataData,
|
||||
} from "@/data/services/schemas/chat/chat_sync_data";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: ChatSyncDataInput): ChatSyncData {
|
||||
return new ChatSyncData(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): ChatSyncData {
|
||||
return ChatSyncData.from(json as ChatSyncDataInput);
|
||||
}
|
||||
|
||||
toJson(): ChatSyncDataData {
|
||||
return ChatSyncDataSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 消息同步请求 DTO
|
||||
*/
|
||||
import {
|
||||
ChatSyncRequestSchema,
|
||||
type ChatSyncRequestInput,
|
||||
type ChatSyncRequestData,
|
||||
} from "@/data/services/schemas/chat/chat_sync_request";
|
||||
import { SyncMessage } from "./sync_message";
|
||||
|
||||
export class ChatSyncRequest {
|
||||
declare readonly messages: SyncMessage[];
|
||||
|
||||
private constructor(input: ChatSyncRequestInput) {
|
||||
const data = ChatSyncRequestSchema.parse(input);
|
||||
Object.assign(this, {
|
||||
...data,
|
||||
messages: data.messages.map((m) => SyncMessage.from(m)),
|
||||
});
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: ChatSyncRequestInput): ChatSyncRequest {
|
||||
return new ChatSyncRequest(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): ChatSyncRequest {
|
||||
return ChatSyncRequest.from(json as ChatSyncRequestInput);
|
||||
}
|
||||
|
||||
toJson(): ChatSyncRequestData {
|
||||
return ChatSyncRequestSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* 游客每日聊天配额数据 DTO
|
||||
*/
|
||||
import {
|
||||
GuestChatQuotaSchema,
|
||||
type GuestChatQuotaInput,
|
||||
type GuestChatQuotaData,
|
||||
} from "@/data/services/schemas/chat/guest_chat_quota";
|
||||
|
||||
export class GuestChatQuota {
|
||||
// 静态常量
|
||||
static readonly maxQuotaPerDay = 40;
|
||||
static readonly maxQuotaPerDayTest = 4;
|
||||
static readonly quotaWarningThreshold = 20;
|
||||
static readonly quotaWarningThresholdTest = 2;
|
||||
static readonly defaultTotalQuota = 50;
|
||||
static readonly defaultTotalQuotaDev = 5;
|
||||
static readonly quotaExhausted = 0;
|
||||
|
||||
declare readonly remaining: number;
|
||||
declare readonly date: string;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 配额耗尽状态值
|
||||
*/
|
||||
static get exhausted(): number {
|
||||
return GuestChatQuota.quotaExhausted;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否处于开发环境
|
||||
*/
|
||||
static get isDevelopment(): boolean {
|
||||
return process.env.NODE_ENV !== "production";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前环境的配额警告阈值
|
||||
*/
|
||||
static get warningThreshold(): number {
|
||||
return GuestChatQuota.isDevelopment
|
||||
? GuestChatQuota.quotaWarningThresholdTest
|
||||
: GuestChatQuota.quotaWarningThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前环境的每日最大配额
|
||||
*/
|
||||
static get threshold(): number {
|
||||
return GuestChatQuota.isDevelopment
|
||||
? GuestChatQuota.maxQuotaPerDayTest
|
||||
: GuestChatQuota.maxQuotaPerDay;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前环境的总配额默认值
|
||||
*/
|
||||
static get totalQuotaDefault(): number {
|
||||
return GuestChatQuota.isDevelopment
|
||||
? GuestChatQuota.defaultTotalQuotaDev
|
||||
: GuestChatQuota.defaultTotalQuota;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建初始配额实例
|
||||
*/
|
||||
static initial(todayString: string): GuestChatQuota {
|
||||
return new GuestChatQuota({
|
||||
remaining: GuestChatQuota.threshold,
|
||||
date: todayString,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否需要重置(跨天)
|
||||
*/
|
||||
needsReset(todayString: string): boolean {
|
||||
return this.date !== todayString;
|
||||
}
|
||||
|
||||
toJson(): GuestChatQuotaData {
|
||||
return GuestChatQuotaSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 图片上传响应 DTO
|
||||
*/
|
||||
import {
|
||||
ImageUploadResponseSchema,
|
||||
type ImageUploadResponseInput,
|
||||
type ImageUploadResponseData,
|
||||
} from "@/data/services/schemas/chat/image_upload_response";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: ImageUploadResponseInput): ImageUploadResponse {
|
||||
return new ImageUploadResponse(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): ImageUploadResponse {
|
||||
return ImageUploadResponse.from(json as ImageUploadResponseInput);
|
||||
}
|
||||
|
||||
toJson(): ImageUploadResponseData {
|
||||
return ImageUploadResponseSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./chat_history_response";
|
||||
export * from "./chat_message";
|
||||
export * from "./chat_send_response";
|
||||
export * from "./chat_sync_data";
|
||||
export * from "./chat_sync_request";
|
||||
export * from "./guest_chat_quota";
|
||||
export * from "./image_upload_response";
|
||||
export * from "./send_message_request";
|
||||
export * from "./stt_data";
|
||||
export * from "./sync_message";
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 发送消息请求 DTO
|
||||
*/
|
||||
import {
|
||||
SendMessageRequestSchema,
|
||||
type SendMessageRequestInput,
|
||||
type SendMessageRequestData,
|
||||
} from "@/data/services/schemas/chat/send_message_request";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: SendMessageRequestInput): SendMessageRequest {
|
||||
return new SendMessageRequest(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): SendMessageRequest {
|
||||
return SendMessageRequest.from(json as SendMessageRequestInput);
|
||||
}
|
||||
|
||||
toJson(): SendMessageRequestData {
|
||||
return SendMessageRequestSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* STT(语音转文字)响应 DTO
|
||||
*/
|
||||
import {
|
||||
SttDataSchema,
|
||||
type SttDataInput,
|
||||
type SttDataData,
|
||||
} from "@/data/services/schemas/chat/stt_data";
|
||||
|
||||
export class SttData {
|
||||
declare readonly text: string;
|
||||
|
||||
private constructor(input: SttDataInput) {
|
||||
const data = SttDataSchema.parse(input);
|
||||
Object.assign(this, data);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
static from(input: SttDataInput): SttData {
|
||||
return new SttData(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): SttData {
|
||||
return SttData.from(json as SttDataInput);
|
||||
}
|
||||
|
||||
toJson(): SttDataData {
|
||||
return SttDataSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 待同步的单条消息 DTO
|
||||
*/
|
||||
import {
|
||||
SyncMessageSchema,
|
||||
type SyncMessageInput,
|
||||
type SyncMessageData,
|
||||
} from "@/data/services/schemas/chat/sync_message";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: SyncMessageInput): SyncMessage {
|
||||
return new SyncMessage(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): SyncMessage {
|
||||
return SyncMessage.from(json as SyncMessageInput);
|
||||
}
|
||||
|
||||
toJson(): SyncMessageData {
|
||||
return SyncMessageSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./auth/apple_login_request";
|
||||
export * from "./auth/facebook_login_request";
|
||||
export * from "./auth/facebook_user_data";
|
||||
export * from "./auth/fb_id_login_request";
|
||||
export * from "./auth/google_login_request";
|
||||
export * from "./auth/guest_login_request";
|
||||
export * from "./auth/guest_login_response";
|
||||
export * from "./auth/login_request";
|
||||
export * from "./auth/login_response";
|
||||
export * from "./auth/logout_response";
|
||||
export * from "./auth/refresh_token_request";
|
||||
export * from "./auth/refresh_token_response";
|
||||
export * from "./auth/register_request";
|
||||
export * from "./auth/send_code_request";
|
||||
export * from "./chat/chat_history_response";
|
||||
export * from "./chat/chat_message";
|
||||
export * from "./chat/chat_send_response";
|
||||
export * from "./chat/chat_sync_data";
|
||||
export * from "./chat/chat_sync_request";
|
||||
export * from "./chat/guest_chat_quota";
|
||||
export * from "./chat/image_upload_response";
|
||||
export * from "./chat/send_message_request";
|
||||
export * from "./chat/stt_data";
|
||||
export * from "./chat/sync_message";
|
||||
export * from "./metrics/app_event";
|
||||
export * from "./metrics/pwa_event";
|
||||
export * from "./user/avatar_data";
|
||||
export * from "./user/credits_data";
|
||||
export * from "./user/credits_history_data";
|
||||
export * from "./user/personality_traits";
|
||||
export * from "./user/recent_memory";
|
||||
export * from "./user/update_profile_request";
|
||||
export * from "./user/user";
|
||||
export * from "./user/user_stats_response";
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 应用事件上报请求 DTO
|
||||
*/
|
||||
import {
|
||||
AppEventSchema,
|
||||
type AppEventInput,
|
||||
type AppEventData,
|
||||
} from "@/data/services/schemas/metrics/app_event";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: AppEventInput): AppEvent {
|
||||
return new AppEvent(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): AppEvent {
|
||||
return AppEvent.from(json as AppEventInput);
|
||||
}
|
||||
|
||||
toJson(): AppEventData {
|
||||
return AppEventSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./app_event";
|
||||
export * from "./pwa_event";
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* PWA 事件上报请求 DTO
|
||||
*/
|
||||
import {
|
||||
PwaEventSchema,
|
||||
type PwaEventInput,
|
||||
type PwaEventData,
|
||||
} from "@/data/services/schemas/metrics/pwa_event";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static from(input: PwaEventInput): PwaEvent {
|
||||
return new PwaEvent(input);
|
||||
}
|
||||
|
||||
static fromJson(json: unknown): PwaEvent {
|
||||
return PwaEvent.from(json as PwaEventInput);
|
||||
}
|
||||
|
||||
toJson(): PwaEventData {
|
||||
return PwaEventSchema.parse(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 头像数据 DTO
|
||||
*/
|
||||
import {
|
||||
AvatarDataSchema,
|
||||
type AvatarDataInput,
|
||||
type AvatarDataData,
|
||||
} from "@/data/services/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/services/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/services/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,12 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./avatar_data";
|
||||
export * from "./credits_data";
|
||||
export * from "./credits_history_data";
|
||||
export * from "./personality_traits";
|
||||
export * from "./recent_memory";
|
||||
export * from "./update_profile_request";
|
||||
export * from "./user";
|
||||
export * from "./user_stats_response";
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 个性特征 DTO
|
||||
*/
|
||||
import {
|
||||
PersonalityTraitsSchema,
|
||||
type PersonalityTraitsInput,
|
||||
type PersonalityTraitsData,
|
||||
} from "@/data/services/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/services/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/services/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/services/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/services/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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Apple 登录请求
|
||||
* 原始 Dart: AppleLoginRequest (lib/data/models/auth/auth_request.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Facebook 登录请求
|
||||
* 原始 Dart: FacebookLoginRequest (lib/data/models/auth/auth_request.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Facebook 用户数据 schema
|
||||
* 原始 Dart: FacebookUserData (lib/data/services/auth/auth_platform.dart)
|
||||
*
|
||||
* 字段对齐 Dart 端 `String?` 可空语义:缺字段时存 `null`。
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
export const FacebookUserDataSchema = z.object({
|
||||
id: z.string().nullable().default(null),
|
||||
name: z.string().nullable().default(null),
|
||||
email: z.string().nullable().default(null),
|
||||
pictureUrl: z.string().nullable().default(null),
|
||||
});
|
||||
|
||||
export type FacebookUserDataInput = z.input<typeof FacebookUserDataSchema>;
|
||||
export type FacebookUserDataData = z.output<typeof FacebookUserDataSchema>;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Facebook ID 登录请求
|
||||
* 原始 Dart: FbIdLoginRequest (lib/data/models/auth/auth_request.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Google 登录请求
|
||||
* 原始 Dart: GoogleLoginRequest (lib/data/models/auth/auth_request.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 游客登录请求
|
||||
* 原始 Dart: GuestLoginRequest (lib/data/models/auth/auth_request.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
export const GuestLoginRequestSchema = z.object({
|
||||
deviceId: z.string(),
|
||||
});
|
||||
|
||||
export type GuestLoginRequestInput = z.input<typeof GuestLoginRequestSchema>;
|
||||
export type GuestLoginRequestData = z.output<typeof GuestLoginRequestSchema>;
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 游客登录响应
|
||||
* 原始 Dart: GuestLoginResponse (lib/data/models/auth/auth_response.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
import { 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>;
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./apple_login_request";
|
||||
export * from "./facebook_login_request";
|
||||
export * from "./facebook_user_data";
|
||||
export * from "./fb_id_login_request";
|
||||
export * from "./google_login_request";
|
||||
export * from "./guest_login_request";
|
||||
export * from "./guest_login_response";
|
||||
export * from "./login_request";
|
||||
export * from "./login_response";
|
||||
export * from "./logout_response";
|
||||
export * from "./refresh_token_request";
|
||||
export * from "./refresh_token_response";
|
||||
export * from "./register_request";
|
||||
export * from "./send_code_request";
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* 登录请求
|
||||
* 原始 Dart: LoginRequest (lib/data/models/auth/auth_request.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 登录响应
|
||||
* 原始 Dart: LoginResponse (lib/data/models/auth/auth_response.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
import { 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>;
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 退出登录响应
|
||||
* 原始 Dart: LogoutResponse (lib/data/models/auth/auth_response.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
export const LogoutResponseSchema = z.object({
|
||||
success: z.boolean().default(true),
|
||||
});
|
||||
|
||||
export type LogoutResponseInput = z.input<typeof LogoutResponseSchema>;
|
||||
export type LogoutResponseData = z.output<typeof LogoutResponseSchema>;
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 刷新 Token 请求
|
||||
* 原始 Dart: RefreshTokenRequest (lib/data/models/auth/auth_request.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
export const RefreshTokenRequestSchema = z.object({
|
||||
refreshToken: z.string(),
|
||||
});
|
||||
|
||||
export type RefreshTokenRequestInput = z.input<typeof RefreshTokenRequestSchema>;
|
||||
export type RefreshTokenRequestData = z.output<typeof RefreshTokenRequestSchema>;
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 刷新 Token 响应
|
||||
* 原始 Dart: RefreshTokenResponse (lib/data/models/auth/auth_response.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* 注册请求
|
||||
* 原始 Dart: RegisterRequest (lib/data/models/auth/auth_request.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* 发送验证码请求
|
||||
* 原始 Dart: SendCodeRequest (lib/data/models/auth/auth_request.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
export const SendCodeRequestSchema = z.object({
|
||||
email: z.string(),
|
||||
});
|
||||
|
||||
export type SendCodeRequestInput = z.input<typeof SendCodeRequestSchema>;
|
||||
export type SendCodeRequestData = z.output<typeof SendCodeRequestSchema>;
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* 聊天历史响应
|
||||
* 原始 Dart: ChatHistoryResponse (lib/data/models/chat/chat_response.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
import { 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>;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 聊天历史中的单条消息
|
||||
* 原始 Dart: ChatMessage (lib/data/models/chat/chat_response.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 发送消息响应
|
||||
* 原始 Dart: ChatSendResponse (lib/data/models/chat/chat_response.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 消息同步响应
|
||||
* 原始 Dart: ChatSyncData (lib/data/models/chat/chat_sync.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 消息同步请求
|
||||
* 原始 Dart: ChatSyncRequest (lib/data/models/chat/chat_sync.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
import { 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>;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 游客每日聊天配额数据
|
||||
* 原始 Dart: GuestChatQuota (lib/data/models/chat/guest_chat_quota.dart)
|
||||
*/
|
||||
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>;
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 图片上传响应
|
||||
* 原始 Dart: ImageUploadResponse (lib/data/models/chat/image_upload_response.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./chat_history_response";
|
||||
export * from "./chat_message";
|
||||
export * from "./chat_send_response";
|
||||
export * from "./chat_sync_data";
|
||||
export * from "./chat_sync_request";
|
||||
export * from "./guest_chat_quota";
|
||||
export * from "./image_upload_response";
|
||||
export * from "./send_message_request";
|
||||
export * from "./stt_data";
|
||||
export * from "./sync_message";
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* 发送消息请求
|
||||
* 原始 Dart: SendMessageRequest (lib/data/models/chat/send_message_request.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* STT(语音转文字)响应
|
||||
* 原始 Dart: SttData (lib/data/models/chat/stt_response.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
export const SttDataSchema = z.object({
|
||||
text: z.string(),
|
||||
});
|
||||
|
||||
export type SttDataInput = z.input<typeof SttDataSchema>;
|
||||
export type SttDataData = z.output<typeof SttDataSchema>;
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 待同步的单条消息
|
||||
* 原始 Dart: SyncMessage (lib/data/models/chat/chat_sync.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./auth/apple_login_request";
|
||||
export * from "./auth/facebook_login_request";
|
||||
export * from "./auth/facebook_user_data";
|
||||
export * from "./auth/fb_id_login_request";
|
||||
export * from "./auth/google_login_request";
|
||||
export * from "./auth/guest_login_request";
|
||||
export * from "./auth/guest_login_response";
|
||||
export * from "./auth/login_request";
|
||||
export * from "./auth/login_response";
|
||||
export * from "./auth/logout_response";
|
||||
export * from "./auth/refresh_token_request";
|
||||
export * from "./auth/refresh_token_response";
|
||||
export * from "./auth/register_request";
|
||||
export * from "./auth/send_code_request";
|
||||
export * from "./chat/chat_history_response";
|
||||
export * from "./chat/chat_message";
|
||||
export * from "./chat/chat_send_response";
|
||||
export * from "./chat/chat_sync_data";
|
||||
export * from "./chat/chat_sync_request";
|
||||
export * from "./chat/guest_chat_quota";
|
||||
export * from "./chat/image_upload_response";
|
||||
export * from "./chat/send_message_request";
|
||||
export * from "./chat/stt_data";
|
||||
export * from "./chat/sync_message";
|
||||
export * from "./metrics/app_event";
|
||||
export * from "./metrics/pwa_event";
|
||||
export * from "./user/avatar_data";
|
||||
export * from "./user/credits_data";
|
||||
export * from "./user/credits_history_data";
|
||||
export * from "./user/personality_traits";
|
||||
export * from "./user/recent_memory";
|
||||
export * from "./user/update_profile_request";
|
||||
export * from "./user/user";
|
||||
export * from "./user/user_stats_response";
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 应用事件上报请求
|
||||
* 原始 Dart: AppEvent (lib/data/models/metrics/app_event.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./app_event";
|
||||
export * from "./pwa_event";
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* PWA 事件上报请求
|
||||
* 原始 Dart: PwaEvent (lib/data/models/metrics/pwa_event.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 头像数据模型
|
||||
* 原始 Dart: AvatarData (lib/data/models/user/user.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 积分数据模型
|
||||
* 原始 Dart: CreditsData (lib/data/models/user/user.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 积分历史记录模型
|
||||
* 原始 Dart: CreditsHistoryData (lib/data/models/user/user.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @file Automatically generated by barrelsby.
|
||||
*/
|
||||
|
||||
export * from "./avatar_data";
|
||||
export * from "./credits_data";
|
||||
export * from "./credits_history_data";
|
||||
export * from "./personality_traits";
|
||||
export * from "./recent_memory";
|
||||
export * from "./update_profile_request";
|
||||
export * from "./user";
|
||||
export * from "./user_stats_response";
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 个性特征模型
|
||||
* 原始 Dart: PersonalityTraits (lib/data/models/user/user.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
export const PERSONALITY_TRAITS_DEFAULTS = {
|
||||
cheerful: 0.5,
|
||||
caring: 0.5,
|
||||
playful: 0.5,
|
||||
serious: 0.5,
|
||||
romantic: 0.5,
|
||||
} as const;
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 最近记忆模型
|
||||
* 原始 Dart: RecentMemory (lib/data/models/user/recent_memory.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 更新个人资料请求
|
||||
* 原始 Dart: UpdateProfileRequest (lib/data/models/user/user.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
|
||||
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>;
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 用户模型
|
||||
* 原始 Dart: User (lib/data/models/user/user.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
import { 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>;
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 用户统计响应
|
||||
* 原始 Dart: UserStatsResponse (lib/data/models/user/user_stats_response.dart)
|
||||
*/
|
||||
import { z } from "zod";
|
||||
import { PersonalityTraitsSchema, PERSONALITY_TRAITS_DEFAULTS } from "./personality_traits";
|
||||
import { 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>;
|
||||
Reference in New Issue
Block a user