refactor(chat): remove guest history synchronization

This commit is contained in:
2026-07-20 14:02:39 +08:00
parent 1f7ab2be04
commit 4d1c85727a
17 changed files with 10 additions and 300 deletions
@@ -1,15 +0,0 @@
{
"characterId": "elio",
"messages": [
{
"role": "user",
"content": "Hi Elio.",
"timestamp": "2026-06-23T02:10:00.000Z"
},
{
"role": "assistant",
"content": "Hi, I am right here with you.",
"timestamp": "2026-06-23T02:10:04.000Z"
}
]
}
@@ -6,8 +6,6 @@ import type {
import {
ChatHistoryResponse,
ChatPreviewsResponse,
ChatSyncRequest,
ChatSyncRequestSchema,
ChatSendResponse,
SendMessageRequestSchema,
UnlockHistoryRequestSchema,
@@ -58,15 +56,6 @@ export class ChatRemoteDataSource {
return Result.wrap(() => this.api.getPreviews(options));
}
async syncGuestHistory(
request: ChatSyncRequest,
options?: ChatRequestOptions,
): Promise<Result<void>> {
return Result.wrap(() =>
this.api.syncGuestHistory(ChatSyncRequestSchema.parse(request), options),
);
}
async getHistory(
characterId: string,
limit = 50,
-8
View File
@@ -10,7 +10,6 @@ import type {
import type {
ChatHistoryResponse,
ChatPreviewsResponse,
ChatSyncRequest,
ChatMessage,
ChatSendResponse,
UnlockHistoryResponse,
@@ -63,13 +62,6 @@ export class ChatRepository implements IChatRepository {
return this.remote.getPreviews(options);
}
async syncGuestHistory(
request: ChatSyncRequest,
options?: ChatRequestOptions,
): Promise<Result<void>> {
return this.remote.syncGuestHistory(request, options);
}
/** 解锁单条历史付费 / 私密消息。 */
async unlockPrivateMessage(
input: UnlockPrivateMessageInput,
@@ -7,7 +7,6 @@
import type {
ChatHistoryResponse,
ChatPreviewsResponse,
ChatSyncRequest,
ChatImageData,
ChatLockDetailData,
ChatLockType,
@@ -79,12 +78,6 @@ export interface IChatRepository {
options?: ChatRequestOptions,
): Promise<Result<ChatPreviewsResponse>>;
/** 把一个角色的游客历史同步到正式账号。 */
syncGuestHistory(
request: ChatSyncRequest,
options?: ChatRequestOptions,
): Promise<Result<void>>;
/** 解锁单条历史付费 / 私密消息。 */
unlockPrivateMessage(
input: UnlockPrivateMessageInput,
@@ -2,7 +2,6 @@ import { describe, expect, it } from "vitest";
import {
ChatPreviewsResponseSchema,
ChatSyncRequestSchema,
SendMessageRequestSchema,
} from "@/data/schemas/chat";
@@ -26,23 +25,12 @@ describe("multi-role chat schemas", () => {
).toThrow();
});
it("parses nullable previews and immutable sync messages", () => {
it("parses nullable immutable previews", () => {
const previews = ChatPreviewsResponseSchema.parse({
items: [{ characterId: "elio", message: null }],
});
const sync = ChatSyncRequestSchema.parse({
characterId: "elio",
messages: [
{
role: "assistant",
content: "Welcome back",
timestamp: "2026-07-20T00:00:00.000Z",
},
],
});
expect(previews.items[0]?.message).toBeNull();
expect(Object.isFrozen(previews.items)).toBe(true);
expect(Object.isFrozen(sync.messages)).toBe(true);
});
});
-1
View File
@@ -7,7 +7,6 @@ export * from "./chat_media";
export * from "./chat_message";
export * from "./chat_payloads";
export * from "./request/send_message_request";
export * from "./request/chat_sync_request";
export * from "./request/unlock_history_request";
export * from "./request/unlock_private_request";
export * from "./response/chat_history_response";
@@ -1,19 +0,0 @@
import { z } from "zod";
export const ChatSyncMessageSchema = z
.object({
role: z.enum(["user", "assistant"]),
content: z.string(),
timestamp: z.string().min(1),
})
.readonly();
export const ChatSyncRequestSchema = z
.object({
characterId: z.string().min(1),
messages: z.array(ChatSyncMessageSchema).min(1).readonly(),
})
.readonly();
export type ChatSyncRequestInput = z.input<typeof ChatSyncRequestSchema>;
export type ChatSyncRequest = z.output<typeof ChatSyncRequestSchema>;
-1
View File
@@ -3,6 +3,5 @@
*/
export * from "./send_message_request";
export * from "./chat_sync_request";
export * from "./unlock_private_request";
export * from "./unlock_history_request";
@@ -1,7 +1,6 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import {
ChatSyncRequestSchema,
SendMessageRequestSchema,
UnlockHistoryRequestSchema,
UnlockPrivateRequestSchema,
@@ -74,30 +73,16 @@ describe("multi-character API contract", () => {
});
});
it("loads previews and syncs guest history", async () => {
it("loads chat previews", async () => {
const api = new ChatApi();
httpClientMock
.mockResolvedValueOnce({ success: true, data: { items: [] } })
.mockResolvedValueOnce({ success: true, data: {} });
httpClientMock.mockResolvedValueOnce({
success: true,
data: { items: [] },
});
await api.getPreviews();
const request = ChatSyncRequestSchema.parse({
characterId: CHARACTER_ID,
messages: [
{
role: "user",
content: "Hello",
timestamp: "2026-07-20T00:00:00.000Z",
},
],
});
await api.syncGuestHistory(request);
expect(httpClientMock).toHaveBeenNthCalledWith(1, "/api/chat/previews", {});
expect(httpClientMock).toHaveBeenNthCalledWith(2, "/api/chat/sync", {
method: "POST",
body: request,
});
expect(httpClientMock).toHaveBeenCalledWith("/api/chat/previews", {});
});
it("forwards request cancellation to the HTTP client", async () => {
+1 -2
View File
@@ -26,6 +26,5 @@
"reportUserInfo": { "method": "post", "path": "/api/data/report-user-info" },
"feedback": { "method": "post", "path": "/api/feedback" },
"characters": { "method": "get", "path": "/api/characters" },
"chatPreviews": { "method": "get", "path": "/api/chat/previews" },
"chatSync": { "method": "post", "path": "/api/chat/sync" }
"chatPreviews": { "method": "get", "path": "/api/chat/previews" }
}
-2
View File
@@ -104,6 +104,4 @@ export class ApiPath {
static readonly chatPreviews = apiContract.chatPreviews.path;
static readonly chatSync = apiContract.chatSync.path;
}
-12
View File
@@ -11,7 +11,6 @@ import {
ChatPreviewsResponseSchema,
ChatSendResponse,
ChatSendResponseSchema,
ChatSyncRequest,
SendMessageRequest,
UnlockHistoryRequest,
UnlockHistoryResponse,
@@ -67,17 +66,6 @@ export class ChatApi {
return ChatPreviewsResponseSchema.parse(unwrap(env));
}
async syncGuestHistory(
body: ChatSyncRequest,
options?: { signal?: AbortSignal },
): Promise<void> {
await httpClient<ApiEnvelope<unknown>>(ApiPath.chatSync, {
method: "POST",
body,
...(options?.signal ? { signal: options.signal } : {}),
}).then(unwrap);
}
/**
* 解锁单条历史付费 / 私密消息
*/
@@ -259,22 +259,6 @@ export class NavigationStorage {
await SessionAsyncUtil.remove(StorageKeys.pendingChatImageReturn);
}
static async saveGuestChatOwnerKey(ownerKey: string): Promise<void> {
await SessionAsyncUtil.setJson(
StorageKeys.guestChatOwnerKey,
ownerKey,
z.string().min(1),
);
}
static async getGuestChatOwnerKey(): Promise<string | null> {
const result = await SessionAsyncUtil.getJson(
StorageKeys.guestChatOwnerKey,
z.string().min(1),
);
return Result.isOk(result) ? result.data : null;
}
private static parsePendingChatUnlock(
value: PendingChatUnlock | null,
): PendingChatUnlock | null {
-1
View File
@@ -28,7 +28,6 @@ export const StorageKeys = {
pendingChatImageReturn: "pending_chat_image_return",
pendingChatUnlock: "pending_chat_unlock",
pendingChatPromotion: "pending_chat_promotion",
guestChatOwnerKey: "guest_chat_owner_key",
// pwa / app info
pwaDialogShown: "pwa_dialog_shown",