refactor(chat): split machine by business flow

This commit is contained in:
2026-07-14 19:04:32 +08:00
parent e48efc36ba
commit 84e677f687
11 changed files with 1403 additions and 1295 deletions
+232
View File
@@ -0,0 +1,232 @@
import {
createChatPromotionState,
shouldPromptUnlockHistory,
} from "../chat-machine.helpers";
import { initialState } from "../chat-state";
import {
guestInitializingState,
userInitializingState,
} from "./history-flow";
import {
guestReadyState,
guestSendingState,
userSendingViaHttpState,
} from "./send-flow";
import {
unlockingHistoryState,
unlockingMessageState,
unlockMachineSetup,
} from "./unlock-flow";
const startGuestSessionAction = unlockMachineSetup.assign(
({ context }) => ({
...initialState,
promotion: context.promotion,
}),
);
const startUserSessionAction = unlockMachineSetup.assign(
({ context }) => ({
...initialState,
promotion: context.promotion,
}),
);
const clearChatSessionAction = unlockMachineSetup.assign(() => ({
...initialState,
}));
const injectPromotionAction = unlockMachineSetup.assign(({ event }) => {
if (event.type !== "ChatPromotionInjected") return {};
return {
promotion: createChatPromotionState(
event.promotion,
event.messageId,
),
};
});
const clearPromotionAction = unlockMachineSetup.assign({ promotion: null });
export const chatMachineSetup = unlockMachineSetup.extend({
actions: {
startGuestSession: startGuestSessionAction,
startUserSession: startUserSessionAction,
clearChatSession: clearChatSessionAction,
injectPromotion: injectPromotionAction,
clearPromotion: clearPromotionAction,
},
});
const idleState = chatMachineSetup.createStateConfig({
on: {
ChatGuestLogin: {
target: "#chat.guestSession",
actions: "startGuestSession",
},
ChatUserLogin: {
target: "#chat.userSession",
actions: "startUserSession",
},
},
});
const guestSessionState = chatMachineSetup.createStateConfig({
invoke: [
{
id: "messageQueue",
src: "httpMessageQueue",
},
{
id: "loadHistory",
src: "loadHistory",
},
],
on: {
ChatUserLogin: {
target: "#chat.userSession",
actions: "startUserSession",
},
ChatNetworkHistoryLoaded: {
actions: "applyNetworkHistoryLoaded",
},
ChatHistoryLoadFailed: {
actions: "markHistoryLoadFailed",
},
ChatQueuedSendStarted: {
actions: "markQueuedSendStarted",
},
ChatQueuedHttpDone: {
actions: "applyQueuedHttpOutput",
},
ChatQueuedSendError: {
actions: "appendQueuedSendErrorMessage",
},
},
initial: "initializing",
states: {
initializing: guestInitializingState,
ready: guestReadyState,
sending: guestSendingState,
},
});
const userReadyState = chatMachineSetup.createStateConfig({
on: {
ChatSendMessage: {
guard: ({ context, event }) =>
context.canSendMessage && event.content.trim().length > 0,
actions: ["appendUserMessage", "enqueueMessage"],
},
ChatSendImage: {
actions: "appendUserImage",
},
ChatUnlockMessageRequested: {
guard: ({ event }) => event.messageId.trim().length > 0,
target: "unlockingMessage",
actions: "markUnlockMessageStarted",
},
},
});
const userSessionState = chatMachineSetup.createStateConfig({
invoke: [
{
id: "messageQueue",
src: "httpMessageQueue",
},
{
id: "loadHistory",
src: "loadHistory",
},
],
on: {
ChatGuestLogin: {
target: "#chat.guestSession",
actions: "startGuestSession",
},
ChatLogout: {
target: "#chat.idle",
actions: "clearChatSession",
},
ChatNetworkHistoryLoaded: [
{
guard: ({ context, event }) =>
event.type === "ChatNetworkHistoryLoaded" &&
context.paymentUnlockPending &&
shouldPromptUnlockHistory(event.output.messages),
target: ".ready",
actions: "showUnlockHistoryPromptFromNetwork",
},
{
guard: ({ context }) => context.paymentUnlockPending,
target: ".ready",
actions: "applyNetworkHistoryLoadedAndClearPayment",
},
{
guard: ({ context }) =>
!context.isUnlockingHistory && !context.isUnlockingMessage,
actions: "applyNetworkHistoryLoaded",
},
],
ChatHistoryLoadFailed: {
actions: "markHistoryLoadFailed",
},
ChatQueuedSendStarted: {
actions: "markQueuedSendStarted",
},
ChatQueuedHttpDone: {
actions: "applyQueuedHttpOutput",
},
ChatQueuedSendError: {
actions: "appendQueuedSendErrorMessage",
},
ChatPaymentSucceeded: [
{
guard: ({ context }) =>
context.historyLoaded &&
shouldPromptUnlockHistory(context.messages),
actions: ["clearUpgradePrompt", "showUnlockHistoryPrompt"],
},
{
guard: ({ context }) => !context.historyLoaded,
actions: ["clearUpgradePrompt", "markPaymentUnlockPending"],
},
{
guard: ({ context }) => context.historyLoaded,
actions: ["clearUpgradePrompt", "dismissUnlockHistoryPrompt"],
},
],
ChatUnlockHistoryConfirmed: {
target: ".unlockingHistory",
actions: "markUnlockHistoryStarted",
},
ChatUnlockHistoryDismissed: {
actions: "dismissUnlockHistoryPrompt",
},
ChatUnlockPaywallNavigationConsumed: {
actions: "clearUnlockPaywallRequest",
},
},
initial: "initializing",
states: {
initializing: userInitializingState,
ready: userReadyState,
sendingViaHttp: userSendingViaHttpState,
unlockingHistory: unlockingHistoryState,
unlockingMessage: unlockingMessageState,
},
});
export const chatRootStateConfig = chatMachineSetup.createStateConfig({
initial: "idle",
on: {
ChatPromotionInjected: { actions: "injectPromotion" },
ChatPromotionCleared: { actions: "clearPromotion" },
},
states: {
idle: idleState,
guestSession: guestSessionState,
userSession: userSessionState,
},
});