172 lines
4.5 KiB
TypeScript
172 lines
4.5 KiB
TypeScript
import { fromCallback, fromPromise } from "xstate";
|
|
|
|
import {
|
|
ChatSendResponse,
|
|
UnlockPrivateResponse,
|
|
type UiMessage,
|
|
} from "@/data/dto/chat";
|
|
import { DEFAULT_CHARACTER_ID } from "@/data/constants/character";
|
|
import { chatMachine } from "@/stores/chat/chat-machine";
|
|
import type { ChatEvent } from "@/stores/chat/chat-events";
|
|
import type {
|
|
UnlockMessageOutput as MachineUnlockMessageOutput,
|
|
UnlockMessageRequest,
|
|
} from "@/stores/chat/helper/unlock";
|
|
import type { ChatHistoryActorInput } from "@/stores/chat/machine/actors/history";
|
|
|
|
export interface SendMessageHttpOutput {
|
|
response: ChatSendResponse;
|
|
reply: UiMessage | null;
|
|
}
|
|
|
|
export interface UnlockHistoryOutput {
|
|
unlocked: boolean;
|
|
reason: string;
|
|
shortfallCredits: number;
|
|
messages: UiMessage[];
|
|
}
|
|
|
|
export interface TestUnlockMessageOutput {
|
|
messageId: string;
|
|
response: UnlockPrivateResponse;
|
|
}
|
|
|
|
export const TEST_CHAT_MACHINE_INPUT = {
|
|
characterId: DEFAULT_CHARACTER_ID,
|
|
};
|
|
|
|
export function makeChatSendResponse(): ChatSendResponse {
|
|
return ChatSendResponse.from({
|
|
reply: "",
|
|
audioUrl: "",
|
|
messageId: "msg-1",
|
|
isGuest: false,
|
|
timestamp: Date.now(),
|
|
image: { type: null, url: null },
|
|
lockDetail: {
|
|
locked: false,
|
|
reason: null,
|
|
},
|
|
});
|
|
}
|
|
|
|
export function makeUnlockPrivateResponse(
|
|
overrides: Partial<Parameters<typeof UnlockPrivateResponse.from>[0]> = {},
|
|
): UnlockPrivateResponse {
|
|
return UnlockPrivateResponse.from({
|
|
unlocked: true,
|
|
content: "unlocked content",
|
|
audioUrl: "",
|
|
reason: "ok",
|
|
creditBalance: 90,
|
|
creditsCharged: 10,
|
|
requiredCredits: 10,
|
|
shortfallCredits: 0,
|
|
...overrides,
|
|
});
|
|
}
|
|
|
|
export function createTestChatMachine(
|
|
options: {
|
|
historyMessages?: UiMessage[];
|
|
sendMessageHttpError?: Error;
|
|
unlockHistoryOutput?: UnlockHistoryOutput;
|
|
unlockHistoryError?: Error;
|
|
unlockMessageOutput?: TestUnlockMessageOutput;
|
|
} = {},
|
|
) {
|
|
return chatMachine.provide({
|
|
actors: {
|
|
loadHistory: createLoadHistoryCallback(options.historyMessages ?? []),
|
|
sendMessageHttp: fromPromise<
|
|
SendMessageHttpOutput,
|
|
{ characterId: string; content: string }
|
|
>(async () => {
|
|
if (options.sendMessageHttpError) {
|
|
throw options.sendMessageHttpError;
|
|
}
|
|
return {
|
|
response: makeChatSendResponse(),
|
|
reply: null,
|
|
};
|
|
}),
|
|
httpMessageQueue: fromCallback<ChatEvent, { characterId: string }>(
|
|
({ receive, sendBack }) => {
|
|
receive((event) => {
|
|
if (event.type !== "ChatSendMessage") return;
|
|
sendBack({ type: "ChatQueuedSendStarted" });
|
|
sendBack({
|
|
type: "ChatQueuedHttpDone",
|
|
output: {
|
|
response: makeChatSendResponse(),
|
|
reply: null,
|
|
},
|
|
});
|
|
});
|
|
return () => undefined;
|
|
},
|
|
),
|
|
unlockHistory: fromPromise<
|
|
UnlockHistoryOutput,
|
|
{ characterId: string }
|
|
>(async () => {
|
|
if (options.unlockHistoryError) {
|
|
throw options.unlockHistoryError;
|
|
}
|
|
return {
|
|
unlocked: true,
|
|
reason: "ok",
|
|
shortfallCredits: 0,
|
|
messages: [],
|
|
...options.unlockHistoryOutput,
|
|
};
|
|
}),
|
|
unlockMessage: fromPromise<
|
|
MachineUnlockMessageOutput,
|
|
UnlockMessageRequest & { characterId: string }
|
|
>(async ({ input }) => {
|
|
const output = options.unlockMessageOutput ?? {
|
|
messageId: input.messageId ?? input.displayMessageId,
|
|
response: makeUnlockPrivateResponse(),
|
|
};
|
|
return {
|
|
displayMessageId: input.displayMessageId,
|
|
request: input,
|
|
response: output.response,
|
|
};
|
|
}),
|
|
},
|
|
});
|
|
}
|
|
|
|
export function createLoadHistoryCallback(
|
|
messages: UiMessage[],
|
|
networkMessages: UiMessage[] = messages,
|
|
pagination: { total: number; limit: number } = {
|
|
total: networkMessages.length,
|
|
limit: 50,
|
|
},
|
|
) {
|
|
return fromCallback<ChatEvent, ChatHistoryActorInput>(({ sendBack }) => {
|
|
sendBack({
|
|
type: "ChatLocalHistoryLoaded",
|
|
output: {
|
|
messages,
|
|
localCount: messages.length,
|
|
},
|
|
});
|
|
sendBack({
|
|
type: "ChatNetworkHistoryLoaded",
|
|
output: {
|
|
messages: networkMessages,
|
|
localOverwritten: true,
|
|
localCount: messages.length,
|
|
networkCount: networkMessages.length,
|
|
total: pagination.total,
|
|
limit: pagination.limit,
|
|
},
|
|
});
|
|
return () => undefined;
|
|
});
|
|
}
|