refactor(data): merge DTO models into schemas

This commit is contained in:
2026-07-17 12:47:18 +08:00
parent 2796010971
commit eac3d8f0a7
274 changed files with 1466 additions and 1956 deletions
@@ -2,7 +2,7 @@ import { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { PaymentPlan } from "@/data/dto/payment";
import { PaymentPlan } from "@/data/schemas/payment";
import { behaviorAnalytics } from "@/lib/analytics";
import { usePaymentPlanAnalytics } from "../use-payment-plan-analytics";
+1 -1
View File
@@ -2,7 +2,7 @@
import { useEffect, useRef } from "react";
import type { PaymentPlan } from "@/data/dto/payment";
import type { PaymentPlan } from "@/data/schemas/payment";
import {
behaviorAnalytics,
type PaymentAnalyticsContext,
+1 -1
View File
@@ -2,7 +2,7 @@
import { type Dispatch, useEffect, useRef } from "react";
import type { PayChannel } from "@/data/dto/payment";
import type { PayChannel } from "@/data/schemas/payment";
import type { PendingPaymentSubscriptionType } from "@/lib/payment/pending_payment_order";
import {
usePaymentDispatch,
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import type { UiMessage } from "@/data/dto/chat";
import type { UiMessage } from "@/stores/chat/ui-message";
import {
buildChatRenderItems,
+1 -1
View File
@@ -1,4 +1,4 @@
import type { UiMessage } from "@/data/dto/chat";
import type { UiMessage } from "@/stores/chat/ui-message";
export type ChatMessageKeyResolver = (message: UiMessage) => string;
+1 -1
View File
@@ -1,6 +1,6 @@
"use client";
import type { LoginStatus } from "@/data/dto/auth";
import type { LoginStatus } from "@/data/schemas/auth";
import type { ChatUpgradeReason } from "@/stores/chat/chat-state";
import { AppEnvUtil } from "@/utils/app-env";
import { BrowserDetector } from "@/utils/browser-detect";
@@ -2,7 +2,7 @@ import { act } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { UiMessage } from "@/data/dto/chat";
import type { UiMessage } from "@/stores/chat/ui-message";
import { ChatArea } from "../chat-area";
+1 -1
View File
@@ -23,7 +23,7 @@ import {
} from "react";
import { LoaderCircle } from "lucide-react";
import type { UiMessage } from "@/data/dto/chat";
import type { UiMessage } from "@/stores/chat/ui-message";
import { DEFAULT_CHARACTER_ID } from "@/data/constants/character";
import { usePullToRefresh } from "@/hooks/use-pull-to-refresh";
@@ -3,7 +3,7 @@
import { useEffect, useState } from "react";
import { shallowEqual } from "@xstate/react";
import type { LoginStatus } from "@/data/dto/auth";
import type { LoginStatus } from "@/data/schemas/auth";
import { useAppNavigator } from "@/router/use-app-navigator";
import {
usePaymentDispatch,
@@ -2,8 +2,8 @@
import { useEffect, useRef } from "react";
import type { LoginStatus } from "@/data/dto/auth";
import type { UiMessage } from "@/data/dto/chat";
import type { LoginStatus } from "@/data/schemas/auth";
import type { UiMessage } from "@/stores/chat/ui-message";
import { resolveSplashLatestMessageCacheIdentity } from "@/lib/chat/splash_latest_message";
import { getLatestSplashMessagePreview } from "@/lib/chat/splash_latest_message_preview";
import { useSplashLatestMessageCache } from "@/providers/splash-latest-message-provider";
+1 -1
View File
@@ -1,6 +1,6 @@
import packageInfo from "../../../package.json";
import type { FeedbackContext } from "@/data/dto/feedback";
import type { FeedbackContext } from "@/data/schemas/feedback";
import { BrowserDetector } from "@/utils/browser-detect";
import { PlatformDetector } from "@/utils/platform-detect";
+1 -1
View File
@@ -16,7 +16,7 @@ import {
import { BackButton } from "@/app/_components";
import { MobileShell } from "@/app/_components/core";
import type { FeedbackCategory } from "@/data/dto/feedback";
import type { FeedbackCategory } from "@/data/schemas/feedback";
import { ROUTES } from "@/router/routes";
import { useAppNavigator } from "@/router/use-app-navigator";
+1 -1
View File
@@ -2,7 +2,7 @@
import { type FormEvent, useEffect, useRef, useState } from "react";
import type { FeedbackCategory } from "@/data/dto/feedback";
import type { FeedbackCategory } from "@/data/schemas/feedback";
import { submitFeedback } from "@/lib/feedback";
import { createFeedbackContext } from "./feedback-context";
@@ -2,7 +2,7 @@ import { act, type Dispatch } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { LoginStatus } from "@/data/dto/auth";
import type { LoginStatus } from "@/data/schemas/auth";
import { ROUTES } from "@/router/routes";
import type { PrivateRoomEvent } from "@/stores/private-room";
import type { PrivateRoomUnlockPaywallRequest } from "@/stores/private-room/private-room-state";
@@ -1,7 +1,7 @@
import { renderToStaticMarkup } from "react-dom/server";
import { describe, expect, it } from "vitest";
import { PrivateAlbum } from "@/data/dto/private-room";
import { PrivateAlbum } from "@/data/schemas/private-room";
import { PrivateAlbumCard } from "../private-album-card";
@@ -3,7 +3,7 @@ import Image from "next/image";
import { ImageIcon, LockKeyhole } from "lucide-react";
import { CharacterAvatar } from "@/app/_components";
import type { PrivateAlbum } from "@/data/dto/private-room";
import type { PrivateAlbum } from "@/data/schemas/private-room";
import { isPrivateAlbumLocked } from "@/lib/private-room/private_album";
import styles from "../private-room-screen.module.css";
@@ -4,7 +4,7 @@ import { useEffect, useRef } from "react";
import Image from "next/image";
import { ChevronLeft, ChevronRight, X } from "lucide-react";
import type { PrivateAlbum } from "@/data/dto/private-room";
import type { PrivateAlbum } from "@/data/schemas/private-room";
import styles from "../private-room-screen.module.css";
@@ -1,4 +1,4 @@
import type { PrivateAlbum } from "@/data/dto/private-room";
import type { PrivateAlbum } from "@/data/schemas/private-room";
import styles from "../private-room-screen.module.css";
@@ -2,7 +2,7 @@
import { type Dispatch, useEffect, useRef } from "react";
import type { LoginStatus } from "@/data/dto/auth";
import type { LoginStatus } from "@/data/schemas/auth";
import { useGuestLoginBootstrap } from "@/hooks/use-guest-login-bootstrap";
import { behaviorAnalytics } from "@/lib/analytics";
import { ROUTES } from "@/router/routes";
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import type { UserView } from "@/data/dto/user";
import type { UserView } from "@/stores/user/user-view";
import {
getSidebarViewModel,
+2 -2
View File
@@ -1,5 +1,5 @@
import type { LoginStatus } from "@/data/dto/auth";
import type { UserView } from "@/data/dto/user";
import type { LoginStatus } from "@/data/schemas/auth";
import type { UserView } from "@/stores/user/user-view";
export type SidebarUserState = "guest" | "member" | "vip";
@@ -2,7 +2,7 @@
import { type Dispatch, useEffect } from "react";
import type { LoginStatus } from "@/data/dto/auth";
import type { LoginStatus } from "@/data/schemas/auth";
interface SidebarAuthBootstrapState {
hasInitialized: boolean;
@@ -2,7 +2,7 @@
import { useEffect, useState } from "react";
import type { LoginStatus } from "@/data/dto/auth";
import type { LoginStatus } from "@/data/schemas/auth";
import { useHasHydrated } from "@/hooks/use-has-hydrated";
import { loadSplashLatestMessagePreview } from "@/lib/chat/splash_latest_message";
import { useSplashLatestMessageCache } from "@/providers/splash-latest-message-provider";
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { PaymentPlan } from "@/data/dto/payment";
import { PaymentPlan } from "@/data/schemas/payment";
import {
canChooseSubscriptionPayChannel,
@@ -2,7 +2,7 @@
import Image from "next/image";
import type { PayChannel } from "@/data/dto/payment";
import type { PayChannel } from "@/data/schemas/payment";
const PAYMENT_METHODS: {
channel: PayChannel;
@@ -1,4 +1,4 @@
import type { PayChannel, PaymentPlan } from "@/data/dto/payment";
import type { PayChannel, PaymentPlan } from "@/data/schemas/payment";
import { getDefaultPayChannelForCountryCode } from "@/lib/payment/default_pay_channel";
import { AppEnvUtil } from "@/utils/app-env";
export { getDefaultPayChannelForCountryCode } from "@/lib/payment/default_pay_channel";
+1 -1
View File
@@ -5,7 +5,7 @@ import { BackButton } from "@/app/_components";
import { Checkbox, MobileShell } from "@/app/_components/core";
import { usePaymentPlanAnalytics } from "@/app/_hooks/use-payment-plan-analytics";
import { AppConstants } from "@/core/app_constants";
import type { PayChannel } from "@/data/dto/payment";
import type { PayChannel } from "@/data/schemas/payment";
import type { SubscriptionReturnTo } from "@/lib/navigation/subscription_exit";
import {
behaviorAnalytics,
@@ -4,7 +4,7 @@ import { useEffect, useRef, useState } from "react";
import { usePaymentRouteFlow } from "@/app/_hooks/use-payment-route-flow";
import { useAppNavigator } from "@/router/use-app-navigator";
import type { PayChannel } from "@/data/dto/payment";
import type { PayChannel } from "@/data/schemas/payment";
import type { SubscriptionReturnTo } from "@/lib/navigation/subscription_exit";
import type { SubscriptionType } from "./subscription-screen.helpers";
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { PaymentPlan } from "@/data/dto/payment";
import { PaymentPlan } from "@/data/schemas/payment";
import type { PaymentPlanInput } from "@/data/schemas/payment/payment_plan";
import {
+2 -2
View File
@@ -1,5 +1,5 @@
import type { LoginStatus } from "@/data/dto/auth";
import type { PaymentPlan } from "@/data/dto/payment";
import type { LoginStatus } from "@/data/schemas/auth";
import type { PaymentPlan } from "@/data/schemas/payment";
import {
getTipCoffeeOption,
type TipCoffeeType,
+1 -1
View File
@@ -8,7 +8,7 @@ import { CharacterAvatar } from "@/app/_components";
import { MobileShell } from "@/app/_components/core";
import { usePaymentPlanAnalytics } from "@/app/_hooks/use-payment-plan-analytics";
import { usePaymentRouteFlow } from "@/app/_hooks/use-payment-route-flow";
import type { PayChannel } from "@/data/dto/payment";
import type { PayChannel } from "@/data/schemas/payment";
import {
behaviorAnalytics,
type PaymentAnalyticsContext,
-39
View File
@@ -1,39 +0,0 @@
import { describe, expect, it } from "vitest";
import { z } from "zod";
import { createSchemaDto, type SchemaDto } from "../schema_dto";
const ExampleSchema = z.object({
id: z.string(),
traceId: z.string().default("generated-trace"),
});
type ExampleDto = SchemaDto<typeof ExampleSchema, "id">;
const ExampleDto = createSchemaDto<typeof ExampleSchema, "id">(
ExampleSchema,
);
describe("createSchemaDto", () => {
it("parses, freezes and serializes through the source schema", () => {
const dto: ExampleDto = ExampleDto.from({ id: "item-1" });
expect(dto).toBeInstanceOf(ExampleDto);
expect(Object.isFrozen(dto)).toBe(true);
expect(dto.id).toBe("item-1");
expect(dto.toJson()).toEqual({
id: "item-1",
traceId: "generated-trace",
});
});
it("keeps non-public schema fields out of the declared DTO interface", () => {
const dto = ExampleDto.fromJson({ id: "item-1", traceId: "trace-1" });
// @ts-expect-error traceId is serialized but not part of the public DTO API.
expect(dto.traceId).toBe("trace-1");
});
it("preserves schema validation errors", () => {
expect(() => ExampleDto.fromJson({ id: 1 })).toThrow(z.ZodError);
});
});
-35
View File
@@ -1,35 +0,0 @@
/**
* Facebook 用户数据 DTO
*
*
*/
import {
FacebookUserDataSchema,
type FacebookUserDataInput,
type FacebookUserDataData,
} from "@/data/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);
}
}
-9
View File
@@ -1,9 +0,0 @@
/**
* @file Automatically generated by barrelsby.
*/
export * from "./auth_panel_mode";
export * from "./facebook_user_data";
export * from "./login_status";
export * from "./request";
export * from "./response";
@@ -1,17 +0,0 @@
/**
* Facebook identity 绑定请求 DTO
*/
import {
FacebookIdentityRequestSchema,
} from "@/data/schemas/auth/request/facebook_identity_request";
import {
createSchemaDto,
type SchemaDto,
} from "@/data/dto/schema_dto";
export type FacebookIdentityRequest = SchemaDto<
typeof FacebookIdentityRequestSchema
>;
export const FacebookIdentityRequest = createSchemaDto(
FacebookIdentityRequestSchema,
);
@@ -1,33 +0,0 @@
/**
* Facebook 登录请求 DTO
*/
import {
FacebookLoginRequestSchema,
type FacebookLoginRequestInput,
type FacebookLoginRequestData,
} from "@/data/schemas/auth/request/facebook_login_request";
export class FacebookLoginRequest {
declare readonly accessToken: string;
declare readonly platform: string;
declare readonly guestId: string;
declare readonly isTestAccount: boolean;
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);
}
}
@@ -1,17 +0,0 @@
/**
* Facebook PSID 登录请求 DTO
*/
import {
FacebookPsidLoginRequestSchema,
} from "@/data/schemas/auth/request/facebook_psid_login_request";
import {
createSchemaDto,
type SchemaDto,
} from "@/data/dto/schema_dto";
export type FacebookPsidLoginRequest = SchemaDto<
typeof FacebookPsidLoginRequestSchema
>;
export const FacebookPsidLoginRequest = createSchemaDto(
FacebookPsidLoginRequestSchema,
);
@@ -1,32 +0,0 @@
/**
* Facebook ID 登录请求 DTO
*/
import {
FbIdLoginRequestSchema,
type FbIdLoginRequestInput,
type FbIdLoginRequestData,
} from "@/data/schemas/auth/request/fb_id_login_request";
export class FbIdLoginRequest {
declare readonly fbId: string;
declare readonly avatarUrl: string;
declare readonly isTestAccount: boolean;
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);
}
}
@@ -1,33 +0,0 @@
/**
* Google 登录请求 DTO
*/
import {
GoogleLoginRequestSchema,
type GoogleLoginRequestInput,
type GoogleLoginRequestData,
} from "@/data/schemas/auth/request/google_login_request";
export class GoogleLoginRequest {
declare readonly idToken: string;
declare readonly platform: string;
declare readonly guestId: string;
declare readonly isTestAccount: boolean;
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);
}
}
@@ -1,31 +0,0 @@
/**
* 游客登录请求 DTO
*/
import {
GuestLoginRequestSchema,
type GuestLoginRequestInput,
type GuestLoginRequestData,
} from "@/data/schemas/auth/request/guest_login_request";
export class GuestLoginRequest {
declare readonly deviceId: string;
declare readonly isTestAccount: boolean;
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);
}
}
-9
View File
@@ -1,9 +0,0 @@
export * from "./facebook_identity_request";
export * from "./facebook_login_request";
export * from "./facebook_psid_login_request";
export * from "./fb_id_login_request";
export * from "./google_login_request";
export * from "./guest_login_request";
export * from "./login_request";
export * from "./refresh_token_request";
export * from "./register_request";
@@ -1,35 +0,0 @@
/**
* 登录请求 DTO
*/
import {
LoginRequestSchema,
type LoginRequestInput,
type LoginRequestData,
} from "@/data/schemas/auth/request/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;
declare readonly isTestAccount: boolean;
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);
}
}
@@ -1,19 +0,0 @@
/**
* 刷新 Token 请求 DTO
*/
import {
RefreshTokenRequestSchema,
} from "@/data/schemas/auth/request/refresh_token_request";
import {
createSchemaDto,
type SchemaDto,
} from "@/data/dto/schema_dto";
export type RefreshTokenRequest = SchemaDto<
typeof RefreshTokenRequestSchema,
"refreshToken"
>;
export const RefreshTokenRequest = createSchemaDto<
typeof RefreshTokenRequestSchema,
"refreshToken"
>(RefreshTokenRequestSchema);
@@ -1,35 +0,0 @@
/**
* 注册请求 DTO
*/
import {
RegisterRequestSchema,
type RegisterRequestInput,
type RegisterRequestData,
} from "@/data/schemas/auth/request/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;
declare readonly isTestAccount: boolean;
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);
}
}
@@ -1,17 +0,0 @@
/**
* Facebook identity 绑定响应 DTO
*/
import {
FacebookIdentityResponseSchema,
} from "@/data/schemas/auth/response/facebook_identity_response";
import {
createSchemaDto,
type SchemaDto,
} from "@/data/dto/schema_dto";
export type FacebookIdentityResponse = SchemaDto<
typeof FacebookIdentityResponseSchema
>;
export const FacebookIdentityResponse = createSchemaDto(
FacebookIdentityResponseSchema,
);
@@ -1,32 +0,0 @@
/**
* Facebook PSID 登录响应 DTO
*/
import {
FacebookPsidLoginResponseSchema,
type FacebookPsidLoginResponseInput,
type FacebookPsidLoginResponseData,
} from "@/data/schemas/auth/response/facebook_psid_login_response";
export class FacebookPsidLoginResponse {
private constructor(input: FacebookPsidLoginResponseInput) {
const data = FacebookPsidLoginResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(
input: FacebookPsidLoginResponseInput,
): FacebookPsidLoginResponse {
return new FacebookPsidLoginResponse(input);
}
static fromJson(json: unknown): FacebookPsidLoginResponse {
return FacebookPsidLoginResponse.from(
json as FacebookPsidLoginResponseInput,
);
}
toJson(): FacebookPsidLoginResponseData {
return FacebookPsidLoginResponseSchema.parse(this);
}
}
@@ -1,37 +0,0 @@
/**
* 游客登录响应 DTO
*/
import {
GuestLoginResponseSchema,
type GuestLoginResponseInput,
type GuestLoginResponseData,
} from "@/data/schemas/auth/response/guest_login_response";
import { User } from "@/data/dto/user/user";
export class GuestLoginResponse {
declare readonly token: string;
declare readonly userId: string;
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;
}
}
-6
View File
@@ -1,6 +0,0 @@
export * from "./facebook_identity_response";
export * from "./facebook_psid_login_response";
export * from "./guest_login_response";
export * from "./login_response";
export * from "./logout_response";
export * from "./refresh_token_response";
@@ -1,36 +0,0 @@
/**
* 登录响应 DTO
*/
import {
LoginResponseSchema,
type LoginResponseInput,
type LoginResponseData,
} from "@/data/schemas/auth/response/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);
}
}
@@ -1,19 +0,0 @@
/**
* 退出登录响应 DTO
*/
import {
LogoutResponseSchema,
} from "@/data/schemas/auth/response/logout_response";
import {
createSchemaDto,
type SchemaDto,
} from "@/data/dto/schema_dto";
export type LogoutResponse = SchemaDto<
typeof LogoutResponseSchema,
"success"
>;
export const LogoutResponse = createSchemaDto<
typeof LogoutResponseSchema,
"success"
>(LogoutResponseSchema);
@@ -1,31 +0,0 @@
/**
* 刷新 Token 响应 DTO
*/
import {
RefreshTokenResponseSchema,
type RefreshTokenResponseInput,
type RefreshTokenResponseData,
} from "@/data/schemas/auth/response/refresh_token_response";
export class RefreshTokenResponse {
declare readonly token: string;
declare readonly refreshToken: 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);
}
}
-29
View File
@@ -1,29 +0,0 @@
import {
CharacterSchema,
type CharacterData,
type CharacterInput,
} from "@/data/schemas/character";
export class Character {
declare readonly id: string;
declare readonly slug: string;
declare readonly displayName: string;
declare readonly avatarUrl: string;
private constructor(input: CharacterInput) {
Object.assign(this, CharacterSchema.parse(input));
Object.freeze(this);
}
static from(input: CharacterInput): Character {
return new Character(input);
}
static fromJson(json: unknown): Character {
return Character.from(json as CharacterInput);
}
toJson(): CharacterData {
return CharacterSchema.parse(this);
}
}
@@ -1,33 +0,0 @@
import {
CharactersResponseSchema,
type CharactersResponseData,
type CharactersResponseInput,
} from "@/data/schemas/character";
import { Character } from "./character";
export class CharactersResponse {
declare readonly items: Character[];
private constructor(input: CharactersResponseInput) {
const data = CharactersResponseSchema.parse(input);
Object.assign(this, {
items: data.items.map((item) => Character.from(item)),
});
Object.freeze(this);
}
static from(input: CharactersResponseInput): CharactersResponse {
return new CharactersResponse(input);
}
static fromJson(json: unknown): CharactersResponse {
return CharactersResponse.from(json as CharactersResponseInput);
}
toJson(): CharactersResponseData {
return CharactersResponseSchema.parse({
items: this.items.map((item) => item.toJson()),
});
}
}
-2
View File
@@ -1,2 +0,0 @@
export * from "./character";
export * from "./characters_response";
-28
View File
@@ -1,28 +0,0 @@
/**
* 聊天列表项 discriminated union
*
*
*
* 4 种类型:
* - ai-disclosure:顶部 AI 披露横幅
* - date-separator:日期分隔条
* - loading-animationAI 正在输入的动画
* - message:实际消息
*/
import type { UiMessage } from "./ui_message";
export type ChatListItem =
| { type: "ai-disclosure" }
| { type: "date-separator"; date: string }
| { type: "loading-animation" }
| { type: "message"; message: UiMessage; key: string };
export const ChatListItemType = {
AiDisclosure: "ai-disclosure",
DateSeparator: "date-separator",
LoadingAnimation: "loading-animation",
Message: "message",
} as const;
export type ChatListItemType =
(typeof ChatListItemType)[keyof typeof ChatListItemType];
-39
View File
@@ -1,39 +0,0 @@
/**
* 聊天历史中的单条消息 DTO
*/
import {
ChatMessageSchema,
type ChatMessageInput,
type ChatMessageData,
type ChatImageData,
type ChatLockDetailData,
} from "@/data/schemas/chat";
export class ChatMessage {
declare readonly role: string;
declare readonly type: string;
declare readonly content: string;
declare readonly id: string;
declare readonly createdAt: string;
declare readonly audioUrl: string | null;
declare readonly image: ChatImageData;
declare readonly lockDetail: ChatLockDetailData;
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);
}
}
-10
View File
@@ -1,10 +0,0 @@
/**
* @file Automatically generated by barrelsby.
*/
export * from "./chat_list_item";
export * from "./chat_media";
export * from "./chat_message";
export * from "./request";
export * from "./response";
export * from "./ui_message";
-3
View File
@@ -1,3 +0,0 @@
export * from "./send_message_request";
export * from "./unlock_private_request";
export * from "./unlock_history_request";
@@ -1,38 +0,0 @@
/**
* 发送消息请求 DTO
*/
import {
SendMessageRequestSchema,
type SendMessageRequestInput,
type SendMessageRequestData,
} from "@/data/schemas/chat/request/send_message_request";
export class SendMessageRequest {
declare readonly characterId: string;
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;
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);
}
}
@@ -1,22 +0,0 @@
import {
UnlockHistoryRequestSchema,
type UnlockHistoryRequestData,
type UnlockHistoryRequestInput,
} from "@/data/schemas/chat/request/unlock_history_request";
export class UnlockHistoryRequest {
declare readonly characterId: string;
private constructor(input: UnlockHistoryRequestInput) {
Object.assign(this, UnlockHistoryRequestSchema.parse(input));
Object.freeze(this);
}
static from(input: UnlockHistoryRequestInput): UnlockHistoryRequest {
return new UnlockHistoryRequest(input);
}
toJson(): UnlockHistoryRequestData {
return UnlockHistoryRequestSchema.parse(this);
}
}
@@ -1,33 +0,0 @@
/**
* 私密消息解锁请求 DTO
*/
import {
UnlockPrivateRequestSchema,
type UnlockPrivateRequestData,
type UnlockPrivateRequestInput,
} from "@/data/schemas/chat/request/unlock_private_request";
export class UnlockPrivateRequest {
declare readonly characterId: string;
declare readonly messageId?: string;
declare readonly lockType?: UnlockPrivateRequestData["lockType"];
declare readonly clientLockId?: string;
private constructor(input: UnlockPrivateRequestInput) {
const data = UnlockPrivateRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: UnlockPrivateRequestInput): UnlockPrivateRequest {
return new UnlockPrivateRequest(input);
}
static fromJson(json: unknown): UnlockPrivateRequest {
return UnlockPrivateRequest.from(json as UnlockPrivateRequestInput);
}
toJson(): UnlockPrivateRequestData {
return UnlockPrivateRequestSchema.parse(this);
}
}
@@ -1,36 +0,0 @@
/**
* 聊天历史响应 DTO
*/
import {
ChatHistoryResponseSchema,
type ChatHistoryResponseInput,
type ChatHistoryResponseData,
} from "@/data/schemas/chat/response/chat_history_response";
import { ChatMessage } from "../chat_message";
export class ChatHistoryResponse {
declare readonly messages: ChatMessage[];
declare readonly total: number;
declare readonly limit: 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);
}
}
@@ -1,42 +0,0 @@
/**
* 发送消息响应 DTO
*/
import {
ChatSendResponseSchema,
type ChatSendResponseInput,
type ChatSendResponseData,
type ChatImageData,
type ChatLockDetailData,
} from "@/data/schemas/chat";
export class ChatSendResponse {
declare readonly reply: string;
declare readonly audioUrl: string;
declare readonly messageId: string;
declare readonly timestamp: number;
declare readonly image: ChatImageData;
declare readonly lockDetail: ChatLockDetailData;
declare readonly canSendMessage: boolean;
declare readonly creditBalance: number;
declare readonly creditsCharged: number;
declare readonly requiredCredits: number;
declare readonly shortfallCredits: 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);
}
}
-4
View File
@@ -1,4 +0,0 @@
export * from "./chat_history_response";
export * from "./chat_send_response";
export * from "./unlock_history_response";
export * from "./unlock_private_response";
@@ -1,33 +0,0 @@
/**
* 一键解锁历史锁定消息响应 DTO
*/
import {
UnlockHistoryResponseSchema,
type UnlockHistoryReason,
type UnlockHistoryResponseData,
type UnlockHistoryResponseInput,
} from "@/data/schemas/chat/response/unlock_history_response";
export class UnlockHistoryResponse {
declare readonly unlocked: boolean;
declare readonly reason: UnlockHistoryReason;
declare readonly shortfallCredits: number;
private constructor(input: UnlockHistoryResponseInput) {
const data = UnlockHistoryResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: UnlockHistoryResponseInput): UnlockHistoryResponse {
return new UnlockHistoryResponse(input);
}
static fromJson(json: unknown): UnlockHistoryResponse {
return UnlockHistoryResponse.from(json as UnlockHistoryResponseInput);
}
toJson(): UnlockHistoryResponseData {
return UnlockHistoryResponseSchema.parse(this);
}
}
@@ -1,41 +0,0 @@
import {
UnlockPrivateResponseSchema,
type UnlockPrivateReason,
type UnlockPrivateResponseData,
type UnlockPrivateResponseInput,
} from "@/data/schemas/chat/response/unlock_private_response";
import type { ChatImageData } from "@/data/schemas/chat";
/**
* 单条历史付费 / 私密消息解锁响应 DTO。
*/
export class UnlockPrivateResponse {
declare readonly unlocked: boolean;
declare readonly messageId: string;
declare readonly content: string;
declare readonly audioUrl: string;
declare readonly image: ChatImageData;
declare readonly reason: UnlockPrivateReason;
declare readonly creditBalance: number;
declare readonly creditsCharged: number;
declare readonly requiredCredits: number;
declare readonly shortfallCredits: number;
private constructor(input: UnlockPrivateResponseInput) {
const data = UnlockPrivateResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: UnlockPrivateResponseInput): UnlockPrivateResponse {
return new UnlockPrivateResponse(input);
}
static fromJson(json: unknown): UnlockPrivateResponse {
return UnlockPrivateResponse.from(json as UnlockPrivateResponseInput);
}
toJson(): UnlockPrivateResponseData {
return UnlockPrivateResponseSchema.parse(this);
}
}
-2
View File
@@ -1,2 +0,0 @@
export * from "./feedback_submission";
export * from "./response";
@@ -1,16 +0,0 @@
import {
FeedbackSubmitResponseSchema,
} from "@/data/schemas/feedback";
import {
createSchemaDto,
type SchemaDto,
} from "@/data/dto/schema_dto";
export type FeedbackSubmitResponse = SchemaDto<
typeof FeedbackSubmitResponseSchema,
"feedbackId"
>;
export const FeedbackSubmitResponse = createSchemaDto<
typeof FeedbackSubmitResponseSchema,
"feedbackId"
>(FeedbackSubmitResponseSchema);
-1
View File
@@ -1 +0,0 @@
export * from "./feedback_submit_response";
-5
View File
@@ -1,5 +0,0 @@
/**
* @file Automatically generated by barrelsby.
*/
export * from "./request";
-17
View File
@@ -1,17 +0,0 @@
/**
* 应用事件上报请求 DTO
*/
import {
AppEventSchema,
} from "@/data/schemas/metrics/request/app_event";
import {
createSchemaDto,
type SchemaDto,
} from "@/data/dto/schema_dto";
type AppEventPublicKey = "userId" | "browser" | "userAgent";
export type AppEvent = SchemaDto<typeof AppEventSchema, AppEventPublicKey>;
export const AppEvent = createSchemaDto<
typeof AppEventSchema,
AppEventPublicKey
>(AppEventSchema);
-2
View File
@@ -1,2 +0,0 @@
export * from "./app_event";
export * from "./pwa_event";
-22
View File
@@ -1,22 +0,0 @@
/**
* PWA 事件上报请求 DTO
*/
import {
PwaEventSchema,
} from "@/data/schemas/metrics/request/pwa_event";
import {
createSchemaDto,
type SchemaDto,
} from "@/data/dto/schema_dto";
type PwaEventPublicKey =
| "deviceId"
| "deviceType"
| "timestamp"
| "pwaInstalled"
| "pwaSupported";
export type PwaEvent = SchemaDto<typeof PwaEventSchema, PwaEventPublicKey>;
export const PwaEvent = createSchemaDto<
typeof PwaEventSchema,
PwaEventPublicKey
>(PwaEventSchema);
-8
View File
@@ -1,8 +0,0 @@
/**
* @file Payment DTO barrel.
*/
export * from "./payment_plan";
export * from "./tip_payment_plan";
export * from "./request";
export * from "./response";
-42
View File
@@ -1,42 +0,0 @@
/**
* 支付套餐 DTO
*/
import {
PaymentPlanSchema,
type PaymentPlanData,
type PaymentPlanInput,
} from "@/data/schemas/payment/payment_plan";
export class PaymentPlan {
declare readonly planId: string;
declare readonly planName: string;
declare readonly orderType: string;
declare readonly vipDays: number | null;
declare readonly dolAmount: number | null;
declare readonly creditBalance: number;
declare readonly amountCents: number;
declare readonly originalAmountCents: number | null;
declare readonly currency: string;
declare readonly isFirstRechargeOffer: boolean;
declare readonly mostPopular: boolean;
declare readonly firstRechargeDiscountPercent: number | null;
declare readonly promotionType: string | null;
private constructor(input: PaymentPlanInput) {
const data = PaymentPlanSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: PaymentPlanInput): PaymentPlan {
return new PaymentPlan(input);
}
static fromJson(json: unknown): PaymentPlan {
return PaymentPlan.from(json as PaymentPlanInput);
}
toJson(): PaymentPlanData {
return PaymentPlanSchema.parse(this);
}
}
@@ -1,39 +0,0 @@
/**
* 创建支付订单请求 DTO
*/
import {
CreatePaymentOrderRequestSchema,
type CreatePaymentOrderRequestData,
type CreatePaymentOrderRequestInput,
type PayChannel,
} from "@/data/schemas/payment/request/create_payment_order_request";
export type { PayChannel };
export class CreatePaymentOrderRequest {
declare readonly planId: string;
declare readonly payChannel: PayChannel;
declare readonly autoRenew: boolean;
private constructor(input: CreatePaymentOrderRequestInput) {
const data = CreatePaymentOrderRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(
input: CreatePaymentOrderRequestInput,
): CreatePaymentOrderRequest {
return new CreatePaymentOrderRequest(input);
}
static fromJson(json: unknown): CreatePaymentOrderRequest {
return CreatePaymentOrderRequest.from(
json as CreatePaymentOrderRequestInput,
);
}
toJson(): CreatePaymentOrderRequestData {
return CreatePaymentOrderRequestSchema.parse(this);
}
}
-1
View File
@@ -1 +0,0 @@
export * from "./create_payment_order_request";
@@ -1,35 +0,0 @@
/**
* 创建支付订单响应 DTO
*/
import {
CreatePaymentOrderResponseSchema,
type CreatePaymentOrderResponseData,
type CreatePaymentOrderResponseInput,
} from "@/data/schemas/payment/response/create_payment_order_response";
export class CreatePaymentOrderResponse {
declare readonly orderId: string;
declare readonly payParams: Record<string, unknown>;
private constructor(input: CreatePaymentOrderResponseInput) {
const data = CreatePaymentOrderResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(
input: CreatePaymentOrderResponseInput,
): CreatePaymentOrderResponse {
return new CreatePaymentOrderResponse(input);
}
static fromJson(json: unknown): CreatePaymentOrderResponse {
return CreatePaymentOrderResponse.from(
json as CreatePaymentOrderResponseInput,
);
}
toJson(): CreatePaymentOrderResponseData {
return CreatePaymentOrderResponseSchema.parse(this);
}
}
-4
View File
@@ -1,4 +0,0 @@
export * from "./create_payment_order_response";
export * from "./payment_order_status_response";
export * from "./payment_plans_response";
export * from "./tip_payment_plans_response";
@@ -1,37 +0,0 @@
/**
* 支付订单状态响应 DTO
*/
import {
PaymentOrderStatusResponseSchema,
type PaymentOrderStatus,
type PaymentOrderStatusResponseData,
type PaymentOrderStatusResponseInput,
} from "@/data/schemas/payment/response/payment_order_status_response";
export type { PaymentOrderStatus };
export class PaymentOrderStatusResponse {
declare readonly status: PaymentOrderStatus;
private constructor(input: PaymentOrderStatusResponseInput) {
const data = PaymentOrderStatusResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(
input: PaymentOrderStatusResponseInput,
): PaymentOrderStatusResponse {
return new PaymentOrderStatusResponse(input);
}
static fromJson(json: unknown): PaymentOrderStatusResponse {
return PaymentOrderStatusResponse.from(
json as PaymentOrderStatusResponseInput,
);
}
toJson(): PaymentOrderStatusResponseData {
return PaymentOrderStatusResponseSchema.parse(this);
}
}
@@ -1,45 +0,0 @@
/**
* 支付套餐列表响应 DTO
*/
import {
PaymentPlansResponseSchema,
type FirstRechargeOfferData,
type PaymentPlansResponseData,
type PaymentPlansResponseInput,
} from "@/data/schemas/payment/response/payment_plans_response";
import { PaymentPlan } from "../payment_plan";
export class PaymentPlansResponse {
declare readonly isFirstRecharge: boolean;
declare readonly firstRechargeOffer: FirstRechargeOfferData | null;
declare readonly plans: PaymentPlan[];
private constructor(input: PaymentPlansResponseInput) {
const data = PaymentPlansResponseSchema.parse(input);
Object.assign(this, {
isFirstRecharge: data.isFirstRecharge,
firstRechargeOffer: data.firstRechargeOffer,
plans: data.plans.map((plan) => PaymentPlan.from(plan)),
});
Object.freeze(this);
}
static from(input: PaymentPlansResponseInput): PaymentPlansResponse {
return new PaymentPlansResponse(input);
}
static fromJson(json: unknown): PaymentPlansResponse {
return PaymentPlansResponse.from(json as PaymentPlansResponseInput);
}
toJson(): PaymentPlansResponseData {
return {
isFirstRecharge: this.isFirstRecharge,
firstRechargeOffer: this.firstRechargeOffer,
plans: this.plans.map((plan) => plan.toJson()),
};
}
}
export type FirstRechargeOffer = FirstRechargeOfferData;
@@ -1,35 +0,0 @@
import {
TipPaymentPlansResponseSchema,
type TipPaymentPlansResponseData,
type TipPaymentPlansResponseInput,
} from "@/data/schemas/payment/response/tip_payment_plans_response";
import { TipPaymentPlan } from "../tip_payment_plan";
export class TipPaymentPlansResponse {
declare readonly plans: TipPaymentPlan[];
private constructor(input: TipPaymentPlansResponseInput) {
const data = TipPaymentPlansResponseSchema.parse(input);
Object.assign(this, {
plans: data.plans.map((plan) => TipPaymentPlan.from(plan)),
});
Object.freeze(this);
}
static from(input: TipPaymentPlansResponseInput): TipPaymentPlansResponse {
return new TipPaymentPlansResponse(input);
}
static fromJson(json: unknown): TipPaymentPlansResponse {
return TipPaymentPlansResponse.from(
json as TipPaymentPlansResponseInput,
);
}
toJson(): TipPaymentPlansResponseData {
return {
plans: this.plans.map((plan) => plan.toJson()),
};
}
}
-30
View File
@@ -1,30 +0,0 @@
import {
TipPaymentPlanSchema,
type TipPaymentPlanData,
type TipPaymentPlanInput,
} from "@/data/schemas/payment/tip_payment_plan";
export class TipPaymentPlan {
declare readonly planId: string;
declare readonly planName: string;
declare readonly amountCents: number;
declare readonly currency: string;
private constructor(input: TipPaymentPlanInput) {
const data = TipPaymentPlanSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: TipPaymentPlanInput): TipPaymentPlan {
return new TipPaymentPlan(input);
}
static fromJson(json: unknown): TipPaymentPlan {
return TipPaymentPlan.from(json as TipPaymentPlanInput);
}
toJson(): TipPaymentPlanData {
return TipPaymentPlanSchema.parse(this);
}
}
-3
View File
@@ -1,3 +0,0 @@
export * from "./private_album";
export * from "./request";
export * from "./response";
@@ -1,37 +0,0 @@
import {
PrivateAlbumSchema,
type PrivateAlbumData,
type PrivateAlbumInput,
} from "@/data/schemas/private-room";
export class PrivateAlbum {
declare readonly albumId: string;
declare readonly title: string;
declare readonly content: string | null;
declare readonly previewText: string;
declare readonly imageCount: number;
declare readonly images: PrivateAlbumData["images"];
declare readonly locked: boolean;
declare readonly unlocked: boolean;
declare readonly unlockCost: number;
declare readonly publishedAt: string | null;
declare readonly lockDetail: PrivateAlbumData["lockDetail"];
private constructor(input: PrivateAlbumInput) {
const data = PrivateAlbumSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: PrivateAlbumInput): PrivateAlbum {
return new PrivateAlbum(input);
}
static fromJson(json: unknown): PrivateAlbum {
return PrivateAlbum.from(json as PrivateAlbumInput);
}
toJson(): PrivateAlbumData {
return PrivateAlbumSchema.parse(this);
}
}
@@ -1 +0,0 @@
export * from "./unlock_private_album_request";
@@ -1,21 +0,0 @@
import {
UnlockPrivateAlbumRequestSchema,
type UnlockPrivateAlbumRequestData,
type UnlockPrivateAlbumRequestInput,
} from "@/data/schemas/private-room";
export class UnlockPrivateAlbumRequest {
private constructor(input: UnlockPrivateAlbumRequestInput) {
const data = UnlockPrivateAlbumRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: UnlockPrivateAlbumRequestInput): UnlockPrivateAlbumRequest {
return new UnlockPrivateAlbumRequest(input);
}
toJson(): UnlockPrivateAlbumRequestData {
return UnlockPrivateAlbumRequestSchema.parse(this);
}
}
@@ -1,2 +0,0 @@
export * from "./private_albums_response";
export * from "./private_album_unlock_response";
@@ -1,38 +0,0 @@
import {
PrivateAlbumUnlockResponseSchema,
type PrivateAlbumUnlockReason,
type PrivateAlbumUnlockResponseData,
type PrivateAlbumUnlockResponseInput,
} from "@/data/schemas/private-room";
export class PrivateAlbumUnlockResponse {
declare readonly albumId: string;
declare readonly locked: boolean;
declare readonly unlocked: boolean;
declare readonly reason: PrivateAlbumUnlockReason | string;
declare readonly unlockCost: number;
declare readonly requiredCredits: number;
declare readonly creditBalance: number;
declare readonly shortfallCredits: number;
declare readonly images: PrivateAlbumUnlockResponseData["images"];
private constructor(input: PrivateAlbumUnlockResponseInput) {
const data = PrivateAlbumUnlockResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: PrivateAlbumUnlockResponseInput): PrivateAlbumUnlockResponse {
return new PrivateAlbumUnlockResponse(input);
}
static fromJson(json: unknown): PrivateAlbumUnlockResponse {
return PrivateAlbumUnlockResponse.from(
json as PrivateAlbumUnlockResponseInput,
);
}
toJson(): PrivateAlbumUnlockResponseData {
return PrivateAlbumUnlockResponseSchema.parse(this);
}
}
@@ -1,36 +0,0 @@
import {
PrivateAlbumsResponseSchema,
type PrivateAlbumsResponseData,
type PrivateAlbumsResponseInput,
} from "@/data/schemas/private-room";
import { PrivateAlbum } from "../private_album";
export class PrivateAlbumsResponse {
declare readonly items: PrivateAlbum[];
declare readonly creditBalance: number;
private constructor(input: PrivateAlbumsResponseInput) {
const data = PrivateAlbumsResponseSchema.parse(input);
Object.assign(this, {
items: data.items.map((item) => PrivateAlbum.from(item)),
creditBalance: data.creditBalance,
});
Object.freeze(this);
}
static from(input: PrivateAlbumsResponseInput): PrivateAlbumsResponse {
return new PrivateAlbumsResponse(input);
}
static fromJson(json: unknown): PrivateAlbumsResponse {
return PrivateAlbumsResponse.from(json as PrivateAlbumsResponseInput);
}
toJson(): PrivateAlbumsResponseData {
return {
items: this.items.map((item) => item.toJson()),
creditBalance: this.creditBalance,
};
}
}
-59
View File
@@ -1,59 +0,0 @@
import type { z } from "zod";
export type SchemaDto<
TSchema extends z.ZodType,
TPublicKey extends keyof z.output<TSchema> = never,
> = Readonly<Pick<z.output<TSchema>, TPublicKey>> & {
toJson(): z.output<TSchema>;
};
export interface SchemaDtoFactory<
TSchema extends z.ZodType,
TPublicKey extends keyof z.output<TSchema> = never,
> {
readonly prototype: SchemaDto<TSchema, TPublicKey>;
[Symbol.hasInstance](value: unknown): boolean;
from(input: z.input<TSchema>): SchemaDto<TSchema, TPublicKey>;
fromJson(json: unknown): SchemaDto<TSchema, TPublicKey>;
}
/**
* 为没有自定义映射逻辑的对象 Schema 创建不可变 DTO。
*
* `TPublicKey` 只暴露业务代码实际读取的字段;完整解析结果仍会保留在实例中,
* 并由 `toJson` 按原 Schema 输出。包含嵌套 DTO 转换或领域方法的模型继续使用
* 显式 class,避免把业务逻辑隐藏进通用工厂。
*/
export function createSchemaDto<
TSchema extends z.ZodType,
TPublicKey extends keyof z.output<TSchema> = never,
>(schema: TSchema): SchemaDtoFactory<TSchema, TPublicKey> {
class GeneratedSchemaDto {
private constructor(input: z.input<TSchema>) {
Object.assign(this, schema.parse(input) as object);
Object.freeze(this);
}
static from(
input: z.input<TSchema>,
): SchemaDto<TSchema, TPublicKey> {
return new GeneratedSchemaDto(input) as SchemaDto<
TSchema,
TPublicKey
>;
}
static fromJson(json: unknown): SchemaDto<TSchema, TPublicKey> {
return GeneratedSchemaDto.from(json as z.input<TSchema>);
}
toJson(): z.output<TSchema> {
return schema.parse(this);
}
}
return GeneratedSchemaDto as unknown as SchemaDtoFactory<
TSchema,
TPublicKey
>;
}
-31
View File
@@ -1,31 +0,0 @@
/**
* 头像数据 DTO
*/
import {
AvatarDataSchema,
type AvatarDataInput,
type AvatarDataData,
} from "@/data/schemas/user/avatar_data";
export class AvatarData {
declare readonly avatarUrl: string;
declare readonly userId: string;
private constructor(input: AvatarDataInput) {
const data = AvatarDataSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: AvatarDataInput): AvatarData {
return new AvatarData(input);
}
static fromJson(json: unknown): AvatarData {
return AvatarData.from(json as AvatarDataInput);
}
toJson(): AvatarDataData {
return AvatarDataSchema.parse(this);
}
}
-10
View File
@@ -1,10 +0,0 @@
/**
* @file Automatically generated by barrelsby.
*/
export * from "./avatar_data";
export * from "./personality_traits";
export * from "./recent_memory";
export * from "./user";
export * from "./user_entitlements";
export * from "./user_view";
-34
View File
@@ -1,34 +0,0 @@
/**
* 个性特征 DTO
*/
import {
PersonalityTraitsSchema,
type PersonalityTraitsInput,
type PersonalityTraitsData,
} from "@/data/schemas/user/personality_traits";
export class PersonalityTraits {
declare readonly cheerful: number;
declare readonly caring: number;
declare readonly playful: number;
declare readonly serious: number;
declare readonly romantic: number;
private constructor(input: PersonalityTraitsInput) {
const data = PersonalityTraitsSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: PersonalityTraitsInput): PersonalityTraits {
return new PersonalityTraits(input);
}
static fromJson(json: unknown): PersonalityTraits {
return PersonalityTraits.from(json as PersonalityTraitsInput);
}
toJson(): PersonalityTraitsData {
return PersonalityTraitsSchema.parse(this);
}
}
-33
View File
@@ -1,33 +0,0 @@
/**
* 最近记忆 DTO
*/
import {
RecentMemorySchema,
type RecentMemoryInput,
type RecentMemoryData,
} from "@/data/schemas/user/recent_memory";
export class RecentMemory {
declare readonly type: string;
declare readonly content: string;
declare readonly importance: number;
declare readonly createdAt: string;
private constructor(input: RecentMemoryInput) {
const data = RecentMemorySchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: RecentMemoryInput): RecentMemory {
return new RecentMemory(input);
}
static fromJson(json: unknown): RecentMemory {
return RecentMemory.from(json as RecentMemoryInput);
}
toJson(): RecentMemoryData {
return RecentMemorySchema.parse(this);
}
}
-64
View File
@@ -1,64 +0,0 @@
/**
* 用户 DTO
*/
import {
UserSchema,
type UserInput,
type UserData,
} from "@/data/schemas/user/user";
import { PersonalityTraits } from "./personality_traits";
export class User {
declare readonly id: string;
declare readonly username: string;
declare readonly email: string;
declare readonly platform: string;
declare readonly country: string;
declare readonly countryCode: string;
declare readonly fbAsid: string;
declare readonly fbPsid: string;
declare readonly intimacy: number;
declare readonly dolBalance: number;
declare readonly creditBalance: number;
declare readonly dailyFreeChatLimit: number;
declare readonly dailyFreeChatUsed: number;
declare readonly dailyFreeChatRemaining: number;
declare readonly dailyFreePrivateLimit: number;
declare readonly dailyFreePrivateUsed: number;
declare readonly dailyFreePrivateRemaining: number;
declare readonly personalityTraits: PersonalityTraits;
declare readonly preferredLanguage: string;
declare readonly createdAt: string;
declare readonly lastMessageAt: string;
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 {
return UserSchema.parse({
...this,
personalityTraits: this.personalityTraits.toJson(),
});
}
}
-39
View File
@@ -1,39 +0,0 @@
/**
* 用户权益快照 DTO
*/
import {
UserEntitlementsSchema,
type UserEntitlementsData,
type UserEntitlementsInput,
} from "@/data/schemas/user/user_entitlements";
export class UserEntitlements {
declare readonly userId: string;
declare readonly isGuest: boolean;
declare readonly isVip: boolean;
declare readonly vipExpiresAt: string | null;
declare readonly creditBalance: number;
declare readonly dolBalance: number;
declare readonly policy: UserEntitlementsData["policy"];
declare readonly costs: UserEntitlementsData["costs"];
declare readonly quotas: UserEntitlementsData["quotas"];
declare readonly historyUnlock: UserEntitlementsData["historyUnlock"];
private constructor(input: UserEntitlementsInput) {
const data = UserEntitlementsSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: UserEntitlementsInput): UserEntitlements {
return new UserEntitlements(input);
}
static fromJson(json: unknown): UserEntitlements {
return UserEntitlements.from(json as UserEntitlementsInput);
}
toJson(): UserEntitlementsData {
return UserEntitlementsSchema.parse(this);
}
}
@@ -4,7 +4,7 @@ import {
FacebookIdentityResponse,
FacebookPsidLoginResponse,
LoginStatus,
} from "@/data/dto/auth";
} from "@/data/schemas/auth";
import { AuthRepository } from "@/data/repositories/auth_repository";
import type { AuthApi } from "@/data/services/api";
import type { IAuthStorage } from "@/data/storage/auth";
@@ -5,7 +5,7 @@ import {
LoginResponse,
LoginStatus,
RefreshTokenResponse,
} from "@/data/dto/auth";
} from "@/data/schemas/auth";
import { AuthRepository } from "@/data/repositories/auth_repository";
import type { AuthApi } from "@/data/services/api";
import type { IAuthStorage } from "@/data/storage/auth";
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from "vitest";
import { LoginStatus } from "@/data/dto/auth";
import { LoginStatus } from "@/data/schemas/auth";
import { Result } from "@/utils/result";
import {

Some files were not shown because too many files have changed in this diff Show More