UNPKG

@yourgpt/widget-web-sdk

Version:

Official YourGPT SDK for JavaScript/TypeScript and React applications

610 lines (602 loc) 16.8 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); /* YourGPT SDK - https://yourgpt.ai */ // src/types/core.ts var YourGPTError = class extends Error { constructor(message, code) { super(message); this.code = code; this.name = "YourGPTError"; } }; // src/utils/index.ts var isBrowser = () => { return typeof window !== "undefined" && typeof document !== "undefined"; }; var isDevelopment = () => { return typeof process !== "undefined" && process.env?.NODE_ENV === "development"; }; var createDebugLogger = (namespace) => { return { log: (message, ...args) => { if (isDevelopment()) { console.log(`[YourGPT SDK:${namespace}] ${message}`, ...args); } }, warn: (message, ...args) => { if (isDevelopment()) { console.warn(`[YourGPT SDK:${namespace}] ${message}`, ...args); } }, error: (message, ...args) => { if (isDevelopment()) { console.error(`[YourGPT SDK:${namespace}] ${message}`, ...args); } } }; }; var waitFor = async (condition, timeout = 5e3, interval = 100) => { const start = Date.now(); while (!condition()) { if (Date.now() - start > timeout) { throw new YourGPTError(`Timeout after ${timeout}ms waiting for condition`); } await new Promise((resolve) => setTimeout(resolve, interval)); } }; var withRetry = async (operation, maxRetries = 3, baseDelay = 1e3) => { let lastError; for (let attempt = 0; attempt <= maxRetries; attempt++) { try { return await operation(); } catch (error) { lastError = error; if (attempt === maxRetries) { throw lastError; } const delay = baseDelay * Math.pow(2, attempt); await new Promise((resolve) => setTimeout(resolve, delay)); } } throw lastError; }; var deepMerge = (target, source) => { const result = { ...target }; for (const key in source) { if (source.hasOwnProperty(key)) { if (typeof source[key] === "object" && source[key] !== null && !Array.isArray(source[key]) && typeof result[key] === "object" && result[key] !== null && !Array.isArray(result[key])) { result[key] = deepMerge(result[key], source[key]); } else { result[key] = source[key]; } } } return result; }; var generateId = () => { return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); }; var validateWidgetId = (widgetId) => { const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; return uuidRegex.test(widgetId); }; var validateUrl = (url) => { try { new URL(url); return true; } catch { return false; } }; var sanitizeHtml = (html) => { if (!isBrowser()) return html; const div = document.createElement("div"); div.textContent = html; return div.innerHTML; }; var debounce = (func, wait) => { let timeout = null; return (...args) => { if (timeout) { clearTimeout(timeout); } timeout = setTimeout(() => func(...args), wait); }; }; var throttle = (func, wait) => { let lastCallTime = 0; return (...args) => { const now = Date.now(); if (now - lastCallTime >= wait) { lastCallTime = now; func(...args); } }; }; var isInViewport = (element) => { if (!isBrowser()) return false; const rect = element.getBoundingClientRect(); return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth); }; var loadScript = (src, async = true) => { return new Promise((resolve, reject) => { if (!isBrowser()) { reject(new YourGPTError("Cannot load script in non-browser environment")); return; } if (document.querySelector(`script[src="${src}"]`)) { resolve(); return; } const script = document.createElement("script"); script.src = src; script.async = async; script.type = "module"; script.onload = () => resolve(); script.onerror = () => reject(new YourGPTError(`Failed to load script: ${src}`)); document.head.appendChild(script); }); }; var loadCSS = (href) => { return new Promise((resolve, reject) => { if (!isBrowser()) { reject(new YourGPTError("Cannot load CSS in non-browser environment")); return; } if (document.querySelector(`link[href="${href}"]`)) { resolve(); return; } const link = document.createElement("link"); link.rel = "stylesheet"; link.type = "text/css"; link.href = href; link.onload = () => resolve(); link.onerror = () => reject(new YourGPTError(`Failed to load CSS: ${href}`)); document.head.appendChild(link); }); }; var EventEmitter = class { constructor() { this.events = {}; } on(event, callback) { if (!this.events[event]) { this.events[event] = []; } this.events[event].push(callback); return () => { this.off(event, callback); }; } off(event, callback) { if (!this.events[event]) return; if (callback) { this.events[event] = this.events[event].filter((cb) => cb !== callback); } else { delete this.events[event]; } } emit(event, data) { if (!this.events[event]) return; this.events[event].forEach((callback) => { try { callback(data); } catch (error) { console.error(`Error in event handler for ${String(event)}:`, error); } }); } removeAllListeners() { this.events = {}; } }; // src/types/enum.ts var WidgetRenderModeE = /* @__PURE__ */ ((WidgetRenderModeE2) => { WidgetRenderModeE2["floating"] = "floating"; WidgetRenderModeE2["embedded"] = "embedded"; WidgetRenderModeE2["iframe"] = "iframe"; return WidgetRenderModeE2; })(WidgetRenderModeE || {}); // src/core/YourGPT.ts var _YourGPTSDK = class _YourGPTSDK extends EventEmitter { constructor() { super(); this.config = null; this.isInitialized = false; this.logger = createDebugLogger("Core"); this.state = { isOpen: false, isVisible: true, isConnected: false, isLoaded: false, messageCount: 0, connectionRetries: 0 }; this.aiActionHandlers = /* @__PURE__ */ new Map(); this.setupGlobalAPI(); } /** * Get singleton instance */ static getInstance() { if (!_YourGPTSDK.instance) { _YourGPTSDK.instance = new _YourGPTSDK(); } return _YourGPTSDK.instance; } /** * Initialize the SDK */ async init(config) { window.YGC_WIDGET_RENDER_MODE = config.mode || "floating" /* floating */; if (this.isInitialized) { this.logger.warn("SDK already initialized"); return this; } this.validateConfig(config); this.config = config; this.logger.log("Initializing SDK with config:", config); this.setupGlobalVariables(); if (config.autoLoad !== false) { await this.loadWidget(); } this.isInitialized = true; this.logger.log("SDK initialized successfully"); return this; } /** * Validate configuration */ validateConfig(config) { if (!config.widgetId) { throw new YourGPTError("Widget ID is required", "MISSING_WIDGET_ID"); } if (!validateWidgetId(config.widgetId)) { throw new YourGPTError("Invalid widget ID format", "INVALID_WIDGET_ID"); } if (config.endpoint && !validateUrl(config.endpoint)) { throw new YourGPTError("Invalid endpoint URL", "INVALID_ENDPOINT"); } } /** * Set up global variables */ setupGlobalVariables() { if (!isBrowser()) return; window.YOURGPT_WIDGET_UID = this.config.widgetId; if (!window.$yourgptChatbot) { window.$yourgptChatbot = {}; } window.$yourgptChatbot.WIDGET_ENDPOINT = this.getEndpoint(); } /** * Get endpoint URL */ getEndpoint() { if (this.config?.endpoint) { return this.config.endpoint; } return this.config?.whitelabel ? "https://widget.d4ai.chat" : ""; } /** * Load widget assets */ async loadWidget() { if (!isBrowser()) { throw new YourGPTError("Cannot load widget in non-browser environment", "NOT_BROWSER"); } const endpoint = this.getEndpoint(); try { this.createRootContainer(); await loadScript(`${endpoint}/chatbot.js`); await waitFor(() => this.isWidgetReady(), 1e4); this.updateState({ isLoaded: true }); this.logger.log("Widget loaded successfully"); } catch (error) { this.logger.error("Failed to load widget:", error); throw new YourGPTError("Failed to load widget", "WIDGET_LOAD_FAILED"); } } /** * Create root container for widget */ createRootContainer() { if (document.getElementById("yourgpt_root")) { return; } const root = document.createElement("div"); root.id = "yourgpt_root"; root.style.cssText = ` position: fixed; z-index: 99999; `; document.body.appendChild(root); } /** * Check if widget is ready */ isWidgetReady() { return Boolean(window.$yourgptChatbot?.execute && window.$yourgptChatbot?.on && window.$yourgptChatbot?.set); } /** * Set up global API for backwards compatibility */ setupGlobalAPI() { if (!isBrowser()) return; if (!window.$yourgptChatbot) { window.$yourgptChatbot = { q: [], execute: (action, ...args) => { window.$yourgptChatbot.q.push(["execute", action, ...args]); }, on: (event, callback) => { window.$yourgptChatbot.q.push(["on", event, callback]); }, off: (event, callback) => { window.$yourgptChatbot.q.push(["off", event, callback]); }, set: (key, value) => { window.$yourgptChatbot.q.push(["set", key, value]); } }; } } /** * Update widget state */ updateState(updates) { this.state = { ...this.state, ...updates }; this.emit("stateChange", this.state); } /** * Execute widget command */ executeCommand(command, ...args) { if (!this.isWidgetReady()) { this.logger.warn("Widget not ready, queueing command:", command); window.$yourgptChatbot?.q?.push(["execute", command, ...args]); return; } window.$yourgptChatbot.execute(command, ...args); } /** * Register event listener */ registerEventListener(event, callback) { if (!this.isWidgetReady()) { this.logger.warn("Widget not ready, queueing event listener:", event); window.$yourgptChatbot?.q?.push(["on", event, callback]); return; } window.$yourgptChatbot.on(event, callback); } /** * Set widget data */ setWidgetData(key, value) { if (!this.isWidgetReady()) { this.logger.warn("Widget not ready, queueing data:", key); window.$yourgptChatbot?.q?.push(["set", key, value]); return; } window.$yourgptChatbot.set(key, value); } /** * Get current configuration */ getConfig() { return this.config; } /** * Get current state */ getState() { return { ...this.state }; } /** * Check if SDK is initialized */ isReady() { return this.isInitialized; } /** * Widget Controls */ open() { this.executeCommand("widget:open"); this.updateState({ isOpen: true }); } close() { this.executeCommand("widget:close"); this.updateState({ isOpen: false }); } toggle() { if (this.state.isOpen) { this.close(); } else { this.open(); } } show() { this.executeCommand("widget:show"); this.updateState({ isVisible: true }); } hide() { this.executeCommand("widget:hide"); this.updateState({ isVisible: false }); } /** * Messaging */ sendMessage(text, autoSend = true) { this.executeCommand("message:send", { text, send: autoSend }); } /** * Advanced Features */ openBottomSheet(url) { this.executeCommand("bottomSheet:open", { url }); } startGame(gameId, options = {}) { this.executeCommand("game:start", { id: gameId, ...options }); } /** * Data Management */ setSessionData(data) { this.setWidgetData("session:data", data); } setVisitorData(data) { this.setWidgetData("visitor:data", data); } setContactData(data) { this.setWidgetData("contact:data", data); } /** * Event Listeners */ onInit(callback) { const wrappedCallback = () => { this.updateState({ isConnected: true }); callback(); }; this.registerEventListener("init", wrappedCallback); return () => window.$yourgptChatbot?.off?.("init", wrappedCallback); } onMessageReceived(callback) { const wrappedCallback = (data) => { this.updateState({ messageCount: this.state.messageCount + 1 }); callback(data); }; this.registerEventListener("message:received", wrappedCallback); return () => window.$yourgptChatbot?.off?.("message:received", wrappedCallback); } onEscalatedToHuman(callback) { this.registerEventListener("escalatedToHuman", callback); return () => window.$yourgptChatbot?.off?.("escalatedToHuman", callback); } onWidgetPopup(callback) { const wrappedCallback = (isOpen) => { this.updateState({ isOpen }); callback(isOpen); }; this.registerEventListener("widget:popup", wrappedCallback); return () => window.$yourgptChatbot?.off?.("widget:popup", wrappedCallback); } /** * AI Actions */ registerAIAction(actionName, handler) { this.aiActionHandlers.set(actionName, handler); this.registerEventListener(`ai:action:${actionName}`, handler); } unregisterAIAction(actionName) { this.aiActionHandlers.delete(actionName); window.$yourgptChatbot?.off?.(`ai:action:${actionName}`); } getRegisteredAIActions() { return Array.from(this.aiActionHandlers.keys()); } /** * Create complete chatbot API */ createChatbotAPI() { return { // State ...this.getState(), // Widget Controls open: this.open.bind(this), close: this.close.bind(this), toggle: this.toggle.bind(this), show: this.show.bind(this), hide: this.hide.bind(this), // Messaging sendMessage: this.sendMessage.bind(this), // Advanced Features openBottomSheet: this.openBottomSheet.bind(this), startGame: this.startGame.bind(this), // Data Management setSessionData: this.setSessionData.bind(this), setVisitorData: this.setVisitorData.bind(this), setContactData: this.setContactData.bind(this), // Event Listeners onInit: this.onInit.bind(this), onMessageReceived: this.onMessageReceived.bind(this), onEscalatedToHuman: this.onEscalatedToHuman.bind(this), onWidgetPopup: this.onWidgetPopup.bind(this) }; } /** * Create AI Actions API */ createAIActionsAPI() { return { registerAction: this.registerAIAction.bind(this), unregisterAction: this.unregisterAIAction.bind(this), registerActions: (actions) => { Object.entries(actions).forEach(([name, handler]) => { this.registerAIAction(name, handler); }); }, getRegisteredActions: this.getRegisteredAIActions.bind(this), get registeredActions() { return this.getRegisteredActions(); } }; } /** * Cleanup */ destroy() { this.removeAllListeners(); this.aiActionHandlers.clear(); this.isInitialized = false; this.config = null; _YourGPTSDK.instance = null; } }; _YourGPTSDK.instance = null; var YourGPTSDK = _YourGPTSDK; var YourGPT = { /** * Initialize the SDK */ init: (config) => { const sdk = YourGPTSDK.getInstance(); return sdk.init(config); }, /** * Get the SDK instance */ getInstance: () => { return YourGPTSDK.getInstance(); } }; var YourGPT_default = YourGPT; // src/index.ts var VERSION = "1.0.0"; exports.EventEmitter = EventEmitter; exports.VERSION = VERSION; exports.WidgetRenderModeE = WidgetRenderModeE; exports.YourGPT = YourGPT_default; exports.YourGPTError = YourGPTError; exports.YourGPTSDK = YourGPTSDK; exports.createDebugLogger = createDebugLogger; exports.debounce = debounce; exports.deepMerge = deepMerge; exports.default = YourGPT_default; exports.generateId = generateId; exports.isBrowser = isBrowser; exports.isDevelopment = isDevelopment; exports.isInViewport = isInViewport; exports.loadCSS = loadCSS; exports.loadScript = loadScript; exports.sanitizeHtml = sanitizeHtml; exports.throttle = throttle; exports.validateUrl = validateUrl; exports.validateWidgetId = validateWidgetId; exports.waitFor = waitFor; exports.withRetry = withRetry; //# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map