🐛 (sendMessage) Correctly preprocess and parse fetched bot
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
import { useToast } from '@/hooks/useToast'
|
import { useToast } from '@/hooks/useToast'
|
||||||
import { Button, ButtonProps, chakra } from '@chakra-ui/react'
|
import { Button, ButtonProps, chakra } from '@chakra-ui/react'
|
||||||
import { Typebot, typebotCreateSchema } from '@typebot.io/schemas'
|
import { Typebot, typebotCreateSchema } from '@typebot.io/schemas'
|
||||||
|
import { preprocessTypebot } from '@typebot.io/schemas/features/typebot/helpers/preprocessTypebot'
|
||||||
import React, { ChangeEvent } from 'react'
|
import React, { ChangeEvent } from 'react'
|
||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onNewTypebot: (typebot: Typebot) => void
|
onNewTypebot: (typebot: Typebot) => void
|
||||||
@@ -18,7 +20,9 @@ export const ImportTypebotFromFileButton = ({
|
|||||||
const file = e.target.files[0]
|
const file = e.target.files[0]
|
||||||
const fileContent = await readFile(file)
|
const fileContent = await readFile(file)
|
||||||
try {
|
try {
|
||||||
const typebot = typebotCreateSchema.parse(JSON.parse(fileContent))
|
const typebot = z
|
||||||
|
.preprocess(preprocessTypebot, typebotCreateSchema)
|
||||||
|
.parse(JSON.parse(fileContent))
|
||||||
onNewTypebot(typebot as Typebot)
|
onNewTypebot(typebot as Typebot)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import {
|
|||||||
SessionState,
|
SessionState,
|
||||||
Variable,
|
Variable,
|
||||||
ReplyLog,
|
ReplyLog,
|
||||||
Typebot,
|
|
||||||
VariableWithValue,
|
VariableWithValue,
|
||||||
Edge,
|
Edge,
|
||||||
|
typebotInSessionStateSchema,
|
||||||
|
TypebotInSession,
|
||||||
} from '@typebot.io/schemas'
|
} from '@typebot.io/schemas'
|
||||||
import { ExecuteLogicResponse } from '@/features/chat/types'
|
import { ExecuteLogicResponse } from '@/features/chat/types'
|
||||||
import { createId } from '@paralleldrive/cuid2'
|
import { createId } from '@paralleldrive/cuid2'
|
||||||
@@ -73,7 +74,7 @@ export const executeTypebotLink = async (
|
|||||||
const addLinkedTypebotToState = async (
|
const addLinkedTypebotToState = async (
|
||||||
state: SessionState,
|
state: SessionState,
|
||||||
block: TypebotLinkBlock,
|
block: TypebotLinkBlock,
|
||||||
linkedTypebot: Pick<Typebot, 'id' | 'edges' | 'groups' | 'variables'>
|
linkedTypebot: TypebotInSession
|
||||||
): Promise<SessionState> => {
|
): Promise<SessionState> => {
|
||||||
const currentTypebotInQueue = state.typebotsQueue[0]
|
const currentTypebotInQueue = state.typebotsQueue[0]
|
||||||
const isPreview = isNotDefined(currentTypebotInQueue.resultId)
|
const isPreview = isNotDefined(currentTypebotInQueue.resultId)
|
||||||
@@ -191,17 +192,19 @@ const fetchTypebot = async (state: SessionState, typebotId: string) => {
|
|||||||
const typebot = await prisma.typebot.findUnique({
|
const typebot = await prisma.typebot.findUnique({
|
||||||
where: { id: typebotId },
|
where: { id: typebotId },
|
||||||
select: {
|
select: {
|
||||||
|
version: true,
|
||||||
id: true,
|
id: true,
|
||||||
edges: true,
|
edges: true,
|
||||||
groups: true,
|
groups: true,
|
||||||
variables: true,
|
variables: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return typebot as Pick<Typebot, 'id' | 'edges' | 'groups' | 'variables'>
|
return typebotInSessionStateSchema.parse(typebot)
|
||||||
}
|
}
|
||||||
const typebot = await prisma.publicTypebot.findUnique({
|
const typebot = await prisma.publicTypebot.findUnique({
|
||||||
where: { typebotId },
|
where: { typebotId },
|
||||||
select: {
|
select: {
|
||||||
|
version: true,
|
||||||
id: true,
|
id: true,
|
||||||
edges: true,
|
edges: true,
|
||||||
groups: true,
|
groups: true,
|
||||||
@@ -209,8 +212,8 @@ const fetchTypebot = async (state: SessionState, typebotId: string) => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (!typebot) return null
|
if (!typebot) return null
|
||||||
return {
|
return typebotInSessionStateSchema.parse({
|
||||||
...typebot,
|
...typebot,
|
||||||
id: typebotId,
|
id: typebotId,
|
||||||
} as Pick<Typebot, 'id' | 'edges' | 'groups' | 'variables'>
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import {
|
|||||||
SessionState,
|
SessionState,
|
||||||
StartParams,
|
StartParams,
|
||||||
StartTypebot,
|
StartTypebot,
|
||||||
|
startTypebotSchema,
|
||||||
Theme,
|
Theme,
|
||||||
Typebot,
|
|
||||||
Variable,
|
Variable,
|
||||||
VariableWithValue,
|
VariableWithValue,
|
||||||
} from '@typebot.io/schemas'
|
} from '@typebot.io/schemas'
|
||||||
@@ -152,6 +152,7 @@ const startSession = async (
|
|||||||
{
|
{
|
||||||
resultId: result?.id,
|
resultId: result?.id,
|
||||||
typebot: {
|
typebot: {
|
||||||
|
version: typebot.version,
|
||||||
id: typebot.id,
|
id: typebot.id,
|
||||||
groups: typebot.groups,
|
groups: typebot.groups,
|
||||||
edges: typebot.edges,
|
edges: typebot.edges,
|
||||||
@@ -268,17 +269,14 @@ const getTypebot = async (
|
|||||||
|
|
||||||
const parsedTypebot =
|
const parsedTypebot =
|
||||||
typebotQuery && 'typebot' in typebotQuery
|
typebotQuery && 'typebot' in typebotQuery
|
||||||
? ({
|
? {
|
||||||
id: typebotQuery.typebotId,
|
id: typebotQuery.typebotId,
|
||||||
...omit(typebotQuery.typebot, 'workspace'),
|
...omit(typebotQuery.typebot, 'workspace'),
|
||||||
...omit(typebotQuery, 'typebot', 'typebotId'),
|
...omit(typebotQuery, 'typebot', 'typebotId'),
|
||||||
} as StartTypebot & Pick<Typebot, 'isArchived' | 'isClosed'>)
|
}
|
||||||
: (typebotQuery as StartTypebot & Pick<Typebot, 'isArchived'>)
|
: typebotQuery
|
||||||
|
|
||||||
if (
|
if (!parsedTypebot || parsedTypebot.isArchived)
|
||||||
!parsedTypebot ||
|
|
||||||
('isArchived' in parsedTypebot && parsedTypebot.isArchived)
|
|
||||||
)
|
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: 'NOT_FOUND',
|
code: 'NOT_FOUND',
|
||||||
message: 'Typebot not found',
|
message: 'Typebot not found',
|
||||||
@@ -299,7 +297,7 @@ const getTypebot = async (
|
|||||||
message: 'Typebot is closed',
|
message: 'Typebot is closed',
|
||||||
})
|
})
|
||||||
|
|
||||||
return parsedTypebot
|
return startTypebotSchema.parse(parsedTypebot)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getResult = async ({
|
const getResult = async ({
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ test('API chat execution should work on published bot', async ({ request }) => {
|
|||||||
data: { message: '8', sessionId: chatSessionId },
|
data: { message: '8', sessionId: chatSessionId },
|
||||||
})
|
})
|
||||||
).json()
|
).json()
|
||||||
|
console.log(messages, input)
|
||||||
expect(messages[0].content.richText).toStrictEqual([
|
expect(messages[0].content.richText).toStrictEqual([
|
||||||
{
|
{
|
||||||
children: [{ text: "I'm gonna shoot multiple inputs now..." }],
|
children: [{ text: "I'm gonna shoot multiple inputs now..." }],
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ export const continueBotFlow =
|
|||||||
formattedReply !== reply ? formattedReply : undefined,
|
formattedReply !== reply ? formattedReply : undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextGroup = getNextGroup(newSessionState)(nextEdgeId)
|
const nextGroup = await getNextGroup(newSessionState)(nextEdgeId)
|
||||||
|
|
||||||
newSessionState = nextGroup.newSessionState
|
newSessionState = nextGroup.newSessionState
|
||||||
|
|
||||||
|
|||||||
@@ -124,7 +124,9 @@ export const executeGroup =
|
|||||||
if (!nextEdgeId && state.typebotsQueue.length === 1)
|
if (!nextEdgeId && state.typebotsQueue.length === 1)
|
||||||
return { messages, newSessionState, clientSideActions, logs }
|
return { messages, newSessionState, clientSideActions, logs }
|
||||||
|
|
||||||
const nextGroup = getNextGroup(newSessionState)(nextEdgeId ?? undefined)
|
const nextGroup = await getNextGroup(newSessionState)(
|
||||||
|
nextEdgeId ?? undefined
|
||||||
|
)
|
||||||
|
|
||||||
newSessionState = nextGroup.newSessionState
|
newSessionState = nextGroup.newSessionState
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { byId } from '@typebot.io/lib'
|
import { byId } from '@typebot.io/lib'
|
||||||
import { Group, SessionState } from '@typebot.io/schemas'
|
import { Group, SessionState } from '@typebot.io/schemas'
|
||||||
|
import { upsertResult } from '../queries/upsertResult'
|
||||||
|
|
||||||
export type NextGroup = {
|
export type NextGroup = {
|
||||||
group?: Group
|
group?: Group
|
||||||
@@ -8,12 +9,20 @@ export type NextGroup = {
|
|||||||
|
|
||||||
export const getNextGroup =
|
export const getNextGroup =
|
||||||
(state: SessionState) =>
|
(state: SessionState) =>
|
||||||
(edgeId?: string): NextGroup => {
|
async (edgeId?: string): Promise<NextGroup> => {
|
||||||
const nextEdge = state.typebotsQueue[0].typebot.edges.find(byId(edgeId))
|
const nextEdge = state.typebotsQueue[0].typebot.edges.find(byId(edgeId))
|
||||||
if (!nextEdge) {
|
if (!nextEdge) {
|
||||||
if (state.typebotsQueue.length > 1) {
|
if (state.typebotsQueue.length > 1) {
|
||||||
const nextEdgeId = state.typebotsQueue[0].edgeIdToTriggerWhenDone
|
const nextEdgeId = state.typebotsQueue[0].edgeIdToTriggerWhenDone
|
||||||
const isMergingWithParent = state.typebotsQueue[0].isMergingWithParent
|
const isMergingWithParent = state.typebotsQueue[0].isMergingWithParent
|
||||||
|
const currentResultId = state.typebotsQueue[0].resultId
|
||||||
|
if (!isMergingWithParent && currentResultId)
|
||||||
|
await upsertResult({
|
||||||
|
resultId: currentResultId,
|
||||||
|
typebot: state.typebotsQueue[0].typebot,
|
||||||
|
isCompleted: true,
|
||||||
|
hasStarted: state.typebotsQueue[0].answers.length > 0,
|
||||||
|
})
|
||||||
const newSessionState = {
|
const newSessionState = {
|
||||||
...state,
|
...state,
|
||||||
typebotsQueue: [
|
typebotsQueue: [
|
||||||
@@ -48,7 +57,7 @@ export const getNextGroup =
|
|||||||
...state.typebotsQueue.slice(2),
|
...state.typebotsQueue.slice(2),
|
||||||
],
|
],
|
||||||
} satisfies SessionState
|
} satisfies SessionState
|
||||||
const nextGroup = getNextGroup(newSessionState)(nextEdgeId)
|
const nextGroup = await getNextGroup(newSessionState)(nextEdgeId)
|
||||||
if (!nextGroup)
|
if (!nextGroup)
|
||||||
return {
|
return {
|
||||||
newSessionState,
|
newSessionState,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const startBotFlow = async (
|
|||||||
const firstEdgeId =
|
const firstEdgeId =
|
||||||
state.typebotsQueue[0].typebot.groups[0].blocks[0].outgoingEdgeId
|
state.typebotsQueue[0].typebot.groups[0].blocks[0].outgoingEdgeId
|
||||||
if (!firstEdgeId) return { messages: [], newSessionState: state }
|
if (!firstEdgeId) return { messages: [], newSessionState: state }
|
||||||
const nextGroup = getNextGroup(state)(firstEdgeId)
|
const nextGroup = await getNextGroup(state)(firstEdgeId)
|
||||||
if (!nextGroup.group) return { messages: [], newSessionState: state }
|
if (!nextGroup.group) return { messages: [], newSessionState: state }
|
||||||
return executeGroup(state)(nextGroup.group)
|
return executeGroup(state)(nextGroup.group)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export const findPublicTypebot = ({ publicId }: Props) =>
|
|||||||
prisma.publicTypebot.findFirst({
|
prisma.publicTypebot.findFirst({
|
||||||
where: { typebot: { publicId } },
|
where: { typebot: { publicId } },
|
||||||
select: {
|
select: {
|
||||||
|
version: true,
|
||||||
groups: true,
|
groups: true,
|
||||||
edges: true,
|
edges: true,
|
||||||
settings: true,
|
settings: true,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export const findTypebot = ({ id, userId }: Props) =>
|
|||||||
prisma.typebot.findFirst({
|
prisma.typebot.findFirst({
|
||||||
where: { id, workspace: { members: { some: { userId } } } },
|
where: { id, workspace: { members: { some: { userId } } } },
|
||||||
select: {
|
select: {
|
||||||
|
version: true,
|
||||||
id: true,
|
id: true,
|
||||||
groups: true,
|
groups: true,
|
||||||
edges: true,
|
edges: true,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
} from '@typebot.io/schemas'
|
} from '@typebot.io/schemas'
|
||||||
|
|
||||||
export const leadGenerationTypebot: StartTypebot = {
|
export const leadGenerationTypebot: StartTypebot = {
|
||||||
|
version: null,
|
||||||
id: 'clckrl4q5000t3b6sabwokaar',
|
id: 'clckrl4q5000t3b6sabwokaar',
|
||||||
groups: [
|
groups: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { inputBlockSchemas } from '../blocks/schemas'
|
|||||||
import { chatCompletionMessageSchema } from '../blocks/integrations/openai'
|
import { chatCompletionMessageSchema } from '../blocks/integrations/openai'
|
||||||
import { sessionStateSchema } from './sessionState'
|
import { sessionStateSchema } from './sessionState'
|
||||||
import { dynamicThemeSchema } from './shared'
|
import { dynamicThemeSchema } from './shared'
|
||||||
|
import { preprocessTypebot } from '../typebot/helpers/preprocessTypebot'
|
||||||
|
|
||||||
const chatSessionSchema = z.object({
|
const chatSessionSchema = z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
@@ -84,14 +85,18 @@ const scriptToExecuteSchema = z.object({
|
|||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
const startTypebotSchema = typebotSchema._def.schema.pick({
|
export const startTypebotSchema = z.preprocess(
|
||||||
id: true,
|
preprocessTypebot,
|
||||||
groups: true,
|
typebotSchema._def.schema.pick({
|
||||||
edges: true,
|
version: true,
|
||||||
variables: true,
|
id: true,
|
||||||
settings: true,
|
groups: true,
|
||||||
theme: true,
|
edges: true,
|
||||||
})
|
variables: true,
|
||||||
|
settings: true,
|
||||||
|
theme: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
const startParamsSchema = z.object({
|
const startParamsSchema = z.object({
|
||||||
typebot: startTypebotSchema
|
typebot: startTypebotSchema
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
import { publicTypebotSchema } from '../publicTypebot'
|
import { publicTypebotSchema } from '../publicTypebot'
|
||||||
|
import { preprocessTypebot } from '../typebot/helpers/preprocessTypebot'
|
||||||
|
|
||||||
export const typebotInSessionStateSchema = publicTypebotSchema._def.schema.pick(
|
export const typebotInSessionStateSchema = z.preprocess(
|
||||||
{
|
preprocessTypebot,
|
||||||
|
publicTypebotSchema._def.schema.pick({
|
||||||
|
version: true,
|
||||||
id: true,
|
id: true,
|
||||||
groups: true,
|
groups: true,
|
||||||
edges: true,
|
edges: true,
|
||||||
variables: true,
|
variables: true,
|
||||||
}
|
})
|
||||||
)
|
)
|
||||||
export type TypebotInSession = z.infer<typeof typebotInSessionStateSchema>
|
export type TypebotInSession = z.infer<typeof typebotInSessionStateSchema>
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
variableSchema,
|
variableSchema,
|
||||||
themeSchema,
|
themeSchema,
|
||||||
settingsSchema,
|
settingsSchema,
|
||||||
typebotSchema,
|
|
||||||
} from './typebot'
|
} from './typebot'
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
import { preprocessTypebot } from './typebot/helpers/preprocessTypebot'
|
import { preprocessTypebot } from './typebot/helpers/preprocessTypebot'
|
||||||
@@ -26,13 +25,4 @@ export const publicTypebotSchema = z.preprocess(
|
|||||||
})
|
})
|
||||||
) satisfies z.ZodType<PrismaPublicTypebot, z.ZodTypeDef, unknown>
|
) satisfies z.ZodType<PrismaPublicTypebot, z.ZodTypeDef, unknown>
|
||||||
|
|
||||||
const publicTypebotWithName = publicTypebotSchema._def.schema.merge(
|
|
||||||
typebotSchema._def.schema.pick({
|
|
||||||
name: true,
|
|
||||||
isArchived: true,
|
|
||||||
isClosed: true,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
export type PublicTypebot = z.infer<typeof publicTypebotSchema>
|
export type PublicTypebot = z.infer<typeof publicTypebotSchema>
|
||||||
export type PublicTypebotWithName = z.infer<typeof publicTypebotWithName>
|
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ export const preprocessTypebot = (typebot: any) => {
|
|||||||
if (!typebot || typebot.version === '5') return typebot
|
if (!typebot || typebot.version === '5') return typebot
|
||||||
return {
|
return {
|
||||||
...typebot,
|
...typebot,
|
||||||
groups: typebot.groups.map(preprocessGroup),
|
groups: typebot.groups ? typebot.groups.map(preprocessGroup) : [],
|
||||||
edges: typebot.edges?.filter(
|
edges: typebot.edges
|
||||||
(edge: any) => edgeSchema.safeParse(edge).success
|
? typebot.edges?.filter((edge: any) => edgeSchema.safeParse(edge).success)
|
||||||
),
|
: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user