rn-kore-bot-socket-lib-v77
Version:
Description of Bot Scocket SDK library
1,237 lines (1,226 loc) • 41.2 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.tsx
var index_exports = {};
__export(index_exports, {
APP_STATE: () => APP_STATE,
ActiveThemeAPI: () => ActiveThemeAPI,
ConnectionState: () => ConnectionState,
LogLevel: () => LogLevel,
Logger: () => Logger,
RTM_EVENT: () => RTM_EVENT,
default: () => index_default
});
module.exports = __toCommonJS(index_exports);
// 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_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
var import_events = require("events");
// bot-sdk/model/BotInfoModel.tsx
var import_react_native = require("react-native");
var BotInfoModel = class {
constructor(chatBot, taskBotId, customData, channelClient = import_react_native.Platform.OS) {
this.chatBot = chatBot;
this.taskBotId = taskBotId;
this.customData = customData;
this.channelClient = channelClient;
}
};
// bot-sdk/rtm/BotClient.tsx
var import_react_native2 = require("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/rtm/BotClient.tsx
var RECONNECT_ATTEMPT_LIMIT = 5;
var BotClient = class extends import_events.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) {
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, true);
}
// async checkConnectivity() {
// try {
// const connectionInfo = await NetInfo.fetch();
// return connectionInfo.isConnected;
// } catch (error) {
// console.log('Error checking connectivity:', error);
// }
// return false;
// }
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.getJwtToken(this.botConfig, isFirstTime);
}
async getJwtToken(config, isFirstTime = true) {
const body = {
clientId: config.clientId,
clientSecret: config.clientSecret,
identity: config.identity,
aud: config.value_aud,
isAnonymous: false
};
this.botUrl = this.getJwtServerUrl();
let jwtAuthorizationUrl = this.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);
this.jwtToken = responseData.jwt;
this.botInfo = new BotInfoModel(config.botName, config.botId, {
identity: "",
userName: ""
});
this.initialize(this.botInfo, this.botCustomData);
await this.connectWithJwToken(this.jwtToken, !isFirstTime);
return true;
} catch (e) {
const duration = Date.now() - startTime;
Logger_default.logApiError(jwtAuthorizationUrl, "POST", e, duration);
Logger_default.logConnectionError("JWT Token Generation Failed", e);
this.emit(RTM_EVENT.ERROR, {
message: "Connection to the bot failed. Please ensure your configuration is valid and try again.",
isBack: false
});
return false;
}
}
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;
Logger_default.logConnectionEvent("JWT Token Authorization Started", {
isReconnectionAttempt,
tokenLength: jwtToken.length
});
this.emit(RTM_EVENT.CONNECTING);
this.botUrl = this.getBotUrl();
let jwtAuthorizationUrl = this.botUrl + "/api/oAuth/token/jwtgrant";
const startTime = Date.now();
let payload = { assertion: jwtToken, botInfo: this.botInfo };
Logger_default.logApiRequest(jwtAuthorizationUrl, "POST", {
botId: this.botInfo?.taskBotId,
botName: this.botInfo?.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);
this.userInfo = responseData.userInfo;
this.authorization = responseData.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);
}
return true;
} catch (e) {
const duration = Date.now() - startTime;
Logger_default.logApiError(jwtAuthorizationUrl, "POST", e, duration);
Logger_default.logConnectionError("JWT Token Authorization Failed", e);
this.emit(RTM_EVENT.ERROR, {
message: "Connection to the bot failed. Please ensure your configuration is valid and try again.",
isBack: false
});
return false;
}
}
async getRtmUrl(isReconnectionAttempt) {
let rtmUrl = this.botUrl + "/api/rtm/start";
let payload = { botInfo: this.botInfo };
let token = this.authorization.accessToken;
const startTime = Date.now();
Logger_default.logApiRequest(rtmUrl, "POST", {
botId: this.botInfo?.taskBotId,
botName: this.botInfo?.botName,
isReconnectionAttempt
});
try {
const response = await this.fetchWithRetries(rtmUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
Authorization: this.authorization.token_type + " " + token
},
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
});
this.connect(responseData, isReconnectionAttempt);
} catch (e) {
const duration = Date.now() - startTime;
Logger_default.logApiError(rtmUrl, "POST", e, duration);
this.isChangeToken = false;
if (e?.response?.status === 401) {
Logger_default.logConnectionError("RTM Start - Unauthorized (401)", e);
this.refreshTokenAndReconnect(!isReconnectionAttempt);
} else if (isReconnectionAttempt) {
Logger_default.logConnectionError("RTM Start - Reconnection Failed", e);
this.reconnect(isReconnectionAttempt, !this.isConnectAtleastOnce);
} else {
Logger_default.logConnectionError("RTM Start - Connection Failed", e);
this.emit(RTM_EVENT.ERROR, {
message: "Error:" + e,
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") {
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 "pong": {
break;
}
default: {
break;
}
}
}
async getBotHistory() {
if (!this.isConnecting || !this.botInfo.taskBotId || !this.authorization || !this.authorization.token_type || !this.authorization.accessToken) {
Logger_default.warn("Bot History - Missing required parameters", {
isConnecting: this.isConnecting,
hasBotId: !!this.botInfo?.taskBotId,
hasAuthorization: !!this.authorization,
hasTokenType: !!this.authorization?.token_type,
hasAccessToken: !!this.authorization?.accessToken
});
return;
}
let rtmUrl = this.botUrl + "/api" + URL_VERSION + "/botmessages/rtm";
const startTime = Date.now();
Logger_default.logApiRequest(rtmUrl, "GET", {
botId: this.botInfo.taskBotId,
limit: 40,
offset: 0,
forward: true
});
const urlWithParams = new URL(rtmUrl);
urlWithParams.searchParams.append("botId", this.botInfo.taskBotId);
urlWithParams.searchParams.append("limit", "40");
urlWithParams.searchParams.append("offset", "0");
urlWithParams.searchParams.append("forward", "true");
try {
const response = await this.fetchWithRetries(urlWithParams.toString(), {
method: "GET",
headers: {
"Accept": "application/json",
Authorization: this.authorization.token_type + " " + this.authorization.accessToken
}
}, 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(rtmUrl, "GET", {
messageCount: responseData?.length || 0,
hasData: !!responseData
}, duration);
const axiosResponse = {
data: responseData,
status: response.status,
statusText: response.statusText,
headers: {}
};
this.emit(RTM_EVENT.GET_HISTORY, axiosResponse, this.botInfo);
} catch (e) {
const duration = Date.now() - startTime;
Logger_default.logApiError(rtmUrl, "GET", e, duration);
}
}
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");
this.botUrl = this.getBotUrl();
let url = `/api/users/${this.getUserId()}/sdknotifications/subscribe`;
let subscribeUrl = this.botUrl + url;
const startTime = Date.now();
let payload = { osType: import_react_native2.Platform.OS, deviceId };
Logger_default.logApiRequest(subscribeUrl, "POST", {});
const headers = { Authorization: `bearer ${this.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");
this.botUrl = this.getBotUrl();
let url = `/api/users/${this.getUserId()}/sdknotifications/unsubscribe`;
let subscribeUrl = this.botUrl + url;
const startTime = Date.now();
let payload = { osType: import_react_native2.Platform.OS, deviceId };
Logger_default.logApiRequest(subscribeUrl, "POST", {});
const headers = {
Authorization: `bearer ${this.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 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}`);
}
}
}
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_LIMIT) {
Logger_default.logConnectionEvent("Reconnection Attempt", {
attemptCount: this.reconnectAttemptCount,
maxAttempts: RECONNECT_ATTEMPT_LIMIT,
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_LIMIT,
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);
}
}
async getSettings() {
if (!this.botInfo.searchIndexId || !this.botInfo.taskBotId || !this.authorization || !this.authorization.token_type || !this.authorization.accessToken || !this.jwtToken) {
Logger_default.warn("Get Settings - Missing required parameters", {
hasSearchIndexId: !!this.botInfo?.searchIndexId,
hasTaskBotId: !!this.botInfo?.taskBotId,
hasAuthorization: !!this.authorization,
hasTokenType: !!this.authorization?.token_type,
hasAccessToken: !!this.authorization?.accessToken,
hasJwtToken: !!this.jwtToken
});
return false;
}
let urlString = this.botUrl + "searchassistapi/searchsdk/stream/" + this.botInfo.taskBotId + "/" + this.botInfo.searchIndexId + "/getresultviewsettings";
const startTime = Date.now();
Logger_default.logApiRequest(urlString, "GET", {
taskBotId: this.botInfo.taskBotId,
searchIndexId: this.botInfo.searchIndexId
});
try {
const response = await this.fetchWithRetries(urlString, {
method: "GET",
headers: {
"Accept": "application/json",
Authorization: this.authorization?.token_type + " " + this.authorization?.accessToken,
auth: this.jwtToken.toString()
}
}, 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) {
this.resultViewSettings = responseData?.settings;
}
return true;
} catch (e) {
const duration = Date.now() - startTime;
Logger_default.logApiError(urlString, "GET", e, duration);
return 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: import_react_native2.Platform.OS
});
var msgData = {
type: "user_message",
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: import_react_native2.Platform.OS
};
this.send(messageToBot);
return msgData;
}
};
// 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") {
try {
return await fetch(url, options);
} catch (err) {
if (retries <= MAX_RETRIES) {
const delay = Math.min(Math.pow(2, retries) / 4 + Math.random(), MAX_RETRIES) * 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 getThemeAPI(botConfig, callback = (data) => {
}) {
Logger_default.info("Theme API - Getting theme for bot", {
botId: botConfig.botId,
botName: botConfig.botName,
hasAuthorization: !!KoreBotClient.getInstance().getAuthorization()
});
if (KoreBotClient.getInstance().getAuthorization()) {
Logger_default.info("Theme API - Using existing authorization");
this.isSocketACtive = true;
await this.getAppTheme(botConfig, callback);
} else {
Logger_default.info("Theme API - No authorization, initializing bot client");
KoreBotClient.getInstance().setAppState(APP_STATE.SLEEP);
KoreBotClient.getInstance().once(RTM_EVENT.ON_JWT_TOKEN_AUTHORIZED, async () => {
Logger_default.info("Theme API - JWT token authorized, fetching theme");
await this.getAppTheme(botConfig, callback);
});
KoreBotClient.getInstance().initializeBotClient(botConfig);
}
}
getAppTheme = async (botConfig, callback = (data) => {
}) => {
let themeurl = botConfig.botUrl + "/api/websdkthemes/" + botConfig.botId + "/activetheme";
const startTime = Date.now();
Logger_default.logApiRequest(themeurl, "GET", {
botId: botConfig.botId,
isSocketActive: this.isSocketACtive
});
const urlWithParams = new URL(themeurl);
urlWithParams.searchParams.append("botId", botConfig.botId);
try {
const response = await this.fetchWithRetries(urlWithParams.toString(), {
method: "GET",
headers: {
"Accept": "application/json",
Authorization: KoreBotClient.getInstance().getAuthorization() || "",
state: "published",
"Accepts-version": "1",
"Accept-Language": "en_US",
"Content-Type": "application/json"
}
}, 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(themeurl, "GET", {
hasThemeData: !!responseData,
themeId: responseData?.themeId,
themeName: responseData?.name
}, duration);
callback(responseData);
if (!this.isSocketACtive) {
Logger_default.info("Theme API - Disconnecting bot client after theme retrieval");
KoreBotClient.disconnectClient();
}
} catch (e) {
const duration = Date.now() - startTime;
Logger_default.logApiError(themeurl, "GET", e, duration);
callback(null);
if (!this.isSocketACtive) {
Logger_default.info("Theme API - Disconnecting bot client after theme error");
KoreBotClient.disconnectClient();
}
}
};
};
// src/index.tsx
var index_default = KoreBotClient;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
APP_STATE,
ActiveThemeAPI,
ConnectionState,
LogLevel,
Logger,
RTM_EVENT
});