feat: setup barrelsby for automatic barrel file generation
Add barrelsby as a dev dependency with a `generate-barrels` npm script and a `barrelesby.json` config targeting `./src`. This automates creation of barrel/index files to simplify imports across the project.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 聊天历史响应
|
||||
* 原始 Dart: ChatHistoryResponse (lib/data/models/chat/chat_response.dart)
|
||||
*
|
||||
* 注:原始 Dart 中 `total` 为 `int?`,按"全部非空"约定兜底为 0。
|
||||
*/
|
||||
import { ChatMessage } from "./chat_message";
|
||||
|
||||
export class ChatHistoryResponse {
|
||||
readonly messages: ChatMessage[];
|
||||
readonly total: number;
|
||||
readonly limit: number;
|
||||
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;
|
||||
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 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"),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 聊天历史中的单条消息
|
||||
* 原始 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;
|
||||
|
||||
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 ?? "";
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
toJson(): Record<string, unknown> {
|
||||
return {
|
||||
role: this.role,
|
||||
content: this.content,
|
||||
id: this.id,
|
||||
createdAt: this.createdAt,
|
||||
};
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* 发送消息响应
|
||||
* 原始 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;
|
||||
|
||||
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;
|
||||
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 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,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 消息同步响应
|
||||
* 原始 Dart: ChatSyncData (lib/data/models/chat/chat_sync.dart)
|
||||
*/
|
||||
export class ChatSyncData {
|
||||
readonly syncedCount: number;
|
||||
readonly totalHistory: number;
|
||||
|
||||
constructor(params: { syncedCount: number; totalHistory: number }) {
|
||||
this.syncedCount = params.syncedCount;
|
||||
this.totalHistory = params.totalHistory;
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
toJson(): Record<string, unknown> {
|
||||
return {
|
||||
syncedCount: this.syncedCount,
|
||||
totalHistory: this.totalHistory,
|
||||
};
|
||||
}
|
||||
|
||||
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"),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 消息同步请求
|
||||
* 原始 Dart: ChatSyncRequest (lib/data/models/chat/chat_sync.dart)
|
||||
*/
|
||||
import { SyncMessage } from "./sync_message";
|
||||
|
||||
export class ChatSyncRequest {
|
||||
readonly messages: SyncMessage[];
|
||||
|
||||
constructor(params: { messages: SyncMessage[] }) {
|
||||
this.messages = params.messages;
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
toJson(): Record<string, unknown> {
|
||||
return { messages: this.messages.map((m) => m.toJson()) };
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* 游客每日聊天配额数据
|
||||
* 原始 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` 字段传入。
|
||||
*/
|
||||
export class GuestChatQuota {
|
||||
readonly remaining: number;
|
||||
readonly date: string;
|
||||
|
||||
// 静态常量
|
||||
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;
|
||||
|
||||
constructor(params: { remaining: number; date: string }) {
|
||||
this.remaining = params.remaining;
|
||||
this.date = params.date;
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 配额耗尽状态值(便捷引用)
|
||||
*/
|
||||
static get exhausted(): number {
|
||||
return GuestChatQuota.quotaExhausted;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否处于开发环境
|
||||
* 通过 `process.env.NODE_ENV` 判断,替代 Dart 中的 `AppEnvUtil.isDevelopment`
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建初始配额实例
|
||||
* @param todayString 当天日期字符串(YYYY-MM-DD),由调用方提供
|
||||
*/
|
||||
static initial(todayString: string): GuestChatQuota {
|
||||
return new GuestChatQuota({
|
||||
remaining: GuestChatQuota.threshold,
|
||||
date: todayString,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否需要重置(跨天)
|
||||
* @param todayString 当天日期字符串(YYYY-MM-DD),由调用方提供
|
||||
*/
|
||||
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 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* 图片上传响应
|
||||
* 原始 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;
|
||||
|
||||
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;
|
||||
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 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"),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// chat 子目录 barrel export
|
||||
export { ChatHistoryResponse } from "./chat_history_response";
|
||||
export { ChatMessage } from "./chat_message";
|
||||
export { ChatSendResponse } from "./chat_send_response";
|
||||
export { ChatSyncData } from "./chat_sync_data";
|
||||
export { ChatSyncRequest } from "./chat_sync_request";
|
||||
export { GuestChatQuota } from "./guest_chat_quota";
|
||||
export { ImageUploadResponse } from "./image_upload_response";
|
||||
export { SendMessageRequest } from "./send_message_request";
|
||||
export { SttData } from "./stt_data";
|
||||
export { SyncMessage } from "./sync_message";
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 发送消息请求 - 用于 /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;
|
||||
|
||||
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;
|
||||
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 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,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* STT(语音转文字)响应
|
||||
* 原始 Dart: SttData (lib/data/models/chat/stt_response.dart)
|
||||
*/
|
||||
export class SttData {
|
||||
readonly text: string;
|
||||
|
||||
constructor(params: { text: string }) {
|
||||
this.text = params.text;
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
toJson(): Record<string, unknown> {
|
||||
return { text: this.text };
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 待同步的单条消息
|
||||
* 原始 Dart: SyncMessage (lib/data/models/chat/chat_sync.dart)
|
||||
*/
|
||||
export class SyncMessage {
|
||||
readonly role: string;
|
||||
readonly content: string;
|
||||
readonly timestamp: string;
|
||||
|
||||
constructor(params: { role: string; content: string; timestamp: string }) {
|
||||
this.role = params.role;
|
||||
this.content = params.content;
|
||||
this.timestamp = params.timestamp;
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
toJson(): Record<string, unknown> {
|
||||
return {
|
||||
role: this.role,
|
||||
content: this.content,
|
||||
timestamp: this.timestamp,
|
||||
};
|
||||
}
|
||||
|
||||
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"),
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user