2
0

♻️ Re-organize workspace folders

This commit is contained in:
Baptiste Arnaud
2023-03-15 08:35:16 +01:00
parent 25c367901f
commit cbc8194f19
987 changed files with 2716 additions and 2770 deletions

View File

@@ -0,0 +1,20 @@
import { z } from 'zod'
import { Credentials as CredentialsFromPrisma } from '@typebot.io/prisma'
export const blockBaseSchema = z.object({
id: z.string(),
groupId: z.string(),
outgoingEdgeId: z.string().optional(),
})
export const optionBaseSchema = z.object({
variableId: z.string().optional(),
})
export const credentialsBaseSchema = z.object({
id: z.string(),
createdAt: z.date(),
workspaceId: z.string(),
name: z.string(),
iv: z.string(),
}) satisfies z.ZodType<Omit<CredentialsFromPrisma, 'data' | 'type'>>

View File

@@ -0,0 +1,19 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { BubbleBlockType } from './enums'
export const audioBubbleContentSchema = z.object({
url: z.string().optional(),
})
export const audioBubbleBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([BubbleBlockType.AUDIO]),
content: audioBubbleContentSchema,
})
)
export const defaultAudioBubbleContent = {}
export type AudioBubbleBlock = z.infer<typeof audioBubbleBlockSchema>
export type AudioBubbleContent = z.infer<typeof audioBubbleContentSchema>

View File

@@ -0,0 +1,21 @@
import { z } from 'zod'
import { variableStringSchema } from '../../utils'
import { blockBaseSchema } from '../baseSchemas'
import { BubbleBlockType } from './enums'
export const embedBubbleContentSchema = z.object({
url: z.string().optional(),
height: z.number().or(variableStringSchema),
})
export const embedBubbleBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([BubbleBlockType.EMBED]),
content: embedBubbleContentSchema,
})
)
export const defaultEmbedBubbleContent: EmbedBubbleContent = { height: 400 }
export type EmbedBubbleBlock = z.infer<typeof embedBubbleBlockSchema>
export type EmbedBubbleContent = z.infer<typeof embedBubbleContentSchema>

View File

@@ -0,0 +1,7 @@
export enum BubbleBlockType {
TEXT = 'text',
IMAGE = 'image',
VIDEO = 'video',
EMBED = 'embed',
AUDIO = 'audio',
}

View File

@@ -0,0 +1,19 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { BubbleBlockType } from './enums'
export const imageBubbleContentSchema = z.object({
url: z.string().optional(),
})
export const imageBubbleBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([BubbleBlockType.IMAGE]),
content: imageBubbleContentSchema,
})
)
export const defaultImageBubbleContent: ImageBubbleContent = {}
export type ImageBubbleBlock = z.infer<typeof imageBubbleBlockSchema>
export type ImageBubbleContent = z.infer<typeof imageBubbleContentSchema>

View File

@@ -0,0 +1,6 @@
export * from './audio'
export * from './embed'
export * from './image'
export * from './text'
export * from './video'
export * from './enums'

View File

@@ -0,0 +1,26 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { BubbleBlockType } from './enums'
export const defaultTextBubbleContent: TextBubbleContent = {
html: '',
richText: [],
plainText: '',
}
export const textBubbleContentSchema = z.object({
html: z.string(),
richText: z.array(z.any()),
plainText: z.string(),
})
export type TextBubbleContent = z.infer<typeof textBubbleContentSchema>
export const textBubbleBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([BubbleBlockType.TEXT]),
content: textBubbleContentSchema,
})
)
export type TextBubbleBlock = z.infer<typeof textBubbleBlockSchema>

View File

@@ -0,0 +1,5 @@
export enum VideoBubbleContentType {
URL = 'url',
YOUTUBE = 'youtube',
VIMEO = 'vimeo',
}

View File

@@ -0,0 +1,2 @@
export * from './enums'
export * from './schemas'

View File

@@ -0,0 +1,22 @@
import { z } from 'zod'
import { blockBaseSchema } from '../../baseSchemas'
import { BubbleBlockType } from '../enums'
import { VideoBubbleContentType } from './enums'
export const videoBubbleContentSchema = z.object({
url: z.string().optional(),
id: z.string().optional(),
type: z.nativeEnum(VideoBubbleContentType).optional(),
})
export const videoBubbleBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([BubbleBlockType.VIDEO]),
content: videoBubbleContentSchema,
})
)
export const defaultVideoBubbleContent: VideoBubbleContent = {}
export type VideoBubbleBlock = z.infer<typeof videoBubbleBlockSchema>
export type VideoBubbleContent = z.infer<typeof videoBubbleContentSchema>

View File

@@ -0,0 +1,7 @@
export * from './baseSchemas'
export * from './bubbles'
export * from './inputs'
export * from './integrations'
export * from './logic'
export * from './start'
export * from './schemas'

View File

@@ -0,0 +1,38 @@
import { z } from 'zod'
import { ItemType } from '../../items/enums'
import { itemBaseSchema } from '../../items/baseSchemas'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
export const choiceInputOptionsSchema = optionBaseSchema.merge(
z.object({
isMultipleChoice: z.boolean(),
buttonLabel: z.string(),
dynamicVariableId: z.string().optional(),
})
)
export const defaultChoiceInputOptions: ChoiceInputOptions = {
buttonLabel: defaultButtonLabel,
isMultipleChoice: false,
}
export const buttonItemSchema = itemBaseSchema.merge(
z.object({
type: z.literal(ItemType.BUTTON),
content: z.string().optional(),
})
)
export const choiceInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.CHOICE]),
items: z.array(buttonItemSchema),
options: choiceInputOptionsSchema,
})
)
export type ButtonItem = z.infer<typeof buttonItemSchema>
export type ChoiceInputBlock = z.infer<typeof choiceInputSchema>
export type ChoiceInputOptions = z.infer<typeof choiceInputOptionsSchema>

View File

@@ -0,0 +1 @@
export const defaultButtonLabel = 'Send'

View File

@@ -0,0 +1,32 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
export const dateInputOptionsSchema = optionBaseSchema.merge(
z.object({
labels: z.object({
button: z.string(),
from: z.string(),
to: z.string(),
}),
hasTime: z.boolean(),
isRange: z.boolean(),
})
)
export const dateInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.DATE]),
options: dateInputOptionsSchema,
})
)
export const defaultDateInputOptions: DateInputOptions = {
hasTime: false,
isRange: false,
labels: { button: defaultButtonLabel, from: 'From:', to: 'To:' },
}
export type DateInputBlock = z.infer<typeof dateInputSchema>
export type DateInputOptions = z.infer<typeof dateInputOptionsSchema>

View File

@@ -0,0 +1,32 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
import { textInputOptionsBaseSchema } from './text'
export const emailInputOptionsSchema = optionBaseSchema
.merge(textInputOptionsBaseSchema)
.merge(
z.object({
retryMessageContent: z.string(),
})
)
export const emailInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.EMAIL]),
options: emailInputOptionsSchema,
})
)
export const defaultEmailInputOptions: EmailInputOptions = {
labels: {
button: defaultButtonLabel,
placeholder: 'Type your email...',
},
retryMessageContent:
"This email doesn't seem to be valid. Can you type it again?",
}
export type EmailInputBlock = z.infer<typeof emailInputSchema>
export type EmailInputOptions = z.infer<typeof emailInputOptionsSchema>

View File

@@ -0,0 +1,12 @@
export enum InputBlockType {
TEXT = 'text input',
NUMBER = 'number input',
EMAIL = 'email input',
URL = 'url input',
DATE = 'date input',
PHONE = 'phone number input',
CHOICE = 'choice input',
PAYMENT = 'payment input',
RATING = 'rating input',
FILE = 'file input',
}

View File

@@ -0,0 +1,41 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { InputBlockType } from './enums'
export const fileInputOptionsSchema = optionBaseSchema.merge(
z.object({
isRequired: z.boolean().optional(),
isMultipleAllowed: z.boolean(),
labels: z.object({
placeholder: z.string(),
button: z.string(),
clear: z.string().optional(),
skip: z.string().optional(),
}),
sizeLimit: z.number().optional(),
})
)
export const fileInputStepSchema = blockBaseSchema.merge(
z.object({
type: z.literal(InputBlockType.FILE),
options: fileInputOptionsSchema,
})
)
export const defaultFileInputOptions = {
isRequired: true,
isMultipleAllowed: false,
labels: {
placeholder: `<strong>
Click to upload
</strong> or drag and drop<br>
(size limit: 10MB)`,
button: 'Upload',
clear: 'Clear',
skip: 'Skip',
},
} satisfies FileInputOptions
export type FileInputBlock = z.infer<typeof fileInputStepSchema>
export type FileInputOptions = z.infer<typeof fileInputOptionsSchema>

View File

@@ -0,0 +1,12 @@
export * from './choice'
export * from './constants'
export * from './date'
export * from './email'
export * from './enums'
export * from './file'
export * from './number'
export * from './payment'
export * from './phone'
export * from './rating'
export * from './text'
export * from './url'

View File

@@ -0,0 +1,29 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
import { textInputOptionsBaseSchema } from './text'
export const numberInputOptionsSchema = optionBaseSchema
.merge(textInputOptionsBaseSchema)
.merge(
z.object({
min: z.number().optional(),
max: z.number().optional(),
step: z.number().optional(),
})
)
export const numberInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.NUMBER]),
options: numberInputOptionsSchema,
})
)
export const defaultNumberInputOptions: NumberInputOptions = {
labels: { button: defaultButtonLabel, placeholder: 'Type a number...' },
}
export type NumberInputBlock = z.infer<typeof numberInputSchema>
export type NumberInputOptions = z.infer<typeof numberInputOptionsSchema>

View File

@@ -0,0 +1,3 @@
export enum PaymentProvider {
STRIPE = 'Stripe',
}

View File

@@ -0,0 +1,2 @@
export * from './enums'
export * from './schemas'

View File

@@ -0,0 +1,77 @@
import { z } from 'zod'
import {
optionBaseSchema,
blockBaseSchema,
credentialsBaseSchema,
} from '../../baseSchemas'
import { InputBlockType } from '../enums'
import { PaymentProvider } from './enums'
export type CreditCardDetails = {
number: string
exp_month: string
exp_year: string
cvc: string
}
export const paymentInputOptionsSchema = optionBaseSchema.merge(
z.object({
provider: z.nativeEnum(PaymentProvider),
labels: z.object({
button: z.string(),
success: z.string().optional(),
}),
additionalInformation: z
.object({
name: z.string().optional(),
email: z.string().optional(),
phoneNumber: z.string().optional(),
})
.optional(),
credentialsId: z.string().optional(),
currency: z.string(),
amount: z.string().optional(),
})
)
export const paymentInputRuntimeOptionsSchema = z.object({
paymentIntentSecret: z.string(),
amountLabel: z.string(),
publicKey: z.string(),
})
export const paymentInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.PAYMENT]),
options: paymentInputOptionsSchema,
})
)
export const stripeCredentialsSchema = z
.object({
type: z.literal('stripe'),
data: z.object({
live: z.object({
secretKey: z.string(),
publicKey: z.string(),
}),
test: z.object({
secretKey: z.string().optional(),
publicKey: z.string().optional(),
}),
}),
})
.merge(credentialsBaseSchema)
export const defaultPaymentInputOptions: PaymentInputOptions = {
provider: PaymentProvider.STRIPE,
labels: { button: 'Pay', success: 'Success' },
currency: 'USD',
}
export type PaymentInputBlock = z.infer<typeof paymentInputSchema>
export type PaymentInputOptions = z.infer<typeof paymentInputOptionsSchema>
export type PaymentInputRuntimeOptions = z.infer<
typeof paymentInputRuntimeOptionsSchema
>
export type StripeCredentials = z.infer<typeof stripeCredentialsSchema>

View File

@@ -0,0 +1,35 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
import { textInputOptionsBaseSchema } from './text'
export const phoneNumberInputOptionsSchema = optionBaseSchema
.merge(textInputOptionsBaseSchema)
.merge(
z.object({
retryMessageContent: z.string(),
defaultCountryCode: z.string().optional(),
})
)
export const phoneNumberInputBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.PHONE]),
options: phoneNumberInputOptionsSchema,
})
)
export const defaultPhoneInputOptions: PhoneNumberInputOptions = {
labels: {
button: defaultButtonLabel,
placeholder: 'Type your phone number...',
},
retryMessageContent:
"This phone number doesn't seem to be valid. Can you type it again?",
}
export type PhoneNumberInputBlock = z.infer<typeof phoneNumberInputBlockSchema>
export type PhoneNumberInputOptions = z.infer<
typeof phoneNumberInputOptionsSchema
>

View File

@@ -0,0 +1,38 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
export const defaultRatingInputOptions: RatingInputOptions = {
buttonType: 'Numbers',
length: 10,
labels: { button: defaultButtonLabel },
customIcon: { isEnabled: false },
}
export const ratingInputOptionsSchema = optionBaseSchema.merge(
z.object({
buttonType: z.literal('Icons').or(z.literal('Numbers')),
length: z.number(),
labels: z.object({
left: z.string().optional(),
right: z.string().optional(),
button: z.string(),
}),
customIcon: z.object({
isEnabled: z.boolean(),
svg: z.string().optional(),
}),
isOneClickSubmitEnabled: z.boolean().optional(),
})
)
export const ratingInputBlockSchema = blockBaseSchema.merge(
z.object({
type: z.literal(InputBlockType.RATING),
options: ratingInputOptionsSchema,
})
)
export type RatingInputBlock = z.infer<typeof ratingInputBlockSchema>
export type RatingInputOptions = z.infer<typeof ratingInputOptionsSchema>

View File

@@ -0,0 +1,34 @@
import { z } from 'zod'
import { blockBaseSchema, optionBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
export const textInputOptionsBaseSchema = z.object({
labels: z.object({
placeholder: z.string(),
button: z.string(),
}),
})
export const textInputOptionsSchema = textInputOptionsBaseSchema
.merge(optionBaseSchema)
.merge(
z.object({
isLong: z.boolean(),
})
)
export const defaultTextInputOptions: TextInputOptions = {
isLong: false,
labels: { button: defaultButtonLabel, placeholder: 'Type your answer...' },
}
export const textInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.TEXT]),
options: textInputOptionsSchema,
})
)
export type TextInputBlock = z.infer<typeof textInputSchema>
export type TextInputOptions = z.infer<typeof textInputOptionsSchema>

View File

@@ -0,0 +1,32 @@
import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
import { textInputOptionsBaseSchema } from './text'
export const urlInputOptionsSchema = optionBaseSchema
.merge(textInputOptionsBaseSchema)
.merge(
z.object({
retryMessageContent: z.string(),
})
)
export const urlInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.URL]),
options: urlInputOptionsSchema,
})
)
export const defaultUrlInputOptions: UrlInputOptions = {
labels: {
button: defaultButtonLabel,
placeholder: 'Type a URL...',
},
retryMessageContent:
"This URL doesn't seem to be valid. Can you type it again?",
}
export type UrlInputBlock = z.infer<typeof urlInputSchema>
export type UrlInputOptions = z.infer<typeof urlInputOptionsSchema>

View File

@@ -0,0 +1,36 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { IntegrationBlockType } from './enums'
export const chatwootTasks = ['Show widget', 'Close widget'] as const
export const chatwootOptionsSchema = z.object({
task: z.enum(chatwootTasks).optional(),
baseUrl: z.string(),
websiteToken: z.string(),
user: z
.object({
id: z.string().optional(),
email: z.string().optional(),
name: z.string().optional(),
avatarUrl: z.string().optional(),
phoneNumber: z.string().optional(),
})
.optional(),
})
export const chatwootBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.CHATWOOT]),
options: chatwootOptionsSchema,
})
)
export const defaultChatwootOptions: ChatwootOptions = {
task: 'Show widget',
baseUrl: 'https://app.chatwoot.com',
websiteToken: '',
}
export type ChatwootBlock = z.infer<typeof chatwootBlockSchema>
export type ChatwootOptions = z.infer<typeof chatwootOptionsSchema>

View File

@@ -0,0 +1,11 @@
export enum IntegrationBlockType {
GOOGLE_SHEETS = 'Google Sheets',
OPEN_AI = 'OpenAI',
GOOGLE_ANALYTICS = 'Google Analytics',
WEBHOOK = 'Webhook',
EMAIL = 'Email',
ZAPIER = 'Zapier',
MAKE_COM = 'Make.com',
PABBLY_CONNECT = 'Pabbly',
CHATWOOT = 'Chatwoot',
}

View File

@@ -0,0 +1,25 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { IntegrationBlockType } from './enums'
export const googleAnalyticsOptionsSchema = z.object({
trackingId: z.string().optional(),
category: z.string().optional(),
action: z.string().optional(),
label: z.string().optional(),
value: z.number().optional(),
})
export const googleAnalyticsBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.GOOGLE_ANALYTICS]),
options: googleAnalyticsOptionsSchema,
})
)
export const defaultGoogleAnalyticsOptions: GoogleAnalyticsOptions = {}
export type GoogleAnalyticsBlock = z.infer<typeof googleAnalyticsBlockSchema>
export type GoogleAnalyticsOptions = z.infer<
typeof googleAnalyticsOptionsSchema
>

View File

@@ -0,0 +1,5 @@
export enum GoogleSheetsAction {
GET = 'Get data from sheet',
INSERT_ROW = 'Insert a row',
UPDATE_ROW = 'Update a row',
}

View File

@@ -0,0 +1,2 @@
export * from './enums'
export * from './schemas'

View File

@@ -0,0 +1,156 @@
import { z } from 'zod'
import { ComparisonOperators, LogicalOperator } from '../../logic/condition'
import { IntegrationBlockType } from '../enums'
import { GoogleSheetsAction } from './enums'
import { blockBaseSchema, credentialsBaseSchema } from '../../baseSchemas'
const cellSchema = z.object({
column: z.string().optional(),
value: z.string().optional(),
id: z.string(),
})
const extractingCellSchema = z.object({
column: z.string().optional(),
id: z.string(),
variableId: z.string().optional(),
})
const googleSheetsOptionsBaseSchema = z.object({
credentialsId: z.string().optional(),
sheetId: z.string().optional(),
spreadsheetId: z.string().optional(),
})
const rowsFilterComparisonSchema = z.object({
id: z.string(),
column: z.string().optional(),
comparisonOperator: z.nativeEnum(ComparisonOperators).optional(),
value: z.string().optional(),
})
const initialGoogleSheetsOptionsSchema = googleSheetsOptionsBaseSchema.merge(
z.object({
action: z.undefined(),
})
)
const googleSheetsGetOptionsSchema = googleSheetsOptionsBaseSchema.merge(
z.object({
action: z.enum([GoogleSheetsAction.GET]),
// TODO: remove referenceCell once migrated to filtering
referenceCell: cellSchema.optional(),
filter: z.object({
comparisons: z.array(rowsFilterComparisonSchema),
logicalOperator: z.nativeEnum(LogicalOperator),
}),
cellsToExtract: z.array(extractingCellSchema),
})
)
const googleSheetsInsertRowOptionsSchema = googleSheetsOptionsBaseSchema.merge(
z.object({
action: z.enum([GoogleSheetsAction.INSERT_ROW]),
cellsToInsert: z.array(cellSchema),
})
)
const googleSheetsUpdateRowOptionsSchema = googleSheetsOptionsBaseSchema.merge(
z.object({
action: z.enum([GoogleSheetsAction.UPDATE_ROW]),
cellsToUpsert: z.array(cellSchema),
referenceCell: cellSchema.optional(),
})
)
export const googleSheetsOptionsSchema = z.discriminatedUnion('action', [
googleSheetsGetOptionsSchema,
googleSheetsInsertRowOptionsSchema,
googleSheetsUpdateRowOptionsSchema,
initialGoogleSheetsOptionsSchema,
])
export const googleSheetsBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.GOOGLE_SHEETS]),
options: googleSheetsOptionsSchema,
})
)
export const googleSheetsCredentialsSchema = z
.object({
type: z.literal('google sheets'),
data: z.object({
refresh_token: z.string().nullish(),
expiry_date: z.number().nullish(),
access_token: z.string().nullish(),
token_type: z.string().nullish(),
id_token: z.string().nullish(),
scope: z.string().optional(),
}),
})
.merge(credentialsBaseSchema)
export const defaultGoogleSheetsOptions: GoogleSheetsOptions = {}
export const defaultGoogleSheetsGetOptions = (
createId: () => string
): GoogleSheetsGetOptions => ({
action: GoogleSheetsAction.GET,
cellsToExtract: [
{
id: createId(),
},
],
filter: {
comparisons: [
{
id: createId(),
},
],
logicalOperator: LogicalOperator.AND,
},
})
export const defaultGoogleSheetsInsertOptions = (
createId: () => string
): GoogleSheetsInsertRowOptions => ({
action: GoogleSheetsAction.INSERT_ROW,
cellsToInsert: [
{
id: createId(),
},
],
})
export const defaultGoogleSheetsUpdateOptions = (
createId: () => string
): GoogleSheetsUpdateRowOptions => ({
action: GoogleSheetsAction.UPDATE_ROW,
cellsToUpsert: [
{
id: createId(),
},
],
})
export type GoogleSheetsBlock = z.infer<typeof googleSheetsBlockSchema>
export type GoogleSheetsOptions = z.infer<typeof googleSheetsOptionsSchema>
export type GoogleSheetsOptionsBase = z.infer<
typeof googleSheetsOptionsBaseSchema
>
export type GoogleSheetsGetOptions = z.infer<
typeof googleSheetsGetOptionsSchema
>
export type GoogleSheetsInsertRowOptions = z.infer<
typeof googleSheetsInsertRowOptionsSchema
>
export type GoogleSheetsUpdateRowOptions = z.infer<
typeof googleSheetsUpdateRowOptionsSchema
>
export type Cell = z.infer<typeof cellSchema>
export type ExtractingCell = z.infer<typeof extractingCellSchema>
export type RowsFilterComparison = z.infer<typeof rowsFilterComparisonSchema>
export type GoogleSheetsCredentials = z.infer<
typeof googleSheetsCredentialsSchema
>

View File

@@ -0,0 +1,9 @@
export * from './chatwoot'
export * from './enums'
export * from './googleAnalytics'
export * from './googleSheets'
export * from './makeCom'
export * from './pabblyConnect'
export * from './sendEmail'
export * from './webhook'
export * from './zapier'

View File

@@ -0,0 +1,14 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { IntegrationBlockType } from './enums'
import { webhookOptionsSchema } from './webhook'
export const makeComBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.MAKE_COM]),
options: webhookOptionsSchema,
webhookId: z.string(),
})
)
export type MakeComBlock = z.infer<typeof makeComBlockSchema>

View File

@@ -0,0 +1,131 @@
import { z } from 'zod'
import { blockBaseSchema, credentialsBaseSchema } from '../baseSchemas'
import { IntegrationBlockType } from './enums'
export const openAITasks = ['Create chat completion', 'Create image'] as const
export const chatCompletionModels = [
'gpt-3.5-turbo',
'gpt-3.5-turbo-0301',
] as const
export const chatCompletionMessageRoles = [
'system',
'user',
'assistant',
] as const
export const chatCompletionMessageCustomRoles = [
'Messages sequence ✨',
] as const
export const chatCompletionResponseValues = [
'Message content',
'Total tokens',
] as const
const openAIBaseOptionsSchema = z.object({
credentialsId: z.string().optional(),
})
const initialOptionsSchema = z
.object({
task: z.undefined(),
})
.merge(openAIBaseOptionsSchema)
const chatCompletionMessageSchema = z.object({
id: z.string(),
role: z.enum(chatCompletionMessageRoles).optional(),
content: z.string().optional(),
})
const chatCompletionCustomMessageSchema = z.object({
id: z.string(),
role: z.enum(chatCompletionMessageCustomRoles),
content: z
.object({
assistantMessagesVariableId: z.string().optional(),
userMessagesVariableId: z.string().optional(),
})
.optional(),
})
const chatCompletionOptionsSchema = z
.object({
task: z.literal(openAITasks[0]),
model: z.enum(chatCompletionModels),
messages: z.array(
z.union([chatCompletionMessageSchema, chatCompletionCustomMessageSchema])
),
responseMapping: z.array(
z.object({
id: z.string(),
valueToExtract: z.enum(chatCompletionResponseValues),
variableId: z.string().optional(),
})
),
})
.merge(openAIBaseOptionsSchema)
const createImageOptionsSchema = z
.object({
task: z.literal(openAITasks[1]),
prompt: z.string().optional(),
advancedOptions: z.object({
size: z.enum(['256x256', '512x512', '1024x1024']).optional(),
}),
responseMapping: z.array(
z.object({
id: z.string(),
valueToExtract: z.enum(['Image URL']),
variableId: z.string().optional(),
})
),
})
.merge(openAIBaseOptionsSchema)
export const openAIBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.OPEN_AI]),
options: z.discriminatedUnion('task', [
initialOptionsSchema,
chatCompletionOptionsSchema,
createImageOptionsSchema,
]),
})
)
export const openAICredentialsSchema = z
.object({
type: z.literal('openai'),
data: z.object({
apiKey: z.string(),
}),
})
.merge(credentialsBaseSchema)
export const defaultChatCompletionOptions = (
createId: () => string
): ChatCompletionOpenAIOptions => ({
task: 'Create chat completion',
messages: [
{
id: createId(),
},
],
responseMapping: [
{
id: createId(),
valueToExtract: 'Message content',
},
],
model: 'gpt-3.5-turbo',
})
export type OpenAICredentials = z.infer<typeof openAICredentialsSchema>
export type OpenAIBlock = z.infer<typeof openAIBlockSchema>
export type ChatCompletionOpenAIOptions = z.infer<
typeof chatCompletionOptionsSchema
>
export type CreateImageOpenAIOptions = z.infer<typeof createImageOptionsSchema>

View File

@@ -0,0 +1,14 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { IntegrationBlockType } from './enums'
import { webhookOptionsSchema } from './webhook'
export const pabblyConnectBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.PABBLY_CONNECT]),
options: webhookOptionsSchema,
webhookId: z.string(),
})
)
export type PabblyConnectBlock = z.infer<typeof pabblyConnectBlockSchema>

View File

@@ -0,0 +1,50 @@
import { z } from 'zod'
import { blockBaseSchema, credentialsBaseSchema } from '../baseSchemas'
import { IntegrationBlockType } from './enums'
export const sendEmailOptionsSchema = z.object({
credentialsId: z.string(),
isCustomBody: z.boolean().optional(),
isBodyCode: z.boolean().optional(),
recipients: z.array(z.string()),
subject: z.string().optional(),
body: z.string().optional(),
replyTo: z.string().optional(),
cc: z.array(z.string()).optional(),
bcc: z.array(z.string()).optional(),
attachmentsVariableId: z.string().optional(),
})
export const sendEmailBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.EMAIL]),
options: sendEmailOptionsSchema,
})
)
export const smtpCredentialsSchema = z
.object({
type: z.literal('smtp'),
data: z.object({
host: z.string().optional(),
username: z.string().optional(),
password: z.string().optional(),
isTlsEnabled: z.boolean().optional(),
port: z.number(),
from: z.object({
email: z.string().optional(),
name: z.string().optional(),
}),
}),
})
.merge(credentialsBaseSchema)
export const defaultSendEmailOptions: SendEmailOptions = {
credentialsId: 'default',
isCustomBody: false,
recipients: [],
}
export type SendEmailBlock = z.infer<typeof sendEmailBlockSchema>
export type SendEmailOptions = z.infer<typeof sendEmailOptionsSchema>
export type SmtpCredentials = z.infer<typeof smtpCredentialsSchema>

View File

@@ -0,0 +1,44 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { IntegrationBlockType } from './enums'
const variableForTestSchema = z.object({
id: z.string(),
variableId: z.string().optional(),
value: z.string().optional(),
})
const responseVariableMappingSchema = z.object({
id: z.string(),
variableId: z.string().optional(),
bodyPath: z.string().optional(),
})
export const webhookOptionsSchema = z.object({
variablesForTest: z.array(variableForTestSchema),
responseVariableMapping: z.array(responseVariableMappingSchema),
isAdvancedConfig: z.boolean().optional(),
isCustomBody: z.boolean().optional(),
})
export const webhookBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.WEBHOOK]),
options: webhookOptionsSchema,
webhookId: z.string(),
})
)
export const defaultWebhookOptions: Omit<WebhookOptions, 'webhookId'> = {
responseVariableMapping: [],
variablesForTest: [],
isAdvancedConfig: false,
isCustomBody: false,
}
export type WebhookBlock = z.infer<typeof webhookBlockSchema>
export type WebhookOptions = z.infer<typeof webhookOptionsSchema>
export type ResponseVariableMapping = z.infer<
typeof responseVariableMappingSchema
>
export type VariableForTest = z.infer<typeof variableForTestSchema>

View File

@@ -0,0 +1,14 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { IntegrationBlockType } from './enums'
import { webhookOptionsSchema } from './webhook'
export const zapierBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.ZAPIER]),
options: webhookOptionsSchema,
webhookId: z.string(),
})
)
export type ZapierBlock = z.infer<typeof zapierBlockSchema>

View File

@@ -0,0 +1,55 @@
import { z } from 'zod'
import { ItemType } from '../../items/enums'
import { itemBaseSchema } from '../../items/baseSchemas'
import { blockBaseSchema } from '../baseSchemas'
import { LogicBlockType } from './enums'
export enum LogicalOperator {
OR = 'OR',
AND = 'AND',
}
export enum ComparisonOperators {
EQUAL = 'Equal to',
NOT_EQUAL = 'Not equal',
CONTAINS = 'Contains',
GREATER = 'Greater than',
LESS = 'Less than',
IS_SET = 'Is set',
}
const comparisonSchema = z.object({
id: z.string(),
variableId: z.string().optional(),
comparisonOperator: z.nativeEnum(ComparisonOperators).optional(),
value: z.string().optional(),
})
const conditionContentSchema = z.object({
logicalOperator: z.nativeEnum(LogicalOperator),
comparisons: z.array(comparisonSchema),
})
export const conditionItemSchema = itemBaseSchema.merge(
z.object({
type: z.literal(ItemType.CONDITION),
content: conditionContentSchema,
})
)
export const conditionBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.CONDITION]),
items: z.array(conditionItemSchema),
})
)
export const defaultConditionContent: ConditionContent = {
comparisons: [],
logicalOperator: LogicalOperator.AND,
}
export type ConditionItem = z.infer<typeof conditionItemSchema>
export type Comparison = z.infer<typeof comparisonSchema>
export type ConditionBlock = z.infer<typeof conditionBlockSchema>
export type ConditionContent = z.infer<typeof conditionContentSchema>

View File

@@ -0,0 +1,9 @@
export enum LogicBlockType {
SET_VARIABLE = 'Set variable',
CONDITION = 'Condition',
REDIRECT = 'Redirect',
SCRIPT = 'Code',
TYPEBOT_LINK = 'Typebot link',
WAIT = 'Wait',
JUMP = 'Jump',
}

View File

@@ -0,0 +1,7 @@
export * from './script'
export * from './condition'
export * from './enums'
export * from './redirect'
export * from './setVariable'
export * from './typebotLink'
export * from './wait'

View File

@@ -0,0 +1,17 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { LogicBlockType } from './enums'
export const jumpOptionsSchema = z.object({
groupId: z.string().optional(),
blockId: z.string().optional(),
})
export const jumpBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.JUMP]),
options: jumpOptionsSchema,
})
)
export type JumpBlock = z.infer<typeof jumpBlockSchema>

View File

@@ -0,0 +1,20 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { LogicBlockType } from './enums'
export const redirectOptionsSchema = z.object({
url: z.string().optional(),
isNewTab: z.boolean(),
})
export const redirectBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.REDIRECT]),
options: redirectOptionsSchema,
})
)
export const defaultRedirectOptions: RedirectOptions = { isNewTab: false }
export type RedirectBlock = z.infer<typeof redirectBlockSchema>
export type RedirectOptions = z.infer<typeof redirectOptionsSchema>

View File

@@ -0,0 +1,21 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { LogicBlockType } from './enums'
export const scriptOptionsSchema = z.object({
name: z.string(),
content: z.string().optional(),
shouldExecuteInParentContext: z.boolean().optional(),
})
export const scriptBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.SCRIPT]),
options: scriptOptionsSchema,
})
)
export const defaultScriptOptions: ScriptOptions = { name: 'Script' }
export type ScriptBlock = z.infer<typeof scriptBlockSchema>
export type ScriptOptions = z.infer<typeof scriptOptionsSchema>

View File

@@ -0,0 +1,21 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { LogicBlockType } from './enums'
export const setVariableOptionsSchema = z.object({
variableId: z.string().optional(),
expressionToEvaluate: z.string().optional(),
isCode: z.boolean().optional(),
})
export const setVariableBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.SET_VARIABLE]),
options: setVariableOptionsSchema,
})
)
export const defaultSetVariablesOptions: SetVariableOptions = {}
export type SetVariableBlock = z.infer<typeof setVariableBlockSchema>
export type SetVariableOptions = z.infer<typeof setVariableOptionsSchema>

View File

@@ -0,0 +1,20 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { LogicBlockType } from './enums'
export const typebotLinkOptionsSchema = z.object({
typebotId: z.string().optional(),
groupId: z.string().optional(),
})
export const typebotLinkBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.TYPEBOT_LINK]),
options: typebotLinkOptionsSchema,
})
)
export const defaultTypebotLinkOptions: TypebotLinkOptions = {}
export type TypebotLinkBlock = z.infer<typeof typebotLinkBlockSchema>
export type TypebotLinkOptions = z.infer<typeof typebotLinkOptionsSchema>

View File

@@ -0,0 +1,19 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
import { LogicBlockType } from './enums'
export const waitOptionsSchema = z.object({
secondsToWaitFor: z.string().optional(),
})
export const waitBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.WAIT]),
options: waitOptionsSchema,
})
)
export const defaultWaitOptions: WaitOptions = {}
export type WaitBlock = z.infer<typeof waitBlockSchema>
export type WaitOptions = z.infer<typeof waitOptionsSchema>

View File

@@ -0,0 +1,161 @@
import { z } from 'zod'
import { BubbleBlockType } from './bubbles/enums'
import { ChoiceInputBlock, choiceInputSchema } from './inputs/choice'
import { InputBlockType } from './inputs/enums'
import { IntegrationBlockType } from './integrations/enums'
import { ConditionBlock, conditionBlockSchema } from './logic/condition'
import { LogicBlockType } from './logic/enums'
import { blockBaseSchema } from './baseSchemas'
import { startBlockSchema } from './start/schemas'
import {
textBubbleBlockSchema,
imageBubbleBlockSchema,
videoBubbleBlockSchema,
embedBubbleBlockSchema,
audioBubbleBlockSchema,
} from './bubbles'
import {
textInputSchema,
emailInputSchema,
numberInputSchema,
urlInputSchema,
phoneNumberInputBlockSchema,
dateInputSchema,
paymentInputSchema,
ratingInputBlockSchema,
fileInputStepSchema,
} from './inputs'
import {
chatwootBlockSchema,
googleAnalyticsBlockSchema,
googleSheetsBlockSchema,
makeComBlockSchema,
pabblyConnectBlockSchema,
sendEmailBlockSchema,
webhookBlockSchema,
zapierBlockSchema,
} from './integrations'
import { openAIBlockSchema } from './integrations/openai'
import {
scriptBlockSchema,
redirectBlockSchema,
setVariableBlockSchema,
typebotLinkBlockSchema,
waitBlockSchema,
} from './logic'
import { jumpBlockSchema } from './logic/jump'
export type DraggableBlock =
| BubbleBlock
| InputBlock
| LogicBlock
| IntegrationBlock
export type BlockType =
| 'start'
| BubbleBlockType
| InputBlockType
| LogicBlockType
| IntegrationBlockType
export type DraggableBlockType =
| BubbleBlockType
| InputBlockType
| LogicBlockType
| IntegrationBlockType
export type BlockWithOptions =
| InputBlock
| Exclude<LogicBlock, ConditionBlock>
| IntegrationBlock
export type BlockWithOptionsType =
| InputBlockType
| Exclude<LogicBlockType, LogicBlockType.CONDITION>
| IntegrationBlockType
export type BlockOptions =
| InputBlockOptions
| LogicBlockOptions
| IntegrationBlockOptions
export type BlockWithItems = ConditionBlock | ChoiceInputBlock
export type BlockBase = z.infer<typeof blockBaseSchema>
export type BlockIndices = {
groupIndex: number
blockIndex: number
}
const bubbleBlockSchema = z.discriminatedUnion('type', [
textBubbleBlockSchema,
imageBubbleBlockSchema,
videoBubbleBlockSchema,
embedBubbleBlockSchema,
audioBubbleBlockSchema,
])
export type BubbleBlock = z.infer<typeof bubbleBlockSchema>
export type BubbleBlockContent = BubbleBlock['content']
export const inputBlockSchema = z.discriminatedUnion('type', [
textInputSchema,
choiceInputSchema,
emailInputSchema,
numberInputSchema,
urlInputSchema,
phoneNumberInputBlockSchema,
dateInputSchema,
paymentInputSchema,
ratingInputBlockSchema,
fileInputStepSchema,
])
export type InputBlock = z.infer<typeof inputBlockSchema>
export type InputBlockOptions = InputBlock['options']
export const logicBlockSchema = z.discriminatedUnion('type', [
scriptBlockSchema,
conditionBlockSchema,
redirectBlockSchema,
setVariableBlockSchema,
typebotLinkBlockSchema,
waitBlockSchema,
jumpBlockSchema,
])
export type LogicBlock = z.infer<typeof logicBlockSchema>
export type LogicBlockOptions = LogicBlock extends
| {
options?: infer Options
}
| {}
? Options
: never
export const integrationBlockSchema = z.discriminatedUnion('type', [
chatwootBlockSchema,
googleAnalyticsBlockSchema,
googleSheetsBlockSchema,
makeComBlockSchema,
openAIBlockSchema,
pabblyConnectBlockSchema,
sendEmailBlockSchema,
webhookBlockSchema,
zapierBlockSchema,
])
export type IntegrationBlock = z.infer<typeof integrationBlockSchema>
export type IntegrationBlockOptions = IntegrationBlock['options']
export const blockSchema = z.union([
startBlockSchema,
bubbleBlockSchema,
inputBlockSchema,
logicBlockSchema,
integrationBlockSchema,
])
export type Block = z.infer<typeof blockSchema>

View File

@@ -0,0 +1 @@
export * from './schemas'

View File

@@ -0,0 +1,11 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
export const startBlockSchema = blockBaseSchema.merge(
z.object({
type: z.literal('start'),
label: z.string(),
})
)
export type StartBlock = z.infer<typeof startBlockSchema>