2
0

feat(integration): Add webhooks

This commit is contained in:
Baptiste Arnaud
2022-01-22 18:24:57 +01:00
parent 66f3e7ee7c
commit a58600a38a
78 changed files with 2399 additions and 800 deletions

View File

@ -44,7 +44,7 @@ export default [
],
},
{
input: 'dist/esm/types/index.d.ts',
input: 'dist/esm/types/src/index.d.ts',
output: [{ file: 'dist/index.d.ts', format: 'esm' }],
plugins: [dts()],
external: [/\.css$/],

View File

@ -55,6 +55,7 @@ export const ChatBlock = ({
}
if (isIntegrationStep(currentStep)) {
const nextEdgeId = await executeIntegration(
typebot.typebotId,
currentStep,
typebot.variables,
updateVariableValue

View File

@ -1,3 +1,3 @@
export * from './components/TypebotViewer'
export { parseVariables } from './services/variable'
export * from 'util'

View File

@ -10,13 +10,18 @@ import {
Cell,
GoogleSheetsGetOptions,
GoogleAnalyticsStep,
Webhook,
WebhookStep,
} from 'models'
import { stringify } from 'qs'
import { sendRequest } from 'utils'
import { sendGaEvent } from '../../lib/gtag'
import { parseVariables, parseVariablesInObject } from './variable'
const safeEval = eval
export const executeIntegration = (
typebotId: string,
step: IntegrationStep,
variables: Table<Variable>,
updateVariableValue: (variableId: string, value: string) => void
@ -26,6 +31,8 @@ export const executeIntegration = (
return executeGoogleSheetIntegration(step, variables, updateVariableValue)
case IntegrationStepType.GOOGLE_ANALYTICS:
return executeGoogleAnalyticsIntegration(step, variables)
case IntegrationStepType.WEBHOOK:
return executeWebhook(typebotId, step, variables, updateVariableValue)
}
}
@ -142,3 +149,26 @@ const parseCellValues = (
[cell.column]: parseVariables({ text: cell.value, variables }),
}
}, {})
const executeWebhook = async (
typebotId: string,
step: WebhookStep,
variables: Table<Variable>,
updateVariableValue: (variableId: string, value: string) => void
) => {
if (!step.options?.webhookId) return step.edgeId
const { data, error } = await sendRequest({
url: `http://localhost:3000/api/typebots/${typebotId}/webhooks/${step.options?.webhookId}/execute`,
method: 'POST',
body: {
variables,
},
})
console.error(error)
step.options.responseVariableMapping?.allIds.forEach((varMappingId) => {
const varMapping = step.options?.responseVariableMapping?.byId[varMappingId]
if (!varMapping?.bodyPath || !varMapping.variableId) return
const value = safeEval(`(${JSON.stringify(data)}).${varMapping?.bodyPath}`)
updateVariableValue(varMapping.variableId, value)
})
}

View File

@ -5,12 +5,12 @@
"main": "./index.tsx",
"types": "./index.tsx",
"devDependencies": {
"prisma": "^3.7.0",
"prisma": "^3.8.1",
"ts-node": "^10.4.0",
"typescript": "^4.5.4"
"typescript": "^4.5.5"
},
"dependencies": {
"@prisma/client": "^3.7.0"
"@prisma/client": "^3.8.1"
},
"scripts": {
"dev": "yarn prisma db push && BROWSER=none yarn prisma studio",

View File

@ -110,6 +110,7 @@ model Typebot {
steps Json
choiceItems Json
variables Json
webhooks Json
edges Json
theme Json
settings Json

View File

@ -1,15 +1,20 @@
import { StepBase } from '.'
import { Table } from '../..'
export type IntegrationStep = GoogleSheetsStep | GoogleAnalyticsStep
export type IntegrationStep =
| GoogleSheetsStep
| GoogleAnalyticsStep
| WebhookStep
export type IntegrationStepOptions =
| GoogleSheetsOptions
| GoogleAnalyticsOptions
| WebhookOptions
export enum IntegrationStepType {
GOOGLE_SHEETS = 'Google Sheets',
GOOGLE_ANALYTICS = 'Google Analytics',
WEBHOOK = 'Webhook',
}
export type GoogleSheetsStep = StepBase & {
@ -22,6 +27,11 @@ export type GoogleAnalyticsStep = StepBase & {
options?: GoogleAnalyticsOptions
}
export type WebhookStep = StepBase & {
type: IntegrationStepType.WEBHOOK
options?: WebhookOptions
}
export type GoogleAnalyticsOptions = {
trackingId?: string
category?: string
@ -66,3 +76,40 @@ export type GoogleSheetsUpdateRowOptions = GoogleSheetsOptionsBase & {
referenceCell?: Cell
cellsToUpsert?: Table<Cell>
}
export type ResponseVariableMapping = { bodyPath?: string; variableId?: string }
export type WebhookOptions = {
webhookId?: string
variablesForTest?: Table<VariableForTest>
responseVariableMapping?: Table<ResponseVariableMapping>
}
export enum HttpMethod {
POST = 'POST',
GET = 'GET',
PUT = 'PUT',
DELETE = 'DELETE',
PATCH = 'PATCH',
HEAD = 'HEAD',
CONNECT = 'CONNECT',
OPTIONS = 'OPTIONS',
TRACE = 'TRACE',
}
export type KeyValue = { key?: string; value?: string }
export type VariableForTest = { variableId?: string; value?: string }
export type Webhook = {
id: string
url?: string
method?: HttpMethod
queryParams?: Table<KeyValue>
headers?: Table<KeyValue>
body?: string
}
export type WebhookResponse = {
statusCode: number
data?: unknown
}

View File

@ -5,16 +5,24 @@ import { Settings } from './settings'
import { Step } from './steps/steps'
import { Theme } from './theme'
import { Variable } from './variable'
import { Webhook } from '.'
export type Typebot = Omit<
TypebotFromPrisma,
'blocks' | 'theme' | 'settings' | 'steps' | 'choiceItems' | 'variables'
| 'blocks'
| 'theme'
| 'settings'
| 'steps'
| 'choiceItems'
| 'variables'
| 'webhooks'
> & {
blocks: Table<Block>
steps: Table<Step>
choiceItems: Table<ChoiceItem>
variables: Table<Variable>
edges: Table<Edge>
webhooks: Table<Webhook>
theme: Theme
settings: Settings
}

View File

@ -13,6 +13,7 @@ import {
Table,
TextInputStep,
TextBubbleStep,
WebhookStep,
} from 'models'
export const sendRequest = async <ResponseData>({
@ -74,3 +75,6 @@ export const isConditionStep = (step: Step): step is ConditionStep =>
export const isIntegrationStep = (step: Step): step is IntegrationStep =>
(Object.values(IntegrationStepType) as string[]).includes(step.type)
export const isWebhookStep = (step: Step): step is WebhookStep =>
step.type === IntegrationStepType.WEBHOOK