Skip to content

Commit

Permalink
🐛 New sendMessage version for the new parser
Browse files Browse the repository at this point in the history
Make sure old client still communicate with old parser
  • Loading branch information
baptisteArno committed Oct 6, 2023
1 parent 6f3e9e9 commit 3838ac9
Show file tree
Hide file tree
Showing 35 changed files with 702 additions and 408 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ test.describe.parallel('Google sheets integration', () => {
.locator('input[placeholder="Type your email..."]')
.press('Enter')
await expect(
page.locator('typebot-standard').locator('text=Your name is:')
).toHaveText(`Your name is: Georges2 Last name`)
page.locator('typebot-standard').locator('text=Georges2')
).toBeVisible()
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const ApiPreviewInstructions = (props: StackProps) => {
lang={'shell'}
value={`${parseApiHost(
typebot?.customDomain
)}/api/v1/sendMessage`}
)}/api/v2/sendMessage`}
/>
<Text>with the following JSON body:</Text>
<CodeEditor isReadOnly lang={'json'} value={startParamsBody} />
Expand All @@ -82,7 +82,7 @@ export const ApiPreviewInstructions = (props: StackProps) => {
lang={'shell'}
value={`${parseApiHost(
typebot?.customDomain
)}/api/v1/sendMessage`}
)}/api/v2/sendMessage`}
/>
<Text>With the following JSON body:</Text>
<CodeEditor isReadOnly lang={'json'} value={replyBody} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const ApiModal = ({
lang={'shell'}
value={`${parseApiHost(
typebot?.customDomain
)}/api/v1/sendMessage`}
)}/api/v2/sendMessage`}
/>
<Text>with the following JSON body:</Text>
<CodeEditor isReadOnly lang={'json'} value={startParamsBody} />
Expand All @@ -81,7 +81,7 @@ export const ApiModal = ({
lang={'shell'}
value={`${parseApiHost(
typebot?.customDomain
)}/api/v1/sendMessage`}
)}/api/v2/sendMessage`}
/>
<Text>With the following JSON body:</Text>
<CodeEditor isReadOnly lang={'json'} value={replyBody} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const parseReactBotProps = ({ typebot, apiHost }: BotProps) => {
}

export const typebotImportCode = isCloudProdInstance()
? `import Typebot from 'https://cdn.jsdelivr.net/npm/@typebot.io/js@0.1/dist/web.js'`
? `import Typebot from 'https://cdn.jsdelivr.net/npm/@typebot.io/js@0.2/dist/web.js'`
: `import Typebot from 'https://cdn.jsdelivr.net/npm/@typebot.io/js@${packageJson.version}/dist/web.js'`

export const parseInlineScript = (script: string) =>
Expand Down
1 change: 1 addition & 0 deletions apps/builder/src/features/whatsapp/startWhatsAppPreview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export const startWhatsAppPreview = authenticatedProcedure

const { newSessionState, messages, input, clientSideActions, logs } =
await startSession({
version: 2,
message: undefined,
startParams: {
isOnlyRegistering: !canSendDirectMessagesToUser,
Expand Down
8 changes: 4 additions & 4 deletions apps/docs/docs/embed/html-javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ There, you can change the container dimensions. Here is a code example:

```html
<script type="module">
import Typebot from 'https://cdn.jsdelivr.net/npm/@typebot.io/js@0.1/dist/web.js'
import Typebot from 'https://cdn.jsdelivr.net/npm/@typebot.io/js@0.2/dist/web.js'
Typebot.initStandard({
typebot: 'my-typebot',
Expand All @@ -32,7 +32,7 @@ Here is an example:

```html
<script type="module">
import Typebot from 'https://cdn.jsdelivr.net/npm/@typebot.io/js@0.1/dist/web.js'
import Typebot from 'https://cdn.jsdelivr.net/npm/@typebot.io/js@0.2/dist/web.js'
Typebot.initPopup({
typebot: 'my-typebot',
Expand Down Expand Up @@ -72,7 +72,7 @@ If you have different bots on the same page you will have to make them distinct

```html
<script type="module">
import Typebot from 'https://cdn.jsdelivr.net/npm/@typebot.io/js@0.1/dist/web.js'
import Typebot from 'https://cdn.jsdelivr.net/npm/@typebot.io/js@0.2/dist/web.js'
Typebot.initStandard({
id: 'bot1'
Expand Down Expand Up @@ -104,7 +104,7 @@ Here is an example:

```html
<script type="module">
import Typebot from 'https://cdn.jsdelivr.net/npm/@typebot.io/js@0.1/dist/web.js'
import Typebot from 'https://cdn.jsdelivr.net/npm/@typebot.io/js@0.2/dist/web.js'
Typebot.initBubble({
typebot: 'my-typebot',
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/docs/embed/webflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ It should look like:

```html
<script type="module">
import Typebot from 'https://cdn.jsdelivr.net/npm/@typebot.io/js@0.1/dist/web.js'
import Typebot from 'https://cdn.jsdelivr.net/npm/@typebot.io/js@0.2/dist/web.js'
Typebot.initPopup({
typebot: 'my-typebot',
Expand Down
6 changes: 3 additions & 3 deletions apps/docs/openapi/chat/_spec_.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
"openapi": "3.0.3",
"info": {
"title": "Chat API",
"version": "1.0.0"
"version": "2.0.0"
},
"servers": [
{
"url": "https://typebot.io/api/v1"
"url": "https://typebot.io/api/v2"
}
],
"paths": {
"/sendMessage": {
"post": {
"operationId": "sendMessage",
"operationId": "sendMessageV2",
"summary": "Send a message",
"description": "To initiate a chat, do not provide a `sessionId` nor a `message`.\n\nContinue the conversation by providing the `sessionId` and the `message` that should answer the previous question.\n\nSet the `isPreview` option to `true` to chat with the non-published version of the typebot.",
"requestBody": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { continueBotFlow } from '@typebot.io/bot-engine/continueBotFlow'
import { parseDynamicTheme } from '@typebot.io/bot-engine/parseDynamicTheme'
import { isDefined } from '@typebot.io/lib/utils'

export const sendMessage = publicProcedure
export const sendMessageV1 = publicProcedure
.meta({
openapi: {
method: 'POST',
Expand Down Expand Up @@ -57,7 +57,12 @@ export const sendMessage = publicProcedure
logs,
clientSideActions,
newSessionState,
} = await startSession({ startParams, userId: user?.id, message })
} = await startSession({
version: 1,
startParams,
userId: user?.id,
message,
})

const allLogs = clientLogs ? [...(logs ?? []), ...clientLogs] : logs

Expand Down Expand Up @@ -98,7 +103,7 @@ export const sendMessage = publicProcedure
newSessionState,
logs,
lastMessageNewFormat,
} = await continueBotFlow(session.state)(message)
} = await continueBotFlow(message, { version: 1, state: session.state })

const allLogs = clientLogs ? [...(logs ?? []), ...clientLogs] : logs

Expand Down
131 changes: 131 additions & 0 deletions apps/viewer/src/features/chat/api/sendMessageV2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { publicProcedure } from '@/helpers/server/trpc'
import {
chatReplySchema,
sendMessageInputSchema,
} from '@typebot.io/schemas/features/chat/schema'
import { TRPCError } from '@trpc/server'
import { getSession } from '@typebot.io/bot-engine/queries/getSession'
import { startSession } from '@typebot.io/bot-engine/startSession'
import { saveStateToDatabase } from '@typebot.io/bot-engine/saveStateToDatabase'
import { restartSession } from '@typebot.io/bot-engine/queries/restartSession'
import { continueBotFlow } from '@typebot.io/bot-engine/continueBotFlow'
import { parseDynamicTheme } from '@typebot.io/bot-engine/parseDynamicTheme'
import { isDefined } from '@typebot.io/lib/utils'

export const sendMessageV2 = publicProcedure
.meta({
openapi: {
method: 'POST',
path: '/sendMessage',
summary: 'Send a message',
description:
'To initiate a chat, do not provide a `sessionId` nor a `message`.\n\nContinue the conversation by providing the `sessionId` and the `message` that should answer the previous question.\n\nSet the `isPreview` option to `true` to chat with the non-published version of the typebot.',
},
})
.input(sendMessageInputSchema)
.output(chatReplySchema)
.mutation(
async ({
input: { sessionId, message, startParams, clientLogs },
ctx: { user },
}) => {
const session = sessionId ? await getSession(sessionId) : null

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.',
})

if (!session) {
if (!startParams)
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'Missing startParams',
})
const {
typebot,
messages,
input,
resultId,
dynamicTheme,
logs,
clientSideActions,
newSessionState,
} = await startSession({
version: 2,
startParams,
userId: user?.id,
message,
})

const allLogs = clientLogs ? [...(logs ?? []), ...clientLogs] : logs

const session = startParams?.isOnlyRegistering
? await restartSession({
state: newSessionState,
})
: await saveStateToDatabase({
session: {
state: newSessionState,
},
input,
logs: allLogs,
clientSideActions,
})

return {
sessionId: session.id,
typebot: typebot
? {
id: typebot.id,
theme: typebot.theme,
settings: typebot.settings,
}
: undefined,
messages,
input,
resultId,
dynamicTheme,
logs,
clientSideActions,
}
} else {
const {
messages,
input,
clientSideActions,
newSessionState,
logs,
lastMessageNewFormat,
} = await continueBotFlow(message, { version: 2, state: session.state })

const allLogs = clientLogs ? [...(logs ?? []), ...clientLogs] : logs

if (newSessionState)
await saveStateToDatabase({
session: {
id: session.id,
state: newSessionState,
},
input,
logs: allLogs,
clientSideActions,
})

return {
messages,
input,
clientSideActions,
dynamicTheme: parseDynamicTheme(newSessionState),
logs,
lastMessageNewFormat,
}
}
}
)
6 changes: 3 additions & 3 deletions apps/viewer/src/helpers/server/generateOpenApi.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { generateOpenApiDocument } from 'trpc-openapi'
import { writeFileSync } from 'fs'
import { appRouter } from './routers/v1/_app'
import { appRouter } from './routers/appRouterV2'

const openApiDocument = generateOpenApiDocument(appRouter, {
title: 'Chat API',
version: '1.0.0',
baseUrl: 'https://typebot.io/api/v1',
version: '2.0.0',
baseUrl: 'https://typebot.io/api/v2',
docsUrl: 'https://docs.typebot.io/api',
})

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { sendMessage } from '@/features/chat/api/sendMessage'
import { sendMessageV1 } from '@/features/chat/api/sendMessageV1'
import { whatsAppRouter } from '@/features/whatsapp/api/router'
import { router } from '../../trpc'
import { router } from '../trpc'
import { updateTypebotInSession } from '@/features/chat/api/updateTypebotInSession'
import { getUploadUrl } from '@/features/fileUpload/api/deprecated/getUploadUrl'
import { generateUploadUrl } from '@/features/fileUpload/api/generateUploadUrl'

export const appRouter = router({
sendMessage,
sendMessageV1,
getUploadUrl,
generateUploadUrl,
updateTypebotInSession,
Expand Down
16 changes: 16 additions & 0 deletions apps/viewer/src/helpers/server/routers/appRouterV2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { sendMessageV2 } from '@/features/chat/api/sendMessageV2'
import { whatsAppRouter } from '@/features/whatsapp/api/router'
import { router } from '../trpc'
import { updateTypebotInSession } from '@/features/chat/api/updateTypebotInSession'
import { getUploadUrl } from '@/features/fileUpload/api/deprecated/getUploadUrl'
import { generateUploadUrl } from '@/features/fileUpload/api/generateUploadUrl'

export const appRouter = router({
sendMessageV2,
getUploadUrl,
generateUploadUrl,
updateTypebotInSession,
whatsAppRouter,
})

export type AppRouter = typeof appRouter
2 changes: 1 addition & 1 deletion apps/viewer/src/pages/api/v1/[...trpc].ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { appRouter } from '@/helpers/server/routers/v1/_app'
import { appRouter } from '@/helpers/server/routers/appRouterV1'
import { captureException } from '@sentry/nextjs'
import { createOpenApiNextHandler } from 'trpc-openapi'
import cors from 'nextjs-cors'
Expand Down
23 changes: 23 additions & 0 deletions apps/viewer/src/pages/api/v2/[...trpc].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { appRouter } from '@/helpers/server/routers/appRouterV2'
import { captureException } from '@sentry/nextjs'
import { createOpenApiNextHandler } from 'trpc-openapi'
import cors from 'nextjs-cors'
import { NextApiRequest, NextApiResponse } from 'next'
import { createContext } from '@/helpers/server/context'

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
await cors(req, res)

return createOpenApiNextHandler({
router: appRouter,
createContext,
onError({ error }) {
if (error.code === 'INTERNAL_SERVER_ERROR') {
captureException(error)
console.error('Something went wrong', error)
}
},
})(req, res)
}

export default handler
Loading

3 comments on commit 3838ac9

@vercel
Copy link

@vercel vercel bot commented on 3838ac9 Oct 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

builder-v2 – ./apps/builder

builder-v2-git-main-typebot-io.vercel.app
builder-v2-typebot-io.vercel.app
app.typebot.io

@vercel
Copy link

@vercel vercel bot commented on 3838ac9 Oct 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs – ./apps/docs

docs-typebot-io.vercel.app
docs.typebot.io
docs-git-main-typebot-io.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 3838ac9 Oct 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

viewer-v2 – ./apps/viewer

survey.collab.day
test.eqfeqfeq.com
viewer.typebot.io
welcome.triplo.ai
www.thegymgame.it
zeropendencia.com
1988.bouclidom.com
a.onewebcenter.com
amancarseat.online
amostra-safe.click
andreimayer.com.br
bebesemcolicas.com
bot.innovacion.fun
bot.jogodospix.com
bot.jogomilion.com
bot.lucide.contact
bot.neferlopez.com
bot.photonative.de
bot.rajatanjak.com
bot.samplehunt.com
bot.sinalcerto.com
bot.wphelpchat.com
bots.robomotion.io
brandingmkt.com.br
bt.chatgptlabs.org
cadu.uninta.edu.br
chat.daftarjer.com
chat.foxbot.online
chat.hand-made.one
chat.tuanpakya.com
chat.webisharp.com
chatbotforthat.com
descobrindotudo.me
dicanatural.online
digitalhelp.com.au
draraquelnutri.com
drcarlosyoshi.site
goalsettingbot.com
golpenuncamais.com
leads.gecoelho.com
noticiasnet.online
novoappespiao.site
omarcodosanjos.com
pant.maxbot.com.br
pantherview.cr8.ai
positivobra.com.br
rollingball.cr8.ai
ruletaiapro.online
bot.leadbooster.help
bot.mycompay.reviews
bot.projetodashi.com
bot.socialcliques.me
cha.onewebcenter.com
chat.febredojogo.com
chat.gnipharmahq.com
chat.hayurihijab.com
chat.jottagreens.com
chatbee.agfunnel.com
click.sevenoways.com
connect.growthguy.in
demo.solidrock.space
detetivepatricia.com
drapamela.gikpro.com
drgisellegarcia.site
encodebot.share5.net
forms.bonanza.design
hello.advergreen.com
viewer-v2-typebot-io.vercel.app
bot.studiotecnicoimmobiliaremerelli.it
mdb.assessoria.boaventura.progenbr.com
mdb.assessoria.jtrebesqui.progenbr.com
pesquisa.escolamodacomproposito.com.br
anamnese.clinicaramosodontologia.com.br
gabinete.baleia.formulario.progenbr.com
mdb.assessoria.carreirinha.progenbr.com
chrome-os-inquiry-system.itschromeos.com
mdb.assessoria.paulomarques.progenbr.com
viewer-v2-git-main-typebot-io.vercel.app
main-menu-for-itschromeos.itschromeos.com
mdb.assessoria.qrcode.ademir.progenbr.com
mdb.assessoria.qrcode.arthur.progenbr.com
mdb.assessoria.qrcode.danilo.progenbr.com
mdb.assessoria.qrcode.marcao.progenbr.com
mdb.assessoria.qrcode.marcio.progenbr.com
mdb.assessoria.qrcode.aloisio.progenbr.com
mdb.assessoria.qrcode.girotto.progenbr.com
mdb.assessoria.qrcode.marinho.progenbr.com
mdb.assessoria.qrcode.rodrigo.progenbr.com
mdb.assessoria.carlosalexandre.progenbr.com
mdb.assessoria.qrcode.desideri.progenbr.com
mdb.assessoria.qrcode.fernanda.progenbr.com
mdb.assessoria.qrcode.jbatista.progenbr.com
mdb.assessoria.qrcode.mauricio.progenbr.com
mdb.assessoria.fernanda.regional.progenbr.com
mdb.assessoria.qrcode.boaventura.progenbr.com
mdb.assessoria.qrcode.jtrebesqui.progenbr.com
mdb.assessoria.qrcode.carreirinha.progenbr.com
mdb.assessoria.qrcode.paulomarques.progenbr.com
mdb.assessoria.qrcode.carlosalexandre.progenbr.com
mdb.assessoria.qrcode.fernanda.regional.progenbr.com

Please sign in to comment.