refactor(data): replace schema classes with readonly models

This commit is contained in:
2026-07-17 13:21:40 +08:00
parent 3437312167
commit ae97366a4a
103 changed files with 1220 additions and 2117 deletions
@@ -1,6 +1,6 @@
/**
* 聊天历史响应
*
*
*/
import { z } from "zod";
@@ -9,45 +9,26 @@ import {
booleanOrFalse,
numberOrZero,
} from "../../nullable-defaults";
import { ChatMessage, ChatMessageSchema } from "../chat_message";
import { ChatMessageSchema } from "../chat_message";
export const ChatHistoryResponseSchema = z.object({
messages: arrayOrEmpty(ChatMessageSchema),
total: numberOrZero,
limit: numberOrZero,
offset: numberOrZero,
isVip: booleanOrFalse,
privateFreeLimit: numberOrZero,
privateUsedToday: numberOrZero,
privateCanViewFree: booleanOrFalse,
});
export const ChatHistoryResponseSchema = z
.object({
messages: arrayOrEmpty(ChatMessageSchema),
total: numberOrZero,
limit: numberOrZero,
offset: numberOrZero,
isVip: booleanOrFalse,
privateFreeLimit: numberOrZero,
privateUsedToday: numberOrZero,
privateCanViewFree: booleanOrFalse,
})
.readonly();
export type ChatHistoryResponseInput = z.input<typeof ChatHistoryResponseSchema>;
export type ChatHistoryResponseData = z.output<typeof ChatHistoryResponseSchema>;
export type ChatHistoryResponseInput = z.input<
typeof ChatHistoryResponseSchema
>;
export type ChatHistoryResponseData = z.output<
typeof ChatHistoryResponseSchema
>;
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);
}
}
export type ChatHistoryResponse = ChatHistoryResponseData;
@@ -1,6 +1,6 @@
/**
* 发送消息响应
*
*
*/
import { z } from "zod";
import {
@@ -10,60 +10,27 @@ import {
numberOrZero,
stringOrEmpty,
} from "../../nullable-defaults";
import {
ChatImageSchema,
ChatLockDetailSchema,
type ChatImageData,
type ChatLockDetailData,
} from "../chat_payloads";
import { ChatImageSchema, ChatLockDetailSchema } from "../chat_payloads";
export const ChatSendResponseSchema = z.object({
reply: stringOrEmpty,
audioUrl: stringOrEmpty,
messageId: stringOrEmpty,
isGuest: booleanOrFalse,
// 函数式 default —— 每次 parse 时重新调 Date.now()(后端不返回 timestamp 时用当下时间)
timestamp: numberOrLazy(() => Date.now()),
image: ChatImageSchema,
lockDetail: ChatLockDetailSchema,
canSendMessage: booleanOrTrue,
creditBalance: numberOrZero,
creditsCharged: numberOrZero,
requiredCredits: numberOrZero,
shortfallCredits: numberOrZero,
});
export const ChatSendResponseSchema = z
.object({
reply: stringOrEmpty,
audioUrl: stringOrEmpty,
messageId: stringOrEmpty,
isGuest: booleanOrFalse,
// 函数式 default —— 每次 parse 时重新调 Date.now()(后端不返回 timestamp 时用当下时间)
timestamp: numberOrLazy(() => Date.now()),
image: ChatImageSchema,
lockDetail: ChatLockDetailSchema,
canSendMessage: booleanOrTrue,
creditBalance: numberOrZero,
creditsCharged: numberOrZero,
requiredCredits: numberOrZero,
shortfallCredits: numberOrZero,
})
.readonly();
export type ChatSendResponseInput = z.input<typeof ChatSendResponseSchema>;
export type ChatSendResponseData = z.output<typeof ChatSendResponseSchema>;
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);
}
}
export type ChatSendResponse = ChatSendResponseData;
@@ -18,21 +18,23 @@ export const UnlockHistoryReasonSchema = z.enum([
"no_locked_messages",
]);
export const UnlockHistoryResponseSchema = z.object({
unlocked: booleanOrFalse,
reason: UnlockHistoryReasonSchema,
totalLocked: numberOrZero,
unlockedCount: numberOrZero,
privateCount: numberOrZero,
imageCount: numberOrZero,
voiceCount: numberOrZero,
requiredCredits: numberOrZero,
currentCredits: numberOrZero,
remainingCredits: numberOrZero,
shortfallCredits: numberOrZero,
costsByMessage: UnlockHistoryCostsByMessageSchema,
messageIds: arrayOrEmpty(z.string()),
});
export const UnlockHistoryResponseSchema = z
.object({
unlocked: booleanOrFalse,
reason: UnlockHistoryReasonSchema,
totalLocked: numberOrZero,
unlockedCount: numberOrZero,
privateCount: numberOrZero,
imageCount: numberOrZero,
voiceCount: numberOrZero,
requiredCredits: numberOrZero,
currentCredits: numberOrZero,
remainingCredits: numberOrZero,
shortfallCredits: numberOrZero,
costsByMessage: UnlockHistoryCostsByMessageSchema,
messageIds: arrayOrEmpty(z.string()),
})
.readonly();
export type UnlockHistoryReason = z.output<typeof UnlockHistoryReasonSchema>;
export type UnlockHistoryResponseInput = z.input<
@@ -42,26 +44,4 @@ export type UnlockHistoryResponseData = z.output<
typeof UnlockHistoryResponseSchema
>;
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);
}
}
export type UnlockHistoryResponse = UnlockHistoryResponseData;
@@ -6,28 +6,30 @@ import {
stringOrEmpty,
stringOrNull,
} from "../../nullable-defaults";
import { ChatImageSchema, type ChatImageData } from "../chat_payloads";
import { ChatLockTypeSchema } from "../chat_lock_type";
import { ChatImageSchema } from "../chat_payloads";
/**
* 单条历史付费 / 私密消息解锁响应。
*/
export const UnlockPrivateReasonSchema = stringOrEmpty;
export const UnlockPrivateResponseSchema = z.object({
unlocked: booleanOrFalse,
content: stringOrEmpty,
messageId: stringOrEmpty,
clientLockId: stringOrNull,
lockType: ChatLockTypeSchema.nullable().default(null),
audioUrl: stringOrEmpty,
image: ChatImageSchema,
reason: UnlockPrivateReasonSchema,
creditBalance: numberOrZero,
creditsCharged: numberOrZero,
requiredCredits: numberOrZero,
shortfallCredits: numberOrZero,
});
export const UnlockPrivateResponseSchema = z
.object({
unlocked: booleanOrFalse,
content: stringOrEmpty,
messageId: stringOrEmpty,
clientLockId: stringOrNull,
lockType: ChatLockTypeSchema.nullable().default(null),
audioUrl: stringOrEmpty,
image: ChatImageSchema,
reason: UnlockPrivateReasonSchema,
creditBalance: numberOrZero,
creditsCharged: numberOrZero,
requiredCredits: numberOrZero,
shortfallCredits: numberOrZero,
})
.readonly();
export type UnlockPrivateReason = z.output<typeof UnlockPrivateReasonSchema>;
export type UnlockPrivateResponseInput = z.input<
@@ -37,36 +39,4 @@ export type UnlockPrivateResponseData = z.output<
typeof UnlockPrivateResponseSchema
>;
/**
* 单条历史付费 / 私密消息解锁响应数据类。
*/
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);
}
}
export type UnlockPrivateResponse = UnlockPrivateResponseData;