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:
2026-06-08 13:07:37 +08:00
parent 14d6e7c41e
commit c22b90c7f4
41 changed files with 2165 additions and 1 deletions
@@ -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"),
});
}
}
+53
View File
@@ -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,
});
}
}
+37
View File
@@ -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"),
});
}
}
+28
View File
@@ -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 });
}
}
+113
View File
@@ -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"),
});
}
}
+11
View File
@@ -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,
});
}
}
+24
View File
@@ -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 });
}
}
+41
View File
@@ -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"),
});
}
}