2024-03-21 10:23:23 +01:00
|
|
|
import { TRPCError } from '@trpc/server'
|
2024-06-19 15:27:45 +02:00
|
|
|
import { isDefined, isNotDefined, isNotEmpty } from '@typebot.io/lib/utils'
|
2024-03-21 10:23:23 +01:00
|
|
|
import { getSession } from '../queries/getSession'
|
|
|
|
import { continueBotFlow } from '../continueBotFlow'
|
|
|
|
import { filterPotentiallySensitiveLogs } from '../logs/filterPotentiallySensitiveLogs'
|
|
|
|
import { parseDynamicTheme } from '../parseDynamicTheme'
|
|
|
|
import { saveStateToDatabase } from '../saveStateToDatabase'
|
|
|
|
import { computeCurrentProgress } from '../computeCurrentProgress'
|
2024-06-19 15:27:45 +02:00
|
|
|
import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants'
|
2024-06-26 10:13:38 +02:00
|
|
|
import { Message } from '@typebot.io/schemas'
|
2024-03-21 10:23:23 +01:00
|
|
|
|
|
|
|
type Props = {
|
|
|
|
origin: string | undefined
|
2024-06-26 10:13:38 +02:00
|
|
|
message?: Message
|
2024-03-21 10:23:23 +01:00
|
|
|
sessionId: string
|
2024-05-23 16:30:56 +02:00
|
|
|
textBubbleContentFormat: 'richText' | 'markdown'
|
2024-03-21 10:23:23 +01:00
|
|
|
}
|
2024-05-23 16:30:56 +02:00
|
|
|
export const continueChat = async ({
|
|
|
|
origin,
|
|
|
|
sessionId,
|
|
|
|
message,
|
|
|
|
textBubbleContentFormat,
|
|
|
|
}: Props) => {
|
2024-03-21 10:23:23 +01:00
|
|
|
const session = await getSession(sessionId)
|
|
|
|
|
|
|
|
if (!session) {
|
|
|
|
throw new TRPCError({
|
|
|
|
code: 'NOT_FOUND',
|
|
|
|
message: 'Session not found.',
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
const isSessionExpired =
|
|
|
|
session &&
|
|
|
|
isDefined(session.state.expiryTimeout) &&
|
|
|
|
session.updatedAt.getTime() + session.state.expiryTimeout < Date.now()
|
|
|
|
|
|
|
|
if (isSessionExpired)
|
|
|
|
throw new TRPCError({
|
|
|
|
code: 'NOT_FOUND',
|
|
|
|
message: 'Session expired. You need to start a new session.',
|
|
|
|
})
|
|
|
|
|
|
|
|
let corsOrigin
|
|
|
|
|
|
|
|
if (
|
|
|
|
session?.state.allowedOrigins &&
|
|
|
|
session.state.allowedOrigins.length > 0
|
|
|
|
) {
|
|
|
|
if (origin && session.state.allowedOrigins.includes(origin))
|
|
|
|
corsOrigin = origin
|
|
|
|
else corsOrigin = session.state.allowedOrigins[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
const {
|
|
|
|
messages,
|
|
|
|
input,
|
|
|
|
clientSideActions,
|
|
|
|
newSessionState,
|
|
|
|
logs,
|
|
|
|
lastMessageNewFormat,
|
|
|
|
visitedEdges,
|
2024-05-15 14:24:55 +02:00
|
|
|
setVariableHistory,
|
2024-03-21 10:23:23 +01:00
|
|
|
} = await continueBotFlow(message, {
|
|
|
|
version: 2,
|
|
|
|
state: session.state,
|
|
|
|
startTime: Date.now(),
|
2024-05-23 16:30:56 +02:00
|
|
|
textBubbleContentFormat,
|
2024-03-21 10:23:23 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
if (newSessionState)
|
|
|
|
await saveStateToDatabase({
|
|
|
|
session: {
|
|
|
|
id: session.id,
|
|
|
|
state: newSessionState,
|
|
|
|
},
|
|
|
|
input,
|
|
|
|
logs,
|
|
|
|
clientSideActions,
|
|
|
|
visitedEdges,
|
2024-05-15 14:24:55 +02:00
|
|
|
setVariableHistory,
|
2024-06-19 15:27:45 +02:00
|
|
|
hasEmbedBubbleWithWaitEvent: messages.some(
|
|
|
|
(message) =>
|
|
|
|
message.type === 'custom-embed' ||
|
|
|
|
(message.type === BubbleBlockType.EMBED &&
|
|
|
|
message.content.waitForEvent?.isEnabled)
|
2024-03-21 10:23:23 +01:00
|
|
|
),
|
|
|
|
})
|
|
|
|
|
|
|
|
const isPreview = isNotDefined(session.state.typebotsQueue[0].resultId)
|
|
|
|
|
|
|
|
const isEnded =
|
|
|
|
newSessionState.progressMetadata &&
|
|
|
|
!input?.id &&
|
|
|
|
(clientSideActions?.filter((c) => c.expectsDedicatedReply).length ?? 0) ===
|
|
|
|
0
|
|
|
|
|
|
|
|
return {
|
|
|
|
messages,
|
|
|
|
input,
|
|
|
|
clientSideActions,
|
|
|
|
dynamicTheme: parseDynamicTheme(newSessionState),
|
|
|
|
logs: isPreview ? logs : logs?.filter(filterPotentiallySensitiveLogs),
|
|
|
|
lastMessageNewFormat,
|
|
|
|
corsOrigin,
|
|
|
|
progress: newSessionState.progressMetadata
|
|
|
|
? isEnded
|
|
|
|
? 100
|
|
|
|
: computeCurrentProgress({
|
|
|
|
typebotsQueue: newSessionState.typebotsQueue,
|
|
|
|
progressMetadata: newSessionState.progressMetadata,
|
|
|
|
currentInputBlockId: input?.id,
|
|
|
|
})
|
|
|
|
: undefined,
|
|
|
|
}
|
|
|
|
}
|