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

This commit is contained in:
2026-06-08 14:50:20 +08:00
parent 700ad0bc1a
commit d7943f5f06
36 changed files with 1204 additions and 1358 deletions
+27 -46
View File
@@ -1,60 +1,41 @@
/**
* 聊天历史响应
* 原始 Dart: ChatHistoryResponse (lib/data/models/chat/chat_response.dart)
*
* 注:原始 Dart 中 `total` 为 `int?`,按"全部非空"约定兜底为 0。
*/
import { ChatMessage } from "./chat_message";
import { z } from "zod";
import { ChatMessage, ChatMessageSchema } from "./chat_message";
export const ChatHistoryResponseSchema = z.object({
messages: z.array(ChatMessageSchema),
total: z.number().default(0),
limit: z.number(),
offset: z.number(),
});
export type ChatHistoryResponseInput = z.input<typeof ChatHistoryResponseSchema>;
export type ChatHistoryResponseData = z.output<typeof ChatHistoryResponseSchema>;
export class ChatHistoryResponse {
readonly messages: ChatMessage[];
readonly total: number;
readonly limit: number;
readonly offset: number;
declare readonly messages: ChatMessage[];
declare readonly total: number;
declare readonly limit: number;
declare readonly offset: number;
constructor(params: {
messages: ChatMessage[];
total?: number;
limit: number;
offset: number;
}) {
this.messages = params.messages;
this.total = params.total ?? 0;
this.limit = params.limit;
this.offset = params.offset;
private constructor(input: ChatHistoryResponseInput) {
const data = ChatHistoryResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
messages: this.messages.map((m) => m.toJson()),
total: this.total,
limit: this.limit,
offset: this.offset,
};
static from(input: ChatHistoryResponseInput): ChatHistoryResponse {
return new ChatHistoryResponse(input);
}
static fromJson(json: Record<string, unknown>): ChatHistoryResponse {
const requireNumber = (key: string): number => {
const v = json[key];
if (typeof v !== "number") {
throw new Error(
`ChatHistoryResponse.${key} is required and must be a number`
);
}
return v;
};
const rawMessages = json.messages;
const messages: ChatMessage[] = Array.isArray(rawMessages)
? (rawMessages as Record<string, unknown>[]).map((m) =>
ChatMessage.fromJson(m)
)
: [];
return new ChatHistoryResponse({
messages,
total: typeof json.total === "number" ? json.total : undefined,
limit: requireNumber("limit"),
offset: requireNumber("offset"),
});
static fromJson(json: unknown): ChatHistoryResponse {
return ChatHistoryResponse.from(json as ChatHistoryResponseInput);
}
toJson(): ChatHistoryResponseData {
return ChatHistoryResponseSchema.parse(this);
}
}
+28 -41
View File
@@ -1,53 +1,40 @@
/**
* 聊天历史中的单条消息
* 原始 Dart: ChatMessage (lib/data/models/chat/chat_response.dart)
*
* 注:原始 Dart 中 `id`/`createdAt` 为 `String?`,按"全部非空"约定兜底为空串。
*/
export class ChatMessage {
readonly role: string;
readonly content: string;
readonly id: string;
readonly createdAt: string;
import { z } from "zod";
constructor(params: {
role: string;
content: string;
id?: string;
createdAt?: string;
}) {
this.role = params.role;
this.content = params.content;
this.id = params.id ?? "";
this.createdAt = params.createdAt ?? "";
export const ChatMessageSchema = z.object({
role: z.string(),
content: z.string(),
id: z.string().default(""),
createdAt: z.string().default(""),
});
export type ChatMessageInput = z.input<typeof ChatMessageSchema>;
export type ChatMessageData = z.output<typeof ChatMessageSchema>;
export class ChatMessage {
declare readonly role: string;
declare readonly content: string;
declare readonly id: string;
declare readonly createdAt: string;
private constructor(input: ChatMessageInput) {
const data = ChatMessageSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
role: this.role,
content: this.content,
id: this.id,
createdAt: this.createdAt,
};
static from(input: ChatMessageInput): ChatMessage {
return new ChatMessage(input);
}
static fromJson(json: Record<string, unknown>): ChatMessage {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`ChatMessage.${key} is required and must be a string`
);
}
return v;
};
return new ChatMessage({
role: requireString("role"),
content: requireString("content"),
id: typeof json.id === "string" ? json.id : undefined,
createdAt:
typeof json.createdAt === "string" ? json.createdAt : undefined,
});
static fromJson(json: unknown): ChatMessage {
return ChatMessage.from(json as ChatMessageInput);
}
toJson(): ChatMessageData {
return ChatMessageSchema.parse(this);
}
}
+42 -86
View File
@@ -1,98 +1,54 @@
/**
* 发送消息响应
* 原始 Dart: ChatSendResponse (lib/data/models/chat/chat_response.dart)
*
* 注:原始 Dart 中 `mode`/`currentMood`/`isGuest` 为可空字段,按"全部非空"约定兜底:
* - 字符串 → ""
* - bool → false
* - int → 0
*/
export class ChatSendResponse {
readonly mode: string;
readonly reply: string;
readonly voiceUrl: string;
readonly audioUrl: string;
readonly intimacyChange: number;
readonly newIntimacy: number;
readonly relationshipStage: string;
readonly currentMood: string;
readonly messageId: string;
readonly isGuest: boolean;
readonly timestamp: number;
import { z } from "zod";
constructor(params: {
mode?: string;
reply: string;
voiceUrl?: string;
audioUrl?: string;
intimacyChange?: number;
newIntimacy?: number;
relationshipStage: string;
currentMood?: string;
messageId: string;
isGuest?: boolean;
timestamp?: number;
}) {
this.mode = params.mode ?? "";
this.reply = params.reply;
this.voiceUrl = params.voiceUrl ?? "";
this.audioUrl = params.audioUrl ?? "";
this.intimacyChange = params.intimacyChange ?? 0;
this.newIntimacy = params.newIntimacy ?? 0;
this.relationshipStage = params.relationshipStage;
this.currentMood = params.currentMood ?? "";
this.messageId = params.messageId;
this.isGuest = params.isGuest ?? false;
this.timestamp = params.timestamp ?? 0;
export const ChatSendResponseSchema = z.object({
mode: z.string().default(""),
reply: z.string(),
voiceUrl: z.string().default(""),
audioUrl: z.string().default(""),
intimacyChange: z.number().default(0),
newIntimacy: z.number().default(0),
relationshipStage: z.string(),
currentMood: z.string().default(""),
messageId: z.string(),
isGuest: z.boolean().default(false),
timestamp: z.number().default(0),
});
export type ChatSendResponseInput = z.input<typeof ChatSendResponseSchema>;
export type ChatSendResponseData = z.output<typeof ChatSendResponseSchema>;
export class ChatSendResponse {
declare readonly mode: string;
declare readonly reply: string;
declare readonly voiceUrl: string;
declare readonly audioUrl: string;
declare readonly intimacyChange: number;
declare readonly newIntimacy: number;
declare readonly relationshipStage: string;
declare readonly currentMood: string;
declare readonly messageId: string;
declare readonly isGuest: boolean;
declare readonly timestamp: number;
private constructor(input: ChatSendResponseInput) {
const data = ChatSendResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
mode: this.mode,
reply: this.reply,
voiceUrl: this.voiceUrl,
audioUrl: this.audioUrl,
intimacyChange: this.intimacyChange,
newIntimacy: this.newIntimacy,
relationshipStage: this.relationshipStage,
currentMood: this.currentMood,
messageId: this.messageId,
isGuest: this.isGuest,
timestamp: this.timestamp,
};
static from(input: ChatSendResponseInput): ChatSendResponse {
return new ChatSendResponse(input);
}
static fromJson(json: Record<string, unknown>): ChatSendResponse {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`ChatSendResponse.${key} is required and must be a string`
);
}
return v;
};
return new ChatSendResponse({
mode: typeof json.mode === "string" ? json.mode : undefined,
reply: requireString("reply"),
voiceUrl:
typeof json.voiceUrl === "string" ? json.voiceUrl : undefined,
audioUrl:
typeof json.audioUrl === "string" ? json.audioUrl : undefined,
intimacyChange:
typeof json.intimacyChange === "number"
? json.intimacyChange
: undefined,
newIntimacy:
typeof json.newIntimacy === "number" ? json.newIntimacy : undefined,
relationshipStage: requireString("relationshipStage"),
currentMood:
typeof json.currentMood === "string" ? json.currentMood : undefined,
messageId: requireString("messageId"),
isGuest: typeof json.isGuest === "boolean" ? json.isGuest : undefined,
timestamp:
typeof json.timestamp === "number" ? json.timestamp : undefined,
});
static fromJson(json: unknown): ChatSendResponse {
return ChatSendResponse.from(json as ChatSendResponseInput);
}
toJson(): ChatSendResponseData {
return ChatSendResponseSchema.parse(this);
}
}
+24 -25
View File
@@ -2,36 +2,35 @@
* 消息同步响应
* 原始 Dart: ChatSyncData (lib/data/models/chat/chat_sync.dart)
*/
export class ChatSyncData {
readonly syncedCount: number;
readonly totalHistory: number;
import { z } from "zod";
constructor(params: { syncedCount: number; totalHistory: number }) {
this.syncedCount = params.syncedCount;
this.totalHistory = params.totalHistory;
export const ChatSyncDataSchema = z.object({
syncedCount: z.number(),
totalHistory: z.number(),
});
export type ChatSyncDataInput = z.input<typeof ChatSyncDataSchema>;
export type ChatSyncDataData = z.output<typeof ChatSyncDataSchema>;
export class ChatSyncData {
declare readonly syncedCount: number;
declare readonly totalHistory: number;
private constructor(input: ChatSyncDataInput) {
const data = ChatSyncDataSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
syncedCount: this.syncedCount,
totalHistory: this.totalHistory,
};
static from(input: ChatSyncDataInput): ChatSyncData {
return new ChatSyncData(input);
}
static fromJson(json: Record<string, unknown>): ChatSyncData {
const requireNumber = (key: string): number => {
const v = json[key];
if (typeof v !== "number") {
throw new Error(
`ChatSyncData.${key} is required and must be a number`
);
}
return v;
};
return new ChatSyncData({
syncedCount: requireNumber("syncedCount"),
totalHistory: requireNumber("totalHistory"),
});
static fromJson(json: unknown): ChatSyncData {
return ChatSyncData.from(json as ChatSyncDataInput);
}
toJson(): ChatSyncDataData {
return ChatSyncDataSchema.parse(this);
}
}
+21 -14
View File
@@ -2,27 +2,34 @@
* 消息同步请求
* 原始 Dart: ChatSyncRequest (lib/data/models/chat/chat_sync.dart)
*/
import { SyncMessage } from "./sync_message";
import { z } from "zod";
import { SyncMessage, SyncMessageSchema } from "./sync_message";
export const ChatSyncRequestSchema = z.object({
messages: z.array(SyncMessageSchema),
});
export type ChatSyncRequestInput = z.input<typeof ChatSyncRequestSchema>;
export type ChatSyncRequestData = z.output<typeof ChatSyncRequestSchema>;
export class ChatSyncRequest {
readonly messages: SyncMessage[];
declare readonly messages: SyncMessage[];
constructor(params: { messages: SyncMessage[] }) {
this.messages = params.messages;
private constructor(input: ChatSyncRequestInput) {
const data = ChatSyncRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return { messages: this.messages.map((m) => m.toJson()) };
static from(input: ChatSyncRequestInput): ChatSyncRequest {
return new ChatSyncRequest(input);
}
static fromJson(json: Record<string, unknown>): ChatSyncRequest {
const rawMessages = json.messages;
const messages: SyncMessage[] = Array.isArray(rawMessages)
? (rawMessages as Record<string, unknown>[]).map((m) =>
SyncMessage.fromJson(m)
)
: [];
return new ChatSyncRequest({ messages });
static fromJson(json: unknown): ChatSyncRequest {
return ChatSyncRequest.from(json as ChatSyncRequestInput);
}
toJson(): ChatSyncRequestData {
return ChatSyncRequestSchema.parse(this);
}
}
+30 -33
View File
@@ -2,17 +2,23 @@
* 游客每日聊天配额数据
* 原始 Dart: GuestChatQuota (lib/data/models/chat/guest_chat_quota.dart)
*
* 注:原始 Dart 中的静态常量与运行时环境判断方法isDevelopment)已迁移为
* 静态成员。环境检测逻辑(threshold / totalQuotaDefault 等)保留为方法,
* 内部使用 `process.env.NODE_ENV` 替代 Dart 中的 `AppEnvUtil.isDevelopment`
* `initial()` 工厂方法已迁移为静态方法;`needReset` getter 保留为实例方法。
*
* Dart 中 `initial()` 依赖 `app_date.DateUtils.todayString()`
* 在 TS 中由调用方通过 `date` 字段传入。
* 注:保留原始 Dart 中的静态常量与运行时环境判断方法
* `process.env.NODE_ENV` 替代 Dart 的 `AppEnvUtil.isDevelopment`。
* `initial()` 工厂方法与 `needReset` 实例方法保留
*/
import { z } from "zod";
export const GuestChatQuotaSchema = z.object({
remaining: z.number(),
date: z.string(),
});
export type GuestChatQuotaInput = z.input<typeof GuestChatQuotaSchema>;
export type GuestChatQuotaData = z.output<typeof GuestChatQuotaSchema>;
export class GuestChatQuota {
readonly remaining: number;
readonly date: string;
declare readonly remaining: number;
declare readonly date: string;
// 静态常量
static readonly maxQuotaPerDay = 40;
@@ -23,12 +29,24 @@ export class GuestChatQuota {
static readonly defaultTotalQuotaDev = 5;
static readonly quotaExhausted = 0;
constructor(params: { remaining: number; date: string }) {
this.remaining = params.remaining;
this.date = params.date;
private constructor(input: GuestChatQuotaInput) {
const data = GuestChatQuotaSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
static from(input: GuestChatQuotaInput): GuestChatQuota {
return new GuestChatQuota(input);
}
static fromJson(json: unknown): GuestChatQuota {
return GuestChatQuota.from(json as GuestChatQuotaInput);
}
toJson(): GuestChatQuotaData {
return GuestChatQuotaSchema.parse(this);
}
/**
* 配额耗尽状态值(便捷引用)
*/
@@ -89,25 +107,4 @@ export class GuestChatQuota {
needsReset(todayString: string): boolean {
return this.date !== todayString;
}
toJson(): Record<string, unknown> {
return {
remaining: this.remaining,
date: this.date,
};
}
static fromJson(json: Record<string, unknown>): GuestChatQuota {
const remaining = json.remaining;
const date = json.date;
if (typeof remaining !== "number") {
throw new Error(
"GuestChatQuota.remaining is required and must be a number"
);
}
if (typeof date !== "string") {
throw new Error("GuestChatQuota.date is required and must be a string");
}
return new GuestChatQuota({ remaining, date });
}
}
+36 -67
View File
@@ -2,78 +2,47 @@
* 图片上传响应
* 原始 Dart: ImageUploadResponse (lib/data/models/chat/image_upload_response.dart)
*/
export class ImageUploadResponse {
readonly success: boolean;
readonly imageId: string;
readonly thumbUrl: string;
readonly mediumUrl: string;
readonly originalUrl: string;
readonly width: number;
readonly height: number;
readonly bytes: number;
import { z } from "zod";
constructor(params: {
success?: boolean;
imageId: string;
thumbUrl: string;
mediumUrl: string;
originalUrl: string;
width: number;
height: number;
bytes: number;
}) {
this.success = params.success ?? true;
this.imageId = params.imageId;
this.thumbUrl = params.thumbUrl;
this.mediumUrl = params.mediumUrl;
this.originalUrl = params.originalUrl;
this.width = params.width;
this.height = params.height;
this.bytes = params.bytes;
export const ImageUploadResponseSchema = z.object({
success: z.boolean().default(true),
imageId: z.string(),
thumbUrl: z.string(),
mediumUrl: z.string(),
originalUrl: z.string(),
width: z.number(),
height: z.number(),
bytes: z.number(),
});
export type ImageUploadResponseInput = z.input<typeof ImageUploadResponseSchema>;
export type ImageUploadResponseData = z.output<typeof ImageUploadResponseSchema>;
export class ImageUploadResponse {
declare readonly success: boolean;
declare readonly imageId: string;
declare readonly thumbUrl: string;
declare readonly mediumUrl: string;
declare readonly originalUrl: string;
declare readonly width: number;
declare readonly height: number;
declare readonly bytes: number;
private constructor(input: ImageUploadResponseInput) {
const data = ImageUploadResponseSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
success: this.success,
imageId: this.imageId,
thumbUrl: this.thumbUrl,
mediumUrl: this.mediumUrl,
originalUrl: this.originalUrl,
width: this.width,
height: this.height,
bytes: this.bytes,
};
static from(input: ImageUploadResponseInput): ImageUploadResponse {
return new ImageUploadResponse(input);
}
static fromJson(json: Record<string, unknown>): ImageUploadResponse {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`ImageUploadResponse.${key} is required and must be a string`
);
}
return v;
};
const requireNumber = (key: string): number => {
const v = json[key];
if (typeof v !== "number") {
throw new Error(
`ImageUploadResponse.${key} is required and must be a number`
);
}
return v;
};
return new ImageUploadResponse({
success: typeof json.success === "boolean" ? json.success : undefined,
imageId: requireString("imageId"),
thumbUrl: requireString("thumbUrl"),
mediumUrl: requireString("mediumUrl"),
originalUrl: requireString("originalUrl"),
width: requireNumber("width"),
height: requireNumber("height"),
bytes: requireNumber("bytes"),
});
static fromJson(json: unknown): ImageUploadResponse {
return ImageUploadResponse.from(json as ImageUploadResponseInput);
}
toJson(): ImageUploadResponseData {
return ImageUploadResponseSchema.parse(this);
}
}
+38 -70
View File
@@ -1,82 +1,50 @@
/**
* 发送消息请求 - 用于 /api/chat/send 接口
* 原始 Dart: SendMessageRequest (lib/data/models/chat/send_message_request.dart)
*
* 注:原始 Dart 中所有图片相关字段为可空,按"全部非空"约定兜底:
* - 字符串 → ""
* - 数字 → 0
*/
export class SendMessageRequest {
readonly message: string;
readonly image: string;
readonly imageId: string;
readonly imageThumbUrl: string;
readonly imageMediumUrl: string;
readonly imageOriginalUrl: string;
readonly imageWidth: number;
readonly imageHeight: number;
readonly useWebSocket: boolean;
import { z } from "zod";
constructor(params: {
message?: string;
image?: string;
imageId?: string;
imageThumbUrl?: string;
imageMediumUrl?: string;
imageOriginalUrl?: string;
imageWidth?: number;
imageHeight?: number;
useWebSocket?: boolean;
}) {
this.message = params.message ?? "";
this.image = params.image ?? "";
this.imageId = params.imageId ?? "";
this.imageThumbUrl = params.imageThumbUrl ?? "";
this.imageMediumUrl = params.imageMediumUrl ?? "";
this.imageOriginalUrl = params.imageOriginalUrl ?? "";
this.imageWidth = params.imageWidth ?? 0;
this.imageHeight = params.imageHeight ?? 0;
this.useWebSocket = params.useWebSocket ?? false;
export const SendMessageRequestSchema = z.object({
message: z.string().default(""),
image: z.string().default(""),
imageId: z.string().default(""),
imageThumbUrl: z.string().default(""),
imageMediumUrl: z.string().default(""),
imageOriginalUrl: z.string().default(""),
imageWidth: z.number().default(0),
imageHeight: z.number().default(0),
useWebSocket: z.boolean().default(false),
});
export type SendMessageRequestInput = z.input<typeof SendMessageRequestSchema>;
export type SendMessageRequestData = z.output<typeof SendMessageRequestSchema>;
export class SendMessageRequest {
declare readonly message: string;
declare readonly image: string;
declare readonly imageId: string;
declare readonly imageThumbUrl: string;
declare readonly imageMediumUrl: string;
declare readonly imageOriginalUrl: string;
declare readonly imageWidth: number;
declare readonly imageHeight: number;
declare readonly useWebSocket: boolean;
private constructor(input: SendMessageRequestInput) {
const data = SendMessageRequestSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
message: this.message,
image: this.image,
imageId: this.imageId,
imageThumbUrl: this.imageThumbUrl,
imageMediumUrl: this.imageMediumUrl,
imageOriginalUrl: this.imageOriginalUrl,
imageWidth: this.imageWidth,
imageHeight: this.imageHeight,
useWebSocket: this.useWebSocket,
};
static from(input: SendMessageRequestInput): SendMessageRequest {
return new SendMessageRequest(input);
}
static fromJson(json: Record<string, unknown>): SendMessageRequest {
return new SendMessageRequest({
message: typeof json.message === "string" ? json.message : undefined,
image: typeof json.image === "string" ? json.image : undefined,
imageId: typeof json.imageId === "string" ? json.imageId : undefined,
imageThumbUrl:
typeof json.imageThumbUrl === "string"
? json.imageThumbUrl
: undefined,
imageMediumUrl:
typeof json.imageMediumUrl === "string"
? json.imageMediumUrl
: undefined,
imageOriginalUrl:
typeof json.imageOriginalUrl === "string"
? json.imageOriginalUrl
: undefined,
imageWidth:
typeof json.imageWidth === "number" ? json.imageWidth : undefined,
imageHeight:
typeof json.imageHeight === "number" ? json.imageHeight : undefined,
useWebSocket:
typeof json.useWebSocket === "boolean" ? json.useWebSocket : undefined,
});
static fromJson(json: unknown): SendMessageRequest {
return SendMessageRequest.from(json as SendMessageRequestInput);
}
toJson(): SendMessageRequestData {
return SendMessageRequestSchema.parse(this);
}
}
+22 -12
View File
@@ -2,23 +2,33 @@
* STT(语音转文字)响应
* 原始 Dart: SttData (lib/data/models/chat/stt_response.dart)
*/
export class SttData {
readonly text: string;
import { z } from "zod";
constructor(params: { text: string }) {
this.text = params.text;
export const SttDataSchema = z.object({
text: z.string(),
});
export type SttDataInput = z.input<typeof SttDataSchema>;
export type SttDataData = z.output<typeof SttDataSchema>;
export class SttData {
declare readonly text: string;
private constructor(input: SttDataInput) {
const data = SttDataSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return { text: this.text };
static from(input: SttDataInput): SttData {
return new SttData(input);
}
static fromJson(json: Record<string, unknown>): SttData {
const text = json.text;
if (typeof text !== "string") {
throw new Error("SttData.text is required and must be a string");
}
return new SttData({ text });
static fromJson(json: unknown): SttData {
return SttData.from(json as SttDataInput);
}
toJson(): SttDataData {
return SttDataSchema.parse(this);
}
}
+26 -29
View File
@@ -2,40 +2,37 @@
* 待同步的单条消息
* 原始 Dart: SyncMessage (lib/data/models/chat/chat_sync.dart)
*/
export class SyncMessage {
readonly role: string;
readonly content: string;
readonly timestamp: string;
import { z } from "zod";
constructor(params: { role: string; content: string; timestamp: string }) {
this.role = params.role;
this.content = params.content;
this.timestamp = params.timestamp;
export const SyncMessageSchema = z.object({
role: z.string(),
content: z.string(),
timestamp: z.string(),
});
export type SyncMessageInput = z.input<typeof SyncMessageSchema>;
export type SyncMessageData = z.output<typeof SyncMessageSchema>;
export class SyncMessage {
declare readonly role: string;
declare readonly content: string;
declare readonly timestamp: string;
private constructor(input: SyncMessageInput) {
const data = SyncMessageSchema.parse(input);
Object.assign(this, data);
Object.freeze(this);
}
toJson(): Record<string, unknown> {
return {
role: this.role,
content: this.content,
timestamp: this.timestamp,
};
static from(input: SyncMessageInput): SyncMessage {
return new SyncMessage(input);
}
static fromJson(json: Record<string, unknown>): SyncMessage {
const requireString = (key: string): string => {
const v = json[key];
if (typeof v !== "string") {
throw new Error(
`SyncMessage.${key} is required and must be a string`
);
}
return v;
};
return new SyncMessage({
role: requireString("role"),
content: requireString("content"),
timestamp: requireString("timestamp"),
});
static fromJson(json: unknown): SyncMessage {
return SyncMessage.from(json as SyncMessageInput);
}
toJson(): SyncMessageData {
return SyncMessageSchema.parse(this);
}
}