import type { BotVersion } from '../botVersions/types' import type { Service } from '../services/types' // ─── Settings ───────────────────────────────────────────────────────────────── export type BotCreatedVersion = 'v1' | 'v2' | 'v3' export type BotLimitations = { hasInteractiveMessage?: boolean hasWebchatTrigger?: boolean } export type BotSettings = { /** If true, only the first matching rule per trigger fires; otherwise all matching rules fire. */ sequentialRuleExecution?: boolean /** Version of the bot builder used to create this bot. v3 uses the visual flow builder. */ botCreatedVersion?: BotCreatedVersion limitations?: BotLimitations } // ─── FlowJson ───────────────────────────────────────────────────────────────── export type BotEvent = | 'MESSAGE_RECEIVED' | 'WIDGET_MESSAGE_RECEIVED' | 'USER_MESSAGE_SENT' | 'MANUAL_TICKET_OPENED' | 'TICKET_OPENED' | 'TICKET_CLOSED' | 'TICKET_BEFORE_CLOSE' | 'TICKET_INACTIVE' | 'ENTER_CONTEXT' | 'LEAVE_CONTEXT' | 'CONTACT_CREATED' | 'CONTACT_RECONNECTED' | 'API_SIGNAL' | 'ANONYMOUS_USER_CREATED_WEBCHAT' export type BotFlowTriggerNode = { id: string type: 'triggerNode' position: { x: number; y: number } data: { trigger: BotEvent } } export type BotFlowMenuNodeAnswer = { id: string text: string fallback?: boolean } export type BotFlowMenuNode = { id: string type: 'menuNode' position: { x: number; y: number } data: { text: string answers?: BotFlowMenuNodeAnswer[] } } export type BotFlowNode = BotFlowTriggerNode | BotFlowMenuNode export type BotFlowEdge = { id: string source: string target: string /** The answer handle ID on the source node this edge originates from, if any. */ sourceHandle: string } /** Visual flow graph used by the flow builder UI. Gets compiled into `contexts` on save. */ export type BotFlowJson = { nodes: BotFlowNode[] edges: BotFlowEdge[] } // ─── Contexts ───────────────────────────────────────────────────────────────── export type BotActionType = | 'SEND_MESSAGE' | 'SEND_TERM' | 'CONFIRM_TERM' | 'SEND_QUESTION' | 'WRITE_CUSTOM_FIELD' | 'TRANSFER_TICKET' | 'CLOSE_TICKET' | 'ADD_TAG' | 'REMOVE_TAG' | 'SET_CONTEXT' | 'RESET_CONTEXT' | 'UNSUBSCRIBE_FROM_CAMPAIGN' | 'SEND_WEBHOOK_COMMAND' | 'AI' | 'HTTP_REQUEST' | 'SET_VAR' export type BotActionDataMap = { SEND_MESSAGE: { text?: string /** File UUID. */ file?: string /** Message mask/template string. */ mask?: string /** WhatsApp Business interactive message payload. */ interactive?: unknown /** Quick reply buttons. */ actions?: { title: string; value: string }[] } SEND_TERM: { /** Acceptance term UUID. */ acceptanceTerms?: string } CONFIRM_TERM: { /** Acceptance term UUID to confirm. */ confirmAcceptanceTerms?: string } SEND_QUESTION: { /** Question UUID. */ question?: string } WRITE_CUSTOM_FIELD: { /** Custom field UUID. */ customField?: string /** Custom field UUID (alias used in some versions). */ customFieldId?: string /** Prompt text sent to the contact asking for input. */ text?: string /** Number of retries before giving up. */ tries?: number /** Message sent when the contact provides an invalid value. */ invalidMessage?: string /** Context ID to navigate to on success. */ successContext?: string /** Context ID to navigate to on failure. */ fallbackContext?: string } TRANSFER_TICKET: { /** Department UUID. */ department?: string /** User UUID. */ user?: string } CLOSE_TICKET: { /** Ticket topic UUIDs. */ ticketTopics?: string[] comments?: string } ADD_TAG: { /** Tag UUIDs to add to the contact. */ tags: string[] } REMOVE_TAG: { /** Tag UUIDs to remove from the contact. */ tags: string[] } SET_CONTEXT: { /** Context ID to navigate to. */ context?: string } RESET_CONTEXT: Record UNSUBSCRIBE_FROM_CAMPAIGN: Record SEND_WEBHOOK_COMMAND: { command?: string } AI: { /** AI agent UUID. */ agentId?: string prompt?: string maxAttempts?: number /** Actions to take based on AI agent outcomes. */ actions?: { context?: string; action: { id: string; type: string } }[] } HTTP_REQUEST: { requestName?: string endpointUrl?: string httpMethod?: 'get' | 'post' | 'put' | 'patch' | 'delete' isAsyncRequest?: boolean bodyType?: 'json' | 'xml' | 'formData' | 'empty' headers?: { key: string; value: string }[] requestBodyFormData?: { key: string; value: string }[] requestBodyJson?: string requestBodyXml?: string retries?: number /** Timeout in milliseconds. */ timeout?: number /** Response properties to extract into bot session variables. */ variables?: { key: string; value: string }[] } SET_VAR: { /** Session variable name. */ key: string /** Value to assign (supports interpolation via `{{variable}}`). */ value: string } } export type BotAction = { [K in BotActionType]: { value: K name?: string data: BotActionDataMap[K] } }[BotActionType] /** * A simple condition matching a single variable against a value. * Key is a variable placeholder like `{{message_text}}` or `{{@customVar}}`. * Value is an object with one operator key (e.g. `$eq`, `$in`, `$between`). */ export type BotSimpleCondition = { [variable: string]: { [operator: string]: string | string[] | number | boolean } } /** Groups multiple simple conditions with a logical AND or OR. */ export type BotGroupCondition = { $and?: BotSimpleCondition[] $or?: BotSimpleCondition[] } export type BotCondition = BotSimpleCondition | BotGroupCondition export type BotRule = { title: string actions: BotAction[] conditions: BotCondition[] fallbackActions: BotAction[] data?: Record } export type BotContext = { name: string /** Map of event type to ordered list of rules evaluated when that event fires. */ triggers: Partial> } /** * Map of context IDs to their configuration. * `@INIT`, `@EVERY`, and `@FALLBACK` are always present built-in contexts. * Additional string keys are user-defined context IDs. */ export type BotContexts = { '@INIT': BotContext '@EVERY': BotContext '@FALLBACK': BotContext [contextId: string]: BotContext } // ─── Bot ────────────────────────────────────────────────────────────────────── export type Bot = { id: string name: string data: Record contexts: BotContexts flowJson: BotFlowJson | null settings: BotSettings currentBotVersionId: string | null accountId: string createdAt: string updatedAt: string deletedAt: string | null // relationships currentBotVersion?: BotVersion | null services?: Service[] } export type CreateBotPayload = { name: string data?: Record contexts?: BotContexts flowJson?: BotFlowJson settings?: BotSettings } export type BotRelationships = 'currentBotVersion' | 'services' export type UpdateBotPayload = { name?: string data?: Record contexts?: BotContexts flowJson?: BotFlowJson settings?: BotSettings currentBotVersionId?: string | null }