112 lines
3.3 KiB
TypeScript
112 lines
3.3 KiB
TypeScript
import { fromPromise } from "xstate";
|
|
|
|
import { loadChatRepository } from "@/data/repositories/chat_repository_loader";
|
|
import { resolveChatConversationKey } from "@/data/repositories/chat_cache_identity";
|
|
import { Logger } from "@/utils/logger";
|
|
import { Result } from "@/utils/result";
|
|
import { isAbortError } from "@/utils/abort";
|
|
|
|
import { readAndSyncHistory } from "../../chat-history-sync";
|
|
import {
|
|
type UnlockMessageRequest,
|
|
type UnlockMessageOutput,
|
|
} from "../../helper/unlock";
|
|
|
|
const log = new Logger("StoresChatChatUnlockFlow");
|
|
|
|
type UiMessage = import("@/stores/chat/ui-message").UiMessage;
|
|
|
|
export interface UnlockHistoryOutput {
|
|
unlocked: boolean;
|
|
reason: string;
|
|
shortfallCredits: number;
|
|
messages: UiMessage[];
|
|
}
|
|
|
|
export const unlockHistoryActor = fromPromise<
|
|
UnlockHistoryOutput,
|
|
{ characterId: string }
|
|
>(async ({ input, signal }) => {
|
|
const chatRepo = await loadChatRepository();
|
|
const unlockResult = await chatRepo.unlockHistory(input.characterId, {
|
|
signal,
|
|
});
|
|
if (Result.isErr(unlockResult)) {
|
|
if (isAbortError(unlockResult.error)) throw unlockResult.error;
|
|
log.error("[chat-machine] unlockHistoryActor failed", {
|
|
error: unlockResult.error,
|
|
});
|
|
throw unlockResult.error;
|
|
}
|
|
|
|
signal.throwIfAborted();
|
|
const history = await readAndSyncHistory(input.characterId, signal);
|
|
return {
|
|
unlocked: unlockResult.data.unlocked,
|
|
reason: unlockResult.data.reason,
|
|
shortfallCredits: unlockResult.data.shortfallCredits,
|
|
messages: history.messages,
|
|
};
|
|
});
|
|
|
|
export const unlockMessageActor = fromPromise<
|
|
UnlockMessageOutput,
|
|
UnlockMessageRequest & { characterId: string }
|
|
>(async ({ input, signal }) => {
|
|
const chatRepo = await loadChatRepository();
|
|
const cacheIdentityResult = await resolveChatConversationKey(
|
|
input.characterId,
|
|
);
|
|
const unlockResult = await chatRepo.unlockPrivateMessage(
|
|
{
|
|
characterId: input.characterId,
|
|
...(input.messageId ? { messageId: input.messageId } : {}),
|
|
...(input.lockType ? { lockType: input.lockType } : {}),
|
|
...(input.clientLockId ? { clientLockId: input.clientLockId } : {}),
|
|
},
|
|
{ signal },
|
|
);
|
|
if (Result.isErr(unlockResult)) {
|
|
if (isAbortError(unlockResult.error)) throw unlockResult.error;
|
|
log.error("[chat-machine] unlockMessageActor failed", {
|
|
messageId: input.messageId,
|
|
clientLockId: input.clientLockId,
|
|
error: unlockResult.error,
|
|
});
|
|
throw unlockResult.error;
|
|
}
|
|
signal.throwIfAborted();
|
|
|
|
if (
|
|
unlockResult.data.unlocked &&
|
|
input.messageId &&
|
|
!input.clientLockId &&
|
|
Result.isOk(cacheIdentityResult)
|
|
) {
|
|
const markResult = await chatRepo.markPrivateMessageUnlockedInLocal(
|
|
input.messageId,
|
|
{
|
|
content: unlockResult.data.content,
|
|
audioUrl: unlockResult.data.audioUrl,
|
|
...(unlockResult.data.image.url
|
|
? { image: unlockResult.data.image }
|
|
: {}),
|
|
lockDetail: { locked: false, reason: null },
|
|
},
|
|
cacheIdentityResult.data,
|
|
);
|
|
if (Result.isErr(markResult)) {
|
|
log.warn("[chat-machine] mark unlocked local message failed", {
|
|
messageId: input.messageId,
|
|
error: markResult.error,
|
|
});
|
|
}
|
|
}
|
|
|
|
return {
|
|
displayMessageId: input.displayMessageId,
|
|
request: input,
|
|
response: unlockResult.data,
|
|
};
|
|
});
|