UNPKG

rn-kore-bot-socket-lib-v77

Version:
1,515 lines (1,507 loc) 53.5 kB
// bot-sdk/constants/Constant.tsx var URL_VERSION = "/1.1"; var RTM_EVENT = { CONNECTING: "connecting", AUTHENTICATED: "authenticated", ON_OPEN: "on_open", ON_DISCONNECT: "disconnect", ON_CLOSE: "on_close", ON_ERROR: "on_error", ON_MESSAGE: "on_message", ON_FAILURE: "failure", PING: "ping", PONG: "pong", ERROR: "error", RECONNECTING: "reconnecting", UNABLE_TO_RTM_START: "unable_to_rtm_start", GET_HISTORY: "get_history", GET_RESULT_VIEW_SETTINGS: "result_view_settings", ON_ACK: "ack", ON_EVENTS: "events", ON_JWT_TOKEN_AUTHORIZED: "ON_JWT_TOKEN_AUTHORIZED" }; var ConnectionState = { CONNECTING: 0, CONNECTED: 1, DISCONNECTED: 2 }; var APP_STATE = { ACTIVE: "active", SLEEP: "sleep" }; // bot-sdk/rtm/BotClient.tsx import { EventEmitter } from "events"; // bot-sdk/model/BotInfoModel.tsx import { Platform } from "react-native"; var BotInfoModel = class { constructor(chatBot, taskBotId, customData, channelClient = Platform.OS) { this.chatBot = chatBot; this.taskBotId = taskBotId; this.customData = customData; this.channelClient = channelClient; } }; // bot-sdk/rtm/BotClient.tsx import { Platform as Platform3 } from "react-native"; // bot-sdk/utils/Logger.tsx var LogLevel = /* @__PURE__ */ ((LogLevel2) => { LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG"; LogLevel2[LogLevel2["INFO"] = 1] = "INFO"; LogLevel2[LogLevel2["WARN"] = 2] = "WARN"; LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR"; return LogLevel2; })(LogLevel || {}); var Logger = class _Logger { static instance; logLevel = 1 /* INFO */; logs = []; maxLogs = 1e3; constructor() { } static getInstance() { if (!_Logger.instance) { _Logger.instance = new _Logger(); } return _Logger.instance; } setLogLevel(level) { this.logLevel = level; } log(level, category, message, data, error) { if (level < this.logLevel) { return; } const logEntry = { timestamp: (/* @__PURE__ */ new Date()).toISOString(), level, category, message, data, error }; this.logs.push(logEntry); if (this.logs.length > this.maxLogs) { this.logs = this.logs.slice(-this.maxLogs); } const levelName = LogLevel[level]; const formattedMessage = `[${logEntry.timestamp}] [${levelName}] [${category}] ${message}`; switch (level) { case 0 /* DEBUG */: console.debug(formattedMessage, data || ""); break; case 1 /* INFO */: console.info(formattedMessage, data || ""); break; case 2 /* WARN */: console.warn(formattedMessage, data || ""); if (error) console.warn("Error details:", error); break; case 3 /* ERROR */: console.error(formattedMessage, data || ""); if (error) console.error("Error details:", error); break; } } // API specific logging methods logApiRequest(endpoint, method, data) { this.log(1 /* INFO */, "API_REQUEST", `${method} ${endpoint}`, data); } logApiSuccess(endpoint, method, responseData, duration) { const message = duration ? `${method} ${endpoint} - Success (${duration}ms)` : `${method} ${endpoint} - Success`; this.log(1 /* INFO */, "API_SUCCESS", message, responseData); } logApiError(endpoint, method, error, duration) { const message = duration ? `${method} ${endpoint} - Error (${duration}ms)` : `${method} ${endpoint} - Error`; this.log(3 /* ERROR */, "API_ERROR", message, { status: error?.response?.status, statusText: error?.response?.statusText, message: error?.message }, error); } // WebSocket specific logging logWebSocketEvent(event, data) { this.log(1 /* INFO */, "WEBSOCKET", `WebSocket ${event}`, data); } logWebSocketError(event, error) { this.log(3 /* ERROR */, "WEBSOCKET_ERROR", `WebSocket ${event}`, void 0, error); } // Connection specific logging logConnectionEvent(event, data) { this.log(1 /* INFO */, "CONNECTION", event, data); } logConnectionError(event, error) { this.log(3 /* ERROR */, "CONNECTION_ERROR", event, void 0, error); } // General logging methods debug(message, data) { this.log(0 /* DEBUG */, "DEBUG", message, data); } info(message, data) { this.log(1 /* INFO */, "INFO", message, data); } warn(message, data, error) { this.log(2 /* WARN */, "WARN", message, data, error); } error(message, data, error) { this.log(3 /* ERROR */, "ERROR", message, data, error); } // Get logs for debugging getLogs(level) { if (level !== void 0) { return this.logs.filter((log) => log.level >= level); } return [...this.logs]; } // Clear logs clearLogs() { this.logs = []; } }; var Logger_default = Logger.getInstance(); // bot-sdk/api/ApiService.tsx import { Platform as Platform2 } from "react-native"; var RECONNECT_ATTEMPT_LIMIT = 5; var ApiService = class { baseUrl; botClient; constructor(baseUrl, botClient) { this.baseUrl = baseUrl; this.botClient = botClient; } async fetchWithRetries(url, options, retries = 1, method = "POST") { try { return await fetch(url, options); } catch (err) { if (retries <= RECONNECT_ATTEMPT_LIMIT) { const delay = Math.min(Math.pow(2, retries) / 4 + Math.random(), RECONNECT_ATTEMPT_LIMIT) * 1e3; await new Promise((resolve) => setTimeout(() => resolve(void 0), delay)); Logger_default.logApiError(url, method, err, delay); return this.fetchWithRetries(url, options, retries + 1, method); } else { throw new Error(`Max retries exceeded. error: ${err}`); } } } async getBotHistory(offset, limit, botConfig, onResponse) { let historyUrl = this.baseUrl + (botConfig.isWebHook ? "/api/chathistory/" + botConfig.botId + "/ivr?&botId=" + botConfig.botId + "&limit=" + limit + "&offset=" + offset : "/api" + URL_VERSION + "/botmessages/rtm"); const startTime = Date.now(); Logger_default.logApiRequest(historyUrl, "GET", { botId: botConfig.botId, limit, offset, forward: true }); const urlWithParams = new URL(historyUrl); if (!botConfig.isWebHook) { urlWithParams.searchParams.append("botId", botConfig.botId); urlWithParams.searchParams.append("limit", limit + ""); urlWithParams.searchParams.append("offset", offset + ""); urlWithParams.searchParams.append("forward", "true"); } try { const response = await this.fetchWithRetries(urlWithParams.toString(), { method: "GET", headers: { "Accept": "application/json", Authorization: botConfig.isWebHook ? "bearer " + this.botClient.getJwtToken() : this.botClient.getAuthorization() + "" } }, 1, "GET"); const duration = Date.now() - startTime; const responseData = await response.json(); if (!response.ok) { const error = new Error(`HTTP ${response.status}`); error.response = { status: response.status, statusText: response.statusText, data: responseData }; onResponse(); return; } Logger_default.logApiSuccess(historyUrl, "GET", { messageCount: responseData?.length || 0, hasData: !!responseData }, duration); const axiosResponse = { data: this.processHistoryResponse(responseData, botConfig.botName || "", botConfig.botId), status: response.status, statusText: response.statusText, headers: {} }; onResponse(axiosResponse); } catch (e) { const duration = Date.now() - startTime; Logger_default.logApiError(historyUrl, "GET", e, duration); onResponse(); } } processHistoryResponse = (botHistory, botName, botId) => { let msgs = []; console.log("BotHistory >>> " + JSON.stringify(botHistory)); if (!botHistory.messages) return []; const moreHistory = botHistory.moreAvailable; const icon = botHistory.icon; const messages = botHistory.messages; if (messages) { for (const msg of messages) { const components = msg.components; const data = (components[0].data.text ? components[0].data.text : "").replaceAll("&quot;", '"'); let botMessage; if (msg.type == "outgoing") { if (!data) continue; botMessage = this.createBotResponse(data, icon, msg.createdOn, msg._id, botName, botId); } else { const tags = msg.tags; const altText = tags.altText; const renderMsg = altText ? altText[0] ? altText[0].value : null : null; botMessage = this.createBotRequest(msg._id, data, msg.createdOn, botName, botId, renderMsg); } msgs.push(botMessage); } } msgs = [...msgs].sort((a, b) => b.timeMillis - a.timeMillis); return { botHistory: msgs, moreAvailable: moreHistory }; }; createBotResponse = (data, icon, createdOn, msgId, botName, botId) => { let payloadOuter; try { payloadOuter = JSON.parse(data); } catch (exception) { payloadOuter = { text: data }; } const componentModel = { type: "template", payload: payloadOuter }; const componentInfo = { body: payloadOuter }; const messageArray = []; const message = { type: "text", component: componentModel, cInfo: componentInfo }; messageArray.push(message); const botInfo = { botName, taskBotId: botId, customData: null, channelClient: Platform2.OS }; return { type: "bot_response", timeMillis: new Date(createdOn).getTime(), messageId: msgId, message: messageArray, from: "bot", isSend: false, icon, createdOn, botInfo }; }; createBotRequest = (msgId, message, createdOn, botName, botId, renderMsg) => { const component = { type: "text", payload: { text: renderMsg ? renderMsg : message, attachments: "", createdOn } }; const botMessage = { type: "text", component, clientMessageId: new Date(createdOn).getTime() }; const botInfo = { botName, taskBotId: botId, customData: null, channelClient: Platform2.OS }; return { type: "user_message", timeMillis: new Date(createdOn).getTime(), messageId: msgId, message: [botMessage], resourceId: "/bot.message", botInfo, createdOn, client: Platform2.OS, isSend: true }; }; async subscribePushNotifications(deviceId) { if (!deviceId) { Logger_default.logConnectionError("Push notification subscription Failed", "deviceId is not VALID!"); return false; } Logger_default.debug("Subscribe notications", "is in-progress"); let url = `/api/users/${this.botClient.getUserId()}/sdknotifications/subscribe`; let subscribeUrl = this.baseUrl + url; const startTime = Date.now(); let payload = { osType: Platform2.OS, deviceId }; Logger_default.logApiRequest(subscribeUrl, "POST", {}); const headers = { Authorization: `bearer ${this.botClient.getAccessToken()}` }; try { const response = await this.fetchWithRetries(subscribeUrl, { method: "POST", headers: { "Content-Type": "application/json", "Accept": "application/json", ...headers }, body: JSON.stringify(payload) }, 1, "POST"); const duration = Date.now() - startTime; if (!response.ok) { const responseData = await response.json().catch(() => ({})); const error = new Error(`HTTP ${response.status}`); error.response = { status: response.status, statusText: response.statusText, data: responseData }; throw error; } Logger_default.logApiSuccess(subscribeUrl, "POST", {}, duration); Logger_default.logConnectionEvent("Push notification subscription Success", {}); return true; } catch (e) { const duration = Date.now() - startTime; Logger_default.logApiError(subscribeUrl, "POST", e, duration); Logger_default.logConnectionError("Push notification subscription Failed", e); return false; } } async unsubscribePushNotifications(deviceId) { if (!deviceId) { Logger_default.logConnectionError("Push notification unsubscription Failed", "deviceId is not VALID!"); return false; } Logger_default.debug("Unsubscribe notications", "is in-progress"); let url = `/api/users/${this.botClient.getUserId()}/sdknotifications/unsubscribe`; let subscribeUrl = this.baseUrl + url; const startTime = Date.now(); let payload = { osType: Platform2.OS, deviceId }; Logger_default.logApiRequest(subscribeUrl, "POST", {}); const headers = { Authorization: `bearer ${this.botClient.getAccessToken()}`, "Content-type": "application/json", "X-HTTP-Method-Override": "DELETE" }; try { const response = await this.fetchWithRetries(subscribeUrl, { method: "POST", headers: { "Accept": "application/json", ...headers }, body: JSON.stringify(payload) }, 1, "POST"); const duration = Date.now() - startTime; if (!response.ok) { const responseData = await response.json().catch(() => ({})); const error = new Error(`HTTP ${response.status}`); error.response = { status: response.status, statusText: response.statusText, data: responseData }; throw error; } Logger_default.logApiSuccess(subscribeUrl, "POST", {}, duration); Logger_default.logConnectionEvent("Push notification unsubscription Success", {}); return true; } catch (e) { const duration = Date.now() - startTime; Logger_default.logApiError(subscribeUrl, "POST", e, duration); Logger_default.logConnectionError("Push notification unsubscription Failed", e); return false; } } async getJwtToken(config, isFirstTime = true, onResponse, onError) { const body = { clientId: config.clientId, clientSecret: config.clientSecret, identity: config.identity, aud: config.value_aud, isAnonymous: false }; const botUrl = this.botClient.getJwtServerUrl(); let jwtAuthorizationUrl = botUrl + "users/sts"; const startTime = Date.now(); Logger_default.logApiRequest(jwtAuthorizationUrl, "POST", { clientId: body.clientId, identity: body.identity, aud: body.aud, isAnonymous: body.isAnonymous }); try { const response = await this.fetchWithRetries(jwtAuthorizationUrl, { method: "POST", headers: { "Content-Type": "application/json", "Accept": "application/json" }, body: JSON.stringify(body) }, 1, "POST"); const duration = Date.now() - startTime; const responseData = await response.json(); if (!response.ok) { const error = new Error(`HTTP ${response.status}`); error.response = { status: response.status, statusText: response.statusText, data: responseData }; throw error; } Logger_default.logApiSuccess(jwtAuthorizationUrl, "POST", { hasJwtToken: !!responseData.jwt, tokenLength: responseData.jwt?.length }, duration); onResponse(responseData.jwt); return true; } catch (e) { const duration = Date.now() - startTime; Logger_default.logApiError(jwtAuthorizationUrl, "POST", e, duration); Logger_default.logConnectionError("JWT Token Generation Failed", e); onError("Connection to the bot failed. Please ensure your configuration is valid and try again."); return false; } } async getJwtGrant(jwtToken, isReconnectionAttempt, onStatus, onResponse, onError) { Logger_default.logConnectionEvent("JWT grant Authorization Started", { isReconnectionAttempt, tokenLength: jwtToken.length }); onStatus(RTM_EVENT.CONNECTING); this.baseUrl = this.botClient.getBotUrl(); let jwtAuthorizationUrl = this.baseUrl + "/api/oAuth/token/jwtgrant"; const startTime = Date.now(); let payload = { assertion: jwtToken, botInfo: this.botClient.getBotInfo() }; Logger_default.logApiRequest(jwtAuthorizationUrl, "POST", { botId: this.botClient.getBotInfo()?.taskBotId, botName: this.botClient.getBotInfo()?.botName }); try { const response = await this.fetchWithRetries(jwtAuthorizationUrl, { method: "POST", headers: { "Content-Type": "application/json", "Accept": "application/json" }, body: JSON.stringify(payload) }, 1, "POST"); const duration = Date.now() - startTime; const responseData = await response.json(); if (!response.ok) { const error = new Error(`HTTP ${response.status}`); error.response = { status: response.status, statusText: response.statusText, data: responseData }; throw error; } Logger_default.logApiSuccess(jwtAuthorizationUrl, "POST", { hasUserInfo: !!responseData.userInfo, hasAuthorization: !!responseData.authorization, userId: responseData.userInfo?.userId, tokenType: responseData.authorization?.token_type }, duration); onResponse(responseData); return true; } catch (e) { const duration = Date.now() - startTime; Logger_default.logApiError(jwtAuthorizationUrl, "POST", e, duration); Logger_default.logConnectionError("JWT Grant Authorization Failed", e); onError("Connection to the bot failed. Please ensure your configuration is valid and try again."); return false; } } async getRtmUrl(isReconnectionAttempt, onResponse, onError) { let rtmUrl = this.baseUrl + "/api/rtm/start"; let payload = { botInfo: this.botClient.getBotInfo() }; const startTime = Date.now(); Logger_default.logApiRequest(rtmUrl, "POST", { botId: this.botClient.getBotInfo()?.taskBotId, botName: this.botClient.getBotInfo()?.botName, isReconnectionAttempt }); try { const response = await this.fetchWithRetries(rtmUrl, { method: "POST", headers: { "Content-Type": "application/json", "Accept": "application/json", Authorization: this.botClient.getAuthorization() + "" }, body: JSON.stringify(payload) }, 1, "POST"); const duration = Date.now() - startTime; const responseData = await response.json(); if (!response.ok) { const error = new Error(`HTTP ${response.status}`); error.response = { status: response.status, statusText: response.statusText, data: responseData }; throw error; } Logger_default.logApiSuccess(rtmUrl, "POST", { hasUrl: !!responseData.url, url: responseData.url?.substring(0, 50) + "..." }, duration); Logger_default.logConnectionEvent("RTM URL Retrieved Successfully", { isReconnectionAttempt, hasWebSocketUrl: !!responseData.url }); onResponse(responseData); } catch (e) { const duration = Date.now() - startTime; Logger_default.logApiError(rtmUrl, "POST", e, duration); onError(e); } } async getSettings(onResponse) { let urlString = this.baseUrl + "/searchassistapi/searchsdk/stream/" + this.botClient.getBotInfo().taskBotId + "/" + this.botClient.getBotInfo().searchIndexId + "/getresultviewsettings"; const startTime = Date.now(); Logger_default.logApiRequest(urlString, "GET", { taskBotId: this.botClient.getBotInfo().taskBotId, searchIndexId: this.botClient.getBotInfo().searchIndexId }); try { const response = await this.fetchWithRetries(urlString, { method: "GET", headers: { "Accept": "application/json", Authorization: this.botClient.getAuthorization() + "", auth: "" } }, 1, "GET"); const duration = Date.now() - startTime; const responseData = await response.json(); if (!response.ok) { const error = new Error(`HTTP ${response.status}`); error.response = { status: response.status, statusText: response.statusText, data: responseData }; throw error; } Logger_default.logApiSuccess(urlString, "GET", { hasSettings: !!responseData?.settings, settingsCount: responseData?.settings?.length || 0 }, duration); if (responseData?.settings) { onResponse(responseData?.settings); } } catch (e) { const duration = Date.now() - startTime; Logger_default.logApiError(urlString, "GET", e, duration); } } async getWebHookBotMeta(jwtToken, botId, onResponse) { let url = this.baseUrl + "/api/botmeta/" + botId; const startTime = Date.now(); Logger_default.logApiRequest(url, "GET", { botId }); const urlWithParams = new URL(url); try { const response = await this.fetchWithRetries(urlWithParams.toString(), { method: "GET", headers: { "Accept": "application/json", Authorization: "bearer " + jwtToken } }, 1, "GET"); const duration = Date.now() - startTime; const responseData = response; if (!response.ok) { const error = new Error(`HTTP ${response.status}`); error.response = { status: response.status, statusText: response.statusText, data: responseData }; onResponse(); return; } Logger_default.logApiSuccess(url, "GET", { messageCount: responseData?.length || 0, hasData: responseData }, duration); const axiosResponse = { data: responseData, status: response.status, statusText: response.statusText, headers: {} }; onResponse(axiosResponse); } catch (e) { const duration = Date.now() - startTime; Logger_default.logApiError(url, "GET", e, duration); onResponse(); } } async sendWebHookMessage(botConfig, isNewSession, msg, onResponse, payload, attachments) { let url = this.baseUrl + "/chatbot/v2/webhook/" + botConfig.botId; const startTime = Date.now(); const urlWithParams = new URL(url); const customData = { userName: "", identity: "", userAgent: Platform2.OS, botToken: this.botClient.getJwtToken() }; const requestPayload = { session: { new: isNewSession }, message: { type: isNewSession ? "event" : "text", val: payload ? payload : msg }, from: { userInfo: { firstName: "", lastName: "", email: "" }, id: botConfig.identity }, to: { id: botConfig.botName, groupInfo: { id: "", name: "" } }, attachments, customData }; console.log("Webhook payload " + JSON.stringify(requestPayload)); Logger_default.logApiRequest(url, "POST", { message: requestPayload }); try { const response = await this.fetchWithRetries(urlWithParams.toString(), { method: "POST", headers: { "Content-Type": "application/json", "Accept": "application/json", Authorization: "bearer " + this.botClient.getJwtToken() }, body: JSON.stringify(requestPayload) }, 1, "POST"); const duration = Date.now() - startTime; const responseData = await response.json(); console.log("Webhook response " + JSON.stringify(responseData)); if (!response.ok) { const error = new Error(`HTTP ${response.status}`); error.response = { status: response.status, statusText: response.statusText, data: responseData }; onResponse(); return; } Logger_default.logApiSuccess(url, "POST", { messageCount: responseData?.length || 0, hasData: !!responseData }, duration); const messages = this.processWebHookResponse(botConfig, responseData); const axiosResponse = { data: messages, status: response.status, statusText: response.statusText, headers: {}, pollId: responseData.pollId }; onResponse(axiosResponse); if (responseData.pollId) { setTimeout(async () => { await this.getPollData(botConfig, responseData.pollId, onResponse); }, 5e3); } } catch (e) { const duration = Date.now() - startTime; Logger_default.logApiError(url, "POST", e, duration); onResponse(); } } processWebHookResponse(botConfig, response) { const messages = response.data; const processedMessages = []; for (const message of messages) { const isObject = typeof message.val === "object"; const payloadInner = { template_type: "text", text: "" }; if (!isObject) { payloadInner.text = message.val; } let payloadOuter = isObject ? message.val : { text: message.val, type: "text", payload: payloadInner }; if (!isObject) { try { payloadOuter = JSON.parse(message.val); } catch (e) { } } const component = { type: isObject ? payloadOuter.type : "text", payload: payloadOuter }; const cInfo = { body: isObject ? payloadOuter : payloadInner }; const botResponseMsg = { type: isObject ? component.type : "text", component, cInfo }; const msgs = [botResponseMsg]; const botInfo = { chatBot: botConfig.botName, taskBotId: botConfig.botId, customData: null, channelClient: Platform2.OS }; const msg = { type: "bot_response", from: "bot", message: msgs, messageId: message.messageId, createdOn: message.createdOn, timeMillis: new Date(message.createdOn).getTime(), botInfo }; processedMessages.push(JSON.stringify(msg)); } return processedMessages; } async getPollData(botConfig, pollId, onResponse) { let url = this.baseUrl + "/chatbot/v2/webhook/" + botConfig.botId + "/poll/" + pollId; const startTime = Date.now(); const urlWithParams = new URL(url); Logger_default.logApiRequest(url, "GET", { pollId }); try { const response = await this.fetchWithRetries(urlWithParams.toString(), { method: "GET", headers: { "Accept": "application/json", Authorization: "bearer " + this.botClient.getJwtToken() } }, 1, "GET"); const duration = Date.now() - startTime; const responseData = await response.json(); console.log("PollData response " + JSON.stringify(responseData)); if (!response.ok) { const error = new Error(`HTTP ${response.status}`); error.response = { status: response.status, statusText: response.statusText, data: responseData }; onResponse(); return; } Logger_default.logApiSuccess(url, "GET", { messageCount: responseData?.length || 0, hasData: !!responseData }, duration); if (!responseData.data) { return; } const messages = this.processWebHookResponse(botConfig, responseData); const axiosResponse = { data: messages, status: response.status, statusText: response.statusText, headers: {} }; onResponse(axiosResponse); if (responseData.pollId) { setTimeout(async () => { await this.getPollData(botConfig, responseData.pollId, onResponse); }, 5e3); } } catch (e) { const duration = Date.now() - startTime; Logger_default.logApiError(url, "GET", e, duration); onResponse(); } } }; // bot-sdk/rtm/BotClient.tsx var RECONNECT_ATTEMPT_LIMIT2 = 5; var BotClient = class extends EventEmitter { pingInterval; pingTimer; receivedLastPong; timer; isConnecting; jwtToken; resultViewSettings; webSocket; botUrl; sessionActive; appState; isNetWorkAvailable; botInfo; customData; userInfo; authorization; botCustomData; isConnectAtleastOnce; connectionState = ConnectionState.DISCONNECTED; reconnectAttemptCount = 0; isReconnectAttemptRequired = false; DATA_IDENTITY = "identity"; DATA_USERNAME = "userName"; RECONNECT_PARAM = "&isReconnect=true"; reconnectTimer; botConfig; isChangeToken; constructor() { super(); this.pingInterval = 1e4; this.receivedLastPong = false; this.isConnecting = false; this.jwtToken = ""; this.resultViewSettings = []; this.webSocket = void 0; this.botUrl = ""; this.sessionActive = false; this.appState = APP_STATE.ACTIVE; this.isNetWorkAvailable = true; this.botCustomData = /* @__PURE__ */ new Map(); this.isChangeToken = true; this.isConnectAtleastOnce = false; } initializeBotClient(config, isFirstTime) { if (config == null || config == void 0) { throw new Error("BotConfigModel object can not be null"); } if (!config.botId || !config.clientId || !config.clientSecret || !config.botUrl || !config.identity || !config.value_aud) { throw new Error("BotConfigModel object has some values are missing"); } this.connectToBot(config, isFirstTime); } // async checkConnectivity() { // try { // const connectionInfo = await NetInfo.fetch(); // return connectionInfo.isConnected; // } catch (error) { // console.log('Error checking connectivity:', error); // } // return false; // } getJwtToken = () => { return this.jwtToken; }; getAccessToken() { return this.authorization?.accessToken; } getUserId = () => { return this.getBotUserId(); }; getBotName = () => { return this.botConfig?.botName; }; getBotUrl = () => { return this.botConfig?.botUrl || ""; }; getJwtServerUrl = () => { return this.botConfig?.jwtServerUrl || ""; }; getAuthorization = () => { if (!this.authorization) { return void 0; } return this.authorization?.token_type + " " + this.authorization?.accessToken; }; async connectToBot(config, isFirstTime = true) { const _this = this; if (this.connectionState == ConnectionState.CONNECTED || this.isConnecting) { console.log("this.connectionState :", this.connectionState); return; } if (!config) { this.emit(RTM_EVENT.ERROR, { message: "BotConfigModel object has some values are missing", isBack: true }); return; } this.botConfig = config; this.botCustomData.clear(); this.botCustomData.set(this.DATA_IDENTITY, ""); this.botCustomData.set(this.DATA_USERNAME, ""); this.isReconnectAttemptRequired = true; await this.createJwtToken(this.botConfig, isFirstTime); } async createJwtToken(config, isFirstTime = true) { if (!this.botConfig) return; this.botInfo = new BotInfoModel(config.botName, config.botId, { identity: "", userName: "" }); this.initialize(this.botInfo, this.botCustomData); if (this.botConfig.jwtToken) { this.jwtToken = this.botConfig.jwtToken; if (!this.botConfig?.isWebHook) { await this.connectWithJwToken(this.jwtToken, !isFirstTime); } else { this.getWebhookMeta(this.botConfig, isFirstTime); } return; } const apiService = new ApiService(this.botConfig?.botName + "", this); await apiService.getJwtToken( this.botConfig, isFirstTime, async (jwtToken) => { this.jwtToken = jwtToken; if (!this.botConfig?.isWebHook) { await this.connectWithJwToken(this.jwtToken, !isFirstTime); } else { this.getWebhookMeta(this.botConfig, isFirstTime); } }, (error) => { this.emit(RTM_EVENT.ERROR, { message: "Connection to the bot failed. Please ensure your configuration is valid and try again.", isBack: false }); } ); } async getWebhookMeta(botConfig, isFirstTime) { const apiService = new ApiService(botConfig.botUrl, this); await apiService.getWebHookBotMeta(this.jwtToken, botConfig.botId, (response) => { if (response) { apiService.sendWebHookMessage( this.botConfig, isFirstTime, "ON_CONNECT", (response2) => { this.emit(RTM_EVENT.ON_OPEN); if (isFirstTime) { this.onWebhookMessages(response2.data); } } ); } }); } initialize(botInfo, customData) { this.botInfo = botInfo; this.customData = customData; } setSessionActive(isActive) { this.sessionActive = isActive; } setAppState(appState) { this.appState = appState; } getAppState() { return this.appState; } setIsNetworkAvailable(isNetWorkAvailable) { this.isNetWorkAvailable = isNetWorkAvailable; } async connectWithJwToken(jwtToken, isReconnectionAttempt) { if (this.isConnecting) { Logger_default.warn("JWT Token Connection already in progress", { isConnecting: this.isConnecting }); return false; } this.jwtToken = jwtToken; const apiService = new ApiService(this.botConfig?.botUrl + "", this); await apiService.getJwtGrant( jwtToken, isReconnectionAttempt, (status) => { this.emit(RTM_EVENT.CONNECTING); }, async (response) => { this.userInfo = response.userInfo; this.authorization = response.authorization; Logger_default.logConnectionEvent("JWT Token Authorization Success", { userId: this.userInfo?.userId, tokenType: this.authorization?.token_type }); this.emit(RTM_EVENT.ON_JWT_TOKEN_AUTHORIZED); if (this.appState === APP_STATE.ACTIVE) { await this.initSocketConnection(isReconnectionAttempt); } }, (error) => { } ); } async getRtmUrl(isReconnectionAttempt) { const apiService = new ApiService(this.botConfig?.botUrl + "", this); await apiService.getRtmUrl(isReconnectionAttempt, (response) => { this.connect(response, isReconnectionAttempt); }, (error) => { this.isChangeToken = false; if (error?.response?.status === 401) { Logger_default.logConnectionError("RTM Start - Unauthorized (401)", error); this.refreshTokenAndReconnect(!isReconnectionAttempt); } else if (isReconnectionAttempt) { Logger_default.logConnectionError("RTM Start - Reconnection Failed", error); this.reconnect(isReconnectionAttempt, !this.isConnectAtleastOnce); } else { Logger_default.logConnectionError("RTM Start - Connection Failed", error); this.emit(RTM_EVENT.ERROR, { message: "Error:" + error, isBack: true }); } }); } connect(data, isReconnectionAttempt) { const _this = this; let botServerUrl = this.botUrl?.replace("/https/g", "wss"); let url = data.url; let wssUrl = url.replace("ws://dummy.com:80", botServerUrl); this.connectionState = ConnectionState.CONNECTING; wssUrl = isReconnectionAttempt ? wssUrl + this.RECONNECT_PARAM : wssUrl; let isManualClose = false; if (this.webSocket && (this.webSocket?.readyState == WebSocket.CONNECTING || this.webSocket?.readyState == WebSocket.OPEN)) { isManualClose = true; this.webSocket?.close(); } const ws = new WebSocket(wssUrl); ws.onopen = () => { this.isConnectAtleastOnce = true; Logger_default.logWebSocketEvent("Connected", { url: wssUrl.substring(0, 100) + "...", isReconnectionAttempt, readyState: ws.readyState }); _this.connectionState = ConnectionState.CONNECTED; _this.emit(RTM_EVENT.ON_OPEN, { message: "Bot socket connected", isReconnectionAttempt }); _this.startSendingPing(); _this.reconnectAttemptCount = 0; }; ws.onclose = (e) => { Logger_default.logWebSocketEvent("Closed", { code: e?.code, reason: e?.reason, isManualClose, wasCleanClose: e?.code === 1e3 }); _this.emit(RTM_EVENT.ON_CLOSE, "Bot socket closed:" + e); if (isManualClose || e?.code === 1e3) { Logger_default.info("WebSocket closed normally (manual or clean close)", { code: e?.code, isManualClose }); return; } if (this.webSocket) { this.webSocket.close(); } _this.webSocket = void 0; _this.isConnecting = false; _this.reconnect(true); _this.connectionState = ConnectionState.DISCONNECTED; }; ws.onmessage = (e) => { let data2 = JSON.parse(e.data); switch (data2.type) { case "pong": _this.receivedLastPong = true; Logger_default.debug("WebSocket Pong received", { timestamp: (/* @__PURE__ */ new Date()).toISOString(), dataLength: e.data.length }); break; default: Logger_default.logWebSocketEvent("Message Received", { type: data2.type, from: data2.from, messageLength: e.data.length, hasMessage: !!data2.message }); _this.onMessage(e.data, false); break; } }; ws.onerror = (e) => { Logger_default.logWebSocketError("Error", e); _this.emit(RTM_EVENT.ON_ERROR, e?.message); if (_this.webSocket) { _this.webSocket.close(); } _this.webSocket = void 0; _this.isConnecting = false; let isReconnect = this.connectionState == ConnectionState.CONNECTED; _this.connectionState = ConnectionState.DISCONNECTED; _this.reconnect(isReconnect); }; _this.webSocket = ws; } onMessage(messageData, isJsonObj = false) { if (!messageData) { return; } var data = null; if (!isJsonObj) { data = JSON.parse(messageData); } else { data = messageData; } switch (data.type) { case "bot_response": { if (data.from === "bot") { if (data.type === "bot_response") { data.timeMillis = new Date(data.createdOn).getTime(); } this.emit(RTM_EVENT.ON_MESSAGE, data); } break; } case "user_message": { if (data.from === "self") { var message = data.message; if (message) { var messageData = { type: "user_message", message: [ { type: "text", component: { type: "text", payload: { text: message.body, createdOn: (/* @__PURE__ */ new Date()).getTime() } }, cInfo: { body: message.body }, clientMessageId: data.id } ] }; this.emit(RTM_EVENT.ON_MESSAGE, messageData); } } break; } case "ack": { this.emit(RTM_EVENT.ON_ACK, data); break; } case "events": { this.emit(RTM_EVENT.ON_EVENTS, data); break; } case "pong": { break; } default: { break; } } } async fetchWithRetries(url, options, retries = 1, method = "POST") { try { return await fetch(url, options); } catch (err) { if (retries <= RECONNECT_ATTEMPT_LIMIT2) { const delay = Math.min(Math.pow(2, retries) / 4 + Math.random(), RECONNECT_ATTEMPT_LIMIT2) * 1e3; await new Promise((resolve) => setTimeout(() => resolve(void 0), delay)); Logger_default.logApiError(url, method, err, delay); return this.fetchWithRetries(url, options, retries + 1, method); } else { throw new Error(`Max retries exceeded. error: ${err}`); } } } getConnectionState() { return this.connectionState; } disconnect() { Logger_default.logConnectionEvent("Bot Disconnect Called", { connectionState: this.connectionState, isConnecting: this.isConnecting, hasWebSocket: !!this.webSocket, reconnectAttemptCount: this.reconnectAttemptCount }); if (this.reconnectTimer) { this.reconnectAttemptCount = 0; clearInterval(this.reconnectTimer); } if (this.pingTimer) { clearInterval(this.pingTimer); } if (this.timer) { clearInterval(this.timer); } this.connectionState = ConnectionState.DISCONNECTED; this.isReconnectAttemptRequired = false; this.userInfo = null; this.authorization = null; this.sessionActive = false; this.isConnecting = false; this.isConnectAtleastOnce = false; if (this.webSocket) { this.webSocket.close(); } this.webSocket = void 0; this.removeAllListeners(); Logger_default.logConnectionEvent("Bot Disconnected Successfully", { connectionState: this.connectionState }); } async initSocketConnection(isReconnectionAttempt) { if (this.isConnecting) { return; } if (this.authorization) { this.isConnecting = true; await this.getRtmUrl(isReconnectionAttempt); } else if (isReconnectionAttempt && this.botConfig) { await this.connectToBot(this.botConfig, !this.isConnectAtleastOnce); } } reconnect(isReconnectionAttempt, resetReconnectAttemptCount) { if (this.isReconnectAttemptRequired && this.reconnectAttemptCount < RECONNECT_ATTEMPT_LIMIT2) { Logger_default.logConnectionEvent("Reconnection Attempt", { attemptCount: this.reconnectAttemptCount, maxAttempts: RECONNECT_ATTEMPT_LIMIT2, isReconnectionAttempt, resetReconnectAttemptCount }); if (this.reconnectTimer) { clearInterval(this.reconnectTimer); } this.reconnectTimer = setTimeout( async () => { this.isConnecting = false; await this.initSocketConnection(isReconnectionAttempt); }, this.getReconnectDelay() ); } else { Logger_default.logConnectionError("Maximum Reconnection Limit Reached", { attemptCount: this.reconnectAttemptCount, maxAttempts: RECONNECT_ATTEMPT_LIMIT2, isReconnectAttemptRequired: this.isReconnectAttemptRequired }); } } async refreshTokenAndReconnect(isReconnectionAttempt) { Logger_default.logConnectionEvent("Refresh Token and Reconnect Started", { isReconnectionAttempt, reconnectAttemptCount: this.reconnectAttemptCount, connectionState: this.connectionState, hasWebSocket: !!this.webSocket }); if (this.reconnectTimer) { this.reconnectAttemptCount = 0; clearInterval(this.reconnectTimer); } this.isReconnectAttemptRequired = false; this.userInfo = null; this.authorization = null; this.sessionActive = false; this.isConnecting = false; this.connectionState = ConnectionState.DISCONNECTED; if (this.webSocket) { this.webSocket.close(); } if (this.webSocket?.readyState == WebSocket.CLOSED || this.webSocket?.readyState == WebSocket.CLOSING || this.receivedLastPong == false) { clearInterval(this.pingTimer); } setTimeout(async () => { this.reconnectAttemptCount = 0; if (this.botConfig) { Logger_default.logConnectionEvent("Initiating Fresh Connection After Token Refresh", { hasBotConfig: !!this.botConfig }); await this.connectToBot(this.botConfig, isReconnectionAttempt); } }, 500); } getReconnectDelay() { this.reconnectAttemptCount++; return 3e3; } checkSocketAndReconnect() { if (!this.webSocket) { this.reconnect(this.isReconnectAttemptRequired); } else { this.refreshTokenAndReconnect(false); } } startSendingPing() { let ws = this.webSocket; if (this.pingTimer) { clearInterval(this.pingTimer); } setTimeout(() => { this.pingTimer = setInterval(() => { if (ws?.readyState == WebSocket.OPEN) { this.receivedLastPong = false; this.send({ type: "ping" }); } else if (ws?.readyState == WebSocket.CLOSED || ws?.readyState == WebSocket.CLOSING || this.receivedLastPong == false) { clearInterval(this.pingTimer); } }, this.pingInterval); }, 1e3); } setTimer() { let ws = this.webSocket; if (this.timer) { clearInterval(this.timer); } this.timer = setTimeout(() => { if (ws?.readyState == WebSocket.OPEN) { this.receivedLastPong = false; this.send({ type: "ping" }); this.setTimer(); } else if (ws?.readyState == WebSocket.CLOSED || ws?.readyState == WebSocket.CLOSING || this.receivedLastPong == false) { clearInterval(this.timer); } }, this.pingInterval); } send = (message) => { switch (this.webSocket?.readyState) { case WebSocket.OPEN: try { let jsonString = JSON.stringify(message); this.webSocket.send(jsonString); Logger_default.logWebSocketEvent("Message Sent", { type: message.type, clientMessageId: message.clientMessageId, resourceid: message.resourceid, messageLength: jsonString.length, client: message.client }); } catch (error) { Logger_default.logWebSocketError("Send Failed", error); } break; default: Logger_default.warn("WebSocket Send Failed - Connection not ready", { readyState: this.webSocket?.readyState, connectionState: this.connectionState, messageType: message.type }); break; } }; getBotAccessToken() { return this.authorization?.accessToken; } getResultViewSettings() { return this.resultViewSettings; } //{"accountId": "60a4179424c895fef482f57c", "identity": "cs-1e38e7d9-20bd-579a-9a7c-9ec6777a39e2/42438ffd-b473-42d1-bd5f-66bd16715ad6", "managedBy": "60a4179424c895fef482f57c", "userId": "u-822d2104-c94e-5dc9-876b-b858b45d065d"} getBotUserId() { return this.userInfo?.userId; } getBotUserIdentity() { return this.userInfo?.identity; } getBotInfo() { return this.botInfo; } sendMessage(message, payload, attachments) { var clientMessageId = (/* @__PURE__ */ new Date()).getTime(); Logger_default.info("Sending message to bot", { clientMessageId, messageLength: message?.length, hasPayload: !!payload, hasAttachments: !!attachments, platform: Platform3.OS }); var msgData = { type: "user_message", timeMillis: clientMessageId, message: [ { type: "text", component: { type: "text", payload: { text: message, attachments, createdOn: clientMessageId } }, clientMessageId } ] }; var messageToBot = { clientMessageId, message: { body: payload || message, renderMsg: payload != null ? message : null, customData: { botToken: this.getBotAccessToken(), kmToken: this.getAccessToken(), kmUId: this.getUserId() } }, resourceid: "/bot.message", botInfo: this.getBotInfo(), id: clientMessageId, client: Platform3.OS }; if (this.botConfig?.isWebHook) { const apiService = new ApiService(this.botConfig.botUrl, this); apiService.sendWebHookMessage(this.botConfig, false, message, (response) => { this.onWebhookMessages(response.data); }, payload, attachments); } else { this.send(messageToBot); } return msgData; } onWebhookMessages(messages) { let index = 0; const loop = () => { if (index >= messages.length) return; this.onMessage(messages[index]); index++; setTimeout(loop, index * 200); }; loop(); } sendEvent(eventName, isZenDeskEvent) { var clientMessageId = (/* @__PURE__ */ new Date()).getTime(); Logger_default.info("Sending Event to bot", { clientMessageId, eventName, isZenDeskEvent, platform: Platform3.OS }); var eventToBot = { clientMessageId, event: eventName, message: { body: isZenDeskEvent == true ? eventName : "", customData: { botToken: this.getBotAccessToken(), kmToken: this.getAccessToken(), kmUId: this.getUserId() } }, resourceid: isZenDeskEvent == true ? "/bot.clientEvent" : "/bot.message", botInfo: this.getBotInfo(), id: clientMessageId, client: Platform3.OS }; this.send(eventToBot); } }; // bot-sdk/rtm/KoreBotClient.tsx var KoreBotClient = class _KoreBotClient extends BotClient { static _instance; constructor() { super(); } static getInstance() { if (this._instance == null) { this._instance = new _KoreBotClient(); } return this._instance; } static disconnectClient() { this._instance.disconnect(); this._instance = null; } setSessionActive(isActive) { super.setSessionActive(isActive); } setAppState(_appState) { super.setAppState(_appState); } setIsNetworkAvailable(isNetWorkAvailable) { super.setIsNetworkAvailable(isNetWorkAvailable); } checkSocketAndReconnect() { super.checkSocketAndReconnect(); } }; // bot-sdk/branding/ActiveThemeAPI.tsx var MAX_RETRIES = 5; var ActiveThemeAPI = class { isSocketACtive = false; async fetchWithRetries(url, options, retries = 1, method = "GET")