@@ -13,6 +13,8 @@ export const valueTypes = [
|
||||
'Random ID',
|
||||
'Moment of the day',
|
||||
'Map item with same index',
|
||||
'Phone number',
|
||||
'Contact name',
|
||||
] as const
|
||||
|
||||
export const hiddenTypes = ['Today']
|
||||
|
||||
@@ -130,6 +130,12 @@ const startParamsSchema = z.object({
|
||||
.describe(
|
||||
'Set this to `true` if you intend to stream OpenAI completions on a client.'
|
||||
),
|
||||
isOnlyRegistering: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe(
|
||||
'If set to `true`, it will only register the session and not start the chat. This is used for other chat platform integration as it can require a session to be registered before sending the first message.'
|
||||
),
|
||||
})
|
||||
|
||||
const replyLogSchema = logSchema
|
||||
|
||||
@@ -2,6 +2,7 @@ import { z } from 'zod'
|
||||
import { answerSchema } from '../answer'
|
||||
import { resultSchema } from '../result'
|
||||
import { typebotInSessionStateSchema, dynamicThemeSchema } from './shared'
|
||||
import { settingsSchema } from '../typebot/settings'
|
||||
|
||||
const answerInSessionStateSchema = answerSchema.pick({
|
||||
content: true,
|
||||
@@ -64,6 +65,16 @@ const sessionStateSchemaV2 = z.object({
|
||||
})
|
||||
.optional(),
|
||||
isStreamEnabled: z.boolean().optional(),
|
||||
whatsApp: z
|
||||
.object({
|
||||
contact: z.object({
|
||||
name: z.string(),
|
||||
phoneNumber: z.string(),
|
||||
}),
|
||||
credentialsId: z.string().optional(),
|
||||
})
|
||||
.optional(),
|
||||
typingEmulation: settingsSchema.shape.typingEmulation.optional(),
|
||||
})
|
||||
|
||||
export type SessionState = z.infer<typeof sessionStateSchemaV2>
|
||||
|
||||
@@ -3,12 +3,14 @@ import { stripeCredentialsSchema } from './blocks/inputs/payment/schemas'
|
||||
import { googleSheetsCredentialsSchema } from './blocks/integrations/googleSheets/schemas'
|
||||
import { openAICredentialsSchema } from './blocks/integrations/openai'
|
||||
import { smtpCredentialsSchema } from './blocks/integrations/sendEmail'
|
||||
import { whatsAppCredentialsSchema } from './whatsapp'
|
||||
|
||||
export const credentialsSchema = z.discriminatedUnion('type', [
|
||||
smtpCredentialsSchema,
|
||||
googleSheetsCredentialsSchema,
|
||||
stripeCredentialsSchema,
|
||||
openAICredentialsSchema,
|
||||
whatsAppCredentialsSchema,
|
||||
])
|
||||
|
||||
export type Credentials = z.infer<typeof credentialsSchema>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { PublicTypebot as PrismaPublicTypebot } from '@typebot.io/prisma'
|
||||
import {
|
||||
groupSchema,
|
||||
edgeSchema,
|
||||
variableSchema,
|
||||
themeSchema,
|
||||
settingsSchema,
|
||||
} from './typebot'
|
||||
import { z } from 'zod'
|
||||
import { preprocessTypebot } from './typebot/helpers/preprocessTypebot'
|
||||
import { edgeSchema } from './typebot/edge'
|
||||
|
||||
export const publicTypebotSchema = z.preprocess(
|
||||
preprocessTypebot,
|
||||
|
||||
21
packages/schemas/features/typebot/edge.ts
Normal file
21
packages/schemas/features/typebot/edge.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
const sourceSchema = z.object({
|
||||
groupId: z.string(),
|
||||
blockId: z.string(),
|
||||
itemId: z.string().optional(),
|
||||
})
|
||||
export type Source = z.infer<typeof sourceSchema>
|
||||
|
||||
const targetSchema = z.object({
|
||||
groupId: z.string(),
|
||||
blockId: z.string().optional(),
|
||||
})
|
||||
export type Target = z.infer<typeof targetSchema>
|
||||
|
||||
export const edgeSchema = z.object({
|
||||
id: z.string(),
|
||||
from: sourceSchema,
|
||||
to: targetSchema,
|
||||
})
|
||||
export type Edge = z.infer<typeof edgeSchema>
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Block } from '../../blocks'
|
||||
import { Group, edgeSchema } from '../typebot'
|
||||
import { edgeSchema } from '../edge'
|
||||
import type { Group } from '../typebot'
|
||||
|
||||
export const preprocessTypebot = (typebot: any) => {
|
||||
if (!typebot || typebot.version === '5') return typebot
|
||||
|
||||
@@ -2,3 +2,4 @@ export * from './typebot'
|
||||
export * from './theme'
|
||||
export * from './settings'
|
||||
export * from './variable'
|
||||
export * from './edge'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { z } from 'zod'
|
||||
import { whatsAppSettingsSchema } from '../whatsapp'
|
||||
|
||||
export const rememberUserStorages = ['session', 'local'] as const
|
||||
|
||||
@@ -35,6 +36,7 @@ export const settingsSchema = z.object({
|
||||
general: generalSettings,
|
||||
typingEmulation: typingEmulation,
|
||||
metadata: metadataSchema,
|
||||
whatsApp: whatsAppSettingsSchema.optional(),
|
||||
})
|
||||
|
||||
export const defaultSettings = ({
|
||||
|
||||
@@ -5,6 +5,7 @@ import { variableSchema } from './variable'
|
||||
import { Typebot as TypebotPrisma } from '@typebot.io/prisma'
|
||||
import { blockSchema } from '../blocks/schemas'
|
||||
import { preprocessTypebot } from './helpers/preprocessTypebot'
|
||||
import { edgeSchema } from './edge'
|
||||
|
||||
export const groupSchema = z.object({
|
||||
id: z.string(),
|
||||
@@ -16,23 +17,6 @@ export const groupSchema = z.object({
|
||||
blocks: z.array(blockSchema),
|
||||
})
|
||||
|
||||
const sourceSchema = z.object({
|
||||
groupId: z.string(),
|
||||
blockId: z.string(),
|
||||
itemId: z.string().optional(),
|
||||
})
|
||||
|
||||
const targetSchema = z.object({
|
||||
groupId: z.string(),
|
||||
blockId: z.string().optional(),
|
||||
})
|
||||
|
||||
export const edgeSchema = z.object({
|
||||
id: z.string(),
|
||||
from: sourceSchema,
|
||||
to: targetSchema,
|
||||
})
|
||||
|
||||
const resultsTablePreferencesSchema = z.object({
|
||||
columnsOrder: z.array(z.string()),
|
||||
columnsVisibility: z.record(z.string(), z.boolean()),
|
||||
@@ -72,6 +56,7 @@ export const typebotSchema = z.preprocess(
|
||||
resultsTablePreferences: resultsTablePreferencesSchema.nullable(),
|
||||
isArchived: z.boolean(),
|
||||
isClosed: z.boolean(),
|
||||
whatsAppPhoneNumberId: z.string().nullable(),
|
||||
}) satisfies z.ZodType<TypebotPrisma, z.ZodTypeDef, unknown>
|
||||
)
|
||||
|
||||
@@ -93,9 +78,7 @@ export const typebotCreateSchema = typebotSchema._def.schema
|
||||
.partial()
|
||||
|
||||
export type Typebot = z.infer<typeof typebotSchema>
|
||||
export type Target = z.infer<typeof targetSchema>
|
||||
export type Source = z.infer<typeof sourceSchema>
|
||||
export type Edge = z.infer<typeof edgeSchema>
|
||||
|
||||
export type Group = z.infer<typeof groupSchema>
|
||||
export type ResultsTablePreferences = z.infer<
|
||||
typeof resultsTablePreferencesSchema
|
||||
|
||||
200
packages/schemas/features/whatsapp.ts
Normal file
200
packages/schemas/features/whatsapp.ts
Normal file
@@ -0,0 +1,200 @@
|
||||
import { z } from 'zod'
|
||||
import { credentialsBaseSchema } from './blocks/baseSchemas'
|
||||
import { ComparisonOperators, LogicalOperator } from './blocks/logic/condition'
|
||||
|
||||
const mediaSchema = z.object({ link: z.string() })
|
||||
|
||||
const headerSchema = z
|
||||
.object({
|
||||
type: z.literal('image'),
|
||||
image: mediaSchema,
|
||||
})
|
||||
.or(
|
||||
z.object({
|
||||
type: z.literal('video'),
|
||||
video: mediaSchema,
|
||||
})
|
||||
)
|
||||
.or(
|
||||
z.object({
|
||||
type: z.literal('text'),
|
||||
text: z.string(),
|
||||
})
|
||||
)
|
||||
|
||||
const bodySchema = z.object({
|
||||
text: z.string(),
|
||||
})
|
||||
|
||||
const actionSchema = z.object({
|
||||
buttons: z.array(
|
||||
z.object({
|
||||
type: z.literal('reply'),
|
||||
reply: z.object({ id: z.string(), title: z.string() }),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
const templateSchema = z.object({
|
||||
name: z.literal('preview_initial_message'),
|
||||
language: z.object({
|
||||
code: z.literal('en'),
|
||||
}),
|
||||
})
|
||||
|
||||
const interactiveSchema = z.object({
|
||||
type: z.literal('button'),
|
||||
header: headerSchema.optional(),
|
||||
body: bodySchema.optional(),
|
||||
action: actionSchema,
|
||||
})
|
||||
|
||||
// https://developers.facebook.com/docs/whatsapp/cloud-api/reference/messages#message-object
|
||||
const sendingMessageSchema = z.discriminatedUnion('type', [
|
||||
z.object({
|
||||
type: z.literal('text'),
|
||||
text: z.object({
|
||||
body: z.string(),
|
||||
preview_url: z.boolean().optional(),
|
||||
}),
|
||||
preview_url: z.boolean().optional(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal('image'),
|
||||
image: mediaSchema,
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal('audio'),
|
||||
audio: mediaSchema,
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal('video'),
|
||||
video: mediaSchema,
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal('interactive'),
|
||||
interactive: interactiveSchema,
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal('template'),
|
||||
template: templateSchema,
|
||||
}),
|
||||
])
|
||||
|
||||
export const incomingMessageSchema = z.discriminatedUnion('type', [
|
||||
z.object({
|
||||
from: z.string(),
|
||||
type: z.literal('text'),
|
||||
text: z.object({
|
||||
body: z.string(),
|
||||
}),
|
||||
timestamp: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
from: z.string(),
|
||||
type: z.literal('button'),
|
||||
button: z.object({
|
||||
text: z.string(),
|
||||
payload: z.string(),
|
||||
}),
|
||||
timestamp: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
from: z.string(),
|
||||
type: z.literal('interactive'),
|
||||
interactive: z.object({
|
||||
button_reply: z.object({
|
||||
id: z.string(),
|
||||
title: z.string(),
|
||||
}),
|
||||
}),
|
||||
timestamp: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
from: z.string(),
|
||||
type: z.literal('image'),
|
||||
image: z.object({ id: z.string() }),
|
||||
timestamp: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
from: z.string(),
|
||||
type: z.literal('video'),
|
||||
video: z.object({ id: z.string() }),
|
||||
timestamp: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
from: z.string(),
|
||||
type: z.literal('audio'),
|
||||
audio: z.object({ id: z.string() }),
|
||||
timestamp: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
from: z.string(),
|
||||
type: z.literal('document'),
|
||||
document: z.object({ id: z.string() }),
|
||||
timestamp: z.string(),
|
||||
}),
|
||||
])
|
||||
|
||||
export const whatsAppWebhookRequestBodySchema = z.object({
|
||||
entry: z.array(
|
||||
z.object({
|
||||
changes: z.array(
|
||||
z.object({
|
||||
value: z.object({
|
||||
contacts: z
|
||||
.array(
|
||||
z.object({
|
||||
profile: z.object({
|
||||
name: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
metadata: z.object({
|
||||
display_phone_number: z.string(),
|
||||
}),
|
||||
messages: z.array(incomingMessageSchema).optional(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
export const whatsAppCredentialsSchema = z
|
||||
.object({
|
||||
type: z.literal('whatsApp'),
|
||||
data: z.object({
|
||||
systemUserAccessToken: z.string(),
|
||||
phoneNumberId: z.string(),
|
||||
}),
|
||||
})
|
||||
.merge(credentialsBaseSchema)
|
||||
|
||||
const whatsAppComparisonSchema = z.object({
|
||||
id: z.string(),
|
||||
comparisonOperator: z.nativeEnum(ComparisonOperators).optional(),
|
||||
value: z.string().optional(),
|
||||
})
|
||||
export type WhatsAppComparison = z.infer<typeof whatsAppComparisonSchema>
|
||||
|
||||
const startConditionSchema = z.object({
|
||||
logicalOperator: z.nativeEnum(LogicalOperator),
|
||||
comparisons: z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
comparisonOperator: z.nativeEnum(ComparisonOperators).optional(),
|
||||
value: z.string().optional(),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
export const whatsAppSettingsSchema = z.object({
|
||||
credentialsId: z.string().optional(),
|
||||
startCondition: startConditionSchema.optional(),
|
||||
})
|
||||
|
||||
export type WhatsAppIncomingMessage = z.infer<typeof incomingMessageSchema>
|
||||
export type WhatsAppSendingMessage = z.infer<typeof sendingMessageSchema>
|
||||
export type WhatsAppCredentials = z.infer<typeof whatsAppCredentialsSchema>
|
||||
Reference in New Issue
Block a user