2
0

⚗️ Implement chat API

This commit is contained in:
Baptiste Arnaud
2022-11-29 10:02:40 +01:00
parent 49ba434350
commit bf0d0c2475
122 changed files with 5075 additions and 292 deletions

View File

@ -1,27 +1,34 @@
import { z } from 'zod'
import { schemaForType } from './utils'
import { Answer as AnswerPrisma, Prisma } from 'db'
export const answerSchema = z.object({
createdAt: z.date(),
resultId: z.string(),
blockId: z.string(),
groupId: z.string(),
variableId: z.string().nullable(),
content: z.string(),
storageUsed: z.number().nullable(),
})
export const answerInputSchema = answerSchema
.omit({
createdAt: true,
resultId: true,
variableId: true,
storageUsed: true,
export const answerSchema = schemaForType<AnswerPrisma>()(
z.object({
createdAt: z.date(),
resultId: z.string(),
blockId: z.string(),
groupId: z.string(),
variableId: z.string().nullable(),
content: z.string(),
storageUsed: z.number().nullable(),
})
.and(
z.object({
variableId: z.string().nullish(),
storageUsed: z.number().nullish(),
})
)
export const answerInputSchema =
schemaForType<Prisma.AnswerUncheckedUpdateInput>()(
answerSchema
.omit({
createdAt: true,
resultId: true,
variableId: true,
storageUsed: true,
})
.and(
z.object({
variableId: z.string().nullish(),
storageUsed: z.number().nullish(),
})
)
)
export type Stats = {

View File

@ -0,0 +1,101 @@
import { z } from 'zod'
import {
audioBubbleContentSchema,
BubbleBlockType,
embedBubbleContentSchema,
googleAnalyticsOptionsSchema,
imageBubbleContentSchema,
inputBlockSchema,
textBubbleContentSchema,
videoBubbleContentSchema,
} from './blocks'
import { publicTypebotSchema } from './publicTypebot'
import { ChatSession as ChatSessionPrisma } from 'db'
import { schemaForType } from './utils'
import { resultSchema } from './result'
const typebotInSessionStateSchema = publicTypebotSchema.pick({
id: true,
groups: true,
edges: true,
variables: true,
})
export const sessionStateSchema = z.object({
typebot: typebotInSessionStateSchema,
linkedTypebots: z.object({
typebots: z.array(typebotInSessionStateSchema),
queue: z.array(z.object({ edgeId: z.string(), typebotId: z.string() })),
}),
currentTypebotId: z.string(),
result: resultSchema.pick({ id: true, variables: true, hasStarted: true }),
isPreview: z.boolean(),
currentBlock: z
.object({
blockId: z.string(),
groupId: z.string(),
})
.optional(),
})
const chatSessionSchema = schemaForType<ChatSessionPrisma>()(
z.object({
id: z.string(),
createdAt: z.date(),
updatedAt: z.date(),
state: sessionStateSchema,
})
)
const simplifiedTextBubbleContentSchema = textBubbleContentSchema.pick({
plainText: true,
html: true,
})
const chatMessageContentSchema = simplifiedTextBubbleContentSchema
.or(imageBubbleContentSchema)
.or(videoBubbleContentSchema)
.or(embedBubbleContentSchema)
.or(audioBubbleContentSchema)
const codeToExecuteSchema = z.object({
content: z.string(),
args: z.array(
z.object({
id: z.string(),
value: z.string().or(z.number()).or(z.boolean()).nullish(),
})
),
})
export const chatReplySchema = z.object({
messages: z.array(
z.object({
type: z.nativeEnum(BubbleBlockType),
content: chatMessageContentSchema,
})
),
input: inputBlockSchema.optional(),
logic: z
.object({
redirectUrl: z.string().optional(),
codeToExecute: codeToExecuteSchema.optional(),
})
.optional(),
integrations: z
.object({
chatwoot: z
.object({
codeToExecute: codeToExecuteSchema,
})
.optional(),
googleAnalytics: googleAnalyticsOptionsSchema.optional(),
})
.optional(),
})
export type ChatSession = z.infer<typeof chatSessionSchema>
export type SessionState = z.infer<typeof sessionStateSchema>
export type TypebotInSession = z.infer<typeof typebotInSessionStateSchema>
export type ChatReply = z.infer<typeof chatReplySchema>
export type ChatMessageContent = z.infer<typeof chatMessageContentSchema>

View File

@ -1,21 +1,32 @@
import { Group, Edge, Settings, Theme, Variable } from './typebot'
import { PublicTypebot as PublicTypebotFromPrisma } from 'db'
import {
groupSchema,
edgeSchema,
variableSchema,
themeSchema,
settingsSchema,
typebotSchema,
} from './typebot'
import { PublicTypebot as PublicTypebotPrisma } from 'db'
import { z } from 'zod'
import { schemaForType } from './utils'
export type PublicTypebot = Omit<
PublicTypebotFromPrisma,
| 'groups'
| 'theme'
| 'settings'
| 'variables'
| 'edges'
| 'createdAt'
| 'updatedAt'
> & {
groups: Group[]
variables: Variable[]
edges: Edge[]
theme: Theme
settings: Settings
createdAt: string
updatedAt: string
}
export const publicTypebotSchema = schemaForType<PublicTypebotPrisma>()(
z.object({
id: z.string(),
createdAt: z.date(),
updatedAt: z.date(),
typebotId: z.string(),
groups: z.array(groupSchema),
edges: z.array(edgeSchema),
variables: z.array(variableSchema),
theme: themeSchema,
settings: settingsSchema,
})
)
const publicTypebotWithName = publicTypebotSchema.and(
typebotSchema.pick({ name: true, isArchived: true, isClosed: true })
)
export type PublicTypebot = z.infer<typeof publicTypebotSchema>
export type PublicTypebotWithName = z.infer<typeof publicTypebotWithName>

View File

@ -2,17 +2,21 @@ import { z } from 'zod'
import { answerInputSchema, answerSchema } from './answer'
import { InputBlockType } from './blocks'
import { variableWithValueSchema } from './typebot/variable'
import { Result as ResultPrisma, Log as LogPrisma } from 'db'
import { schemaForType } from './utils'
export const resultSchema = z.object({
id: z.string(),
createdAt: z.date(),
updatedAt: z.date(),
typebotId: z.string(),
variables: z.array(variableWithValueSchema),
isCompleted: z.boolean(),
hasStarted: z.boolean().nullable(),
isArchived: z.boolean().nullable(),
})
export const resultSchema = schemaForType<ResultPrisma>()(
z.object({
id: z.string(),
createdAt: z.date(),
updatedAt: z.date(),
typebotId: z.string(),
variables: z.array(variableWithValueSchema),
isCompleted: z.boolean(),
hasStarted: z.boolean().nullable(),
isArchived: z.boolean().nullable(),
})
)
export const resultWithAnswersSchema = resultSchema.and(
z.object({
@ -26,23 +30,22 @@ export const resultWithAnswersInputSchema = resultSchema.and(
})
)
export const logSchema = z.object({
id: z.string(),
createdAt: z.date(),
resultId: z.string(),
status: z.string(),
description: z.string(),
details: z.string().nullable(),
})
export const logSchema = schemaForType<LogPrisma>()(
z.object({
id: z.string(),
createdAt: z.date(),
resultId: z.string(),
status: z.string(),
description: z.string(),
details: z.string().nullable(),
})
)
export type Result = z.infer<typeof resultSchema>
export type ResultWithAnswers = z.infer<typeof resultWithAnswersSchema>
export type ResultWithAnswersInput = z.infer<
typeof resultWithAnswersInputSchema
>
export type Log = z.infer<typeof logSchema>
export type ResultValues = Pick<

View File

@ -3,8 +3,10 @@ import { settingsSchema } from './settings'
import { blockSchema } from '../blocks'
import { themeSchema } from './theme'
import { variableSchema } from './variable'
import { Typebot as TypebotPrisma } from 'db'
import { schemaForType } from '../utils'
const groupSchema = z.object({
export const groupSchema = z.object({
id: z.string(),
title: z.string(),
graphCoordinates: z.object({
@ -25,7 +27,7 @@ const targetSchema = z.object({
blockId: z.string().optional(),
})
const edgeSchema = z.object({
export const edgeSchema = z.object({
id: z.string(),
from: sourceSchema,
to: targetSchema,
@ -37,27 +39,29 @@ const resultsTablePreferencesSchema = z.object({
columnsWidth: z.record(z.string(), z.number()),
})
const typebotSchema = z.object({
version: z.enum(['2']).optional(),
id: z.string(),
name: z.string(),
groups: z.array(groupSchema),
edges: z.array(edgeSchema),
variables: z.array(variableSchema),
theme: themeSchema,
settings: settingsSchema,
createdAt: z.string(),
updatedAt: z.string(),
icon: z.string().nullable(),
publishedTypebotId: z.string().nullable(),
folderId: z.string().nullable(),
publicId: z.string().nullable(),
customDomain: z.string().nullable(),
workspaceId: z.string(),
resultsTablePreferences: resultsTablePreferencesSchema.optional(),
isArchived: z.boolean(),
isClosed: z.boolean(),
})
export const typebotSchema = schemaForType<TypebotPrisma>()(
z.object({
version: z.enum(['2']).optional(),
id: z.string(),
name: z.string(),
groups: z.array(groupSchema),
edges: z.array(edgeSchema),
variables: z.array(variableSchema),
theme: themeSchema,
settings: settingsSchema,
createdAt: z.date(),
updatedAt: z.date(),
icon: z.string().nullable(),
publishedTypebotId: z.string().nullable(),
folderId: z.string().nullable(),
publicId: z.string().nullable(),
customDomain: z.string().nullable(),
workspaceId: z.string(),
resultsTablePreferences: resultsTablePreferencesSchema.nullable(),
isArchived: z.boolean(),
isClosed: z.boolean(),
})
)
export type Typebot = z.infer<typeof typebotSchema>
export type Target = z.infer<typeof targetSchema>

View File

@ -1 +1,9 @@
import { z } from 'zod'
export type IdMap<T> = { [id: string]: T }
export const schemaForType =
<T>() =>
<S extends z.ZodType<T, any, any>>(arg: S) => {
return arg
}