@opencx/widget-core 4.0.28 → 4.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/api/client.ts","../src/api/api-caller.ts","../src/utils/is-exhaustive.ts","../src/utils/PrimitiveState.ts","../src/utils/Poller.ts","../src/utils/run-catching.ts","../src/context/active-session-polling.ctx.ts","../src/context/contact.ctx.ts","../src/utils/uuid.ts","../src/context/csat.ctx.ts","../src/context/session.ctx.ts","../src/context/message.ctx.ts","../src/context/router.ctx.ts","../src/context/storage.ctx.ts","../src/context/widget.ctx.ts","../src/translation/ar.ts","../src/translation/da.ts","../src/translation/de.ts","../src/translation/en.ts","../src/translation/es.ts","../src/translation/fi.ts","../src/translation/fr.ts","../src/translation/it.ts","../src/translation/nl.ts","../src/translation/no.ts","../src/translation/pl.ts","../src/translation/pt.ts","../src/translation/ro.ts","../src/translation/sv.ts","../src/translation/tr.ts","../src/translation/index.ts"],"sourcesContent":["import createClient, { type Middleware } from 'openapi-fetch';\nimport type { paths } from './schema';\nimport type { components } from './schema';\n\ntype Options = {\n baseUrl: string;\n onRequest?: Middleware['onRequest'];\n onResponse?: Middleware['onResponse'];\n onError?: Middleware['onError'];\n};\n\nconst defaultOnError: Middleware['onError'] = (onErrorOptions) => {\n console.log(onErrorOptions.error);\n};\n\nexport const basicClient = (options: Options) => {\n const client = createClient<paths>({\n baseUrl: options.baseUrl,\n });\n\n const middlewares: Middleware = {\n onRequest: options.onRequest,\n onResponse: options.onResponse,\n onError: options.onError || defaultOnError,\n };\n\n client.use(middlewares);\n return client;\n};\n\nexport type Endpoint = keyof paths;\nexport type Dto = components['schemas'];\n","import { type Dto, type Endpoint, basicClient } from './client';\nimport type { WidgetConfig } from '../types/widget-config';\nimport type {\n ResolveSessionDto,\n SendMessageDto,\n VoteInputDto,\n} from '../types/dtos';\n\nexport class ApiCaller {\n private client: ReturnType<typeof basicClient>;\n private config: WidgetConfig;\n private userToken: string | null = null;\n\n constructor({ config }: { config: WidgetConfig }) {\n this.config = config;\n this.userToken = config.user?.token || null;\n\n const { baseUrl, headers } = this.constructClientOptions(\n config.user?.token,\n );\n this.client = this.createOpenAPIClient({ baseUrl, headers });\n }\n\n private constructClientOptions = (token: string | null | undefined) => {\n const baseUrl =\n import.meta.env.MODE === 'test'\n ? 'http://localhost:8080'\n : this.config.apiUrl || 'https://api.open.cx';\n const headers = {\n 'X-Bot-Token': this.config.token,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: token ? `Bearer ${token}` : undefined,\n };\n\n return { baseUrl, headers };\n };\n\n private createOpenAPIClient = ({\n baseUrl,\n headers,\n }: ReturnType<typeof this.constructClientOptions>) => {\n return basicClient({\n baseUrl,\n onRequest: ({ request }) => {\n Object.entries(headers).forEach(([key, value]) => {\n if (value) {\n request.headers.set(key, value);\n }\n });\n },\n });\n };\n\n setAuthToken = (token: string) => {\n this.userToken = token;\n const { baseUrl, headers } = this.constructClientOptions(token);\n this.client = this.createOpenAPIClient({ baseUrl, headers });\n };\n\n getExternalWidgetConfig = async () => {\n return await this.client.GET('/backend/widget/v2/config', {\n params: { header: { 'X-Bot-Token': this.config.token } },\n });\n };\n\n sendMessage = async (body: SendMessageDto, abortSignal?: AbortSignal) => {\n return await this.client.POST('/backend/widget/v2/chat/send', {\n body,\n signal: abortSignal,\n });\n };\n\n createUnverifiedContact = async (body: Dto['CreateUnverifiedContactDto']) => {\n return await this.client.POST(\n '/backend/widget/v2/contact/create-unverified',\n {\n params: { header: { 'x-bot-token': this.config.token } },\n body,\n },\n );\n };\n\n createSession = async (body: Dto['CreateWidgetSessionDto']) => {\n return await this.client.POST('/backend/widget/v2/create-session', {\n body,\n });\n };\n\n pollSessionAndHistory = async ({\n sessionId,\n lastMessageTimestamp,\n abortSignal,\n }: {\n sessionId: string;\n lastMessageTimestamp?: string;\n abortSignal: AbortSignal;\n }) => {\n const query = lastMessageTimestamp ? { lastMessageTimestamp } : undefined;\n return await this.client.GET('/backend/widget/v2/poll/{sessionId}', {\n params: { path: { sessionId }, query },\n signal: abortSignal,\n });\n };\n\n getSessions = async ({\n cursor,\n filters,\n abortSignal,\n }: {\n cursor: string | undefined;\n filters: Record<string, string>;\n abortSignal?: AbortSignal;\n }) => {\n return await this.client.GET('/backend/widget/v2/sessions', {\n params: { query: { cursor, filters: JSON.stringify(filters) } },\n signal: abortSignal,\n });\n };\n\n /**\n * openapi-fetch usually works fine for file uploads, but this time around it parses the payload in a weird way and results in 413 errors (payload too large)\n * Anyway, good old XHR even does it better with progress events\n */\n uploadFile = async ({\n file,\n abortSignal,\n onProgress,\n }: {\n file: File;\n abortSignal: AbortSignal;\n onProgress?: (percentage: number) => void;\n }): Promise<Dto['UploadWidgetFileResponseDto']> => {\n return new Promise((resolve, reject) => {\n const formData = new FormData();\n formData.append('file', file);\n\n const xhr = new XMLHttpRequest();\n\n // Set up abort functionality\n if (abortSignal) {\n abortSignal.addEventListener('abort', () => {\n xhr.abort();\n reject(new DOMException('Aborted', 'AbortError'));\n });\n\n // If already aborted, reject immediately\n if (abortSignal.aborted) {\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n }\n\n xhr.upload.addEventListener('progress', (event) => {\n if (event.lengthComputable && onProgress) {\n const percentage = Math.round((event.loaded / event.total) * 100);\n onProgress(percentage);\n }\n });\n\n // Handle completion\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n const data = JSON.parse(xhr.responseText);\n resolve(data);\n } catch (error) {\n reject(new Error(`Failed to parse response: ${error}`));\n }\n } else {\n reject(new Error(`Upload failed with status: ${xhr.status}`));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new Error('Network error occurred'));\n });\n\n xhr.addEventListener('timeout', () => {\n reject(new Error('Upload timed out'));\n });\n\n const { baseUrl } = this.constructClientOptions(this.userToken);\n\n const path = '/backend/widget/v2/upload' satisfies Endpoint;\n const uploadUrl = `${baseUrl}${path}`;\n xhr.open('POST', uploadUrl);\n\n xhr.setRequestHeader('X-Bot-Token', this.config.token);\n const userToken = this.userToken ?? this.config.user?.token;\n if (userToken) {\n xhr.setRequestHeader('Authorization', `Bearer ${this.userToken}`);\n } else {\n console.error('User token not set');\n }\n\n xhr.send(formData);\n });\n };\n\n vote = async (body: VoteInputDto) => {\n return await this.client.POST('/backend/widget/v2/chat/vote', { body });\n };\n\n resolveSession = async (\n body: ResolveSessionDto,\n abortSignal?: AbortSignal,\n ) => {\n return await this.client.POST('/backend/widget/v2/session/resolve', {\n body,\n signal: abortSignal,\n });\n };\n\n createStateCheckpoint = async (\n body: Dto['WidgetCreateStateCheckpointInputDto'],\n ) => {\n return await this.client.POST('/backend/widget/v2/checkpoint', {\n body,\n });\n };\n\n submitCsat = async (body: Dto['WidgetSubmitCsatInputDto']) => {\n return await this.client.POST('/backend/widget/v2/submit-csat', { body });\n };\n}\n","export function isExhaustive(value: never, funcName: string) {\n console.error(`Missing case for ${value} in ${funcName}`);\n}\n","import isEqual from 'lodash.isequal';\n\nexport type Subscriber<T> = (data: T) => void;\n\nexport class PrimitiveState<S> {\n private subscribers = new Set<Subscriber<S>>();\n private state: S;\n private initialState: S;\n\n constructor(state: S) {\n this.state = state;\n this.initialState = state;\n }\n\n get = (): S => this.state;\n\n set = (newState: S): void => {\n if (!isEqual(this.state, newState)) {\n this.state = newState;\n this.notifySubscribers(newState);\n }\n };\n\n setPartial = (_s: Partial<S>): void => {\n if (_s === undefined || _s === null) return;\n const newState = { ...this.state, ..._s };\n this.set(newState);\n };\n\n reset = (): void => {\n this.set(this.initialState);\n };\n\n private notifySubscribers = (state: S) => {\n const subscribersArray = Array.from(this.subscribers);\n subscribersArray.forEach((callback) => {\n try {\n callback(state);\n } catch (error) {\n if (import.meta.env.MODE !== 'test') {\n console.error(error);\n }\n }\n });\n };\n\n subscribe = (callback: Subscriber<S>): (() => void) => {\n this.subscribers.add(callback);\n\n return () => {\n this.subscribers.delete(callback);\n };\n };\n}\n","import { PrimitiveState } from './PrimitiveState';\n\nexport type PollingState = {\n isPolling: boolean;\n isError: boolean;\n};\n\nexport class Poller {\n state = new PrimitiveState<PollingState>({\n isPolling: false,\n isError: false,\n });\n private abortController = new AbortController();\n\n reset = () => {\n this.abortController.abort('Resetting poller');\n this.stopPolling?.();\n this.stopPolling = null;\n };\n\n private stopPolling: (() => void) | null = null;\n\n startPolling = (\n cb: (abortSignal: AbortSignal) => Promise<void>,\n intervalMs: number,\n ) => {\n if (this.stopPolling) return;\n\n const timeouts: NodeJS.Timeout[] = [];\n\n const poll = async () => {\n this.abortController = new AbortController();\n this.state.setPartial({ isPolling: true });\n\n try {\n await cb(this.abortController.signal);\n } catch (error) {\n if (this.abortController.signal.aborted) {\n // If aborted, just return and do not schedule the nest poll\n return;\n }\n console.error('Failed to poll:', error);\n this.state.setPartial({ isError: true });\n } finally {\n this.state.setPartial({ isPolling: false });\n }\n\n // Another check to stop scheduling polls in case someone removes the early return in the catch above\n if (this.abortController.signal.aborted) {\n console.log('Poller aborted, not scheduling anymore');\n } else {\n timeouts.push(setTimeout(poll, intervalMs));\n }\n };\n\n poll();\n\n this.stopPolling = () => {\n timeouts.forEach(clearTimeout);\n this.state.reset();\n };\n };\n}\n","export function run<T>(fn: () => T): T {\n return fn();\n}\n\nexport type Result<T, E> =\n | { data: T; error?: undefined }\n | { data?: undefined; error: E };\n\n/**\n * Many thanks to @m-tabaza for this utility... Kotlin vibes\n */\nexport function runCatching<T, E = unknown>(\n callback: () => Promise<T>,\n): Promise<Result<T, E>>;\nexport function runCatching<T, E = unknown>(callback: () => T): Result<T, E>;\nexport function runCatching<T, E = unknown>(\n callback: () => T | Promise<T>,\n): Result<T, E> | Promise<Result<T, E>> {\n try {\n const result = callback();\n\n if (result instanceof Promise) {\n return result.then((data) => ({ data })).catch((error: E) => ({ error }));\n }\n\n return { data: result };\n } catch (error) {\n return { error: error as E };\n }\n}\n","import type { ApiCaller } from '../api/api-caller';\nimport type { ActionCallDto, MessageDto } from '../types/dtos';\nimport {\n type WidgetMessageU,\n type WidgetSystemMessageU,\n} from '../types/messages';\nimport type { WidgetConfig } from '../types/widget-config';\nimport { isExhaustive } from '../utils/is-exhaustive';\nimport { Poller } from '../utils/Poller';\nimport { runCatching } from '../utils/run-catching';\nimport type { MessageCtx } from './message.ctx';\nimport type { SessionCtx } from './session.ctx';\n\nexport class ActiveSessionPollingCtx {\n private api: ApiCaller;\n private config: WidgetConfig;\n private sessionCtx: SessionCtx;\n private messageCtx: MessageCtx;\n private sessionPollingIntervalSeconds: number;\n\n private poller = new Poller();\n private fetchSessionAndFullHistoryAbortController = new AbortController();\n\n constructor({\n api,\n config,\n sessionCtx,\n messageCtx,\n sessionPollingIntervalSeconds,\n }: {\n api: ApiCaller;\n config: WidgetConfig;\n sessionCtx: SessionCtx;\n messageCtx: MessageCtx;\n sessionPollingIntervalSeconds: number;\n }) {\n this.api = api;\n this.config = config;\n this.sessionCtx = sessionCtx;\n this.messageCtx = messageCtx;\n this.sessionPollingIntervalSeconds = sessionPollingIntervalSeconds;\n\n this.registerPolling();\n }\n\n private registerPolling = () => {\n this.sessionCtx.sessionState.subscribe(({ session }) => {\n if (session?.id) {\n this.poller.startPolling(async (abortSignal) => {\n this.fetchSessionAndHistory({ sessionId: session.id, abortSignal });\n }, this.sessionPollingIntervalSeconds * 1000);\n } else {\n this.poller.reset();\n }\n });\n\n /**\n * When session is closed... fetch the whole history... because of some race conditions that might happen.\n *\n * example:\n * - the csat_requested system message is sometimes inserted in db before the AI's response, but the AI's response might sometimes arrive before the polling's response, which makes the `lastMessageTimestamp` greater than the csat_requested system message's timestamp... so it's never polled in that case\n */\n this.sessionCtx.sessionState.subscribe(({ session }) => {\n if (session?.id && !session.isOpened) {\n try {\n this.fetchSessionAndFullHistoryAbortController =\n new AbortController();\n this.fetchSessionAndHistory({\n sessionId: session.id,\n abortSignal: this.fetchSessionAndFullHistoryAbortController.signal,\n fetchFullHistory: true,\n });\n } catch (error) {\n if (!this.fetchSessionAndFullHistoryAbortController.signal.aborted) {\n console.error('Failed to fetch session and full history:', error);\n }\n }\n } else {\n this.fetchSessionAndFullHistoryAbortController.abort();\n }\n });\n };\n\n fetchSessionAndHistory = async ({\n sessionId,\n abortSignal,\n fetchFullHistory = false,\n }: {\n sessionId: string;\n abortSignal: AbortSignal;\n fetchFullHistory?: boolean;\n }): Promise<void> => {\n /**\n * This is a bit of an implicit contract... there are two cases here\n * 1. If there are no messages in state, it means the user selected a previous session from the sessions screen and got routed to the chat,\n * in this case, we want to show a loading indicator until the initial fetch is done\n * 2. There is a single message in state, which is the optimistically rendered user message,\n * in this case, we don't want to show a loading indicator\n */\n if (this.messageCtx.state.get().messages.length === 0) {\n this.messageCtx.state.setPartial({ isInitialFetchLoading: true });\n }\n\n const messages = this.messageCtx.state.get().messages;\n const lastMessageTimestamp =\n messages.length > 0\n ? (messages[messages.length - 1]?.timestamp ?? undefined)\n : undefined;\n\n const { data } = await this.api.pollSessionAndHistory({\n sessionId,\n abortSignal,\n lastMessageTimestamp: fetchFullHistory ? undefined : lastMessageTimestamp,\n });\n\n if (data?.session) {\n this.sessionCtx.sessionState.setPartial({ session: data.session });\n this.sessionCtx.setSessions([data.session]);\n }\n\n if (data?.history && data.history.length > 0) {\n // Get a fresh reference to current messages after the poll is done\n const prevMessages = this.messageCtx.state.get().messages;\n const newMessages = data.history\n .map(this.mapHistoryToMessage)\n .filter((msg): msg is WidgetMessageU => msg !== null)\n .filter(\n (newMsg) =>\n !prevMessages.some((existingMsg) => existingMsg.id === newMsg.id),\n );\n this.messageCtx.state.setPartial({\n messages: [...prevMessages, ...newMessages],\n });\n }\n\n if (this.messageCtx.state.get().isInitialFetchLoading) {\n this.messageCtx.state.setPartial({ isInitialFetchLoading: false });\n }\n };\n\n mapHistoryToMessage = (history: MessageDto): WidgetMessageU | null => {\n const commonFields = {\n id: history.publicId,\n timestamp: history.sentAt || '',\n attachments: history.attachments || undefined,\n };\n\n if (history.sender.kind === 'user') {\n return {\n ...commonFields,\n type: 'USER',\n content: history.content.text || '',\n deliveredAt: history.sentAt || '',\n };\n }\n\n if (history.sender.kind === 'agent') {\n return {\n ...commonFields,\n type: 'AGENT',\n component: 'agent_message',\n data: {\n message: history.content.text || '',\n },\n agent: {\n name: history.sender.name || '',\n avatar: history.sender.avatar || '',\n id: null,\n isAi: false,\n },\n };\n }\n\n if (history.sender.kind === 'ai') {\n const action =\n history.actionCalls && history.actionCalls.length > 0\n ? history.actionCalls[history.actionCalls.length - 1]\n : undefined;\n\n return {\n ...commonFields,\n type: 'AI',\n component: 'bot_message',\n agent: {\n id: null,\n name: this.config.bot?.name || '',\n isAi: true,\n avatar: this.config.bot?.avatar || '',\n },\n data: {\n message: history.content.text || '',\n action: action\n ? {\n name: action.actionName,\n data: this.extractActionResult(action),\n }\n : undefined,\n },\n };\n }\n\n if (history.sender.kind === 'system') {\n const message = this.constructSystemMessage(history);\n if (message === null) return null;\n\n return { ...message };\n }\n\n return null;\n };\n\n constructSystemMessage = (\n history: MessageDto,\n ): WidgetSystemMessageU | null => {\n if (!history || !history.systemMessagePayload) return null;\n switch (history.systemMessagePayload.type) {\n case 'state_checkpoint':\n return {\n id: history.publicId,\n type: 'SYSTEM',\n subtype: 'state_checkpoint',\n data: { payload: history.systemMessagePayload.payload },\n timestamp: history.sentAt || '',\n attachments: undefined,\n };\n case 'csat_requested':\n return {\n id: history.publicId,\n type: 'SYSTEM',\n subtype: 'csat_requested',\n data: { payload: undefined },\n timestamp: history.sentAt || '',\n attachments: undefined,\n };\n case 'csat_submitted':\n return {\n id: history.publicId,\n type: 'SYSTEM',\n subtype: 'csat_submitted',\n data: {\n payload: {\n score: history.systemMessagePayload.payload.score ?? undefined,\n feedback:\n history.systemMessagePayload.payload.feedback ?? undefined,\n },\n },\n timestamp: history.sentAt || '',\n attachments: undefined,\n };\n case 'none':\n return null;\n default:\n isExhaustive(\n history.systemMessagePayload,\n this.constructSystemMessage.name,\n );\n return null;\n }\n };\n\n extractActionResult = (action: ActionCallDto) => {\n const result = action.result;\n\n if (result === null) return result;\n if (typeof result !== 'object') return result;\n\n if (\n 'responseBodyText' in result &&\n typeof result.responseBodyText === 'string'\n ) {\n const responseBodyText = result.responseBodyText;\n const parsed = runCatching(() => JSON.parse(responseBodyText)).data;\n if (parsed) return parsed;\n }\n\n return action.result;\n };\n}\n","import { PrimitiveState } from '../utils/PrimitiveState';\nimport { ApiCaller } from '../api/api-caller';\nimport { type WidgetConfig } from '../types/widget-config';\nimport { type Dto } from '../api/client';\nimport type { StorageCtx } from './storage.ctx';\nimport { v4 } from 'uuid';\n\ntype ContactState = {\n contact: {\n token: string;\n externalId: string | undefined;\n } | null;\n extraCollectedData: Record<string, string> | undefined;\n isCreatingUnverifiedContact: boolean;\n isErrorCreatingUnverifiedContact: boolean;\n};\n\nexport class ContactCtx {\n private config: WidgetConfig;\n private storageCtx?: StorageCtx;\n private api: ApiCaller;\n state: PrimitiveState<ContactState>;\n\n constructor({\n config,\n api,\n storageCtx,\n }: {\n api: ApiCaller;\n config: WidgetConfig;\n storageCtx?: StorageCtx;\n }) {\n this.config = config;\n this.storageCtx = storageCtx;\n this.api = api;\n\n this.state = new PrimitiveState<ContactState>({\n contact: config.user?.token\n ? {\n token: config.user.token,\n // Set optional externalId from config... not local storage\n externalId: config.user.externalId,\n }\n : null,\n extraCollectedData: undefined,\n isCreatingUnverifiedContact: false,\n isErrorCreatingUnverifiedContact: false,\n });\n\n this.autoCreateUnverifiedUserIfNotExists();\n }\n\n shouldCollectData = (): boolean => {\n if (!this.state.get().contact?.token && this.config.collectUserData) {\n return true;\n }\n return false;\n };\n\n private autoCreateUnverifiedUserIfNotExists = async () => {\n /**\n * If token is passed in config... we consider it as a verified user and do nothing (we don't force generate an externalId)\n * If a non-verified user take their token and place it in the config... the backend will refuse their requests saying that a non-verified token must have an externalId to create and get sessions\n */\n if (this.config.user?.token) return;\n\n /**\n * If collectUserData is true... we check if the user entered their credentials before, otherwise, show them the welcome screen so they can enter their credentials\n */\n if (this.config.collectUserData && !this.config.user?.data?.email) {\n /**\n * If extra data collection fields are passed,\n * we do not check for a persisted token.\n * This will force the contact to enter the extra data fields every time they visit the page.\n */\n if (this.config.extraDataCollectionFields?.length) {\n return;\n }\n\n const persistedToken = await this.storageCtx?.getContactToken();\n if (persistedToken) {\n await this.setUnverifiedContact(persistedToken);\n }\n // return early whether there is a persisted token or not\n return;\n }\n\n /**\n * If there is no email, then it is an anonymous contact, we check if the contact is persisted or we create a new one\n */\n if (!this.config.user?.data?.email) {\n const persistedToken = await this.storageCtx?.getContactToken();\n if (persistedToken) {\n await this.setUnverifiedContact(persistedToken);\n // return early only if there is a persisted token\n return;\n }\n }\n\n /**\n * If we reach here... then it is one of two\n * 1. There is an email passed in the config, let's just upsert the unverified contact without checking for persistence; maybe the email in the config did change.\n * 2. It is an anonymous contact (without an email) using this device for the first time.\n *\n * This is still safe even if the email in the config is tampered with by the contact, because there is a client-side externalId that will be generated for the current device...\n * So, only sessions created on this device will be accessible.\n */\n await this.createUnverifiedContact({\n email: this.config.user?.data?.email,\n non_verified_name: this.config.user?.data?.name,\n non_verified_custom_data: this.config.user?.data?.customData,\n });\n };\n\n createUnverifiedContact = async (\n payload: Dto['CreateUnverifiedContactDto'],\n extraCollectedData?: Record<string, string>,\n ): Promise<void> => {\n this.state.setPartial({ extraCollectedData });\n\n try {\n this.state.setPartial({\n isCreatingUnverifiedContact: true,\n isErrorCreatingUnverifiedContact: false,\n });\n\n const { data } = await this.api.createUnverifiedContact(payload);\n if (data?.token) {\n await this.setUnverifiedContact(data.token);\n } else {\n this.state.setPartial({ isErrorCreatingUnverifiedContact: true });\n }\n } finally {\n this.state.setPartial({ isCreatingUnverifiedContact: false });\n }\n };\n\n setUnverifiedContact = async (token: string) => {\n const persistedExternalId = await this.storageCtx?.getExternalContactId();\n /** Give priority to `externalId` from the config */\n const externalId: string =\n this.config.user?.externalId || persistedExternalId || v4();\n this.api.setAuthToken(token);\n // Set token in state after setting the token in the api handler\n await this.storageCtx?.setContactToken(token);\n await this.storageCtx?.setExternalContactId(externalId);\n this.state.setPartial({ contact: { token, externalId } });\n };\n}\n","import { v4 as uuidv4 } from 'uuid';\n\nexport function genUuid() {\n return uuidv4();\n}\n","import type { ApiCaller } from '../api/api-caller';\nimport type { Dto } from '../api/client';\nimport type { SafeOmit } from '../types/helpers';\nimport type { WidgetConfig } from '../types/widget-config';\nimport { genUuid } from '../utils/uuid';\nimport type { MessageCtx } from './message.ctx';\nimport type { SessionCtx } from './session.ctx';\n\nexport class CsatCtx {\n private config: WidgetConfig;\n private api: ApiCaller;\n private sessionCtx: SessionCtx;\n private messageCtx: MessageCtx;\n\n constructor({\n config,\n api,\n sessionCtx,\n messageCtx,\n }: {\n config: WidgetConfig;\n api: ApiCaller;\n sessionCtx: SessionCtx;\n messageCtx: MessageCtx;\n }) {\n this.config = config;\n this.api = api;\n this.sessionCtx = sessionCtx;\n this.messageCtx = messageCtx;\n }\n\n submitCsat = async (\n body: Pick<Dto['WidgetSubmitCsatInputDto'], 'score' | 'feedback'>,\n ) => {\n const currentSessionId = this.sessionCtx.sessionState.get().session?.id;\n if (!currentSessionId) {\n return { data: null, error: 'No session id found' };\n }\n\n const uuid = genUuid();\n this.messageCtx.state.setPartial({\n messages: [\n ...this.messageCtx.state.get().messages,\n {\n id: uuid,\n type: 'SYSTEM',\n subtype: 'csat_submitted',\n timestamp: new Date().toISOString(),\n data: {\n payload: {\n score: body.score,\n feedback: body.feedback,\n },\n },\n },\n ],\n });\n\n const { data, error } = await this.api.submitCsat({\n ...body,\n system_message_uuid: uuid,\n session_id: currentSessionId,\n });\n return { data, error };\n };\n}\n","import type { ApiCaller } from '../api/api-caller';\nimport type { Dto } from '../api/client';\nimport type { SessionDto } from '../types/dtos';\nimport type { WidgetConfig } from '../types/widget-config';\nimport { Poller } from '../utils/Poller';\nimport { PrimitiveState } from '../utils/PrimitiveState';\nimport { runCatching } from '../utils/run-catching';\nimport type { ContactCtx } from './contact.ctx';\n\ntype SessionState = {\n /**\n * The currently selected session.\n * Can be null if no session is selected, or if in chat screen and the session is not created yet.\n */\n session: SessionDto | null;\n isCreatingSession: boolean;\n isResolvingSession: boolean;\n};\ntype SessionsState = {\n /** List of all user sessions */\n data: SessionDto[];\n /** A cursor to get the next page of sessions */\n cursor: string | undefined;\n /** Indicates if no more pages are left */\n isLastPage: boolean;\n /** Did fetch for the first time */\n didStartInitialFetch: boolean;\n isInitialFetchLoading: boolean;\n};\n\nexport class SessionCtx {\n private config: WidgetConfig;\n private api: ApiCaller;\n private contactCtx: ContactCtx;\n private sessionsPollingIntervalSeconds: number;\n private sessionsRefresher = new Poller();\n\n public sessionState = new PrimitiveState<SessionState>({\n session: null,\n isCreatingSession: false,\n isResolvingSession: false,\n });\n public sessionsState = new PrimitiveState<SessionsState>({\n data: [],\n cursor: undefined,\n isLastPage: false,\n didStartInitialFetch: false,\n /**\n * Initialize this as `true` so it always starts loading until the first fetch is done\n */\n isInitialFetchLoading: true,\n });\n\n constructor({\n config,\n api,\n contactCtx,\n sessionsPollingIntervalSeconds,\n }: {\n config: WidgetConfig;\n api: ApiCaller;\n contactCtx: ContactCtx;\n sessionsPollingIntervalSeconds: number;\n }) {\n this.config = config;\n this.api = api;\n this.contactCtx = contactCtx;\n this.sessionsPollingIntervalSeconds = sessionsPollingIntervalSeconds;\n\n this.registerSessionsRefresherWrapper();\n }\n\n /** Clears the session and stops polling */\n reset = async () => {\n // Reset the session only, leave sessions as-is\n this.sessionState.reset();\n };\n\n private registerSessionsRefresherWrapper = () => {\n if (\n // If the widget config was initially provided with a contact token, no state change would be triggered, so we just fetch\n this.contactCtx.state.get().contact?.token &&\n !this.sessionsState.get().didStartInitialFetch\n ) {\n this.registerSessionsRefresher();\n } else {\n // In other cases where auto authenticate is fired, the token would be eventually set in state, so we wait for it\n this.contactCtx.state.subscribe(({ contact }) => {\n if (contact?.token && !this.sessionsState.get().didStartInitialFetch) {\n this.registerSessionsRefresher();\n }\n });\n }\n };\n\n private registerSessionsRefresher = () => {\n this.sessionsRefresher.startPolling(async () => {\n if (this.sessionsState.get().didStartInitialFetch === false) {\n this.sessionsState.setPartial({ didStartInitialFetch: true });\n }\n\n await this.refreshSessions();\n\n if (this.sessionsState.get().isInitialFetchLoading === true) {\n this.sessionsState.setPartial({ isInitialFetchLoading: false });\n }\n }, this.sessionsPollingIntervalSeconds * 1000);\n };\n\n private getParsedCustomData =\n (): Dto['CreateWidgetSessionDto']['customData'] => {\n return Object.fromEntries<\n NonNullable<Dto['CreateWidgetSessionDto']['customData']>[string]\n >(\n Object.entries(this.config.sessionCustomData || {}).map(\n ([key, value]) => {\n if (typeof value === 'string') return [key, value];\n if (typeof value === 'boolean') return [key, value];\n if (typeof value === 'number') return [key, value];\n // TODO maybe better to unnest instead of stringify-ing\n return [key, runCatching(() => JSON.stringify(value))?.data || ''];\n },\n ),\n );\n };\n\n createSession = async () => {\n this.sessionState.setPartial({ session: null, isCreatingSession: true });\n\n const externalId = this.contactCtx.state.get().contact?.externalId;\n\n const customData: Dto['CreateWidgetSessionDto']['customData'] = {\n ...this.getParsedCustomData(),\n ...(externalId ? { external_id: externalId } : {}),\n };\n const { data: session, error } = await this.api.createSession({\n customData: Object.keys(customData).length > 0 ? customData : undefined,\n });\n if (session) {\n this.sessionState.setPartial({ session, isCreatingSession: false });\n return session;\n }\n\n this.sessionState.setPartial({ isCreatingSession: false });\n console.error('Failed to create session:', error);\n return null;\n };\n\n loadMoreSessions = async () => {\n if (this.sessionsState.get().isLastPage) return;\n\n const { data } = await this.getSessions({\n cursor: this.sessionsState.get().cursor,\n });\n\n if (data) {\n const allSessions = [...this.sessionsState.get().data, ...data.items];\n // TODO sort by updated at\n const deduped = allSessions.filter(\n (s, i, self) => i === self.findIndex((_s) => s.id === _s.id),\n );\n\n this.sessionsState.setPartial({\n data: deduped,\n cursor: data.next || undefined,\n isLastPage: data.next === null,\n });\n }\n };\n\n private getSessions = async ({ cursor }: { cursor: string | undefined }) => {\n if (!this.contactCtx.state.get().contact?.token) return { data: null };\n\n const externalId = this.contactCtx.state.get().contact?.externalId;\n return await this.api.getSessions({\n cursor,\n filters: externalId\n ? {\n external_id: externalId,\n }\n : {},\n });\n };\n\n setSessions = (data: SessionDto[]) => {\n const sessions = [...data, ...this.sessionsState.get().data].filter(\n (s, i, self) => i === self.findIndex((_s) => s.id === _s.id),\n );\n this.sessionsState.setPartial({ data: sessions });\n };\n\n refreshSessions = async () => {\n // Get the first page only (pass no `cursor`)\n const { data } = await this.getSessions({ cursor: undefined });\n if (!data) return;\n this.setSessions(data.items);\n };\n\n resolveSession = async () => {\n const currentSession = this.sessionState.get().session;\n if (!currentSession || !currentSession.isOpened) {\n return { success: false, error: 'Session is not opened' } as const;\n }\n\n this.sessionState.setPartial({ isResolvingSession: true });\n\n const { data: session, error } = await this.api.resolveSession({\n session_id: currentSession.id,\n });\n\n if (session) {\n this.sessionState.setPartial({ session, isResolvingSession: false });\n return { success: true, data: session } as const;\n }\n\n this.sessionState.setPartial({ isResolvingSession: false });\n return { success: false, error } as const;\n };\n\n createStateCheckpoint = async (\n payload: Dto['WidgetCreateStateCheckpointInputDto']['payload'],\n ) => {\n const session_id = this.sessionState.get().session?.id;\n if (!session_id) return;\n\n const { data, error } = await this.api.createStateCheckpoint({\n session_id,\n payload,\n });\n\n if (data?.success) return { success: true } as const;\n\n return { success: false } as const;\n };\n}\n","import { ApiCaller } from '../api/api-caller';\nimport type { WidgetConfig } from '../types/widget-config';\nimport {\n type WidgetAiMessage,\n type WidgetMessageU,\n type WidgetUserMessage,\n} from '../types/messages';\nimport type {\n MessageAttachmentType,\n SendMessageDto,\n SendMessageOutputDto,\n} from '../types/dtos';\nimport { PrimitiveState } from '../utils/PrimitiveState';\nimport { genUuid } from '../utils/uuid';\nimport { SessionCtx } from './session.ctx';\nimport type { ContactCtx } from './contact.ctx';\n\ntype MessageCtxState = {\n messages: WidgetMessageU[];\n /** Regardless of assignee */\n isSendingMessage: boolean;\n isSendingMessageToAI: boolean;\n lastAIResMightSolveUserIssue: boolean;\n isInitialFetchLoading: boolean;\n};\n\nexport class MessageCtx {\n private config: WidgetConfig;\n private api: ApiCaller;\n private contactCtx: ContactCtx;\n private sessionCtx: SessionCtx;\n\n public state = new PrimitiveState<MessageCtxState>({\n messages: [],\n isSendingMessage: false,\n isSendingMessageToAI: false,\n lastAIResMightSolveUserIssue: false,\n isInitialFetchLoading: false,\n });\n\n private sendMessageAbortController = new AbortController();\n\n constructor({\n config,\n api,\n sessionCtx,\n contactCtx,\n }: {\n config: WidgetConfig;\n api: ApiCaller;\n sessionCtx: SessionCtx;\n contactCtx: ContactCtx;\n }) {\n this.config = config;\n this.api = api;\n this.sessionCtx = sessionCtx;\n this.contactCtx = contactCtx;\n }\n\n reset = () => {\n this.sendMessageAbortController.abort('Resetting chat');\n this.state.reset();\n };\n\n sendMessage = async (input: {\n content: SendMessageDto['content'];\n attachments?: SendMessageDto['attachments'];\n customData?: SendMessageDto['custom_data'];\n exitModePrompt?: string;\n }): Promise<void> => {\n try {\n /* ------------------------------------------------------ */\n /* Prevent sending if there is no content */\n /* ------------------------------------------------------ */\n if (\n !input.content.trim() &&\n (!input.attachments || input.attachments.length === 0)\n ) {\n console.warn(\n 'Cannot send an empty message of no content or attachments',\n );\n return;\n }\n /* ------------------------------------------------------ */\n /* Prevent sending while waiting for AI res */\n /* ------------------------------------------------------ */\n const session = this.sessionCtx.sessionState.get().session;\n const assignee = session?.assignee.kind;\n const isAssignedToAI = assignee === 'ai';\n const isSendingToAI = this.state.get().isSendingMessageToAI;\n const lastMessage = this.state.get().messages.at(-1);\n if (\n isSendingToAI ||\n // If last message is from user, then bot response did not arrive yet\n (isAssignedToAI && lastMessage?.type === 'USER')\n ) {\n console.warn('Cannot send messages while awaiting AI response');\n return;\n }\n\n /* ------------------------------------------------------ */\n /* Start */\n /* ------------------------------------------------------ */\n this.sendMessageAbortController = new AbortController();\n this.state.setPartial({\n lastAIResMightSolveUserIssue: false,\n isSendingMessage: true,\n isSendingMessageToAI: !!isAssignedToAI || !session,\n });\n /* ------------------------------------------------------ */\n /* Optimistically add message to rendered messages */\n /* ------------------------------------------------------ */\n const currentMessages = this.state.get().messages;\n const shouldInsertInitialMessages =\n !this.sessionCtx.sessionState.get().session?.id &&\n currentMessages.length === 0 &&\n this.config.advancedInitialMessages?.some((m) => m.persistent);\n const insertableInitialMessages = shouldInsertInitialMessages\n ? (this.config.advancedInitialMessages || [])\n .filter((m) => m.persistent)\n .map(\n (m) =>\n ({\n id: genUuid(),\n component: 'bot_message',\n type: 'AI',\n timestamp: new Date().toISOString(),\n data: {\n message: m.message,\n },\n }) satisfies WidgetAiMessage,\n )\n : [];\n const userMessage = this.toUserMessage(\n input.content.trim(),\n input.attachments || undefined,\n );\n this.state.setPartial({\n messages: [\n ...insertableInitialMessages,\n ...currentMessages,\n userMessage,\n ],\n });\n\n /* ------------------------------------------------------ */\n /* Create session if not exists */\n /* ------------------------------------------------------ */\n if (!this.sessionCtx.sessionState.get().session?.id) {\n const createdSession = await this.sessionCtx.createSession();\n\n // TODO: apply some retry logic here\n if (!createdSession) {\n console.error('Failed to create session');\n return;\n }\n\n // Refresh sessions list instantly to get the newly created session in the sessions list\n void this.sessionCtx.refreshSessions();\n }\n const sessionId = this.sessionCtx.sessionState.get().session?.id;\n if (!sessionId) return;\n /* ------------------------------------------------------ */\n /* Send and wait for bot response */\n /* ------------------------------------------------------ */\n const { data } = await this.api.sendMessage(\n {\n uuid: userMessage.id,\n bot_token: this.config.token,\n headers: this.config.headers,\n query_params: this.config.queryParams,\n body_properties: this.config.bodyProperties,\n session_id: sessionId,\n content: userMessage.content,\n attachments: input.attachments,\n clientContext: this.config.context,\n custom_data: {\n ...(this.config.messageCustomData || {}),\n ...(input.customData || {}),\n },\n language: this.config.language,\n exit_mode_prompt: input.exitModePrompt,\n initial_messages: shouldInsertInitialMessages\n ? insertableInitialMessages.map((m) => ({\n uuid: m.id,\n content: m.data.message,\n }))\n : undefined,\n },\n this.sendMessageAbortController.signal,\n );\n\n if (data?.success) {\n /* ------------------------------------------------------ */\n /* Append bot reply if not fetched from polling */\n /* ------------------------------------------------------ */\n const botMessage = this.toBotMessage(data);\n if (botMessage) {\n const prevMessages = this.state.get().messages;\n const shouldAppend = !prevMessages.some(\n (m) => m.id === botMessage.id,\n );\n if (!shouldAppend) {\n this.state.setPartial({\n lastAIResMightSolveUserIssue:\n data.autopilotResponse?.mightSolveUserIssue ||\n data.uiResponse?.mightSolveUserIssue,\n });\n return;\n }\n this.state.setPartial({\n messages: [...prevMessages, botMessage],\n lastAIResMightSolveUserIssue:\n data.autopilotResponse?.mightSolveUserIssue ||\n data.uiResponse?.mightSolveUserIssue,\n });\n }\n if (data.session) {\n this.sessionCtx.sessionState.setPartial({ session: data.session });\n }\n } else {\n const errorMessage = this.toBotErrorMessage(\n data?.error?.message || 'Something went wrong. Please refresh the page or try again.',\n );\n const currentMessages = this.state.get().messages;\n this.state.setPartial({\n messages: [...currentMessages, errorMessage],\n });\n }\n } catch (error) {\n if (!this.sendMessageAbortController.signal.aborted) {\n console.error('Failed to send message:', error);\n }\n } finally {\n this.state.setPartial({\n isSendingMessage: false,\n isSendingMessageToAI: false,\n });\n }\n };\n\n private toUserMessage = (\n content: string,\n attachments?: MessageAttachmentType[],\n ): WidgetUserMessage => {\n const messageContent = (() => {\n const extraCollectedData = this.contactCtx.state.get().extraCollectedData;\n // Prepend extra collected data if this is the first message in the session\n if (\n this.state.get().messages.length === 0 &&\n extraCollectedData &&\n Object.keys(extraCollectedData).length > 0\n ) {\n const data = Object.entries(extraCollectedData)\n .filter(([_, value]) => !!value)\n .map(([key, value]) => `${key}: ${value}`)\n .join(' \\n');\n return `${data} \\n\\n${content}`;\n }\n\n return content;\n })();\n\n return {\n id: genUuid(),\n type: 'USER',\n content: messageContent,\n deliveredAt: new Date().toISOString(),\n attachments,\n timestamp: new Date().toISOString(),\n };\n };\n\n private toBotMessage = (\n response: SendMessageOutputDto,\n ): WidgetAiMessage | null => {\n if (response.success && response.autopilotResponse) {\n return {\n type: 'AI',\n id: response.autopilotResponse.id || genUuid(),\n timestamp: new Date().toISOString(),\n component: 'bot_message',\n agent: this.config.bot\n ? {\n name: this.config.bot.name || '',\n isAi: true,\n avatar: this.config.bot.avatar || '',\n id: null,\n }\n : undefined,\n data: {\n message: response.autopilotResponse.value.content,\n action: response.uiResponse?.value.name\n ? {\n name: response.uiResponse.value.name,\n data: response.uiResponse.value.request_response,\n }\n : undefined,\n },\n };\n }\n\n return null;\n };\n\n private toBotErrorMessage = (message: string): WidgetAiMessage => {\n return {\n type: 'AI',\n id: genUuid(),\n timestamp: new Date().toISOString(),\n component: 'bot_message',\n data: {\n message,\n variant: 'error',\n action: undefined,\n },\n };\n };\n}\n","import type { WidgetConfig } from '../types/widget-config';\nimport { PrimitiveState } from '../utils/PrimitiveState';\nimport type { ContactCtx } from './contact.ctx';\nimport type { SessionCtx } from './session.ctx';\nimport type { WidgetCtx } from './widget.ctx';\n\nexport type ScreenU =\n | /** A welcome screen to collect user data. Useful in public non-logged-in environments */\n 'welcome'\n /** Show a list of the user's previous sessions */\n | 'sessions'\n /** Self-explanatory */\n | 'chat';\n\ntype RouterState = {\n screen: ScreenU;\n};\n\nexport class RouterCtx {\n state: PrimitiveState<RouterState>;\n\n private config: WidgetConfig;\n private contactCtx: ContactCtx;\n private sessionCtx: SessionCtx;\n private resetChat: WidgetCtx['resetChat'];\n\n constructor({\n config,\n contactCtx,\n sessionCtx,\n resetChat,\n }: {\n config: WidgetConfig;\n contactCtx: ContactCtx;\n sessionCtx: SessionCtx;\n resetChat: WidgetCtx['resetChat'];\n }) {\n this.config = config;\n this.contactCtx = contactCtx;\n this.sessionCtx = sessionCtx;\n this.resetChat = resetChat;\n this.state = new PrimitiveState<RouterState>({\n screen: this.contactCtx.shouldCollectData()\n ? 'welcome'\n : this.config.router?.chatScreenOnly\n ? 'chat'\n : 'sessions',\n });\n\n this.registerRoutingListener();\n }\n\n private registerRoutingListener = () => {\n this.contactCtx.state.subscribe(({ contact }) => {\n // Auto navigate to sessions screen after collecting user data\n if (contact?.token && this.state.get().screen === 'welcome') {\n this.state.setPartial({\n screen: this.config.router?.chatScreenOnly ? 'chat' : 'sessions',\n });\n }\n });\n\n this.sessionCtx.sessionsState.subscribe(\n ({ isInitialFetchLoading, data }) => {\n if (\n this.config.router?.chatScreenOnly &&\n // Do not route to a chat if we are currently inside one already\n // This also applies to newly created sessions; the new session will be in `sessionState` before it is refreshed and included in `sessionsState`\n !this.sessionCtx.sessionState.get().session?.id\n ) {\n const mostRecentOpenSessionId = data.find((s) => s.isOpened)?.id;\n return mostRecentOpenSessionId\n ? this.toChatScreen(mostRecentOpenSessionId)\n : undefined;\n }\n\n if (data.length) return;\n if (this.config.router?.goToChatIfNoSessions === false) return;\n\n // Auto navigate to chat screen if contact has no previous sessions\n if (!isInitialFetchLoading && this.state.get().screen !== 'chat') {\n this.toChatScreen();\n }\n },\n );\n };\n\n toSessionsScreen = () => {\n this.resetChat();\n this.state.setPartial({ screen: 'sessions' });\n };\n\n /**\n * @param sessionId The ID of the session to open, or `undefined` if it is a new chat session\n */\n toChatScreen = (sessionId?: string) => {\n this.resetChat();\n\n if (sessionId) {\n const session = this.sessionCtx.sessionsState\n .get()\n .data.find((s) => s.id === sessionId);\n // Do not navigate if session is not found (this shouldn't happen, unless a wrong ID is passed)\n if (!session) return;\n this.sessionCtx.sessionState.setPartial({ session });\n }\n\n this.state.setPartial({ screen: 'chat' });\n };\n}\n","import type { ExternalStorage } from '../types/external-storage';\nimport type { WidgetConfig } from '../types/widget-config';\n\nexport class StorageCtx {\n private storage: ExternalStorage;\n private config: WidgetConfig;\n\n private KEYS = {\n contactToken: (orgToken: string) =>\n `opencx-widget:org-token-${orgToken}:contact-token`,\n externalContactId: (orgToken: string) =>\n `opencx-widget:org-token-${orgToken}:external-contact-id`,\n };\n\n constructor({\n storage,\n config,\n }: {\n storage: ExternalStorage;\n config: WidgetConfig;\n }) {\n this.storage = storage;\n this.config = config;\n }\n\n setContactToken = async (token: string) => {\n await this.storage.set(this.KEYS.contactToken(this.config.token), token);\n };\n getContactToken = async () => {\n return this.storage.get(this.KEYS.contactToken(this.config.token));\n };\n\n setExternalContactId = async (id: string) => {\n await this.storage.set(this.KEYS.externalContactId(this.config.token), id);\n };\n getExternalContactId = async () => {\n return this.storage.get(this.KEYS.externalContactId(this.config.token));\n };\n}\n","import { ApiCaller } from '../api/api-caller';\nimport type { ModeDto } from '../types/dtos';\nimport type { ExternalStorage } from '../types/external-storage';\nimport type { WidgetConfig } from '../types/widget-config';\nimport { ActiveSessionPollingCtx } from './active-session-polling.ctx';\nimport { ContactCtx } from './contact.ctx';\nimport { CsatCtx } from './csat.ctx';\nimport { MessageCtx } from './message.ctx';\nimport { RouterCtx } from './router.ctx';\nimport { SessionCtx } from './session.ctx';\nimport { StorageCtx } from './storage.ctx';\n\nexport class WidgetCtx {\n public config: WidgetConfig;\n public api: ApiCaller;\n\n public contactCtx: ContactCtx;\n public sessionCtx: SessionCtx;\n public messageCtx: MessageCtx;\n public csatCtx: CsatCtx;\n public routerCtx: RouterCtx;\n public storageCtx?: StorageCtx;\n public modes: ModeDto[] = [];\n\n public org: {\n id: string;\n name: string;\n };\n private static pollingIntervalsSeconds: {\n session: number;\n sessions: number;\n } | null = null;\n private activeSessionPollingCtx: ActiveSessionPollingCtx;\n\n private constructor({\n config,\n storage,\n modes,\n org,\n }: {\n config: WidgetConfig;\n storage?: ExternalStorage;\n modes: ModeDto[];\n org: {\n id: string;\n name: string;\n };\n }) {\n if (!WidgetCtx.pollingIntervalsSeconds) {\n throw Error(\n 'Widget polling values are not defined, did you call WidgetCtx.initialize()',\n );\n }\n\n this.config = config;\n this.org = org;\n this.api = new ApiCaller({ config });\n this.storageCtx = storage ? new StorageCtx({ storage, config }) : undefined;\n this.modes = modes;\n\n this.contactCtx = new ContactCtx({\n api: this.api,\n config: this.config,\n storageCtx: this.storageCtx,\n });\n\n this.sessionCtx = new SessionCtx({\n config: this.config,\n api: this.api,\n contactCtx: this.contactCtx,\n sessionsPollingIntervalSeconds:\n WidgetCtx.pollingIntervalsSeconds.sessions,\n });\n\n this.messageCtx = new MessageCtx({\n config: this.config,\n api: this.api,\n sessionCtx: this.sessionCtx,\n contactCtx: this.contactCtx,\n });\n\n this.csatCtx = new CsatCtx({\n config: this.config,\n api: this.api,\n sessionCtx: this.sessionCtx,\n messageCtx: this.messageCtx,\n });\n\n this.activeSessionPollingCtx = new ActiveSessionPollingCtx({\n api: this.api,\n config: this.config,\n sessionCtx: this.sessionCtx,\n messageCtx: this.messageCtx,\n sessionPollingIntervalSeconds: WidgetCtx.pollingIntervalsSeconds.session,\n });\n\n this.routerCtx = new RouterCtx({\n config: this.config,\n contactCtx: this.contactCtx,\n sessionCtx: this.sessionCtx,\n resetChat: this.resetChat,\n });\n }\n\n static initialize = async ({\n config,\n storage,\n }: {\n config: WidgetConfig;\n storage?: ExternalStorage;\n }) => {\n const externalConfig = await new ApiCaller({\n config,\n }).getExternalWidgetConfig();\n\n if (!externalConfig.data) {\n throw new Error('Failed to fetch widget config');\n }\n\n this.pollingIntervalsSeconds = {\n session: externalConfig.data?.sessionPollingIntervalSeconds || 10,\n sessions: externalConfig.data?.sessionsPollingIntervalSeconds || 60,\n };\n\n return new WidgetCtx({\n config,\n storage,\n modes: externalConfig.data?.modes || [],\n org: {\n id: externalConfig.data.org.id,\n name: externalConfig.data.org.name,\n },\n });\n };\n\n resetChat = () => {\n this.sessionCtx.reset();\n this.messageCtx.reset();\n };\n}\n","import type { TranslationInterface } from '.';\n\nexport const ArabicLanguage: TranslationInterface = {\n write_a_message_placeholder: 'اكتب رسالة...',\n your_issue_has_been_resolved: 'تم حل مشكلتك!',\n new_conversation: 'محادثة جديدة',\n welcome_screen_title: 'مرحبًا بك في دردشة الدعم الخاصة بنا',\n welcome_screen_description:\n 'نحن هنا للمساعدة! ابدأ محادثة وسنرد عليك في أقرب وقت ممكن.',\n your_name_placeholder: 'اسمك',\n your_email_placeholder: 'عنوان بريدك الإلكتروني',\n start_chat_button: 'تحدث إلى الدعم',\n start_chat_button_loading: 'جاري الاتصال...',\n i_need_more_help: 'أحتاج المزيد من المساعدة',\n this_was_helpful: 'كان هذا مفيدًا',\n optional: 'اختياري',\n no_conversations_yet: 'لا يوجد محادثات',\n back_to_conversations: 'العودة إلى المحادثات',\n closed_conversations: 'المحادثات المغلقة',\n};\n","import type { TranslationInterface } from '.';\n\nexport const DanishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Skriv en besked...',\n your_issue_has_been_resolved: 'Dit problem er løst!',\n new_conversation: 'Ny samtale',\n welcome_screen_title: 'Velkommen til vores support chat',\n welcome_screen_description:\n 'Vi er her for at hjælpe! Start en samtale, og vi vender tilbage til dig så hurtigt som muligt.',\n your_name_placeholder: 'Dit navn',\n your_email_placeholder: 'Din e-mailadresse',\n start_chat_button: 'Tal med support',\n start_chat_button_loading: 'Forbinder...',\n i_need_more_help: 'Jeg har brug for mere hjælp',\n this_was_helpful: 'Dette var nyttigt',\n optional: 'Valgfrit',\n no_conversations_yet: 'Ingen samtaler endnu',\n back_to_conversations: 'Tilbage til samtaler',\n closed_conversations: 'Lukkede samtaler',\n};\n","import type { TranslationInterface } from '.';\n\nexport const GermanLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Nachricht schreiben...',\n your_issue_has_been_resolved: 'Ihr Problem wurde gelöst!',\n new_conversation: 'Neue Konversation',\n welcome_screen_title: 'Willkommen in unserem Support-Chat',\n welcome_screen_description:\n 'Wir sind hier, um zu helfen! Beginnen Sie ein Gesprách und wir werden so schnell wie mogelijk antworten.',\n your_name_placeholder: 'Ihr Name',\n your_email_placeholder: 'Ihre E-Mail-Adresse',\n start_chat_button: 'Mit dem Support sprechen',\n start_chat_button_loading: 'Verbindung wird hergestellt...',\n i_need_more_help: 'Ich brauche weitere Hilfe',\n this_was_helpful: 'Dies war hilfreich',\n optional: 'Optional',\n no_conversations_yet: 'noch keine Gespräche',\n back_to_conversations: 'Zurück zur Konversationen',\n closed_conversations: 'Geschlossene Konversationen',\n};\n","import type { TranslationInterface } from '.';\n\nexport const EnglishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Write a message...',\n your_issue_has_been_resolved: 'Your issue has been resolved!',\n new_conversation: 'New conversation',\n welcome_screen_title: 'Welcome to our support chat',\n welcome_screen_description:\n \"We're here to help! Start a conversation and we'll get back to you as soon as possible.\",\n your_name_placeholder: 'Your name',\n your_email_placeholder: 'Your email address',\n start_chat_button: 'Talk to support',\n start_chat_button_loading: 'Connecting...',\n i_need_more_help: 'I need more help',\n this_was_helpful: 'This was helpful',\n optional: 'Optional',\n no_conversations_yet: 'No conversations yet',\n back_to_conversations: 'Back to conversations',\n closed_conversations: 'Closed conversations',\n};\n","import type { TranslationInterface } from '.';\n\nexport const SpanishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Escribe un mensaje...',\n your_issue_has_been_resolved: '¡Tu problema fue resuelto!',\n new_conversation: 'Nueva conversación',\n welcome_screen_title: 'Bienvenido a nuestro chat de soporte',\n welcome_screen_description:\n '¡Estamos aquí para ayudarte! Inicia una conversación y responderemos lo antes posible.',\n your_name_placeholder: 'Tu nombre',\n your_email_placeholder: 'Tu correo electrónico',\n start_chat_button: 'Hablar con soporte',\n start_chat_button_loading: 'Conectando...',\n i_need_more_help: 'Necesito más ayuda',\n this_was_helpful: 'Esto fue útil',\n optional: 'Opcional',\n no_conversations_yet: 'Sin conversaciones aún',\n back_to_conversations: 'Volver a conversaciones',\n closed_conversations: 'Conversaciones cerradas',\n};\n","import type { TranslationInterface } from '.';\n\nexport const FinnishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Kirjoita viesti...',\n your_issue_has_been_resolved: 'Ongelmasi on ratkaistu!',\n new_conversation: 'Uusi keskustelu',\n welcome_screen_title: 'Tervetuloa tukichattiin',\n welcome_screen_description:\n 'Olemme täällä auttamassa! Aloita keskustelu ja palaamme sinulle mahdollisimman pian.',\n your_name_placeholder: 'Nimesi',\n your_email_placeholder: 'Sähköpostiosoitteesi',\n start_chat_button: 'Keskustele tuen kanssa',\n start_chat_button_loading: 'Yhdistetään...',\n i_need_more_help: 'Tarvitsen lisää apua',\n this_was_helpful: 'Tämä oli hyödyllistä',\n optional: 'Valinnainen',\n no_conversations_yet: 'Ei vielä keskusteluja',\n back_to_conversations: 'Takaisin keskusteluihin',\n closed_conversations: 'Suljetut keskustelut',\n};\n","import type { TranslationInterface } from '.';\n\nexport const FrenchLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Écrivez un message...',\n your_issue_has_been_resolved: 'Votre problème a été résolu !',\n new_conversation: 'Nouvelle conversation',\n welcome_screen_title: 'Bienvenue dans notre chat de support',\n welcome_screen_description:\n 'Nous sommes là pour vous aider ! Commencez une conversation et nous vous répondrons dès que possible.',\n your_name_placeholder: 'Votre nom',\n your_email_placeholder: 'Votre adresse e-mail',\n start_chat_button: 'Parler au support',\n start_chat_button_loading: 'Connexion...',\n i_need_more_help: \"Je besoin d'aide plus\",\n this_was_helpful: \"C'était utile\",\n optional: 'Optionnel',\n no_conversations_yet: 'Aucune conversation pour le moment',\n back_to_conversations: 'Retour aux conversations',\n closed_conversations: 'Conversations fermées',\n};\n","import type { TranslationInterface } from '.';\n\nexport const ItalianLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Scrivi un messaggio...',\n your_issue_has_been_resolved: 'Il tuo problema è stato risolto!',\n new_conversation: 'Nuova conversazione',\n welcome_screen_title: 'Benvenuto nella nostra chat di supporto',\n welcome_screen_description:\n 'Siamo qui per aiutarti! Inizia una conversazione e ti risponderemo il prima possibile.',\n your_name_placeholder: 'Il tuo nome',\n your_email_placeholder: 'Il tuo indirizzo email',\n start_chat_button: 'Parla con il supporto',\n start_chat_button_loading: 'Connessione in corso...',\n i_need_more_help: 'Ho bisogno di ulteriore aiuto',\n this_was_helpful: 'Questo è stato utile',\n optional: 'Opzionale',\n no_conversations_yet: 'Nessuna conversazione ancora',\n back_to_conversations: 'Torna alle conversazioni',\n closed_conversations: 'Conversazioni chiuse',\n};\n","import type { TranslationInterface } from '.';\n\nexport const DutchLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Schrijf een bericht...',\n your_issue_has_been_resolved: 'Uw probleem is opgelost!',\n new_conversation: 'Nieuw gesprek',\n welcome_screen_title: 'Welkom bij onze supportchat',\n welcome_screen_description:\n 'We zijn hier om te helpen! Begin een gesprek en we nemen zo snel mogelijk contact met u op.',\n your_name_placeholder: 'Uw naam',\n your_email_placeholder: 'Uw e-mailadres',\n start_chat_button: 'Praat met ondersteuning',\n start_chat_button_loading: 'Verbinding maken...',\n i_need_more_help: 'Ik heb nog meer hulp nodig',\n this_was_helpful: 'Mijn vraag is opgelost',\n optional: 'Optioneel',\n no_conversations_yet: 'Nog geen gesprekken',\n back_to_conversations: 'Terug naar gesprekken',\n closed_conversations: 'Afgesloten gesprekken',\n};\n","import type { TranslationInterface } from '.';\n\nexport const NorwegianLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Skriv en melding...',\n your_issue_has_been_resolved: 'Problemet ditt er løst!',\n new_conversation: 'Ny samtale',\n welcome_screen_title: 'Velkommen til vår kundestøtte-chat',\n welcome_screen_description:\n 'Vi er her for å hjelpe! Start en samtale så kommer vi tilbake til deg så snart som mulig.',\n your_name_placeholder: 'Ditt navn',\n your_email_placeholder: 'Din e-postadresse',\n start_chat_button: 'Snakk med kundestøtte',\n start_chat_button_loading: 'Kobler til...',\n i_need_more_help: 'Jeg trenger mer hjelp',\n this_was_helpful: 'Dette var nyttig',\n optional: 'Valgfritt',\n no_conversations_yet: 'Ingen samtaler ennå',\n back_to_conversations: 'Tilbake til samtaler',\n closed_conversations: 'Lukkede samtaler',\n};\n","import type { TranslationInterface } from '.';\n\nexport const PolishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Napisz wiadomość...',\n your_issue_has_been_resolved: 'Twój problem został rozwiązany!',\n new_conversation: 'Nowa rozmowa',\n welcome_screen_title: 'Witamy w naszym czacie wsparcia',\n welcome_screen_description:\n 'Jesteśmy tutaj, aby pomóc! Rozpocznij rozmowę, a odpowiemy jak najszybciej.',\n your_name_placeholder: 'Twoje imię',\n your_email_placeholder: 'Twój adres email',\n start_chat_button: 'Porozmawiaj ze wsparciem',\n start_chat_button_loading: 'Łączenie...',\n i_need_more_help: 'Potrzebuję więcej pomocy',\n this_was_helpful: 'To było pomocne',\n optional: 'Opcjonalne',\n no_conversations_yet: 'Jeszcze brak rozmów',\n back_to_conversations: 'Powrót do rozmów',\n closed_conversations: 'Zamknięte rozmowy',\n};\n","import type { TranslationInterface } from '.';\n\nexport const PortugueseLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Escreva uma mensagem...',\n your_issue_has_been_resolved: 'Seu problema foi resolvido!',\n new_conversation: 'Nova conversa',\n welcome_screen_title: 'Bem-vindo ao nosso chat de suporte',\n welcome_screen_description:\n 'Estamos aqui para ajudar! Inicie uma conversa e responderemos o mais rápido possível.',\n your_name_placeholder: 'Seu nome',\n your_email_placeholder: 'Seu endereço de email',\n start_chat_button: 'Falar com o suporte',\n start_chat_button_loading: 'Conectando...',\n i_need_more_help: 'preciso de mais ajuda',\n this_was_helpful: 'Isso foi útil',\n optional: 'Opcional',\n no_conversations_yet: 'Nenhuma conversa ainda',\n back_to_conversations: 'Voltar para conversas',\n closed_conversations: 'Conversas fechadas',\n};\n","import type { TranslationInterface } from '.';\n\nexport const RomanianLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Scrie un mesaj...',\n your_issue_has_been_resolved: 'Problema ta a fost rezolvată!',\n new_conversation: 'Conversație nouă',\n welcome_screen_title: 'Bine ai venit la chat-ul nostru de suport',\n welcome_screen_description:\n 'Suntem aici să te ajutăm! Începe o conversație și îți vom răspunde cât mai curând posibil.',\n your_name_placeholder: 'Numele tău',\n your_email_placeholder: 'Adresa ta de email',\n start_chat_button: 'Vorbește cu suportul',\n start_chat_button_loading: 'Se conectează...',\n i_need_more_help: 'Am nevoie de mai mult ajutor',\n this_was_helpful: 'Acest lucru a fost util',\n optional: 'Opțional',\n no_conversations_yet: 'Încă nu există conversații',\n back_to_conversations: 'Înapoi la conversații',\n closed_conversations: 'Conversații închise',\n};\n","import type { TranslationInterface } from '.';\n\nexport const SwedishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Skriv ett meddelande...',\n your_issue_has_been_resolved: 'Ditt problem har lösts!',\n new_conversation: 'Ny konversation',\n welcome_screen_title: 'Välkommen till vår supportchatt',\n welcome_screen_description:\n 'Vi är här för att hjälpa! Starta en konversation så återkommer vi till dig så snart som möjligt.',\n your_name_placeholder: 'Ditt namn',\n your_email_placeholder: 'Din e-postadress',\n start_chat_button: 'Prata med support',\n start_chat_button_loading: 'Ansluter...',\n i_need_more_help: 'Jag behöver mer hjälp',\n this_was_helpful: 'Detta var användbart',\n optional: 'Frivilligt',\n no_conversations_yet: 'Inga konversationer ännu',\n back_to_conversations: 'Tillbaka till konversationer',\n closed_conversations: 'Stängda konversationer',\n};\n","import type { TranslationInterface } from '.';\n\nexport const TurkishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Bir mesaj yazın...',\n your_issue_has_been_resolved: 'Sorununuz çözüldü!',\n new_conversation: 'Yeni konuşma',\n welcome_screen_title: 'Destek sohbetimize hoş geldiniz',\n welcome_screen_description:\n 'Yardım etmek için buradayız! Bir konuşma başlatın, en kısa sürede size geri döneceğiz.',\n your_name_placeholder: 'Adınız',\n your_email_placeholder: 'E-posta adresiniz',\n start_chat_button: 'Destekle konuş',\n start_chat_button_loading: 'Bağlanıyor...',\n i_need_more_help: 'Daha fazla yardıma ihtiyacım var',\n this_was_helpful: 'Bu yardımcı oldu',\n optional: 'İsteğe bağlı',\n no_conversations_yet: 'Henüz konuşma yok',\n back_to_conversations: 'Konuşmalara geri dön',\n closed_conversations: 'Kapatılan konuşmalar',\n};\n","import type { WidgetConfig } from '../types/widget-config';\nimport { ArabicLanguage } from './ar';\nimport { DanishLanguage } from './da';\nimport { GermanLanguage } from './de';\nimport { EnglishLanguage } from './en';\nimport { SpanishLanguage } from './es';\nimport { FinnishLanguage } from './fi';\nimport { FrenchLanguage } from './fr';\nimport { ItalianLanguage } from './it';\nimport { DutchLanguage } from './nl';\nimport { NorwegianLanguage } from './no';\nimport { PolishLanguage } from './pl';\nimport { PortugueseLanguage } from './pt';\nimport { RomanianLanguage } from './ro';\nimport { SwedishLanguage } from './sv';\nimport { TurkishLanguage } from './tr';\n\nconst languages = {\n en: EnglishLanguage,\n ar: ArabicLanguage,\n nl: DutchLanguage,\n fr: FrenchLanguage,\n de: GermanLanguage,\n pt: PortugueseLanguage,\n es: SpanishLanguage,\n tr: TurkishLanguage,\n pl: PolishLanguage,\n fi: FinnishLanguage,\n it: ItalianLanguage,\n no: NorwegianLanguage,\n ro: RomanianLanguage,\n da: DanishLanguage,\n sv: SwedishLanguage,\n} as const;\n\nexport const LANGUAGES = Object.keys(languages) as (keyof typeof languages)[];\nexport type Language = (typeof LANGUAGES)[number];\n\nexport function isSupportedLanguage(\n lang: string | null | undefined,\n): lang is Language {\n return LANGUAGES.includes(lang as Language);\n}\n\nexport function getTranslation(\n key: TranslationKeyU,\n lang: Language,\n overrides: WidgetConfig['translationOverrides'],\n): string {\n return overrides?.[lang]?.[key] || languages[lang][key] || '';\n}\n\nexport type TranslationInterface = {\n i_need_more_help: string;\n this_was_helpful: string;\n write_a_message_placeholder: string;\n your_issue_has_been_resolved: string;\n new_conversation: string;\n back_to_conversations: string;\n closed_conversations: string;\n no_conversations_yet: string;\n welcome_screen_title: string;\n welcome_screen_description: string;\n your_name_placeholder: string;\n your_email_placeholder: string;\n optional: string;\n start_chat_button: string;\n start_chat_button_loading: string;\n};\nexport type TranslationKeyU = keyof TranslationInterface;\n"],"names":["defaultOnError","onErrorOptions","basicClient","options","client","createClient","middlewares","ApiCaller","config","token","baseUrl","headers","request","key","value","body","abortSignal","sessionId","lastMessageTimestamp","query","cursor","filters","file","onProgress","resolve","reject","formData","xhr","event","percentage","data","error","uploadUrl","_a","_b","isExhaustive","funcName","PrimitiveState","state","newState","isEqual","_s","callback","Poller","cb","intervalMs","timeouts","poll","runCatching","result","ActiveSessionPollingCtx","api","sessionCtx","messageCtx","sessionPollingIntervalSeconds","session","fetchFullHistory","messages","prevMessages","newMessages","msg","newMsg","existingMsg","history","commonFields","action","message","responseBodyText","parsed","ContactCtx","storageCtx","_c","_d","persistedToken","_e","_g","_f","_h","_j","_i","_l","_k","_n","_m","payload","extraCollectedData","persistedExternalId","externalId","v4","genUuid","uuidv4","CsatCtx","currentSessionId","uuid","SessionCtx","contactCtx","sessionsPollingIntervalSeconds","contact","customData","deduped","s","i","self","sessions","currentSession","session_id","MessageCtx","input","isAssignedToAI","isSendingToAI","lastMessage","currentMessages","shouldInsertInitialMessages","m","insertableInitialMessages","userMessage","botMessage","errorMessage","content","attachments","messageContent","_","response","RouterCtx","resetChat","isInitialFetchLoading","mostRecentOpenSessionId","StorageCtx","storage","orgToken","id","_WidgetCtx","modes","org","externalConfig","WidgetCtx","ArabicLanguage","DanishLanguage","GermanLanguage","EnglishLanguage","SpanishLanguage","FinnishLanguage","FrenchLanguage","ItalianLanguage","DutchLanguage","NorwegianLanguage","PolishLanguage","PortugueseLanguage","RomanianLanguage","SwedishLanguage","TurkishLanguage","languages","LANGUAGES","isSupportedLanguage","lang","getTranslation","overrides"],"mappings":"+JAWMA,EAAyCC,GAAmB,CAChE,QAAQ,IAAIA,EAAe,KAAK,CAClC,EAEaC,EAAeC,GAAqB,CAC/C,MAAMC,EAASC,EAAoB,CACjC,QAASF,EAAQ,OAAA,CAClB,EAEKG,EAA0B,CAC9B,UAAWH,EAAQ,UACnB,WAAYA,EAAQ,WACpB,QAASA,EAAQ,SAAWH,CAAA,EAG9B,OAAAI,EAAO,IAAIE,CAAW,EACfF,CACT,ECpBO,MAAMG,CAAU,CAKrB,YAAY,CAAE,OAAAC,GAAoC,SAFlD,KAAQ,UAA2B,KAYnC,KAAQ,uBAA0BC,GAAqC,CACrE,MAAMC,EAGA,KAAK,OAAO,QAAU,sBACtBC,EAAU,CACd,cAAe,KAAK,OAAO,MAC3B,eAAgB,mBAChB,OAAQ,mBACR,cAAeF,EAAQ,UAAUA,CAAK,GAAK,MAAA,EAG7C,MAAO,CAAE,QAAAC,EAAS,QAAAC,CAAAA,CACpB,EAEA,KAAQ,oBAAsB,CAAC,CAC7B,QAAAD,EACA,QAAAC,CAAA,IAEOT,EAAY,CACjB,QAAAQ,EACA,UAAW,CAAC,CAAE,QAAAE,KAAc,CAC1B,OAAO,QAAQD,CAAO,EAAE,QAAQ,CAAC,CAACE,EAAKC,CAAK,IAAM,CAC5CA,GACFF,EAAQ,QAAQ,IAAIC,EAAKC,CAAK,CAElC,CAAC,CACH,CAAA,CACD,EAGH,KAAA,aAAgBL,GAAkB,CAChC,KAAK,UAAYA,EACjB,KAAM,CAAE,QAAAC,EAAS,QAAAC,GAAY,KAAK,uBAAuBF,CAAK,EAC9D,KAAK,OAAS,KAAK,oBAAoB,CAAE,QAAAC,EAAS,QAAAC,EAAS,CAC7D,EAEA,KAAA,wBAA0B,SACjB,MAAM,KAAK,OAAO,IAAI,4BAA6B,CACxD,OAAQ,CAAE,OAAQ,CAAE,cAAe,KAAK,OAAO,MAAM,CAAE,CACxD,EAGH,KAAA,YAAc,MAAOI,EAAsBC,IAClC,MAAM,KAAK,OAAO,KAAK,+BAAgC,CAC5D,KAAAD,EACA,OAAQC,CAAA,CACT,EAGH,KAAA,wBAA0B,MAAOD,GACxB,MAAM,KAAK,OAAO,KACvB,+CACA,CACE,OAAQ,CAAE,OAAQ,CAAE,cAAe,KAAK,OAAO,MAAM,EACrD,KAAAA,CAAA,CACF,EAIJ,KAAA,cAAgB,MAAOA,GACd,MAAM,KAAK,OAAO,KAAK,oCAAqC,CACjE,KAAAA,CAAA,CACD,EAGH,KAAA,sBAAwB,MAAO,CAC7B,UAAAE,EACA,qBAAAC,EACA,YAAAF,CAAA,IAKI,CACJ,MAAMG,EAAQD,EAAuB,CAAE,qBAAAA,CAAA,EAAyB,OAChE,OAAO,MAAM,KAAK,OAAO,IAAI,sCAAuC,CAClE,OAAQ,CAAE,KAAM,CAAE,UAAAD,CAAA,EAAa,MAAAE,CAAA,EAC/B,OAAQH,CAAA,CACT,CACH,EAEA,KAAA,YAAc,MAAO,CACnB,OAAAI,EACA,QAAAC,EACA,YAAAL,CAAA,IAMO,MAAM,KAAK,OAAO,IAAI,8BAA+B,CAC1D,OAAQ,CAAE,MAAO,CAAE,OAAAI,EAAQ,QAAS,KAAK,UAAUC,CAAO,EAAE,EAC5D,OAAQL,CAAA,CACT,EAOH,KAAA,WAAa,MAAO,CAClB,KAAAM,EACA,YAAAN,EACA,WAAAO,CAAA,IAMO,IAAI,QAAQ,CAACC,EAASC,IAAW,OACtC,MAAMC,EAAW,IAAI,SACrBA,EAAS,OAAO,OAAQJ,CAAI,EAE5B,MAAMK,EAAM,IAAI,eAGhB,GAAIX,IACFA,EAAY,iBAAiB,QAAS,IAAM,CAC1CW,EAAI,MAAA,EACJF,EAAO,IAAI,aAAa,UAAW,YAAY,CAAC,CAClD,CAAC,EAGGT,EAAY,SAAS,CACvBS,EAAO,IAAI,aAAa,UAAW,YAAY,CAAC,EAChD,MACF,CAGFE,EAAI,OAAO,iBAAiB,WAAaC,GAAU,CACjD,GAAIA,EAAM,kBAAoBL,EAAY,CACxC,MAAMM,EAAa,KAAK,MAAOD,EAAM,OAASA,EAAM,MAAS,GAAG,EAChEL,EAAWM,CAAU,CACvB,CACF,CAAC,EAGDF,EAAI,iBAAiB,OAAQ,IAAM,CACjC,GAAIA,EAAI,QAAU,KAAOA,EAAI,OAAS,IACpC,GAAI,CACF,MAAMG,EAAO,KAAK,MAAMH,EAAI,YAAY,EACxCH,EAAQM,CAAI,CACd,OAASC,EAAO,CACdN,EAAO,IAAI,MAAM,6BAA6BM,CAAK,EAAE,CAAC,CACxD,MAEAN,EAAO,IAAI,MAAM,8BAA8BE,EAAI,MAAM,EAAE,CAAC,CAEhE,CAAC,EAEDA,EAAI,iBAAiB,QAAS,IAAM,CAClCF,EAAO,IAAI,MAAM,wBAAwB,CAAC,CAC5C,CAAC,EAEDE,EAAI,iBAAiB,UAAW,IAAM,CACpCF,EAAO,IAAI,MAAM,kBAAkB,CAAC,CACtC,CAAC,EAED,KAAM,CAAE,QAAAf,CAAAA,EAAY,KAAK,uBAAuB,KAAK,SAAS,EAGxDsB,EAAY,GAAGtB,CAAO,4BAC5BiB,EAAI,KAAK,OAAQK,CAAS,EAE1BL,EAAI,iBAAiB,cAAe,KAAK,OAAO,KAAK,EACnC,KAAK,aAAaM,EAAA,KAAK,OAAO,OAAZ,YAAAA,EAAkB,OAEpDN,EAAI,iBAAiB,gBAAiB,UAAU,KAAK,SAAS,EAAE,EAEhE,QAAQ,MAAM,oBAAoB,EAGpCA,EAAI,KAAKD,CAAQ,CACnB,CAAC,EAGH,KAAA,KAAO,MAAOX,GACL,MAAM,KAAK,OAAO,KAAK,+BAAgC,CAAE,KAAAA,EAAM,EAGxE,KAAA,eAAiB,MACfA,EACAC,IAEO,MAAM,KAAK,OAAO,KAAK,qCAAsC,CAClE,KAAAD,EACA,OAAQC,CAAA,CACT,EAGH,KAAA,sBAAwB,MACtBD,GAEO,MAAM,KAAK,OAAO,KAAK,gCAAiC,CAC7D,KAAAA,CAAA,CACD,EAGH,KAAA,WAAa,MAAOA,GACX,MAAM,KAAK,OAAO,KAAK,iCAAkC,CAAE,KAAAA,EAAM,EAjNxE,KAAK,OAASP,EACd,KAAK,YAAYyB,EAAAzB,EAAO,OAAP,YAAAyB,EAAa,QAAS,KAEvC,KAAM,CAAE,QAAAvB,EAAS,QAAAC,CAAA,EAAY,KAAK,wBAChCuB,EAAA1B,EAAO,OAAP,YAAA0B,EAAa,KAAA,EAEf,KAAK,OAAS,KAAK,oBAAoB,CAAE,QAAAxB,EAAS,QAAAC,EAAS,CAC7D,CA4MF,CCjOO,SAASwB,EAAarB,EAAcsB,EAAkB,CAC3D,QAAQ,MAAM,oBAAoBtB,CAAK,OAAOsB,CAAQ,EAAE,CAC1D,CCEO,MAAMC,CAAkB,CAK7B,YAAYC,EAAU,CAJtB,KAAQ,gBAAkB,IAS1B,KAAA,IAAM,IAAS,KAAK,MAEpB,KAAA,IAAOC,GAAsB,CACtBC,EAAQ,KAAK,MAAOD,CAAQ,IAC/B,KAAK,MAAQA,EACb,KAAK,kBAAkBA,CAAQ,EAEnC,EAEA,KAAA,WAAcE,GAAyB,CACrC,GAAwBA,GAAO,KAAM,OACrC,MAAMF,EAAW,CAAE,GAAG,KAAK,MAAO,GAAGE,CAAA,EACrC,KAAK,IAAIF,CAAQ,CACnB,EAEA,KAAA,MAAQ,IAAY,CAClB,KAAK,IAAI,KAAK,YAAY,CAC5B,EAEA,KAAQ,kBAAqBD,GAAa,CACf,MAAM,KAAK,KAAK,WAAW,EACnC,QAASI,GAAa,CACrC,GAAI,CACFA,EAASJ,CAAK,CAChB,OAASP,EAAO,CAEZ,QAAQ,MAAMA,CAAK,CAEvB,CACF,CAAC,CACH,EAEA,KAAA,UAAaW,IACX,KAAK,YAAY,IAAIA,CAAQ,EAEtB,IAAM,CACX,KAAK,YAAY,OAAOA,CAAQ,CAClC,GAzCA,KAAK,MAAQJ,EACb,KAAK,aAAeA,CACtB,CAyCF,CC9CO,MAAMK,CAAO,CAAb,aAAA,CACL,KAAA,MAAQ,IAAIN,EAA6B,CACvC,UAAW,GACX,QAAS,EAAA,CACV,EACD,KAAQ,gBAAkB,IAAI,gBAE9B,KAAA,MAAQ,IAAM,OACZ,KAAK,gBAAgB,MAAM,kBAAkB,GAC7CJ,EAAA,KAAK,cAAL,MAAAA,EAAA,WACA,KAAK,YAAc,IACrB,EAEA,KAAQ,YAAmC,KAE3C,KAAA,aAAe,CACbW,EACAC,IACG,CACH,GAAI,KAAK,YAAa,OAEtB,MAAMC,EAA6B,CAAA,EAE7BC,EAAO,SAAY,CACvB,KAAK,gBAAkB,IAAI,gBAC3B,KAAK,MAAM,WAAW,CAAE,UAAW,GAAM,EAEzC,GAAI,CACF,MAAMH,EAAG,KAAK,gBAAgB,MAAM,CACtC,OAASb,EAAO,CACd,GAAI,KAAK,gBAAgB,OAAO,QAE9B,OAEF,QAAQ,MAAM,kBAAmBA,CAAK,EACtC,KAAK,MAAM,WAAW,CAAE,QAAS,GAAM,CACzC,QAAA,CACE,KAAK,MAAM,WAAW,CAAE,UAAW,GAAO,CAC5C,CAGI,KAAK,gBAAgB,OAAO,QAC9B,QAAQ,IAAI,wCAAwC,EAEpDe,EAAS,KAAK,WAAWC,EAAMF,CAAU,CAAC,CAE9C,EAEAE,EAAA,EAEA,KAAK,YAAc,IAAM,CACvBD,EAAS,QAAQ,YAAY,EAC7B,KAAK,MAAM,MAAA,CACb,CACF,CAAA,CACF,CC/CO,SAASE,EACdN,EACsC,CACtC,GAAI,CACF,MAAMO,EAASP,EAAA,EAEf,OAAIO,aAAkB,QACbA,EAAO,KAAMnB,IAAU,CAAE,KAAAA,CAAA,EAAO,EAAE,MAAOC,IAAc,CAAE,MAAAA,GAAQ,EAGnE,CAAE,KAAMkB,CAAA,CACjB,OAASlB,EAAO,CACd,MAAO,CAAE,MAAAA,CAAA,CACX,CACF,CChBO,MAAMmB,CAAwB,CAUnC,YAAY,CACV,IAAAC,EACA,OAAA3C,EACA,WAAA4C,EACA,WAAAC,EACA,8BAAAC,CAAA,EAOC,CAfH,KAAQ,OAAS,IAAIX,EACrB,KAAQ,0CAA4C,IAAI,gBAwBxD,KAAQ,gBAAkB,IAAM,CAC9B,KAAK,WAAW,aAAa,UAAU,CAAC,CAAE,QAAAY,KAAc,CAClDA,GAAA,MAAAA,EAAS,GACX,KAAK,OAAO,aAAa,MAAOvC,GAAgB,CAC9C,KAAK,uBAAuB,CAAE,UAAWuC,EAAQ,GAAI,YAAAvC,EAAa,CACpE,EAAG,KAAK,8BAAgC,GAAI,EAE5C,KAAK,OAAO,MAAA,CAEhB,CAAC,EAQD,KAAK,WAAW,aAAa,UAAU,CAAC,CAAE,QAAAuC,KAAc,CACtD,GAAIA,GAAA,MAAAA,EAAS,IAAM,CAACA,EAAQ,SAC1B,GAAI,CACF,KAAK,0CACH,IAAI,gBACN,KAAK,uBAAuB,CAC1B,UAAWA,EAAQ,GACnB,YAAa,KAAK,0CAA0C,OAC5D,iBAAkB,EAAA,CACnB,CACH,OAASxB,EAAO,CACT,KAAK,0CAA0C,OAAO,SACzD,QAAQ,MAAM,4CAA6CA,CAAK,CAEpE,MAEA,KAAK,0CAA0C,MAAA,CAEnD,CAAC,CACH,EAEA,KAAA,uBAAyB,MAAO,CAC9B,UAAAd,EACA,YAAAD,EACA,iBAAAwC,EAAmB,EAAA,IAKA,OAQf,KAAK,WAAW,MAAM,MAAM,SAAS,SAAW,GAClD,KAAK,WAAW,MAAM,WAAW,CAAE,sBAAuB,GAAM,EAGlE,MAAMC,EAAW,KAAK,WAAW,MAAM,MAAM,SACvCvC,EACJuC,EAAS,OAAS,IACbxB,EAAAwB,EAASA,EAAS,OAAS,CAAC,IAA5B,YAAAxB,EAA+B,YAAa,OAC7C,OAEA,CAAE,KAAAH,CAAA,EAAS,MAAM,KAAK,IAAI,sBAAsB,CACpD,UAAAb,EACA,YAAAD,EACA,qBAAsBwC,EAAmB,OAAYtC,CAAA,CACtD,EAOD,GALIY,GAAA,MAAAA,EAAM,UACR,KAAK,WAAW,aAAa,WAAW,CAAE,QAASA,EAAK,QAAS,EACjE,KAAK,WAAW,YAAY,CAACA,EAAK,OAAO,CAAC,GAGxCA,GAAA,MAAAA,EAAM,SAAWA,EAAK,QAAQ,OAAS,EAAG,CAE5C,MAAM4B,EAAe,KAAK,WAAW,MAAM,MAAM,SAC3CC,EAAc7B,EAAK,QACtB,IAAI,KAAK,mBAAmB,EAC5B,OAAQ8B,GAA+BA,IAAQ,IAAI,EACnD,OACEC,GACC,CAACH,EAAa,KAAMI,GAAgBA,EAAY,KAAOD,EAAO,EAAE,CAAA,EAEtE,KAAK,WAAW,MAAM,WAAW,CAC/B,SAAU,CAAC,GAAGH,EAAc,GAAGC,CAAW,CAAA,CAC3C,CACH,CAEI,KAAK,WAAW,MAAM,IAAA,EAAM,uBAC9B,KAAK,WAAW,MAAM,WAAW,CAAE,sBAAuB,GAAO,CAErE,EAEA,KAAA,oBAAuBI,GAA+C,SACpE,MAAMC,EAAe,CACnB,GAAID,EAAQ,SACZ,UAAWA,EAAQ,QAAU,GAC7B,YAAaA,EAAQ,aAAe,MAAA,EAGtC,GAAIA,EAAQ,OAAO,OAAS,OAC1B,MAAO,CACL,GAAGC,EACH,KAAM,OACN,QAASD,EAAQ,QAAQ,MAAQ,GACjC,YAAaA,EAAQ,QAAU,EAAA,EAInC,GAAIA,EAAQ,OAAO,OAAS,QAC1B,MAAO,CACL,GAAGC,EACH,KAAM,QACN,UAAW,gBACX,KAAM,CACJ,QAASD,EAAQ,QAAQ,MAAQ,EAAA,EAEnC,MAAO,CACL,KAAMA,EAAQ,OAAO,MAAQ,GAC7B,OAAQA,EAAQ,OAAO,QAAU,GACjC,GAAI,KACJ,KAAM,EAAA,CACR,EAIJ,GAAIA,EAAQ,OAAO,OAAS,KAAM,CAChC,MAAME,EACJF,EAAQ,aAAeA,EAAQ,YAAY,OAAS,EAChDA,EAAQ,YAAYA,EAAQ,YAAY,OAAS,CAAC,EAClD,OAEN,MAAO,CACL,GAAGC,EACH,KAAM,KACN,UAAW,cACX,MAAO,CACL,GAAI,KACJ,OAAM/B,EAAA,KAAK,OAAO,MAAZ,YAAAA,EAAiB,OAAQ,GAC/B,KAAM,GACN,SAAQC,EAAA,KAAK,OAAO,MAAZ,YAAAA,EAAiB,SAAU,EAAA,EAErC,KAAM,CACJ,QAAS6B,EAAQ,QAAQ,MAAQ,GACjC,OAAQE,EACJ,CACE,KAAMA,EAAO,WACb,KAAM,KAAK,oBAAoBA,CAAM,CAAA,EAEvC,MAAA,CACN,CAEJ,CAEA,GAAIF,EAAQ,OAAO,OAAS,SAAU,CACpC,MAAMG,EAAU,KAAK,uBAAuBH,CAAO,EACnD,OAAIG,IAAY,KAAa,KAEtB,CAAE,GAAGA,CAAA,CACd,CAEA,OAAO,IACT,EAEA,KAAA,uBACEH,GACgC,CAChC,GAAI,CAACA,GAAW,CAACA,EAAQ,qBAAsB,OAAO,KACtD,OAAQA,EAAQ,qBAAqB,KAAA,CACnC,IAAK,mBACH,MAAO,CACL,GAAIA,EAAQ,SACZ,KAAM,SACN,QAAS,mBACT,KAAM,CAAE,QAASA,EAAQ,qBAAqB,OAAA,EAC9C,UAAWA,EAAQ,QAAU,GAC7B,YAAa,MAAA,EAEjB,IAAK,iBACH,MAAO,CACL,GAAIA,EAAQ,SACZ,KAAM,SACN,QAAS,iBACT,KAAM,CAAE,QAAS,MAAA,EACjB,UAAWA,EAAQ,QAAU,GAC7B,YAAa,MAAA,EAEjB,IAAK,iBACH,MAAO,CACL,GAAIA,EAAQ,SACZ,KAAM,SACN,QAAS,iBACT,KAAM,CACJ,QAAS,CACP,MAAOA,EAAQ,qBAAqB,QAAQ,OAAS,OACrD,SACEA,EAAQ,qBAAqB,QAAQ,UAAY,MAAA,CACrD,EAEF,UAAWA,EAAQ,QAAU,GAC7B,YAAa,MAAA,EAEjB,IAAK,OACH,OAAO,KACT,QACE,OAAA5B,EACE4B,EAAQ,qBACR,KAAK,uBAAuB,IAAA,EAEvB,IAAA,CAEb,EAEA,KAAA,oBAAuBE,GAA0B,CAC/C,MAAMhB,EAASgB,EAAO,OAGtB,GADIhB,IAAW,MACX,OAAOA,GAAW,SAAU,OAAOA,EAEvC,GACE,qBAAsBA,GACtB,OAAOA,EAAO,kBAAqB,SACnC,CACA,MAAMkB,EAAmBlB,EAAO,iBAC1BmB,EAASpB,EAAY,IAAM,KAAK,MAAMmB,CAAgB,CAAC,EAAE,KAC/D,GAAIC,EAAQ,OAAOA,CACrB,CAEA,OAAOH,EAAO,MAChB,EAhPE,KAAK,IAAMd,EACX,KAAK,OAAS3C,EACd,KAAK,WAAa4C,EAClB,KAAK,WAAaC,EAClB,KAAK,8BAAgCC,EAErC,KAAK,gBAAA,CACP,CA0OF,CCpQO,MAAMe,CAAW,CAMtB,YAAY,CACV,OAAA7D,EACA,IAAA2C,EACA,WAAAmB,CAAA,EAKC,OAqBH,KAAA,kBAAoB,IAAe,OACjC,MAAI,MAACrC,EAAA,KAAK,MAAM,IAAA,EAAM,UAAjB,MAAAA,EAA0B,QAAS,KAAK,OAAO,gBAItD,EAEA,KAAQ,oCAAsC,SAAY,iCAKxD,GAAI,GAAAA,EAAA,KAAK,OAAO,OAAZ,MAAAA,EAAkB,OAKtB,IAAI,KAAK,OAAO,iBAAmB,GAACsC,GAAArC,EAAA,KAAK,OAAO,OAAZ,YAAAA,EAAkB,OAAlB,MAAAqC,EAAwB,OAAO,CAMjE,IAAIC,EAAA,KAAK,OAAO,4BAAZ,MAAAA,EAAuC,OACzC,OAGF,MAAMC,EAAiB,OAAMC,EAAA,KAAK,aAAL,YAAAA,EAAiB,mBAC1CD,GACF,MAAM,KAAK,qBAAqBA,CAAc,EAGhD,MACF,CAKA,GAAI,GAACE,GAAAC,EAAA,KAAK,OAAO,OAAZ,YAAAA,EAAkB,OAAlB,MAAAD,EAAwB,OAAO,CAClC,MAAMF,EAAiB,OAAMI,EAAA,KAAK,aAAL,YAAAA,EAAiB,mBAC9C,GAAIJ,EAAgB,CAClB,MAAM,KAAK,qBAAqBA,CAAc,EAE9C,MACF,CACF,CAUA,MAAM,KAAK,wBAAwB,CACjC,OAAOK,GAAAC,EAAA,KAAK,OAAO,OAAZ,YAAAA,EAAkB,OAAlB,YAAAD,EAAwB,MAC/B,mBAAmBE,GAAAC,EAAA,KAAK,OAAO,OAAZ,YAAAA,EAAkB,OAAlB,YAAAD,EAAwB,KAC3C,0BAA0BE,GAAAC,EAAA,KAAK,OAAO,OAAZ,YAAAA,EAAkB,OAAlB,YAAAD,EAAwB,UAAA,CACnD,EACH,EAEA,KAAA,wBAA0B,MACxBE,EACAC,IACkB,CAClB,KAAK,MAAM,WAAW,CAAE,mBAAAA,CAAA,CAAoB,EAE5C,GAAI,CACF,KAAK,MAAM,WAAW,CACpB,4BAA6B,GAC7B,iCAAkC,EAAA,CACnC,EAED,KAAM,CAAE,KAAAvD,CAAA,EAAS,MAAM,KAAK,IAAI,wBAAwBsD,CAAO,EAC3DtD,GAAA,MAAAA,EAAM,MACR,MAAM,KAAK,qBAAqBA,EAAK,KAAK,EAE1C,KAAK,MAAM,WAAW,CAAE,iCAAkC,GAAM,CAEpE,QAAA,CACE,KAAK,MAAM,WAAW,CAAE,4BAA6B,GAAO,CAC9D,CACF,EAEA,KAAA,qBAAuB,MAAOrB,GAAkB,aAC9C,MAAM6E,EAAsB,OAAMrD,EAAA,KAAK,aAAL,YAAAA,EAAiB,wBAE7CsD,IACJrD,EAAA,KAAK,OAAO,OAAZ,YAAAA,EAAkB,aAAcoD,GAAuBE,KAAA,EACzD,KAAK,IAAI,aAAa/E,CAAK,EAE3B,OAAM8D,EAAA,KAAK,aAAL,YAAAA,EAAiB,gBAAgB9D,IACvC,OAAM+D,EAAA,KAAK,aAAL,YAAAA,EAAiB,qBAAqBe,IAC5C,KAAK,MAAM,WAAW,CAAE,QAAS,CAAE,MAAA9E,EAAO,WAAA8E,CAAA,EAAc,CAC1D,EAnHE,KAAK,OAAS/E,EACd,KAAK,WAAa8D,EAClB,KAAK,IAAMnB,EAEX,KAAK,MAAQ,IAAId,EAA6B,CAC5C,SAASJ,EAAAzB,EAAO,OAAP,MAAAyB,EAAa,MAClB,CACE,MAAOzB,EAAO,KAAK,MAEnB,WAAYA,EAAO,KAAK,UAAA,EAE1B,KACJ,mBAAoB,OACpB,4BAA6B,GAC7B,iCAAkC,EAAA,CACnC,EAED,KAAK,oCAAA,CACP,CAkGF,CClJO,SAASiF,GAAU,CACxB,OAAOC,KAAA,CACT,CCIO,MAAMC,CAAQ,CAMnB,YAAY,CACV,OAAAnF,EACA,IAAA2C,EACA,WAAAC,EACA,WAAAC,CAAA,EAMC,CAOH,KAAA,WAAa,MACXtC,GACG,OACH,MAAM6E,GAAmB3D,EAAA,KAAK,WAAW,aAAa,IAAA,EAAM,UAAnC,YAAAA,EAA4C,GACrE,GAAI,CAAC2D,EACH,MAAO,CAAE,KAAM,KAAM,MAAO,qBAAA,EAG9B,MAAMC,EAAOJ,EAAA,EACb,KAAK,WAAW,MAAM,WAAW,CAC/B,SAAU,CACR,GAAG,KAAK,WAAW,MAAM,MAAM,SAC/B,CACE,GAAII,EACJ,KAAM,SACN,QAAS,iBACT,UAAW,IAAI,KAAA,EAAO,YAAA,EACtB,KAAM,CACJ,QAAS,CACP,MAAO9E,EAAK,MACZ,SAAUA,EAAK,QAAA,CACjB,CACF,CACF,CACF,CACD,EAED,KAAM,CAAE,KAAAe,EAAM,MAAAC,CAAA,EAAU,MAAM,KAAK,IAAI,WAAW,CAChD,GAAGhB,EACH,oBAAqB8E,EACrB,WAAYD,CAAA,CACb,EACD,MAAO,CAAE,KAAA9D,EAAM,MAAAC,CAAA,CACjB,EAvCE,KAAK,OAASvB,EACd,KAAK,IAAM2C,EACX,KAAK,WAAaC,EAClB,KAAK,WAAaC,CACpB,CAoCF,CCnCO,MAAMyC,CAAW,CAuBtB,YAAY,CACV,OAAAtF,EACA,IAAA2C,EACA,WAAA4C,EACA,+BAAAC,CAAA,EAMC,CA5BH,KAAQ,kBAAoB,IAAIrD,EAEhC,KAAO,aAAe,IAAIN,EAA6B,CACrD,QAAS,KACT,kBAAmB,GACnB,mBAAoB,EAAA,CACrB,EACD,KAAO,cAAgB,IAAIA,EAA8B,CACvD,KAAM,CAAA,EACN,OAAQ,OACR,WAAY,GACZ,qBAAsB,GAItB,sBAAuB,EAAA,CACxB,EAsBD,KAAA,MAAQ,SAAY,CAElB,KAAK,aAAa,MAAA,CACpB,EAEA,KAAQ,iCAAmC,IAAM,QAG7CJ,EAAA,KAAK,WAAW,MAAM,MAAM,UAA5B,MAAAA,EAAqC,OACrC,CAAC,KAAK,cAAc,MAAM,qBAE1B,KAAK,0BAAA,EAGL,KAAK,WAAW,MAAM,UAAU,CAAC,CAAE,QAAAgE,KAAc,CAC3CA,GAAA,MAAAA,EAAS,OAAS,CAAC,KAAK,cAAc,IAAA,EAAM,sBAC9C,KAAK,0BAAA,CAET,CAAC,CAEL,EAEA,KAAQ,0BAA4B,IAAM,CACxC,KAAK,kBAAkB,aAAa,SAAY,CAC1C,KAAK,cAAc,IAAA,EAAM,uBAAyB,IACpD,KAAK,cAAc,WAAW,CAAE,qBAAsB,GAAM,EAG9D,MAAM,KAAK,gBAAA,EAEP,KAAK,cAAc,IAAA,EAAM,wBAA0B,IACrD,KAAK,cAAc,WAAW,CAAE,sBAAuB,GAAO,CAElE,EAAG,KAAK,+BAAiC,GAAI,CAC/C,EAEA,KAAQ,oBACN,IACS,OAAO,YAGZ,OAAO,QAAQ,KAAK,OAAO,mBAAqB,CAAA,CAAE,EAAE,IAClD,CAAC,CAACpF,EAAKC,CAAK,IAAM,OAChB,OAAI,OAAOA,GAAU,SAAiB,CAACD,EAAKC,CAAK,EAC7C,OAAOA,GAAU,UAAkB,CAACD,EAAKC,CAAK,EAC9C,OAAOA,GAAU,SAAiB,CAACD,EAAKC,CAAK,EAE1C,CAACD,IAAKoB,EAAAe,EAAY,IAAM,KAAK,UAAUlC,CAAK,CAAC,IAAvC,YAAAmB,EAA0C,OAAQ,EAAE,CACnE,CAAA,CACF,EAIN,KAAA,cAAgB,SAAY,OAC1B,KAAK,aAAa,WAAW,CAAE,QAAS,KAAM,kBAAmB,GAAM,EAEvE,MAAMsD,GAAatD,EAAA,KAAK,WAAW,MAAM,IAAA,EAAM,UAA5B,YAAAA,EAAqC,WAElDiE,EAA0D,CAC9D,GAAG,KAAK,oBAAA,EACR,GAAIX,EAAa,CAAE,YAAaA,GAAe,CAAA,CAAC,EAE5C,CAAE,KAAMhC,EAAS,MAAAxB,CAAA,EAAU,MAAM,KAAK,IAAI,cAAc,CAC5D,WAAY,OAAO,KAAKmE,CAAU,EAAE,OAAS,EAAIA,EAAa,MAAA,CAC/D,EACD,OAAI3C,GACF,KAAK,aAAa,WAAW,CAAE,QAAAA,EAAS,kBAAmB,GAAO,EAC3DA,IAGT,KAAK,aAAa,WAAW,CAAE,kBAAmB,GAAO,EACzD,QAAQ,MAAM,4BAA6BxB,CAAK,EACzC,KACT,EAEA,KAAA,iBAAmB,SAAY,CAC7B,GAAI,KAAK,cAAc,IAAA,EAAM,WAAY,OAEzC,KAAM,CAAE,KAAAD,CAAA,EAAS,MAAM,KAAK,YAAY,CACtC,OAAQ,KAAK,cAAc,MAAM,MAAA,CAClC,EAED,GAAIA,EAAM,CAGR,MAAMqE,EAFc,CAAC,GAAG,KAAK,cAAc,MAAM,KAAM,GAAGrE,EAAK,KAAK,EAExC,OAC1B,CAACsE,EAAGC,EAAGC,IAASD,IAAMC,EAAK,UAAW7D,GAAO2D,EAAE,KAAO3D,EAAG,EAAE,CAAA,EAG7D,KAAK,cAAc,WAAW,CAC5B,KAAM0D,EACN,OAAQrE,EAAK,MAAQ,OACrB,WAAYA,EAAK,OAAS,IAAA,CAC3B,CACH,CACF,EAEA,KAAQ,YAAc,MAAO,CAAE,OAAAV,KAA6C,SAC1E,GAAI,GAACa,EAAA,KAAK,WAAW,MAAM,IAAA,EAAM,UAA5B,MAAAA,EAAqC,OAAO,MAAO,CAAE,KAAM,IAAA,EAEhE,MAAMsD,GAAarD,EAAA,KAAK,WAAW,MAAM,IAAA,EAAM,UAA5B,YAAAA,EAAqC,WACxD,OAAO,MAAM,KAAK,IAAI,YAAY,CAChC,OAAAd,EACA,QAASmE,EACL,CACE,YAAaA,CAAA,EAEf,CAAA,CAAC,CACN,CACH,EAEA,KAAA,YAAezD,GAAuB,CACpC,MAAMyE,EAAW,CAAC,GAAGzE,EAAM,GAAG,KAAK,cAAc,IAAA,EAAM,IAAI,EAAE,OAC3D,CAACsE,EAAGC,EAAGC,IAASD,IAAMC,EAAK,UAAW7D,GAAO2D,EAAE,KAAO3D,EAAG,EAAE,CAAA,EAE7D,KAAK,cAAc,WAAW,CAAE,KAAM8D,EAAU,CAClD,EAEA,KAAA,gBAAkB,SAAY,CAE5B,KAAM,CAAE,KAAAzE,GAAS,MAAM,KAAK,YAAY,CAAE,OAAQ,OAAW,EACxDA,GACL,KAAK,YAAYA,EAAK,KAAK,CAC7B,EAEA,KAAA,eAAiB,SAAY,CAC3B,MAAM0E,EAAiB,KAAK,aAAa,IAAA,EAAM,QAC/C,GAAI,CAACA,GAAkB,CAACA,EAAe,SACrC,MAAO,CAAE,QAAS,GAAO,MAAO,uBAAA,EAGlC,KAAK,aAAa,WAAW,CAAE,mBAAoB,GAAM,EAEzD,KAAM,CAAE,KAAMjD,EAAS,MAAAxB,CAAA,EAAU,MAAM,KAAK,IAAI,eAAe,CAC7D,WAAYyE,EAAe,EAAA,CAC5B,EAED,OAAIjD,GACF,KAAK,aAAa,WAAW,CAAE,QAAAA,EAAS,mBAAoB,GAAO,EAC5D,CAAE,QAAS,GAAM,KAAMA,CAAA,IAGhC,KAAK,aAAa,WAAW,CAAE,mBAAoB,GAAO,EACnD,CAAE,QAAS,GAAO,MAAAxB,CAAA,EAC3B,EAEA,KAAA,sBAAwB,MACtBqD,GACG,OACH,MAAMqB,GAAaxE,EAAA,KAAK,aAAa,IAAA,EAAM,UAAxB,YAAAA,EAAiC,GACpD,GAAI,CAACwE,EAAY,OAEjB,KAAM,CAAE,KAAA3E,EAAM,MAAAC,CAAA,EAAU,MAAM,KAAK,IAAI,sBAAsB,CAC3D,WAAA0E,EACA,QAAArB,CAAA,CACD,EAED,OAAItD,GAAA,MAAAA,EAAM,QAAgB,CAAE,QAAS,EAAA,EAE9B,CAAE,QAAS,EAAA,CACpB,EAzKE,KAAK,OAAStB,EACd,KAAK,IAAM2C,EACX,KAAK,WAAa4C,EAClB,KAAK,+BAAiCC,EAEtC,KAAK,iCAAA,CACP,CAoKF,CChNO,MAAMU,CAAW,CAgBtB,YAAY,CACV,OAAAlG,EACA,IAAA2C,EACA,WAAAC,EACA,WAAA2C,CAAA,EAMC,CApBH,KAAO,MAAQ,IAAI1D,EAAgC,CACjD,SAAU,CAAA,EACV,iBAAkB,GAClB,qBAAsB,GACtB,6BAA8B,GAC9B,sBAAuB,EAAA,CACxB,EAED,KAAQ,2BAA6B,IAAI,gBAmBzC,KAAA,MAAQ,IAAM,CACZ,KAAK,2BAA2B,MAAM,gBAAgB,EACtD,KAAK,MAAM,MAAA,CACb,EAEA,KAAA,YAAc,MAAOsE,GAKA,uBACnB,GAAI,CAIF,GACE,CAACA,EAAM,QAAQ,KAAA,IACd,CAACA,EAAM,aAAeA,EAAM,YAAY,SAAW,GACpD,CACA,QAAQ,KACN,2DAAA,EAEF,MACF,CAIA,MAAMpD,EAAU,KAAK,WAAW,aAAa,MAAM,QAE7CqD,GADWrD,GAAA,YAAAA,EAAS,SAAS,QACC,KAC9BsD,EAAgB,KAAK,MAAM,IAAA,EAAM,qBACjCC,EAAc,KAAK,MAAM,MAAM,SAAS,GAAG,EAAE,EACnD,GACED,GAECD,IAAkBE,GAAA,YAAAA,EAAa,QAAS,OACzC,CACA,QAAQ,KAAK,iDAAiD,EAC9D,MACF,CAKA,KAAK,2BAA6B,IAAI,gBACtC,KAAK,MAAM,WAAW,CACpB,6BAA8B,GAC9B,iBAAkB,GAClB,qBAAsB,CAAC,CAACF,GAAkB,CAACrD,CAAA,CAC5C,EAID,MAAMwD,EAAkB,KAAK,MAAM,IAAA,EAAM,SACnCC,EACJ,GAAC/E,EAAA,KAAK,WAAW,aAAa,IAAA,EAAM,UAAnC,MAAAA,EAA4C,KAC7C8E,EAAgB,SAAW,KAC3B7E,EAAA,KAAK,OAAO,0BAAZ,YAAAA,EAAqC,KAAM+E,GAAMA,EAAE,aAC/CC,EAA4BF,GAC7B,KAAK,OAAO,yBAA2B,IACrC,OAAQC,GAAMA,EAAE,UAAU,EAC1B,IACEA,IACE,CACC,GAAIxB,EAAA,EACJ,UAAW,cACX,KAAM,KACN,UAAW,IAAI,KAAA,EAAO,YAAA,EACtB,KAAM,CACJ,QAASwB,EAAE,OAAA,CACb,EACF,EAEN,CAAA,EACEE,EAAc,KAAK,cACvBR,EAAM,QAAQ,KAAA,EACdA,EAAM,aAAe,MAAA,EAavB,GAXA,KAAK,MAAM,WAAW,CACpB,SAAU,CACR,GAAGO,EACH,GAAGH,EACHI,CAAA,CACF,CACD,EAKG,GAAC5C,EAAA,KAAK,WAAW,aAAa,IAAA,EAAM,UAAnC,MAAAA,EAA4C,IAAI,CAInD,GAAI,CAHmB,MAAM,KAAK,WAAW,cAAA,EAGxB,CACnB,QAAQ,MAAM,0BAA0B,EACxC,MACF,CAGK,KAAK,WAAW,gBAAA,CACvB,CACA,MAAMtD,GAAYuD,EAAA,KAAK,WAAW,aAAa,IAAA,EAAM,UAAnC,YAAAA,EAA4C,GAC9D,GAAI,CAACvD,EAAW,OAIhB,KAAM,CAAE,KAAAa,CAAA,EAAS,MAAM,KAAK,IAAI,YAC9B,CACE,KAAMqF,EAAY,GAClB,UAAW,KAAK,OAAO,MACvB,QAAS,KAAK,OAAO,QACrB,aAAc,KAAK,OAAO,YAC1B,gBAAiB,KAAK,OAAO,eAC7B,WAAYlG,EACZ,QAASkG,EAAY,QACrB,YAAaR,EAAM,YACnB,cAAe,KAAK,OAAO,QAC3B,YAAa,CACX,GAAI,KAAK,OAAO,mBAAqB,CAAA,EACrC,GAAIA,EAAM,YAAc,CAAA,CAAC,EAE3B,SAAU,KAAK,OAAO,SACtB,iBAAkBA,EAAM,eACxB,iBAAkBK,EACdE,EAA0B,IAAKD,IAAO,CACpC,KAAMA,EAAE,GACR,QAASA,EAAE,KAAK,OAAA,EAChB,EACF,MAAA,EAEN,KAAK,2BAA2B,MAAA,EAGlC,GAAInF,GAAA,MAAAA,EAAM,QAAS,CAIjB,MAAMsF,EAAa,KAAK,aAAatF,CAAI,EACzC,GAAIsF,EAAY,CACd,MAAM1D,EAAe,KAAK,MAAM,IAAA,EAAM,SAItC,GAAI,CAHiB,CAACA,EAAa,KAChCuD,GAAMA,EAAE,KAAOG,EAAW,EAAA,EAEV,CACjB,KAAK,MAAM,WAAW,CACpB,+BACE1C,EAAA5C,EAAK,oBAAL,YAAA4C,EAAwB,wBACxBE,EAAA9C,EAAK,aAAL,YAAA8C,EAAiB,oBAAA,CACpB,EACD,MACF,CACA,KAAK,MAAM,WAAW,CACpB,SAAU,CAAC,GAAGlB,EAAc0D,CAAU,EACtC,+BACEzC,EAAA7C,EAAK,oBAAL,YAAA6C,EAAwB,wBACxBE,EAAA/C,EAAK,aAAL,YAAA+C,EAAiB,oBAAA,CACpB,CACH,CACI/C,EAAK,SACP,KAAK,WAAW,aAAa,WAAW,CAAE,QAASA,EAAK,QAAS,CAErE,KAAO,CACL,MAAMuF,EAAe,KAAK,oBACxBtC,EAAAjD,GAAA,YAAAA,EAAM,QAAN,YAAAiD,EAAa,UAAW,6DAAA,EAEpBgC,EAAkB,KAAK,MAAM,IAAA,EAAM,SACzC,KAAK,MAAM,WAAW,CACpB,SAAU,CAAC,GAAGA,EAAiBM,CAAY,CAAA,CAC5C,CACH,CACF,OAAStF,EAAO,CACT,KAAK,2BAA2B,OAAO,SAC1C,QAAQ,MAAM,0BAA2BA,CAAK,CAElD,QAAA,CACE,KAAK,MAAM,WAAW,CACpB,iBAAkB,GAClB,qBAAsB,EAAA,CACvB,CACH,CACF,EAEA,KAAQ,cAAgB,CACtBuF,EACAC,IACsB,CACtB,MAAMC,GAAkB,IAAM,CAC5B,MAAMnC,EAAqB,KAAK,WAAW,MAAM,MAAM,mBAEvD,OACE,KAAK,MAAM,IAAA,EAAM,SAAS,SAAW,GACrCA,GACA,OAAO,KAAKA,CAAkB,EAAE,OAAS,EAMlC,GAJM,OAAO,QAAQA,CAAkB,EAC3C,OAAO,CAAC,CAACoC,EAAG3G,CAAK,IAAM,CAAC,CAACA,CAAK,EAC9B,IAAI,CAAC,CAACD,EAAKC,CAAK,IAAM,GAAGD,CAAG,KAAKC,CAAK,EAAE,EACxC,KAAK;AAAA,CAAK,CACC;AAAA;AAAA,EAAQwG,CAAO,GAGxBA,CACT,GAAA,EAEA,MAAO,CACL,GAAI7B,EAAA,EACJ,KAAM,OACN,QAAS+B,EACT,YAAa,IAAI,KAAA,EAAO,YAAA,EACxB,YAAAD,EACA,UAAW,IAAI,KAAA,EAAO,YAAA,CAAY,CAEtC,EAEA,KAAQ,aACNG,GAC2B,OAC3B,OAAIA,EAAS,SAAWA,EAAS,kBACxB,CACL,KAAM,KACN,GAAIA,EAAS,kBAAkB,IAAMjC,EAAA,EACrC,UAAW,IAAI,KAAA,EAAO,YAAA,EACtB,UAAW,cACX,MAAO,KAAK,OAAO,IACf,CACE,KAAM,KAAK,OAAO,IAAI,MAAQ,GAC9B,KAAM,GACN,OAAQ,KAAK,OAAO,IAAI,QAAU,GAClC,GAAI,IAAA,EAEN,OACJ,KAAM,CACJ,QAASiC,EAAS,kBAAkB,MAAM,QAC1C,QAAQzF,EAAAyF,EAAS,aAAT,MAAAzF,EAAqB,MAAM,KAC/B,CACE,KAAMyF,EAAS,WAAW,MAAM,KAChC,KAAMA,EAAS,WAAW,MAAM,gBAAA,EAElC,MAAA,CACN,EAIG,IACT,EAEA,KAAQ,kBAAqBxD,IACpB,CACL,KAAM,KACN,GAAIuB,EAAA,EACJ,UAAW,IAAI,KAAA,EAAO,YAAA,EACtB,UAAW,cACX,KAAM,CACJ,QAAAvB,EACA,QAAS,QACT,OAAQ,MAAA,CACV,GAtQF,KAAK,OAAS1D,EACd,KAAK,IAAM2C,EACX,KAAK,WAAaC,EAClB,KAAK,WAAa2C,CACpB,CAqQF,CC5SO,MAAM4B,CAAU,CAQrB,YAAY,CACV,OAAAnH,EACA,WAAAuF,EACA,WAAA3C,EACA,UAAAwE,CAAA,EAMC,OAgBH,KAAQ,wBAA0B,IAAM,CACtC,KAAK,WAAW,MAAM,UAAU,CAAC,CAAE,QAAA3B,KAAc,OAE3CA,GAAA,MAAAA,EAAS,OAAS,KAAK,MAAM,IAAA,EAAM,SAAW,WAChD,KAAK,MAAM,WAAW,CACpB,QAAQhE,EAAA,KAAK,OAAO,SAAZ,MAAAA,EAAoB,eAAiB,OAAS,UAAA,CACvD,CAEL,CAAC,EAED,KAAK,WAAW,cAAc,UAC5B,CAAC,CAAE,sBAAA4F,EAAuB,KAAA/F,KAAW,aACnC,IACEG,EAAA,KAAK,OAAO,SAAZ,MAAAA,EAAoB,gBAGpB,GAACC,EAAA,KAAK,WAAW,aAAa,IAAA,EAAM,UAAnC,MAAAA,EAA4C,IAC7C,CACA,MAAM4F,GAA0BvD,EAAAzC,EAAK,KAAMsE,GAAMA,EAAE,QAAQ,IAA3B,YAAA7B,EAA8B,GAC9D,OAAOuD,EACH,KAAK,aAAaA,CAAuB,EACzC,MACN,CAEIhG,EAAK,UACL0C,EAAA,KAAK,OAAO,SAAZ,YAAAA,EAAoB,wBAAyB,IAG7C,CAACqD,GAAyB,KAAK,MAAM,IAAA,EAAM,SAAW,QACxD,KAAK,aAAA,CAET,CAAA,CAEJ,EAEA,KAAA,iBAAmB,IAAM,CACvB,KAAK,UAAA,EACL,KAAK,MAAM,WAAW,CAAE,OAAQ,WAAY,CAC9C,EAKA,KAAA,aAAgB5G,GAAuB,CAGrC,GAFA,KAAK,UAAA,EAEDA,EAAW,CACb,MAAMsC,EAAU,KAAK,WAAW,cAC7B,IAAA,EACA,KAAK,KAAM6C,GAAMA,EAAE,KAAOnF,CAAS,EAEtC,GAAI,CAACsC,EAAS,OACd,KAAK,WAAW,aAAa,WAAW,CAAE,QAAAA,EAAS,CACrD,CAEA,KAAK,MAAM,WAAW,CAAE,OAAQ,OAAQ,CAC1C,EAvEE,KAAK,OAAS/C,EACd,KAAK,WAAauF,EAClB,KAAK,WAAa3C,EAClB,KAAK,UAAYwE,EACjB,KAAK,MAAQ,IAAIvF,EAA4B,CAC3C,OAAQ,KAAK,WAAW,oBACpB,WACAJ,EAAA,KAAK,OAAO,SAAZ,MAAAA,EAAoB,eAClB,OACA,UAAA,CACP,EAED,KAAK,wBAAA,CACP,CA2DF,CC1GO,MAAM8F,CAAW,CAWtB,YAAY,CACV,QAAAC,EACA,OAAAxH,CAAA,EAIC,CAbH,KAAQ,KAAO,CACb,aAAeyH,GACb,2BAA2BA,CAAQ,iBACrC,kBAAoBA,GAClB,2BAA2BA,CAAQ,sBAAA,EAcvC,KAAA,gBAAkB,MAAOxH,GAAkB,CACzC,MAAM,KAAK,QAAQ,IAAI,KAAK,KAAK,aAAa,KAAK,OAAO,KAAK,EAAGA,CAAK,CACzE,EACA,KAAA,gBAAkB,SACT,KAAK,QAAQ,IAAI,KAAK,KAAK,aAAa,KAAK,OAAO,KAAK,CAAC,EAGnE,KAAA,qBAAuB,MAAOyH,GAAe,CAC3C,MAAM,KAAK,QAAQ,IAAI,KAAK,KAAK,kBAAkB,KAAK,OAAO,KAAK,EAAGA,CAAE,CAC3E,EACA,KAAA,qBAAuB,SACd,KAAK,QAAQ,IAAI,KAAK,KAAK,kBAAkB,KAAK,OAAO,KAAK,CAAC,EAftE,KAAK,QAAUF,EACf,KAAK,OAASxH,CAChB,CAeF,CC1BO,MAAM2H,EAAN,MAAMA,CAAU,CAsBb,YAAY,CAClB,OAAA3H,EACA,QAAAwH,EACA,MAAAI,EACA,IAAAC,CAAA,EASC,CACD,GA1BF,KAAO,MAAmB,CAAA,EAiH1B,KAAA,UAAY,IAAM,CAChB,KAAK,WAAW,MAAA,EAChB,KAAK,WAAW,MAAA,CAClB,EA1FM,CAACF,EAAU,wBACb,MAAM,MACJ,4EAAA,EAIJ,KAAK,OAAS3H,EACd,KAAK,IAAM6H,EACX,KAAK,IAAM,IAAI9H,EAAU,CAAE,OAAAC,EAAQ,EACnC,KAAK,WAAawH,EAAU,IAAID,EAAW,CAAE,QAAAC,EAAS,OAAAxH,CAAA,CAAQ,EAAI,OAClE,KAAK,MAAQ4H,EAEb,KAAK,WAAa,IAAI/D,EAAW,CAC/B,IAAK,KAAK,IACV,OAAQ,KAAK,OACb,WAAY,KAAK,UAAA,CAClB,EAED,KAAK,WAAa,IAAIyB,EAAW,CAC/B,OAAQ,KAAK,OACb,IAAK,KAAK,IACV,WAAY,KAAK,WACjB,+BACEqC,EAAU,wBAAwB,QAAA,CACrC,EAED,KAAK,WAAa,IAAIzB,EAAW,CAC/B,OAAQ,KAAK,OACb,IAAK,KAAK,IACV,WAAY,KAAK,WACjB,WAAY,KAAK,UAAA,CAClB,EAED,KAAK,QAAU,IAAIf,EAAQ,CACzB,OAAQ,KAAK,OACb,IAAK,KAAK,IACV,WAAY,KAAK,WACjB,WAAY,KAAK,UAAA,CAClB,EAED,KAAK,wBAA0B,IAAIzC,EAAwB,CACzD,IAAK,KAAK,IACV,OAAQ,KAAK,OACb,WAAY,KAAK,WACjB,WAAY,KAAK,WACjB,8BAA+BiF,EAAU,wBAAwB,OAAA,CAClE,EAED,KAAK,UAAY,IAAIR,EAAU,CAC7B,OAAQ,KAAK,OACb,WAAY,KAAK,WACjB,WAAY,KAAK,WACjB,UAAW,KAAK,SAAA,CACjB,CACH,CAqCF,EA/GEQ,EAAe,wBAGJ,KAyEXA,EAAO,WAAa,MAAO,CACzB,OAAA3H,EACA,QAAAwH,CAAA,IAII,WACJ,MAAMM,EAAiB,MAAM,IAAI/H,EAAU,CACzC,OAAAC,CAAA,CACD,EAAE,wBAAA,EAEH,GAAI,CAAC8H,EAAe,KAClB,MAAM,IAAI,MAAM,+BAA+B,EAGjD,OAAAH,EAAK,wBAA0B,CAC7B,UAASlG,EAAAqG,EAAe,OAAf,YAAArG,EAAqB,gCAAiC,GAC/D,WAAUC,EAAAoG,EAAe,OAAf,YAAApG,EAAqB,iCAAkC,EAAA,EAG5D,IAAIiG,EAAU,CACnB,OAAA3H,EACA,QAAAwH,EACA,QAAOzD,EAAA+D,EAAe,OAAf,YAAA/D,EAAqB,QAAS,CAAA,EACrC,IAAK,CACH,GAAI+D,EAAe,KAAK,IAAI,GAC5B,KAAMA,EAAe,KAAK,IAAI,IAAA,CAChC,CACD,CACH,EAzHK,IAAMC,EAANJ,ECVA,MAAMK,EAAuC,CAClD,4BAA6B,gBAC7B,6BAA8B,gBAC9B,iBAAkB,eAClB,qBAAsB,sCACtB,2BACE,6DACF,sBAAuB,OACvB,uBAAwB,yBACxB,kBAAmB,iBACnB,0BAA2B,kBAC3B,iBAAkB,2BAClB,iBAAkB,iBAClB,SAAU,UACV,qBAAsB,kBACtB,sBAAuB,uBACvB,qBAAsB,mBACxB,ECjBaC,EAAuC,CAClD,4BAA6B,qBAC7B,6BAA8B,uBAC9B,iBAAkB,aAClB,qBAAsB,mCACtB,2BACE,iGACF,sBAAuB,WACvB,uBAAwB,oBACxB,kBAAmB,kBACnB,0BAA2B,eAC3B,iBAAkB,8BAClB,iBAAkB,oBAClB,SAAU,WACV,qBAAsB,uBACtB,sBAAuB,uBACvB,qBAAsB,kBACxB,ECjBaC,EAAuC,CAClD,4BAA6B,yBAC7B,6BAA8B,4BAC9B,iBAAkB,oBAClB,qBAAsB,qCACtB,2BACE,2GACF,sBAAuB,WACvB,uBAAwB,sBACxB,kBAAmB,2BACnB,0BAA2B,iCAC3B,iBAAkB,4BAClB,iBAAkB,qBAClB,SAAU,WACV,qBAAsB,uBACtB,sBAAuB,4BACvB,qBAAsB,6BACxB,ECjBaC,EAAwC,CACnD,4BAA6B,qBAC7B,6BAA8B,gCAC9B,iBAAkB,mBAClB,qBAAsB,8BACtB,2BACE,0FACF,sBAAuB,YACvB,uBAAwB,qBACxB,kBAAmB,kBACnB,0BAA2B,gBAC3B,iBAAkB,mBAClB,iBAAkB,mBAClB,SAAU,WACV,qBAAsB,uBACtB,sBAAuB,wBACvB,qBAAsB,sBACxB,ECjBaC,GAAwC,CACnD,4BAA6B,wBAC7B,6BAA8B,6BAC9B,iBAAkB,qBAClB,qBAAsB,uCACtB,2BACE,yFACF,sBAAuB,YACvB,uBAAwB,wBACxB,kBAAmB,qBACnB,0BAA2B,gBAC3B,iBAAkB,qBAClB,iBAAkB,gBAClB,SAAU,WACV,qBAAsB,yBACtB,sBAAuB,0BACvB,qBAAsB,yBACxB,ECjBaC,GAAwC,CACnD,4BAA6B,qBAC7B,6BAA8B,0BAC9B,iBAAkB,kBAClB,qBAAsB,0BACtB,2BACE,uFACF,sBAAuB,SACvB,uBAAwB,uBACxB,kBAAmB,yBACnB,0BAA2B,iBAC3B,iBAAkB,uBAClB,iBAAkB,uBAClB,SAAU,cACV,qBAAsB,wBACtB,sBAAuB,0BACvB,qBAAsB,sBACxB,ECjBaC,GAAuC,CAClD,4BAA6B,wBAC7B,6BAA8B,gCAC9B,iBAAkB,wBAClB,qBAAsB,uCACtB,2BACE,wGACF,sBAAuB,YACvB,uBAAwB,uBACxB,kBAAmB,oBACnB,0BAA2B,eAC3B,iBAAkB,wBAClB,iBAAkB,iBAClB,SAAU,YACV,qBAAsB,qCACtB,sBAAuB,2BACvB,qBAAsB,uBACxB,ECjBaC,GAAwC,CACnD,4BAA6B,yBAC7B,6BAA8B,mCAC9B,iBAAkB,sBAClB,qBAAsB,0CACtB,2BACE,yFACF,sBAAuB,cACvB,uBAAwB,yBACxB,kBAAmB,wBACnB,0BAA2B,0BAC3B,iBAAkB,gCAClB,iBAAkB,uBAClB,SAAU,YACV,qBAAsB,+BACtB,sBAAuB,2BACvB,qBAAsB,sBACxB,ECjBaC,GAAsC,CACjD,4BAA6B,yBAC7B,6BAA8B,2BAC9B,iBAAkB,gBAClB,qBAAsB,8BACtB,2BACE,8FACF,sBAAuB,UACvB,uBAAwB,iBACxB,kBAAmB,0BACnB,0BAA2B,sBAC3B,iBAAkB,6BAClB,iBAAkB,yBAClB,SAAU,YACV,qBAAsB,sBACtB,sBAAuB,wBACvB,qBAAsB,uBACxB,ECjBaC,GAA0C,CACrD,4BAA6B,sBAC7B,6BAA8B,0BAC9B,iBAAkB,aAClB,qBAAsB,qCACtB,2BACE,4FACF,sBAAuB,YACvB,uBAAwB,oBACxB,kBAAmB,wBACnB,0BAA2B,gBAC3B,iBAAkB,wBAClB,iBAAkB,mBAClB,SAAU,YACV,qBAAsB,sBACtB,sBAAuB,uBACvB,qBAAsB,kBACxB,ECjBaC,GAAuC,CAClD,4BAA6B,sBAC7B,6BAA8B,kCAC9B,iBAAkB,eAClB,qBAAsB,kCACtB,2BACE,8EACF,sBAAuB,aACvB,uBAAwB,mBACxB,kBAAmB,2BACnB,0BAA2B,cAC3B,iBAAkB,2BAClB,iBAAkB,kBAClB,SAAU,aACV,qBAAsB,sBACtB,sBAAuB,mBACvB,qBAAsB,mBACxB,ECjBaC,GAA2C,CACtD,4BAA6B,0BAC7B,6BAA8B,8BAC9B,iBAAkB,gBAClB,qBAAsB,qCACtB,2BACE,wFACF,sBAAuB,WACvB,uBAAwB,wBACxB,kBAAmB,sBACnB,0BAA2B,gBAC3B,iBAAkB,wBAClB,iBAAkB,gBAClB,SAAU,WACV,qBAAsB,yBACtB,sBAAuB,wBACvB,qBAAsB,oBACxB,ECjBaC,GAAyC,CACpD,4BAA6B,oBAC7B,6BAA8B,gCAC9B,iBAAkB,mBAClB,qBAAsB,4CACtB,2BACE,6FACF,sBAAuB,aACvB,uBAAwB,qBACxB,kBAAmB,uBACnB,0BAA2B,mBAC3B,iBAAkB,+BAClB,iBAAkB,0BAClB,SAAU,WACV,qBAAsB,6BACtB,sBAAuB,wBACvB,qBAAsB,qBACxB,ECjBaC,GAAwC,CACnD,4BAA6B,0BAC7B,6BAA8B,0BAC9B,iBAAkB,kBAClB,qBAAsB,kCACtB,2BACE,mGACF,sBAAuB,YACvB,uBAAwB,mBACxB,kBAAmB,oBACnB,0BAA2B,cAC3B,iBAAkB,wBAClB,iBAAkB,uBAClB,SAAU,aACV,qBAAsB,2BACtB,sBAAuB,+BACvB,qBAAsB,wBACxB,ECjBaC,GAAwC,CACnD,4BAA6B,qBAC7B,6BAA8B,qBAC9B,iBAAkB,eAClB,qBAAsB,kCACtB,2BACE,yFACF,sBAAuB,SACvB,uBAAwB,oBACxB,kBAAmB,iBACnB,0BAA2B,gBAC3B,iBAAkB,mCAClB,iBAAkB,mBAClB,SAAU,eACV,qBAAsB,oBACtB,sBAAuB,uBACvB,qBAAsB,sBACxB,ECFMC,EAAY,CAChB,GAAIZ,EACJ,GAAIH,EACJ,GAAIQ,GACJ,GAAIF,GACJ,GAAIJ,EACJ,GAAIS,GACJ,GAAIP,GACJ,GAAIU,GACJ,GAAIJ,GACJ,GAAIL,GACJ,GAAIE,GACJ,GAAIE,GACJ,GAAIG,GACJ,GAAIX,EACJ,GAAIY,EACN,EAEaG,GAAY,OAAO,KAAKD,CAAS,EAGvC,SAASE,GACdC,EACkB,CAClB,OAAOF,GAAU,SAASE,CAAgB,CAC5C,CAEO,SAASC,GACd9I,EACA6I,EACAE,EACQ,OACR,QAAO3H,EAAA2H,GAAA,YAAAA,EAAYF,KAAZ,YAAAzH,EAAoBpB,KAAQ0I,EAAUG,CAAI,EAAE7I,CAAG,GAAK,EAC7D"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/api/client.ts","../src/api/api-caller.ts","../src/utils/is-exhaustive.ts","../src/utils/PrimitiveState.ts","../src/utils/Poller.ts","../src/utils/run-catching.ts","../src/context/active-session-polling.ctx.ts","../src/context/contact.ctx.ts","../src/utils/uuid.ts","../src/context/csat.ctx.ts","../src/context/session.ctx.ts","../src/context/message.ctx.ts","../src/context/router.ctx.ts","../src/context/storage.ctx.ts","../src/context/widget.ctx.ts","../src/translation/ar.ts","../src/translation/da.ts","../src/translation/de.ts","../src/translation/en.ts","../src/translation/es.ts","../src/translation/fi.ts","../src/translation/fr.ts","../src/translation/it.ts","../src/translation/nl.ts","../src/translation/no.ts","../src/translation/pl.ts","../src/translation/pt.ts","../src/translation/ro.ts","../src/translation/sv.ts","../src/translation/tr.ts","../src/translation/index.ts"],"sourcesContent":["import createClient, { type Middleware } from 'openapi-fetch';\nimport type { paths } from './schema';\nimport type { components } from './schema';\n\ntype Options = {\n baseUrl: string;\n onRequest?: Middleware['onRequest'];\n onResponse?: Middleware['onResponse'];\n onError?: Middleware['onError'];\n};\n\nconst defaultOnError: Middleware['onError'] = (onErrorOptions) => {\n console.log(onErrorOptions.error);\n};\n\nexport const basicClient = (options: Options) => {\n const client = createClient<paths>({\n baseUrl: options.baseUrl,\n });\n\n const middlewares: Middleware = {\n onRequest: options.onRequest,\n onResponse: options.onResponse,\n onError: options.onError || defaultOnError,\n };\n\n client.use(middlewares);\n return client;\n};\n\nexport type Endpoint = keyof paths;\nexport type Dto = components['schemas'];\n","import { type Dto, type Endpoint, basicClient } from './client';\nimport type { WidgetConfig } from '../types/widget-config';\nimport type {\n ResolveSessionDto,\n SendMessageDto,\n VoteInputDto,\n} from '../types/dtos';\n\nexport class ApiCaller {\n private client: ReturnType<typeof basicClient>;\n private config: WidgetConfig;\n private userToken: string | null = null;\n\n constructor({ config }: { config: WidgetConfig }) {\n this.config = config;\n this.userToken = config.user?.token || null;\n\n const { baseUrl, headers } = this.constructClientOptions(\n config.user?.token,\n );\n this.client = this.createOpenAPIClient({ baseUrl, headers });\n }\n\n private constructClientOptions = (token: string | null | undefined) => {\n const baseUrl =\n import.meta.env.MODE === 'test'\n ? 'http://localhost:8080'\n : this.config.apiUrl || 'https://api.open.cx';\n const headers = {\n 'X-Bot-Token': this.config.token,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n Authorization: token ? `Bearer ${token}` : undefined,\n };\n\n return { baseUrl, headers };\n };\n\n private createOpenAPIClient = ({\n baseUrl,\n headers,\n }: ReturnType<typeof this.constructClientOptions>) => {\n return basicClient({\n baseUrl,\n onRequest: ({ request }) => {\n Object.entries(headers).forEach(([key, value]) => {\n if (value) {\n request.headers.set(key, value);\n }\n });\n },\n });\n };\n\n setAuthToken = (token: string) => {\n this.userToken = token;\n const { baseUrl, headers } = this.constructClientOptions(token);\n this.client = this.createOpenAPIClient({ baseUrl, headers });\n };\n\n getExternalWidgetConfig = async () => {\n return await this.client.GET('/backend/widget/v2/config', {\n params: { header: { 'X-Bot-Token': this.config.token } },\n });\n };\n\n sendMessage = async (body: SendMessageDto, abortSignal?: AbortSignal) => {\n return await this.client.POST('/backend/widget/v2/chat/send', {\n body,\n signal: abortSignal,\n });\n };\n\n createUnverifiedContact = async (body: Dto['CreateUnverifiedContactDto']) => {\n return await this.client.POST(\n '/backend/widget/v2/contact/create-unverified',\n {\n params: { header: { 'x-bot-token': this.config.token } },\n body,\n },\n );\n };\n\n createSession = async (body: Dto['CreateWidgetSessionDto']) => {\n return await this.client.POST('/backend/widget/v2/create-session', {\n body,\n });\n };\n\n pollSessionAndHistory = async ({\n sessionId,\n lastMessageTimestamp,\n abortSignal,\n }: {\n sessionId: string;\n lastMessageTimestamp?: string;\n abortSignal: AbortSignal;\n }) => {\n const query = lastMessageTimestamp ? { lastMessageTimestamp } : undefined;\n return await this.client.GET('/backend/widget/v2/poll/{sessionId}', {\n params: { path: { sessionId }, query },\n signal: abortSignal,\n });\n };\n\n getSessions = async ({\n cursor,\n filters,\n abortSignal,\n }: {\n cursor: string | undefined;\n filters: Record<string, string>;\n abortSignal?: AbortSignal;\n }) => {\n return await this.client.GET('/backend/widget/v2/sessions', {\n params: { query: { cursor, filters: JSON.stringify(filters) } },\n signal: abortSignal,\n });\n };\n\n /**\n * openapi-fetch usually works fine for file uploads, but this time around it parses the payload in a weird way and results in 413 errors (payload too large)\n * Anyway, good old XHR even does it better with progress events\n */\n uploadFile = async ({\n file,\n abortSignal,\n onProgress,\n }: {\n file: File;\n abortSignal: AbortSignal;\n onProgress?: (percentage: number) => void;\n }): Promise<Dto['UploadWidgetFileResponseDto']> => {\n return new Promise((resolve, reject) => {\n const formData = new FormData();\n formData.append('file', file);\n\n const xhr = new XMLHttpRequest();\n\n // Set up abort functionality\n if (abortSignal) {\n abortSignal.addEventListener('abort', () => {\n xhr.abort();\n reject(new DOMException('Aborted', 'AbortError'));\n });\n\n // If already aborted, reject immediately\n if (abortSignal.aborted) {\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n }\n\n xhr.upload.addEventListener('progress', (event) => {\n if (event.lengthComputable && onProgress) {\n const percentage = Math.round((event.loaded / event.total) * 100);\n onProgress(percentage);\n }\n });\n\n // Handle completion\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n const data = JSON.parse(xhr.responseText);\n resolve(data);\n } catch (error) {\n reject(new Error(`Failed to parse response: ${error}`));\n }\n } else {\n reject(new Error(`Upload failed with status: ${xhr.status}`));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new Error('Network error occurred'));\n });\n\n xhr.addEventListener('timeout', () => {\n reject(new Error('Upload timed out'));\n });\n\n const { baseUrl } = this.constructClientOptions(this.userToken);\n\n const path = '/backend/widget/v2/upload' satisfies Endpoint;\n const uploadUrl = `${baseUrl}${path}`;\n xhr.open('POST', uploadUrl);\n\n xhr.setRequestHeader('X-Bot-Token', this.config.token);\n const userToken = this.userToken ?? this.config.user?.token;\n if (userToken) {\n xhr.setRequestHeader('Authorization', `Bearer ${this.userToken}`);\n } else {\n console.error('User token not set');\n }\n\n xhr.send(formData);\n });\n };\n\n vote = async (body: VoteInputDto) => {\n return await this.client.POST('/backend/widget/v2/chat/vote', { body });\n };\n\n resolveSession = async (\n body: ResolveSessionDto,\n abortSignal?: AbortSignal,\n ) => {\n return await this.client.POST('/backend/widget/v2/session/resolve', {\n body,\n signal: abortSignal,\n });\n };\n\n createStateCheckpoint = async (\n body: Dto['WidgetCreateStateCheckpointInputDto'],\n ) => {\n return await this.client.POST('/backend/widget/v2/checkpoint', {\n body,\n });\n };\n\n submitCsat = async (body: Dto['WidgetSubmitCsatInputDto']) => {\n return await this.client.POST('/backend/widget/v2/submit-csat', { body });\n };\n}\n","export function isExhaustive(value: never, funcName: string) {\n console.error(`Missing case for ${value} in ${funcName}`);\n}\n","import isEqual from 'lodash.isequal';\n\nexport type Subscriber<T> = (data: T) => void;\n\nexport class PrimitiveState<S> {\n private subscribers = new Set<Subscriber<S>>();\n private state: S;\n private initialState: S;\n\n constructor(state: S) {\n this.state = state;\n this.initialState = state;\n }\n\n get = (): S => this.state;\n\n set = (newState: S): void => {\n if (!isEqual(this.state, newState)) {\n this.state = newState;\n this.notifySubscribers(newState);\n }\n };\n\n setPartial = (_s: Partial<S>): void => {\n if (_s === undefined || _s === null) return;\n const newState = { ...this.state, ..._s };\n this.set(newState);\n };\n\n reset = (): void => {\n this.set(this.initialState);\n };\n\n private notifySubscribers = (state: S) => {\n const subscribersArray = Array.from(this.subscribers);\n subscribersArray.forEach((callback) => {\n try {\n callback(state);\n } catch (error) {\n if (import.meta.env.MODE !== 'test') {\n console.error(error);\n }\n }\n });\n };\n\n subscribe = (callback: Subscriber<S>): (() => void) => {\n this.subscribers.add(callback);\n\n return () => {\n this.subscribers.delete(callback);\n };\n };\n}\n","import { PrimitiveState } from './PrimitiveState';\n\nexport type PollingState = {\n isPolling: boolean;\n isError: boolean;\n};\n\nexport class Poller {\n state = new PrimitiveState<PollingState>({\n isPolling: false,\n isError: false,\n });\n private abortController = new AbortController();\n\n reset = () => {\n this.abortController.abort('Resetting poller');\n this.stopPolling?.();\n this.stopPolling = null;\n };\n\n private stopPolling: (() => void) | null = null;\n\n startPolling = (\n cb: (abortSignal: AbortSignal) => Promise<void>,\n intervalMs: number,\n ) => {\n if (this.stopPolling) return;\n\n const timeouts: NodeJS.Timeout[] = [];\n\n const poll = async () => {\n this.abortController = new AbortController();\n this.state.setPartial({ isPolling: true });\n\n try {\n await cb(this.abortController.signal);\n } catch (error) {\n if (this.abortController.signal.aborted) {\n // If aborted, just return and do not schedule the nest poll\n return;\n }\n console.error('Failed to poll:', error);\n this.state.setPartial({ isError: true });\n } finally {\n this.state.setPartial({ isPolling: false });\n }\n\n // Another check to stop scheduling polls in case someone removes the early return in the catch above\n if (this.abortController.signal.aborted) {\n console.log('Poller aborted, not scheduling anymore');\n } else {\n timeouts.push(setTimeout(poll, intervalMs));\n }\n };\n\n poll();\n\n this.stopPolling = () => {\n timeouts.forEach(clearTimeout);\n this.state.reset();\n };\n };\n}\n","export function run<T>(fn: () => T): T {\n return fn();\n}\n\nexport type Result<T, E> =\n | { data: T; error?: undefined }\n | { data?: undefined; error: E };\n\n/**\n * Many thanks to @m-tabaza for this utility... Kotlin vibes\n */\nexport function runCatching<T, E = unknown>(\n callback: () => Promise<T>,\n): Promise<Result<T, E>>;\nexport function runCatching<T, E = unknown>(callback: () => T): Result<T, E>;\nexport function runCatching<T, E = unknown>(\n callback: () => T | Promise<T>,\n): Result<T, E> | Promise<Result<T, E>> {\n try {\n const result = callback();\n\n if (result instanceof Promise) {\n return result.then((data) => ({ data })).catch((error: E) => ({ error }));\n }\n\n return { data: result };\n } catch (error) {\n return { error: error as E };\n }\n}\n","import type { ApiCaller } from '../api/api-caller';\nimport type { ActionCallDto, MessageDto } from '../types/dtos';\nimport {\n type WidgetMessageU,\n type WidgetSystemMessageU,\n} from '../types/messages';\nimport type { WidgetConfig } from '../types/widget-config';\nimport { isExhaustive } from '../utils/is-exhaustive';\nimport { Poller } from '../utils/Poller';\nimport { runCatching } from '../utils/run-catching';\nimport type { MessageCtx } from './message.ctx';\nimport type { SessionCtx } from './session.ctx';\n\nexport class ActiveSessionPollingCtx {\n private api: ApiCaller;\n private config: WidgetConfig;\n private sessionCtx: SessionCtx;\n private messageCtx: MessageCtx;\n private sessionPollingIntervalSeconds: number;\n\n private poller = new Poller();\n private fetchSessionAndFullHistoryAbortController = new AbortController();\n\n constructor({\n api,\n config,\n sessionCtx,\n messageCtx,\n sessionPollingIntervalSeconds,\n }: {\n api: ApiCaller;\n config: WidgetConfig;\n sessionCtx: SessionCtx;\n messageCtx: MessageCtx;\n sessionPollingIntervalSeconds: number;\n }) {\n this.api = api;\n this.config = config;\n this.sessionCtx = sessionCtx;\n this.messageCtx = messageCtx;\n this.sessionPollingIntervalSeconds = sessionPollingIntervalSeconds;\n\n this.registerPolling();\n }\n\n private registerPolling = () => {\n this.sessionCtx.sessionState.subscribe(({ session }) => {\n if (session?.id) {\n this.poller.startPolling(async (abortSignal) => {\n this.fetchSessionAndHistory({ sessionId: session.id, abortSignal });\n }, this.sessionPollingIntervalSeconds * 1000);\n } else {\n this.poller.reset();\n }\n });\n\n /**\n * When session is closed... fetch the whole history... because of some race conditions that might happen.\n *\n * example:\n * - the csat_requested system message is sometimes inserted in db before the AI's response, but the AI's response might sometimes arrive before the polling's response, which makes the `lastMessageTimestamp` greater than the csat_requested system message's timestamp... so it's never polled in that case\n */\n this.sessionCtx.sessionState.subscribe(({ session }) => {\n if (session?.id && !session.isOpened) {\n try {\n this.fetchSessionAndFullHistoryAbortController =\n new AbortController();\n this.fetchSessionAndHistory({\n sessionId: session.id,\n abortSignal: this.fetchSessionAndFullHistoryAbortController.signal,\n fetchFullHistory: true,\n });\n } catch (error) {\n if (!this.fetchSessionAndFullHistoryAbortController.signal.aborted) {\n console.error('Failed to fetch session and full history:', error);\n }\n }\n } else {\n this.fetchSessionAndFullHistoryAbortController.abort();\n }\n });\n };\n\n fetchSessionAndHistory = async ({\n sessionId,\n abortSignal,\n fetchFullHistory = false,\n }: {\n sessionId: string;\n abortSignal: AbortSignal;\n fetchFullHistory?: boolean;\n }): Promise<void> => {\n /**\n * This is a bit of an implicit contract... there are two cases here\n * 1. If there are no messages in state, it means the user selected a previous session from the sessions screen and got routed to the chat,\n * in this case, we want to show a loading indicator until the initial fetch is done\n * 2. There is a single message in state, which is the optimistically rendered user message,\n * in this case, we don't want to show a loading indicator\n */\n if (this.messageCtx.state.get().messages.length === 0) {\n this.messageCtx.state.setPartial({ isInitialFetchLoading: true });\n }\n\n const messages = this.messageCtx.state.get().messages;\n const lastMessageTimestamp =\n messages.length > 0\n ? (messages[messages.length - 1]?.timestamp ?? undefined)\n : undefined;\n\n const { data } = await this.api.pollSessionAndHistory({\n sessionId,\n abortSignal,\n lastMessageTimestamp: fetchFullHistory ? undefined : lastMessageTimestamp,\n });\n\n if (data?.session) {\n this.sessionCtx.sessionState.setPartial({ session: data.session });\n this.sessionCtx.setSessions([data.session]);\n }\n\n if (data?.history && data.history.length > 0) {\n // Get a fresh reference to current messages after the poll is done\n const prevMessages = this.messageCtx.state.get().messages;\n const newMessages = data.history\n .map(this.mapHistoryToMessage)\n .filter((msg): msg is WidgetMessageU => msg !== null)\n .filter(\n (newMsg) =>\n !prevMessages.some((existingMsg) => existingMsg.id === newMsg.id),\n );\n this.messageCtx.state.setPartial({\n messages: [...prevMessages, ...newMessages],\n });\n }\n\n if (this.messageCtx.state.get().isInitialFetchLoading) {\n this.messageCtx.state.setPartial({ isInitialFetchLoading: false });\n }\n };\n\n mapHistoryToMessage = (history: MessageDto): WidgetMessageU | null => {\n const commonFields = {\n id: history.publicId,\n timestamp: history.sentAt || '',\n attachments: history.attachments || undefined,\n };\n\n if (history.sender.kind === 'user') {\n return {\n ...commonFields,\n type: 'USER',\n content: history.content.text || '',\n deliveredAt: history.sentAt || '',\n };\n }\n\n if (history.sender.kind === 'agent') {\n return {\n ...commonFields,\n type: 'AGENT',\n component: 'agent_message',\n data: {\n message: history.content.text || '',\n },\n agent: {\n name: history.sender.name || '',\n avatar: history.sender.avatar || '',\n id: null,\n isAi: false,\n },\n };\n }\n\n if (history.sender.kind === 'ai') {\n const action =\n history.actionCalls && history.actionCalls.length > 0\n ? history.actionCalls[history.actionCalls.length - 1]\n : undefined;\n\n return {\n ...commonFields,\n type: 'AI',\n component: 'bot_message',\n agent: {\n id: null,\n name: this.config.bot?.name || '',\n isAi: true,\n avatar: this.config.bot?.avatar || '',\n },\n data: {\n message: history.content.text || '',\n action: action\n ? {\n name: action.actionName,\n data: this.extractActionResult(action),\n }\n : undefined,\n },\n };\n }\n\n if (history.sender.kind === 'system') {\n const message = this.constructSystemMessage(history);\n if (message === null) return null;\n\n return { ...message };\n }\n\n return null;\n };\n\n constructSystemMessage = (\n history: MessageDto,\n ): WidgetSystemMessageU | null => {\n if (!history || !history.systemMessagePayload) return null;\n switch (history.systemMessagePayload.type) {\n case 'state_checkpoint':\n return {\n id: history.publicId,\n type: 'SYSTEM',\n subtype: 'state_checkpoint',\n data: { payload: history.systemMessagePayload.payload },\n timestamp: history.sentAt || '',\n attachments: undefined,\n };\n case 'csat_requested':\n return {\n id: history.publicId,\n type: 'SYSTEM',\n subtype: 'csat_requested',\n data: { payload: undefined },\n timestamp: history.sentAt || '',\n attachments: undefined,\n };\n case 'csat_submitted':\n return {\n id: history.publicId,\n type: 'SYSTEM',\n subtype: 'csat_submitted',\n data: {\n payload: {\n score: history.systemMessagePayload.payload.score ?? undefined,\n feedback:\n history.systemMessagePayload.payload.feedback ?? undefined,\n },\n },\n timestamp: history.sentAt || '',\n attachments: undefined,\n };\n case 'none':\n return null;\n default:\n isExhaustive(\n history.systemMessagePayload,\n this.constructSystemMessage.name,\n );\n return null;\n }\n };\n\n extractActionResult = (action: ActionCallDto) => {\n const result = action.result;\n\n if (result === null) return result;\n if (typeof result !== 'object') return result;\n\n if (\n 'responseBodyText' in result &&\n typeof result.responseBodyText === 'string'\n ) {\n const responseBodyText = result.responseBodyText;\n const parsed = runCatching(() => JSON.parse(responseBodyText)).data;\n if (parsed) return parsed;\n }\n\n return action.result;\n };\n}\n","import { PrimitiveState } from '../utils/PrimitiveState';\nimport { ApiCaller } from '../api/api-caller';\nimport { type WidgetConfig } from '../types/widget-config';\nimport { type Dto } from '../api/client';\nimport type { StorageCtx } from './storage.ctx';\nimport { v4 } from 'uuid';\n\ntype ContactState = {\n contact: {\n token: string;\n externalId: string | undefined;\n } | null;\n extraCollectedData: Record<string, string> | undefined;\n isCreatingUnverifiedContact: boolean;\n isErrorCreatingUnverifiedContact: boolean;\n};\n\nexport class ContactCtx {\n private config: WidgetConfig;\n private storageCtx?: StorageCtx;\n private api: ApiCaller;\n state: PrimitiveState<ContactState>;\n\n constructor({\n config,\n api,\n storageCtx,\n }: {\n api: ApiCaller;\n config: WidgetConfig;\n storageCtx?: StorageCtx;\n }) {\n this.config = config;\n this.storageCtx = storageCtx;\n this.api = api;\n\n this.state = new PrimitiveState<ContactState>({\n contact: config.user?.token\n ? {\n token: config.user.token,\n // Set optional externalId from config... not local storage\n externalId: config.user.externalId,\n }\n : null,\n extraCollectedData: undefined,\n isCreatingUnverifiedContact: false,\n isErrorCreatingUnverifiedContact: false,\n });\n\n this.autoCreateUnverifiedUserIfNotExists();\n }\n\n shouldCollectData = (): boolean => {\n if (!this.state.get().contact?.token && this.config.collectUserData) {\n return true;\n }\n return false;\n };\n\n private autoCreateUnverifiedUserIfNotExists = async () => {\n /**\n * If token is passed in config... we consider it as a verified user and do nothing (we don't force generate an externalId)\n * If a non-verified user take their token and place it in the config... the backend will refuse their requests saying that a non-verified token must have an externalId to create and get sessions\n */\n if (this.config.user?.token) return;\n\n /**\n * If collectUserData is true... we check if the user entered their credentials before, otherwise, show them the welcome screen so they can enter their credentials\n */\n if (this.config.collectUserData && !this.config.user?.data?.email) {\n /**\n * If extra data collection fields are passed,\n * we do not check for a persisted token.\n * This will force the contact to enter the extra data fields every time they visit the page.\n */\n if (this.config.extraDataCollectionFields?.length) {\n return;\n }\n\n const persistedToken = await this.storageCtx?.getContactToken();\n if (persistedToken) {\n await this.setUnverifiedContact(persistedToken);\n }\n // return early whether there is a persisted token or not\n return;\n }\n\n /**\n * If there is no email, then it is an anonymous contact, we check if the contact is persisted or we create a new one\n */\n if (!this.config.user?.data?.email) {\n const persistedToken = await this.storageCtx?.getContactToken();\n if (persistedToken) {\n await this.setUnverifiedContact(persistedToken);\n // return early only if there is a persisted token\n return;\n }\n }\n\n /**\n * If we reach here... then it is one of two\n * 1. There is an email passed in the config, let's just upsert the unverified contact without checking for persistence; maybe the email in the config did change.\n * 2. It is an anonymous contact (without an email) using this device for the first time.\n *\n * This is still safe even if the email in the config is tampered with by the contact, because there is a client-side externalId that will be generated for the current device...\n * So, only sessions created on this device will be accessible.\n */\n await this.createUnverifiedContact({\n email: this.config.user?.data?.email,\n non_verified_name: this.config.user?.data?.name,\n non_verified_custom_data: this.config.user?.data?.customData,\n });\n };\n\n createUnverifiedContact = async (\n payload: Dto['CreateUnverifiedContactDto'],\n extraCollectedData?: Record<string, string>,\n ): Promise<void> => {\n this.state.setPartial({ extraCollectedData });\n\n try {\n this.state.setPartial({\n isCreatingUnverifiedContact: true,\n isErrorCreatingUnverifiedContact: false,\n });\n\n const { data } = await this.api.createUnverifiedContact(payload);\n if (data?.token) {\n await this.setUnverifiedContact(data.token);\n } else {\n this.state.setPartial({ isErrorCreatingUnverifiedContact: true });\n }\n } finally {\n this.state.setPartial({ isCreatingUnverifiedContact: false });\n }\n };\n\n setUnverifiedContact = async (token: string) => {\n const persistedExternalId = await this.storageCtx?.getExternalContactId();\n /** Give priority to `externalId` from the config */\n const externalId: string =\n this.config.user?.externalId || persistedExternalId || v4();\n this.api.setAuthToken(token);\n // Set token in state after setting the token in the api handler\n await this.storageCtx?.setContactToken(token);\n await this.storageCtx?.setExternalContactId(externalId);\n this.state.setPartial({ contact: { token, externalId } });\n };\n}\n","import { v4 as uuidv4 } from 'uuid';\n\nexport function genUuid() {\n return uuidv4();\n}\n","import type { ApiCaller } from '../api/api-caller';\nimport type { Dto } from '../api/client';\nimport type { SafeOmit } from '../types/helpers';\nimport type { WidgetConfig } from '../types/widget-config';\nimport { genUuid } from '../utils/uuid';\nimport type { MessageCtx } from './message.ctx';\nimport type { SessionCtx } from './session.ctx';\n\nexport class CsatCtx {\n private config: WidgetConfig;\n private api: ApiCaller;\n private sessionCtx: SessionCtx;\n private messageCtx: MessageCtx;\n\n constructor({\n config,\n api,\n sessionCtx,\n messageCtx,\n }: {\n config: WidgetConfig;\n api: ApiCaller;\n sessionCtx: SessionCtx;\n messageCtx: MessageCtx;\n }) {\n this.config = config;\n this.api = api;\n this.sessionCtx = sessionCtx;\n this.messageCtx = messageCtx;\n }\n\n submitCsat = async (\n body: Pick<Dto['WidgetSubmitCsatInputDto'], 'score' | 'feedback'>,\n ) => {\n const currentSessionId = this.sessionCtx.sessionState.get().session?.id;\n if (!currentSessionId) {\n return { data: null, error: 'No session id found' };\n }\n\n const uuid = genUuid();\n this.messageCtx.state.setPartial({\n messages: [\n ...this.messageCtx.state.get().messages,\n {\n id: uuid,\n type: 'SYSTEM',\n subtype: 'csat_submitted',\n timestamp: new Date().toISOString(),\n data: {\n payload: {\n score: body.score,\n feedback: body.feedback,\n },\n },\n },\n ],\n });\n\n const { data, error } = await this.api.submitCsat({\n ...body,\n system_message_uuid: uuid,\n session_id: currentSessionId,\n });\n return { data, error };\n };\n}\n","import type { ApiCaller } from '../api/api-caller';\nimport type { Dto } from '../api/client';\nimport type { SessionDto } from '../types/dtos';\nimport type { WidgetConfig } from '../types/widget-config';\nimport { Poller } from '../utils/Poller';\nimport { PrimitiveState } from '../utils/PrimitiveState';\nimport { runCatching } from '../utils/run-catching';\nimport type { ContactCtx } from './contact.ctx';\n\ntype SessionState = {\n /**\n * The currently selected session.\n * Can be null if no session is selected, or if in chat screen and the session is not created yet.\n */\n session: SessionDto | null;\n isCreatingSession: boolean;\n isResolvingSession: boolean;\n};\ntype SessionsState = {\n /** List of all user sessions */\n data: SessionDto[];\n /** A cursor to get the next page of sessions */\n cursor: string | undefined;\n /** Indicates if no more pages are left */\n isLastPage: boolean;\n /** Did fetch for the first time */\n didStartInitialFetch: boolean;\n isInitialFetchLoading: boolean;\n};\n\nexport class SessionCtx {\n private config: WidgetConfig;\n private api: ApiCaller;\n private contactCtx: ContactCtx;\n private sessionsPollingIntervalSeconds: number;\n private sessionsRefresher = new Poller();\n\n public sessionState = new PrimitiveState<SessionState>({\n session: null,\n isCreatingSession: false,\n isResolvingSession: false,\n });\n public sessionsState = new PrimitiveState<SessionsState>({\n data: [],\n cursor: undefined,\n isLastPage: false,\n didStartInitialFetch: false,\n /**\n * Initialize this as `true` so it always starts loading until the first fetch is done\n */\n isInitialFetchLoading: true,\n });\n\n constructor({\n config,\n api,\n contactCtx,\n sessionsPollingIntervalSeconds,\n }: {\n config: WidgetConfig;\n api: ApiCaller;\n contactCtx: ContactCtx;\n sessionsPollingIntervalSeconds: number;\n }) {\n this.config = config;\n this.api = api;\n this.contactCtx = contactCtx;\n this.sessionsPollingIntervalSeconds = sessionsPollingIntervalSeconds;\n\n this.registerSessionsRefresherWrapper();\n }\n\n /** Clears the session and stops polling */\n reset = async () => {\n // Reset the session only, leave sessions as-is\n this.sessionState.reset();\n };\n\n private registerSessionsRefresherWrapper = () => {\n if (\n // If the widget config was initially provided with a contact token, no state change would be triggered, so we just fetch\n this.contactCtx.state.get().contact?.token &&\n !this.sessionsState.get().didStartInitialFetch\n ) {\n this.registerSessionsRefresher();\n } else {\n // In other cases where auto authenticate is fired, the token would be eventually set in state, so we wait for it\n this.contactCtx.state.subscribe(({ contact }) => {\n if (contact?.token && !this.sessionsState.get().didStartInitialFetch) {\n this.registerSessionsRefresher();\n }\n });\n }\n };\n\n private registerSessionsRefresher = () => {\n this.sessionsRefresher.startPolling(async () => {\n if (this.sessionsState.get().didStartInitialFetch === false) {\n this.sessionsState.setPartial({ didStartInitialFetch: true });\n }\n\n await this.refreshSessions();\n\n if (this.sessionsState.get().isInitialFetchLoading === true) {\n this.sessionsState.setPartial({ isInitialFetchLoading: false });\n }\n }, this.sessionsPollingIntervalSeconds * 1000);\n };\n\n private getParsedCustomData =\n (): Dto['CreateWidgetSessionDto']['customData'] => {\n return Object.fromEntries<\n NonNullable<Dto['CreateWidgetSessionDto']['customData']>[string]\n >(\n Object.entries(this.config.sessionCustomData || {}).map(\n ([key, value]) => {\n if (typeof value === 'string') return [key, value];\n if (typeof value === 'boolean') return [key, value];\n if (typeof value === 'number') return [key, value];\n // TODO maybe better to unnest instead of stringify-ing\n return [key, runCatching(() => JSON.stringify(value))?.data || ''];\n },\n ),\n );\n };\n\n createSession = async () => {\n this.sessionState.setPartial({ session: null, isCreatingSession: true });\n\n const externalId = this.contactCtx.state.get().contact?.externalId;\n\n const customData: Dto['CreateWidgetSessionDto']['customData'] = {\n ...this.getParsedCustomData(),\n ...(externalId ? { external_id: externalId } : {}),\n };\n const { data: session, error } = await this.api.createSession({\n customData: Object.keys(customData).length > 0 ? customData : undefined,\n });\n if (session) {\n this.sessionState.setPartial({ session, isCreatingSession: false });\n return session;\n }\n\n this.sessionState.setPartial({ isCreatingSession: false });\n console.error('Failed to create session:', error);\n return null;\n };\n\n loadMoreSessions = async () => {\n if (this.sessionsState.get().isLastPage) return;\n\n const { data } = await this.getSessions({\n cursor: this.sessionsState.get().cursor,\n });\n\n if (data) {\n const allSessions = [...this.sessionsState.get().data, ...data.items];\n // TODO sort by updated at\n const deduped = allSessions.filter(\n (s, i, self) => i === self.findIndex((_s) => s.id === _s.id),\n );\n\n this.sessionsState.setPartial({\n data: deduped,\n cursor: data.next || undefined,\n isLastPage: data.next === null,\n });\n }\n };\n\n private getSessions = async ({ cursor }: { cursor: string | undefined }) => {\n if (!this.contactCtx.state.get().contact?.token) return { data: null };\n\n const externalId = this.contactCtx.state.get().contact?.externalId;\n return await this.api.getSessions({\n cursor,\n filters: externalId\n ? {\n external_id: externalId,\n }\n : {},\n });\n };\n\n setSessions = (data: SessionDto[]) => {\n const sessions = [...data, ...this.sessionsState.get().data].filter(\n (s, i, self) => i === self.findIndex((_s) => s.id === _s.id),\n );\n this.sessionsState.setPartial({ data: sessions });\n };\n\n refreshSessions = async () => {\n // Get the first page only (pass no `cursor`)\n const { data } = await this.getSessions({ cursor: undefined });\n if (!data) return;\n this.setSessions(data.items);\n };\n\n resolveSession = async () => {\n const currentSession = this.sessionState.get().session;\n if (!currentSession || !currentSession.isOpened) {\n return { success: false, error: 'Session is not opened' } as const;\n }\n\n this.sessionState.setPartial({ isResolvingSession: true });\n\n const { data: session, error } = await this.api.resolveSession({\n session_id: currentSession.id,\n });\n\n if (session) {\n this.sessionState.setPartial({ session, isResolvingSession: false });\n return { success: true, data: session } as const;\n }\n\n this.sessionState.setPartial({ isResolvingSession: false });\n return { success: false, error } as const;\n };\n\n createStateCheckpoint = async (\n payload: Dto['WidgetCreateStateCheckpointInputDto']['payload'],\n ) => {\n const session_id = this.sessionState.get().session?.id;\n if (!session_id) return;\n\n const { data, error } = await this.api.createStateCheckpoint({\n session_id,\n payload,\n });\n\n if (data?.success) return { success: true } as const;\n\n return { success: false } as const;\n };\n}\n","import { ApiCaller } from '../api/api-caller';\nimport type { WidgetConfig } from '../types/widget-config';\nimport {\n type WidgetAiMessage,\n type WidgetMessageU,\n type WidgetUserMessage,\n} from '../types/messages';\nimport type {\n MessageAttachmentType,\n SendMessageDto,\n SendMessageOutputDto,\n} from '../types/dtos';\nimport { PrimitiveState } from '../utils/PrimitiveState';\nimport { genUuid } from '../utils/uuid';\nimport { SessionCtx } from './session.ctx';\nimport type { ContactCtx } from './contact.ctx';\n\ntype MessageCtxState = {\n messages: WidgetMessageU[];\n /** Regardless of assignee */\n isSendingMessage: boolean;\n isSendingMessageToAI: boolean;\n lastAIResMightSolveUserIssue: boolean;\n isInitialFetchLoading: boolean;\n};\n\nexport class MessageCtx {\n private config: WidgetConfig;\n private api: ApiCaller;\n private contactCtx: ContactCtx;\n private sessionCtx: SessionCtx;\n\n public state = new PrimitiveState<MessageCtxState>({\n messages: [],\n isSendingMessage: false,\n isSendingMessageToAI: false,\n lastAIResMightSolveUserIssue: false,\n isInitialFetchLoading: false,\n });\n\n private sendMessageAbortController = new AbortController();\n\n constructor({\n config,\n api,\n sessionCtx,\n contactCtx,\n }: {\n config: WidgetConfig;\n api: ApiCaller;\n sessionCtx: SessionCtx;\n contactCtx: ContactCtx;\n }) {\n this.config = config;\n this.api = api;\n this.sessionCtx = sessionCtx;\n this.contactCtx = contactCtx;\n }\n\n reset = () => {\n this.sendMessageAbortController.abort('Resetting chat');\n this.state.reset();\n };\n\n sendMessage = async (input: {\n content: SendMessageDto['content'];\n attachments?: SendMessageDto['attachments'];\n customData?: SendMessageDto['custom_data'];\n exitModePrompt?: string;\n }): Promise<void> => {\n try {\n /* ------------------------------------------------------ */\n /* Prevent sending if there is no content */\n /* ------------------------------------------------------ */\n if (\n !input.content.trim() &&\n (!input.attachments || input.attachments.length === 0)\n ) {\n console.warn(\n 'Cannot send an empty message of no content or attachments',\n );\n return;\n }\n /* ------------------------------------------------------ */\n /* Prevent sending while waiting for AI res */\n /* ------------------------------------------------------ */\n const session = this.sessionCtx.sessionState.get().session;\n const assignee = session?.assignee.kind;\n const isAssignedToAI = assignee === 'ai';\n const isSendingToAI = this.state.get().isSendingMessageToAI;\n const lastMessage = this.state.get().messages.at(-1);\n if (\n isSendingToAI ||\n // If last message is from user, then bot response did not arrive yet\n (isAssignedToAI && lastMessage?.type === 'USER')\n ) {\n console.warn('Cannot send messages while awaiting AI response');\n return;\n }\n\n /* ------------------------------------------------------ */\n /* Start */\n /* ------------------------------------------------------ */\n this.sendMessageAbortController = new AbortController();\n this.state.setPartial({\n lastAIResMightSolveUserIssue: false,\n isSendingMessage: true,\n isSendingMessageToAI: !!isAssignedToAI || !session,\n });\n /* ------------------------------------------------------ */\n /* Optimistically add message to rendered messages */\n /* ------------------------------------------------------ */\n const currentMessages = this.state.get().messages;\n const shouldInsertInitialMessages =\n !this.sessionCtx.sessionState.get().session?.id &&\n currentMessages.length === 0 &&\n this.config.advancedInitialMessages?.some((m) => m.persistent);\n const insertableInitialMessages = shouldInsertInitialMessages\n ? (this.config.advancedInitialMessages || [])\n .filter((m) => m.persistent)\n .map(\n (m) =>\n ({\n id: genUuid(),\n component: 'bot_message',\n type: 'AI',\n timestamp: new Date().toISOString(),\n data: {\n message: m.message,\n },\n agent: this.config.bot ? { ...this.config.bot, isAi: true, id: null } : undefined,\n }) satisfies WidgetAiMessage,\n )\n : [];\n const userMessage = this.toUserMessage(\n input.content.trim(),\n input.attachments || undefined,\n );\n this.state.setPartial({\n messages: [\n ...insertableInitialMessages,\n ...currentMessages,\n userMessage,\n ],\n });\n\n /* ------------------------------------------------------ */\n /* Create session if not exists */\n /* ------------------------------------------------------ */\n if (!this.sessionCtx.sessionState.get().session?.id) {\n const createdSession = await this.sessionCtx.createSession();\n\n // TODO: apply some retry logic here\n if (!createdSession) {\n console.error('Failed to create session');\n return;\n }\n\n // Refresh sessions list instantly to get the newly created session in the sessions list\n void this.sessionCtx.refreshSessions();\n }\n const sessionId = this.sessionCtx.sessionState.get().session?.id;\n if (!sessionId) return;\n /* ------------------------------------------------------ */\n /* Send and wait for bot response */\n /* ------------------------------------------------------ */\n const { data } = await this.api.sendMessage(\n {\n uuid: userMessage.id,\n bot_token: this.config.token,\n headers: this.config.headers,\n query_params: this.config.queryParams,\n body_properties: this.config.bodyProperties,\n session_id: sessionId,\n content: userMessage.content,\n attachments: input.attachments,\n clientContext: this.config.context,\n custom_data: {\n ...(this.config.messageCustomData || {}),\n ...(input.customData || {}),\n },\n language: this.config.language,\n exit_mode_prompt: input.exitModePrompt,\n initial_messages: shouldInsertInitialMessages\n ? insertableInitialMessages.map((m) => ({\n uuid: m.id,\n content: m.data.message,\n }))\n : undefined,\n },\n this.sendMessageAbortController.signal,\n );\n\n if (data?.success) {\n /* ------------------------------------------------------ */\n /* Append bot reply if not fetched from polling */\n /* ------------------------------------------------------ */\n const botMessage = this.toBotMessage(data);\n if (botMessage) {\n const prevMessages = this.state.get().messages;\n const shouldAppend = !prevMessages.some(\n (m) => m.id === botMessage.id,\n );\n if (!shouldAppend) {\n this.state.setPartial({\n lastAIResMightSolveUserIssue:\n data.autopilotResponse?.mightSolveUserIssue ||\n data.uiResponse?.mightSolveUserIssue,\n });\n return;\n }\n this.state.setPartial({\n messages: [...prevMessages, botMessage],\n lastAIResMightSolveUserIssue:\n data.autopilotResponse?.mightSolveUserIssue ||\n data.uiResponse?.mightSolveUserIssue,\n });\n }\n if (data.session) {\n this.sessionCtx.sessionState.setPartial({ session: data.session });\n }\n } else {\n const errorMessage = this.toBotErrorMessage(\n data?.error?.message || 'Something went wrong. Please refresh the page or try again.',\n );\n const currentMessages = this.state.get().messages;\n this.state.setPartial({\n messages: [...currentMessages, errorMessage],\n });\n }\n } catch (error) {\n if (!this.sendMessageAbortController.signal.aborted) {\n console.error('Failed to send message:', error);\n }\n } finally {\n this.state.setPartial({\n isSendingMessage: false,\n isSendingMessageToAI: false,\n });\n }\n };\n\n private toUserMessage = (\n content: string,\n attachments?: MessageAttachmentType[],\n ): WidgetUserMessage => {\n const messageContent = (() => {\n const extraCollectedData = this.contactCtx.state.get().extraCollectedData;\n // Prepend extra collected data if this is the first message in the session\n if (\n this.state.get().messages.length === 0 &&\n extraCollectedData &&\n Object.keys(extraCollectedData).length > 0\n ) {\n const data = Object.entries(extraCollectedData)\n .filter(([_, value]) => !!value)\n .map(([key, value]) => `${key}: ${value}`)\n .join(' \\n');\n return `${data} \\n\\n${content}`;\n }\n\n return content;\n })();\n\n return {\n id: genUuid(),\n type: 'USER',\n content: messageContent,\n deliveredAt: new Date().toISOString(),\n attachments,\n timestamp: new Date().toISOString(),\n };\n };\n\n private toBotMessage = (\n response: SendMessageOutputDto,\n ): WidgetAiMessage | null => {\n if (response.success && response.autopilotResponse) {\n return {\n type: 'AI',\n id: response.autopilotResponse.id || genUuid(),\n timestamp: new Date().toISOString(),\n component: 'bot_message',\n agent: this.config.bot\n ? {\n name: this.config.bot.name || '',\n isAi: true,\n avatar: this.config.bot.avatar || '',\n id: null,\n }\n : undefined,\n data: {\n message: response.autopilotResponse.value.content,\n action: response.uiResponse?.value.name\n ? {\n name: response.uiResponse.value.name,\n data: response.uiResponse.value.request_response,\n }\n : undefined,\n },\n };\n }\n\n return null;\n };\n\n private toBotErrorMessage = (message: string): WidgetAiMessage => {\n return {\n type: 'AI',\n id: genUuid(),\n timestamp: new Date().toISOString(),\n component: 'bot_message',\n data: {\n message,\n variant: 'error',\n action: undefined,\n },\n };\n };\n}\n","import type { WidgetConfig } from '../types/widget-config';\nimport { PrimitiveState } from '../utils/PrimitiveState';\nimport type { ContactCtx } from './contact.ctx';\nimport type { SessionCtx } from './session.ctx';\nimport type { WidgetCtx } from './widget.ctx';\n\nexport type ScreenU =\n | /** A welcome screen to collect user data. Useful in public non-logged-in environments */\n 'welcome'\n /** Show a list of the user's previous sessions */\n | 'sessions'\n /** Self-explanatory */\n | 'chat';\n\ntype RouterState = {\n screen: ScreenU;\n};\n\nexport class RouterCtx {\n state: PrimitiveState<RouterState>;\n\n private config: WidgetConfig;\n private contactCtx: ContactCtx;\n private sessionCtx: SessionCtx;\n private resetChat: WidgetCtx['resetChat'];\n\n constructor({\n config,\n contactCtx,\n sessionCtx,\n resetChat,\n }: {\n config: WidgetConfig;\n contactCtx: ContactCtx;\n sessionCtx: SessionCtx;\n resetChat: WidgetCtx['resetChat'];\n }) {\n this.config = config;\n this.contactCtx = contactCtx;\n this.sessionCtx = sessionCtx;\n this.resetChat = resetChat;\n this.state = new PrimitiveState<RouterState>({\n screen: this.contactCtx.shouldCollectData()\n ? 'welcome'\n : this.config.router?.chatScreenOnly\n ? 'chat'\n : 'sessions',\n });\n\n this.registerRoutingListener();\n }\n\n private registerRoutingListener = () => {\n this.contactCtx.state.subscribe(({ contact }) => {\n // Auto navigate to sessions screen after collecting user data\n if (contact?.token && this.state.get().screen === 'welcome') {\n this.state.setPartial({\n screen: this.config.router?.chatScreenOnly ? 'chat' : 'sessions',\n });\n }\n });\n\n this.sessionCtx.sessionsState.subscribe(\n ({ isInitialFetchLoading, data }) => {\n if (\n this.config.router?.chatScreenOnly &&\n // Do not route to a chat if we are currently inside one already\n // This also applies to newly created sessions; the new session will be in `sessionState` before it is refreshed and included in `sessionsState`\n !this.sessionCtx.sessionState.get().session?.id\n ) {\n const mostRecentOpenSessionId = data.find((s) => s.isOpened)?.id;\n return mostRecentOpenSessionId\n ? this.toChatScreen(mostRecentOpenSessionId)\n : undefined;\n }\n\n if (data.length) return;\n if (this.config.router?.goToChatIfNoSessions === false) return;\n\n // Auto navigate to chat screen if contact has no previous sessions\n if (!isInitialFetchLoading && this.state.get().screen !== 'chat') {\n this.toChatScreen();\n }\n },\n );\n };\n\n toSessionsScreen = () => {\n this.resetChat();\n this.state.setPartial({ screen: 'sessions' });\n };\n\n /**\n * @param sessionId The ID of the session to open, or `undefined` if it is a new chat session\n */\n toChatScreen = (sessionId?: string) => {\n this.resetChat();\n\n if (sessionId) {\n const session = this.sessionCtx.sessionsState\n .get()\n .data.find((s) => s.id === sessionId);\n // Do not navigate if session is not found (this shouldn't happen, unless a wrong ID is passed)\n if (!session) return;\n this.sessionCtx.sessionState.setPartial({ session });\n }\n\n this.state.setPartial({ screen: 'chat' });\n };\n}\n","import type { ExternalStorage } from '../types/external-storage';\nimport type { WidgetConfig } from '../types/widget-config';\n\nexport class StorageCtx {\n private storage: ExternalStorage;\n private config: WidgetConfig;\n\n private KEYS = {\n contactToken: (orgToken: string) =>\n `opencx-widget:org-token-${orgToken}:contact-token`,\n externalContactId: (orgToken: string) =>\n `opencx-widget:org-token-${orgToken}:external-contact-id`,\n };\n\n constructor({\n storage,\n config,\n }: {\n storage: ExternalStorage;\n config: WidgetConfig;\n }) {\n this.storage = storage;\n this.config = config;\n }\n\n setContactToken = async (token: string) => {\n await this.storage.set(this.KEYS.contactToken(this.config.token), token);\n };\n getContactToken = async () => {\n return this.storage.get(this.KEYS.contactToken(this.config.token));\n };\n\n setExternalContactId = async (id: string) => {\n await this.storage.set(this.KEYS.externalContactId(this.config.token), id);\n };\n getExternalContactId = async () => {\n return this.storage.get(this.KEYS.externalContactId(this.config.token));\n };\n}\n","import { ApiCaller } from '../api/api-caller';\nimport type { ModeDto } from '../types/dtos';\nimport type { ExternalStorage } from '../types/external-storage';\nimport type { WidgetConfig } from '../types/widget-config';\nimport { ActiveSessionPollingCtx } from './active-session-polling.ctx';\nimport { ContactCtx } from './contact.ctx';\nimport { CsatCtx } from './csat.ctx';\nimport { MessageCtx } from './message.ctx';\nimport { RouterCtx } from './router.ctx';\nimport { SessionCtx } from './session.ctx';\nimport { StorageCtx } from './storage.ctx';\n\nexport class WidgetCtx {\n public config: WidgetConfig;\n public api: ApiCaller;\n\n public contactCtx: ContactCtx;\n public sessionCtx: SessionCtx;\n public messageCtx: MessageCtx;\n public csatCtx: CsatCtx;\n public routerCtx: RouterCtx;\n public storageCtx?: StorageCtx;\n public modes: ModeDto[] = [];\n\n public org: {\n id: string;\n name: string;\n };\n private static pollingIntervalsSeconds: {\n session: number;\n sessions: number;\n } | null = null;\n private activeSessionPollingCtx: ActiveSessionPollingCtx;\n\n private constructor({\n config,\n storage,\n modes,\n org,\n }: {\n config: WidgetConfig;\n storage?: ExternalStorage;\n modes: ModeDto[];\n org: {\n id: string;\n name: string;\n };\n }) {\n if (!WidgetCtx.pollingIntervalsSeconds) {\n throw Error(\n 'Widget polling values are not defined, did you call WidgetCtx.initialize()',\n );\n }\n\n this.config = config;\n this.org = org;\n this.api = new ApiCaller({ config });\n this.storageCtx = storage ? new StorageCtx({ storage, config }) : undefined;\n this.modes = modes;\n\n this.contactCtx = new ContactCtx({\n api: this.api,\n config: this.config,\n storageCtx: this.storageCtx,\n });\n\n this.sessionCtx = new SessionCtx({\n config: this.config,\n api: this.api,\n contactCtx: this.contactCtx,\n sessionsPollingIntervalSeconds:\n WidgetCtx.pollingIntervalsSeconds.sessions,\n });\n\n this.messageCtx = new MessageCtx({\n config: this.config,\n api: this.api,\n sessionCtx: this.sessionCtx,\n contactCtx: this.contactCtx,\n });\n\n this.csatCtx = new CsatCtx({\n config: this.config,\n api: this.api,\n sessionCtx: this.sessionCtx,\n messageCtx: this.messageCtx,\n });\n\n this.activeSessionPollingCtx = new ActiveSessionPollingCtx({\n api: this.api,\n config: this.config,\n sessionCtx: this.sessionCtx,\n messageCtx: this.messageCtx,\n sessionPollingIntervalSeconds: WidgetCtx.pollingIntervalsSeconds.session,\n });\n\n this.routerCtx = new RouterCtx({\n config: this.config,\n contactCtx: this.contactCtx,\n sessionCtx: this.sessionCtx,\n resetChat: this.resetChat,\n });\n }\n\n static initialize = async ({\n config,\n storage,\n }: {\n config: WidgetConfig;\n storage?: ExternalStorage;\n }) => {\n const externalConfig = await new ApiCaller({\n config,\n }).getExternalWidgetConfig();\n\n if (!externalConfig.data) {\n throw new Error('Failed to fetch widget config');\n }\n\n this.pollingIntervalsSeconds = {\n session: externalConfig.data?.sessionPollingIntervalSeconds || 10,\n sessions: externalConfig.data?.sessionsPollingIntervalSeconds || 60,\n };\n\n return new WidgetCtx({\n config,\n storage,\n modes: externalConfig.data?.modes || [],\n org: {\n id: externalConfig.data.org.id,\n name: externalConfig.data.org.name,\n },\n });\n };\n\n resetChat = () => {\n this.sessionCtx.reset();\n this.messageCtx.reset();\n };\n}\n","import type { TranslationInterface } from '.';\n\nexport const ArabicLanguage: TranslationInterface = {\n write_a_message_placeholder: 'اكتب رسالة...',\n your_issue_has_been_resolved: 'تم حل مشكلتك!',\n new_conversation: 'محادثة جديدة',\n welcome_screen_title: 'مرحبًا بك في دردشة الدعم الخاصة بنا',\n welcome_screen_description:\n 'نحن هنا للمساعدة! ابدأ محادثة وسنرد عليك في أقرب وقت ممكن.',\n your_name_placeholder: 'اسمك',\n your_email_placeholder: 'عنوان بريدك الإلكتروني',\n start_chat_button: 'تحدث إلى الدعم',\n start_chat_button_loading: 'جاري الاتصال...',\n i_need_more_help: 'أحتاج المزيد من المساعدة',\n this_was_helpful: 'كان هذا مفيدًا',\n optional: 'اختياري',\n no_conversations_yet: 'لا يوجد محادثات',\n back_to_conversations: 'العودة إلى المحادثات',\n closed_conversations: 'المحادثات المغلقة',\n};\n","import type { TranslationInterface } from '.';\n\nexport const DanishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Skriv en besked...',\n your_issue_has_been_resolved: 'Dit problem er løst!',\n new_conversation: 'Ny samtale',\n welcome_screen_title: 'Velkommen til vores support chat',\n welcome_screen_description:\n 'Vi er her for at hjælpe! Start en samtale, og vi vender tilbage til dig så hurtigt som muligt.',\n your_name_placeholder: 'Dit navn',\n your_email_placeholder: 'Din e-mailadresse',\n start_chat_button: 'Tal med support',\n start_chat_button_loading: 'Forbinder...',\n i_need_more_help: 'Jeg har brug for mere hjælp',\n this_was_helpful: 'Dette var nyttigt',\n optional: 'Valgfrit',\n no_conversations_yet: 'Ingen samtaler endnu',\n back_to_conversations: 'Tilbage til samtaler',\n closed_conversations: 'Lukkede samtaler',\n};\n","import type { TranslationInterface } from '.';\n\nexport const GermanLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Nachricht schreiben...',\n your_issue_has_been_resolved: 'Ihr Problem wurde gelöst!',\n new_conversation: 'Neue Konversation',\n welcome_screen_title: 'Willkommen in unserem Support-Chat',\n welcome_screen_description:\n 'Wir sind hier, um zu helfen! Beginnen Sie ein Gesprách und wir werden so schnell wie mogelijk antworten.',\n your_name_placeholder: 'Ihr Name',\n your_email_placeholder: 'Ihre E-Mail-Adresse',\n start_chat_button: 'Mit dem Support sprechen',\n start_chat_button_loading: 'Verbindung wird hergestellt...',\n i_need_more_help: 'Ich brauche weitere Hilfe',\n this_was_helpful: 'Dies war hilfreich',\n optional: 'Optional',\n no_conversations_yet: 'noch keine Gespräche',\n back_to_conversations: 'Zurück zur Konversationen',\n closed_conversations: 'Geschlossene Konversationen',\n};\n","import type { TranslationInterface } from '.';\n\nexport const EnglishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Write a message...',\n your_issue_has_been_resolved: 'Your issue has been resolved!',\n new_conversation: 'New conversation',\n welcome_screen_title: 'Welcome to our support chat',\n welcome_screen_description:\n \"We're here to help! Start a conversation and we'll get back to you as soon as possible.\",\n your_name_placeholder: 'Your name',\n your_email_placeholder: 'Your email address',\n start_chat_button: 'Talk to support',\n start_chat_button_loading: 'Connecting...',\n i_need_more_help: 'I need more help',\n this_was_helpful: 'This was helpful',\n optional: 'Optional',\n no_conversations_yet: 'No conversations yet',\n back_to_conversations: 'Back to conversations',\n closed_conversations: 'Closed conversations',\n};\n","import type { TranslationInterface } from '.';\n\nexport const SpanishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Escribe un mensaje...',\n your_issue_has_been_resolved: '¡Tu problema fue resuelto!',\n new_conversation: 'Nueva conversación',\n welcome_screen_title: 'Bienvenido a nuestro chat de soporte',\n welcome_screen_description:\n '¡Estamos aquí para ayudarte! Inicia una conversación y responderemos lo antes posible.',\n your_name_placeholder: 'Tu nombre',\n your_email_placeholder: 'Tu correo electrónico',\n start_chat_button: 'Hablar con soporte',\n start_chat_button_loading: 'Conectando...',\n i_need_more_help: 'Necesito más ayuda',\n this_was_helpful: 'Esto fue útil',\n optional: 'Opcional',\n no_conversations_yet: 'Sin conversaciones aún',\n back_to_conversations: 'Volver a conversaciones',\n closed_conversations: 'Conversaciones cerradas',\n};\n","import type { TranslationInterface } from '.';\n\nexport const FinnishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Kirjoita viesti...',\n your_issue_has_been_resolved: 'Ongelmasi on ratkaistu!',\n new_conversation: 'Uusi keskustelu',\n welcome_screen_title: 'Tervetuloa tukichattiin',\n welcome_screen_description:\n 'Olemme täällä auttamassa! Aloita keskustelu ja palaamme sinulle mahdollisimman pian.',\n your_name_placeholder: 'Nimesi',\n your_email_placeholder: 'Sähköpostiosoitteesi',\n start_chat_button: 'Keskustele tuen kanssa',\n start_chat_button_loading: 'Yhdistetään...',\n i_need_more_help: 'Tarvitsen lisää apua',\n this_was_helpful: 'Tämä oli hyödyllistä',\n optional: 'Valinnainen',\n no_conversations_yet: 'Ei vielä keskusteluja',\n back_to_conversations: 'Takaisin keskusteluihin',\n closed_conversations: 'Suljetut keskustelut',\n};\n","import type { TranslationInterface } from '.';\n\nexport const FrenchLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Écrivez un message...',\n your_issue_has_been_resolved: 'Votre problème a été résolu !',\n new_conversation: 'Nouvelle conversation',\n welcome_screen_title: 'Bienvenue dans notre chat de support',\n welcome_screen_description:\n 'Nous sommes là pour vous aider ! Commencez une conversation et nous vous répondrons dès que possible.',\n your_name_placeholder: 'Votre nom',\n your_email_placeholder: 'Votre adresse e-mail',\n start_chat_button: 'Parler au support',\n start_chat_button_loading: 'Connexion...',\n i_need_more_help: \"Je besoin d'aide plus\",\n this_was_helpful: \"C'était utile\",\n optional: 'Optionnel',\n no_conversations_yet: 'Aucune conversation pour le moment',\n back_to_conversations: 'Retour aux conversations',\n closed_conversations: 'Conversations fermées',\n};\n","import type { TranslationInterface } from '.';\n\nexport const ItalianLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Scrivi un messaggio...',\n your_issue_has_been_resolved: 'Il tuo problema è stato risolto!',\n new_conversation: 'Nuova conversazione',\n welcome_screen_title: 'Benvenuto nella nostra chat di supporto',\n welcome_screen_description:\n 'Siamo qui per aiutarti! Inizia una conversazione e ti risponderemo il prima possibile.',\n your_name_placeholder: 'Il tuo nome',\n your_email_placeholder: 'Il tuo indirizzo email',\n start_chat_button: 'Parla con il supporto',\n start_chat_button_loading: 'Connessione in corso...',\n i_need_more_help: 'Ho bisogno di ulteriore aiuto',\n this_was_helpful: 'Questo è stato utile',\n optional: 'Opzionale',\n no_conversations_yet: 'Nessuna conversazione ancora',\n back_to_conversations: 'Torna alle conversazioni',\n closed_conversations: 'Conversazioni chiuse',\n};\n","import type { TranslationInterface } from '.';\n\nexport const DutchLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Schrijf een bericht...',\n your_issue_has_been_resolved: 'Uw probleem is opgelost!',\n new_conversation: 'Nieuw gesprek',\n welcome_screen_title: 'Welkom bij onze supportchat',\n welcome_screen_description:\n 'We zijn hier om te helpen! Begin een gesprek en we nemen zo snel mogelijk contact met u op.',\n your_name_placeholder: 'Uw naam',\n your_email_placeholder: 'Uw e-mailadres',\n start_chat_button: 'Praat met ondersteuning',\n start_chat_button_loading: 'Verbinding maken...',\n i_need_more_help: 'Ik heb nog meer hulp nodig',\n this_was_helpful: 'Mijn vraag is opgelost',\n optional: 'Optioneel',\n no_conversations_yet: 'Nog geen gesprekken',\n back_to_conversations: 'Terug naar gesprekken',\n closed_conversations: 'Afgesloten gesprekken',\n};\n","import type { TranslationInterface } from '.';\n\nexport const NorwegianLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Skriv en melding...',\n your_issue_has_been_resolved: 'Problemet ditt er løst!',\n new_conversation: 'Ny samtale',\n welcome_screen_title: 'Velkommen til vår kundestøtte-chat',\n welcome_screen_description:\n 'Vi er her for å hjelpe! Start en samtale så kommer vi tilbake til deg så snart som mulig.',\n your_name_placeholder: 'Ditt navn',\n your_email_placeholder: 'Din e-postadresse',\n start_chat_button: 'Snakk med kundestøtte',\n start_chat_button_loading: 'Kobler til...',\n i_need_more_help: 'Jeg trenger mer hjelp',\n this_was_helpful: 'Dette var nyttig',\n optional: 'Valgfritt',\n no_conversations_yet: 'Ingen samtaler ennå',\n back_to_conversations: 'Tilbake til samtaler',\n closed_conversations: 'Lukkede samtaler',\n};\n","import type { TranslationInterface } from '.';\n\nexport const PolishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Napisz wiadomość...',\n your_issue_has_been_resolved: 'Twój problem został rozwiązany!',\n new_conversation: 'Nowa rozmowa',\n welcome_screen_title: 'Witamy w naszym czacie wsparcia',\n welcome_screen_description:\n 'Jesteśmy tutaj, aby pomóc! Rozpocznij rozmowę, a odpowiemy jak najszybciej.',\n your_name_placeholder: 'Twoje imię',\n your_email_placeholder: 'Twój adres email',\n start_chat_button: 'Porozmawiaj ze wsparciem',\n start_chat_button_loading: 'Łączenie...',\n i_need_more_help: 'Potrzebuję więcej pomocy',\n this_was_helpful: 'To było pomocne',\n optional: 'Opcjonalne',\n no_conversations_yet: 'Jeszcze brak rozmów',\n back_to_conversations: 'Powrót do rozmów',\n closed_conversations: 'Zamknięte rozmowy',\n};\n","import type { TranslationInterface } from '.';\n\nexport const PortugueseLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Escreva uma mensagem...',\n your_issue_has_been_resolved: 'Seu problema foi resolvido!',\n new_conversation: 'Nova conversa',\n welcome_screen_title: 'Bem-vindo ao nosso chat de suporte',\n welcome_screen_description:\n 'Estamos aqui para ajudar! Inicie uma conversa e responderemos o mais rápido possível.',\n your_name_placeholder: 'Seu nome',\n your_email_placeholder: 'Seu endereço de email',\n start_chat_button: 'Falar com o suporte',\n start_chat_button_loading: 'Conectando...',\n i_need_more_help: 'preciso de mais ajuda',\n this_was_helpful: 'Isso foi útil',\n optional: 'Opcional',\n no_conversations_yet: 'Nenhuma conversa ainda',\n back_to_conversations: 'Voltar para conversas',\n closed_conversations: 'Conversas fechadas',\n};\n","import type { TranslationInterface } from '.';\n\nexport const RomanianLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Scrie un mesaj...',\n your_issue_has_been_resolved: 'Problema ta a fost rezolvată!',\n new_conversation: 'Conversație nouă',\n welcome_screen_title: 'Bine ai venit la chat-ul nostru de suport',\n welcome_screen_description:\n 'Suntem aici să te ajutăm! Începe o conversație și îți vom răspunde cât mai curând posibil.',\n your_name_placeholder: 'Numele tău',\n your_email_placeholder: 'Adresa ta de email',\n start_chat_button: 'Vorbește cu suportul',\n start_chat_button_loading: 'Se conectează...',\n i_need_more_help: 'Am nevoie de mai mult ajutor',\n this_was_helpful: 'Acest lucru a fost util',\n optional: 'Opțional',\n no_conversations_yet: 'Încă nu există conversații',\n back_to_conversations: 'Înapoi la conversații',\n closed_conversations: 'Conversații închise',\n};\n","import type { TranslationInterface } from '.';\n\nexport const SwedishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Skriv ett meddelande...',\n your_issue_has_been_resolved: 'Ditt problem har lösts!',\n new_conversation: 'Ny konversation',\n welcome_screen_title: 'Välkommen till vår supportchatt',\n welcome_screen_description:\n 'Vi är här för att hjälpa! Starta en konversation så återkommer vi till dig så snart som möjligt.',\n your_name_placeholder: 'Ditt namn',\n your_email_placeholder: 'Din e-postadress',\n start_chat_button: 'Prata med support',\n start_chat_button_loading: 'Ansluter...',\n i_need_more_help: 'Jag behöver mer hjälp',\n this_was_helpful: 'Detta var användbart',\n optional: 'Frivilligt',\n no_conversations_yet: 'Inga konversationer ännu',\n back_to_conversations: 'Tillbaka till konversationer',\n closed_conversations: 'Stängda konversationer',\n};\n","import type { TranslationInterface } from '.';\n\nexport const TurkishLanguage: TranslationInterface = {\n write_a_message_placeholder: 'Bir mesaj yazın...',\n your_issue_has_been_resolved: 'Sorununuz çözüldü!',\n new_conversation: 'Yeni konuşma',\n welcome_screen_title: 'Destek sohbetimize hoş geldiniz',\n welcome_screen_description:\n 'Yardım etmek için buradayız! Bir konuşma başlatın, en kısa sürede size geri döneceğiz.',\n your_name_placeholder: 'Adınız',\n your_email_placeholder: 'E-posta adresiniz',\n start_chat_button: 'Destekle konuş',\n start_chat_button_loading: 'Bağlanıyor...',\n i_need_more_help: 'Daha fazla yardıma ihtiyacım var',\n this_was_helpful: 'Bu yardımcı oldu',\n optional: 'İsteğe bağlı',\n no_conversations_yet: 'Henüz konuşma yok',\n back_to_conversations: 'Konuşmalara geri dön',\n closed_conversations: 'Kapatılan konuşmalar',\n};\n","import type { WidgetConfig } from '../types/widget-config';\nimport { ArabicLanguage } from './ar';\nimport { DanishLanguage } from './da';\nimport { GermanLanguage } from './de';\nimport { EnglishLanguage } from './en';\nimport { SpanishLanguage } from './es';\nimport { FinnishLanguage } from './fi';\nimport { FrenchLanguage } from './fr';\nimport { ItalianLanguage } from './it';\nimport { DutchLanguage } from './nl';\nimport { NorwegianLanguage } from './no';\nimport { PolishLanguage } from './pl';\nimport { PortugueseLanguage } from './pt';\nimport { RomanianLanguage } from './ro';\nimport { SwedishLanguage } from './sv';\nimport { TurkishLanguage } from './tr';\n\nconst languages = {\n en: EnglishLanguage,\n ar: ArabicLanguage,\n nl: DutchLanguage,\n fr: FrenchLanguage,\n de: GermanLanguage,\n pt: PortugueseLanguage,\n es: SpanishLanguage,\n tr: TurkishLanguage,\n pl: PolishLanguage,\n fi: FinnishLanguage,\n it: ItalianLanguage,\n no: NorwegianLanguage,\n ro: RomanianLanguage,\n da: DanishLanguage,\n sv: SwedishLanguage,\n} as const;\n\nexport const LANGUAGES = Object.keys(languages) as (keyof typeof languages)[];\nexport type Language = (typeof LANGUAGES)[number];\n\nexport function isSupportedLanguage(\n lang: string | null | undefined,\n): lang is Language {\n return LANGUAGES.includes(lang as Language);\n}\n\nexport function getTranslation(\n key: TranslationKeyU,\n lang: Language,\n overrides: WidgetConfig['translationOverrides'],\n): string {\n return overrides?.[lang]?.[key] || languages[lang][key] || '';\n}\n\nexport type TranslationInterface = {\n i_need_more_help: string;\n this_was_helpful: string;\n write_a_message_placeholder: string;\n your_issue_has_been_resolved: string;\n new_conversation: string;\n back_to_conversations: string;\n closed_conversations: string;\n no_conversations_yet: string;\n welcome_screen_title: string;\n welcome_screen_description: string;\n your_name_placeholder: string;\n your_email_placeholder: string;\n optional: string;\n start_chat_button: string;\n start_chat_button_loading: string;\n};\nexport type TranslationKeyU = keyof TranslationInterface;\n"],"names":["defaultOnError","onErrorOptions","basicClient","options","client","createClient","middlewares","ApiCaller","config","token","baseUrl","headers","request","key","value","body","abortSignal","sessionId","lastMessageTimestamp","query","cursor","filters","file","onProgress","resolve","reject","formData","xhr","event","percentage","data","error","uploadUrl","_a","_b","isExhaustive","funcName","PrimitiveState","state","newState","isEqual","_s","callback","Poller","cb","intervalMs","timeouts","poll","runCatching","result","ActiveSessionPollingCtx","api","sessionCtx","messageCtx","sessionPollingIntervalSeconds","session","fetchFullHistory","messages","prevMessages","newMessages","msg","newMsg","existingMsg","history","commonFields","action","message","responseBodyText","parsed","ContactCtx","storageCtx","_c","_d","persistedToken","_e","_g","_f","_h","_j","_i","_l","_k","_n","_m","payload","extraCollectedData","persistedExternalId","externalId","v4","genUuid","uuidv4","CsatCtx","currentSessionId","uuid","SessionCtx","contactCtx","sessionsPollingIntervalSeconds","contact","customData","deduped","s","i","self","sessions","currentSession","session_id","MessageCtx","input","isAssignedToAI","isSendingToAI","lastMessage","currentMessages","shouldInsertInitialMessages","m","insertableInitialMessages","userMessage","botMessage","errorMessage","content","attachments","messageContent","_","response","RouterCtx","resetChat","isInitialFetchLoading","mostRecentOpenSessionId","StorageCtx","storage","orgToken","id","_WidgetCtx","modes","org","externalConfig","WidgetCtx","ArabicLanguage","DanishLanguage","GermanLanguage","EnglishLanguage","SpanishLanguage","FinnishLanguage","FrenchLanguage","ItalianLanguage","DutchLanguage","NorwegianLanguage","PolishLanguage","PortugueseLanguage","RomanianLanguage","SwedishLanguage","TurkishLanguage","languages","LANGUAGES","isSupportedLanguage","lang","getTranslation","overrides"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -586,7 +586,8 @@ class K {
|
|
|
586
586
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
587
587
|
data: {
|
|
588
588
|
message: _.message
|
|
589
|
-
}
|
|
589
|
+
},
|
|
590
|
+
agent: this.config.bot ? { ...this.config.bot, isAi: !0, id: null } : void 0
|
|
590
591
|
})
|
|
591
592
|
) : [], I = this.toUserMessage(
|
|
592
593
|
s.content.trim(),
|