2
0
Files
bot/packages/schemas/features/chat/sessionState.ts
Baptiste Arnaud 4f953ac272 (whatsapp) Add custom session expiration (#842)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
### Summary by CodeRabbit

- New Feature: Introduced session expiry timeout for WhatsApp
integration, allowing users to set the duration after which a session
expires.
- New Feature: Added an option to enable/disable the start bot condition
in WhatsApp integration settings.
- Refactor: Enhanced error handling by throwing specific errors when
necessary conditions are not met.
- Refactor: Improved UI components like `NumberInput` and
`SwitchWithLabel` for better usability.
- Bug Fix: Fixed issues related to session resumption and message
sending in expired sessions. Now, if a session is expired, a new one
will be started instead of attempting to resume the old one.
- Chore: Updated various schemas to reflect changes in session
management and WhatsApp settings.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2023-09-22 17:12:15 +02:00

141 lines
4.1 KiB
TypeScript

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,
blockId: true,
variableId: true,
})
const answerInSessionStateSchemaV2 = z.object({
key: z.string(),
value: z.string(),
})
export type AnswerInSessionState = z.infer<typeof answerInSessionStateSchemaV2>
const resultInSessionStateSchema = resultSchema
.pick({
variables: true,
})
.merge(
z.object({
answers: z.array(answerInSessionStateSchema),
id: z.string().optional(),
})
)
const sessionStateSchemaV1 = z.object({
typebot: typebotInSessionStateSchema,
dynamicTheme: dynamicThemeSchema.optional(),
linkedTypebots: z.object({
typebots: z.array(typebotInSessionStateSchema),
queue: z.array(z.object({ edgeId: z.string(), typebotId: z.string() })),
}),
currentTypebotId: z.string(),
result: resultInSessionStateSchema,
currentBlock: z
.object({
blockId: z.string(),
groupId: z.string(),
})
.optional(),
isStreamEnabled: z.boolean().optional(),
})
const sessionStateSchemaV2 = z.object({
version: z.literal('2'),
typebotsQueue: z.array(
z.object({
edgeIdToTriggerWhenDone: z.string().optional(),
isMergingWithParent: z.boolean().optional(),
resultId: z.string().optional(),
answers: z.array(answerInSessionStateSchemaV2),
typebot: typebotInSessionStateSchema,
})
),
dynamicTheme: dynamicThemeSchema.optional(),
currentBlock: z
.object({
blockId: z.string(),
groupId: z.string(),
})
.optional(),
isStreamEnabled: z.boolean().optional(),
whatsApp: z
.object({
contact: z.object({
name: z.string(),
phoneNumber: z.string(),
}),
})
.optional(),
expiryTimeout: z
.number()
.min(1)
.optional()
.describe('Expiry timeout in milliseconds'),
typingEmulation: settingsSchema.shape.typingEmulation.optional(),
})
export type SessionState = z.infer<typeof sessionStateSchemaV2>
export const sessionStateSchema = sessionStateSchemaV1
.or(sessionStateSchemaV2)
.transform((state): SessionState => {
if ('version' in state) return state
return {
version: '2',
typebotsQueue: [
{
typebot: state.typebot,
resultId: state.result.id,
answers: state.result.answers.map((answer) => ({
key:
(answer.variableId
? state.typebot.variables.find(
(variable) => variable.id === answer.variableId
)?.name
: state.typebot.groups.find((group) =>
group.blocks.find((block) => block.id === answer.blockId)
)?.title) ?? '',
value: answer.content,
})),
isMergingWithParent: true,
edgeIdToTriggerWhenDone:
state.linkedTypebots.queue.length > 0
? state.linkedTypebots.queue[0].edgeId
: undefined,
},
...state.linkedTypebots.typebots.map(
(typebot, index) =>
({
typebot,
resultId: state.result.id,
answers: state.result.answers.map((answer) => ({
key:
(answer.variableId
? state.typebot.variables.find(
(variable) => variable.id === answer.variableId
)?.name
: state.typebot.groups.find((group) =>
group.blocks.find(
(block) => block.id === answer.blockId
)
)?.title) ?? '',
value: answer.content,
})),
edgeIdToTriggerWhenDone: state.linkedTypebots.queue.at(index + 1)
?.edgeId,
} satisfies SessionState['typebotsQueue'][number])
),
],
dynamicTheme: state.dynamicTheme,
currentBlock: state.currentBlock,
isStreamEnabled: state.isStreamEnabled,
}
})