{"version":3,"sources":["jsdelivr-header.js","/npm/@pindai-ai/chat-widget@2.0.3/src/i18n.js","/npm/@pindai-ai/chat-widget@2.0.3/src/main.js"],"names":[],"mappings":"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","file":"/npm/@pindai-ai/chat-widget@2.0.3/dist/pindai-chat-widget.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/@pindai-ai/chat-widget@2.0.3/dist/pindai-chat-widget.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/**\n * Internationalization (i18n) System for Pindai Chat Widget\n * Supports Indonesian (id) and English (en) locales\n */\n\nexport const translations = {\n  en: {\n    // Widget UI\n    title: 'Pindai Agent',\n    placeholder: 'Write a message...',\n    initialMessage: 'Hello! How can I help you today?',\n    send: 'Send',\n    close: 'Close',\n    upload: 'Upload file',\n    removeFile: 'Remove file',\n\n    // Loading and status\n    typingIndicator: 'AI is typing...',\n    sending: 'Sending...',\n    justNow: 'Just now',\n    minutesAgo: '{minutes}m ago',\n\n    // Offline/Online status\n    offline: 'Offline - messages will be sent when online',\n    connectionRestored: 'Connection restored',\n    connectionLost: 'No internet connection',\n\n    // Error messages\n    errorGeneric: 'An error occurred. Please try again.',\n    errorTimeout: 'Request timeout. Please try again.',\n    errorNetwork: 'No internet connection. Check your network.',\n    errorServer: 'Server is busy. Please try again later.',\n    errorRateLimit: 'Too many messages. Please wait {seconds} seconds.',\n    errorInvalidResponse: 'Invalid server response. Please contact support.',\n\n    // File upload errors\n    fileTypeNotSupported: 'File type not supported: {filename}',\n    fileTooLarge: 'File too large: {filename} (max {maxSize}MB)',\n    maxFilesExceeded: 'Maximum {maxFiles} files allowed',\n\n    // Quick replies (default suggestions)\n    quickReply1: 'How can I extract data from documents?',\n    quickReply2: 'What file types are supported?',\n    quickReply3: 'Tell me about pricing',\n    quickReply4: 'Contact support',\n\n    // Accessibility labels\n    ariaOpenChat: 'Open chat widget',\n    ariaCloseChat: 'Close chat window',\n    ariaSendMessage: 'Send message',\n    ariaMessageInput: 'Type your message',\n    ariaUploadFile: 'Upload file',\n    ariaRemoveFile: 'Remove file',\n    ariaChatWindow: 'Chat window',\n    ariaMessageLog: 'Chat messages',\n  },\n\n  id: {\n    // Widget UI\n    title: 'Pindai Agent',\n    placeholder: 'Tulis pesan...',\n    initialMessage: 'Halo! Bagaimana saya bisa membantu Anda hari ini?',\n    send: 'Kirim',\n    close: 'Tutup',\n    upload: 'Unggah file',\n    removeFile: 'Hapus file',\n\n    // Loading and status\n    typingIndicator: 'AI sedang mengetik...',\n    sending: 'Mengirim...',\n    justNow: 'Baru saja',\n    minutesAgo: '{minutes}m yang lalu',\n\n    // Offline/Online status\n    offline: 'Offline - pesan akan dikirim saat online',\n    connectionRestored: 'Koneksi kembali',\n    connectionLost: 'Tidak ada koneksi internet',\n\n    // Error messages\n    errorGeneric: 'Terjadi kesalahan. Silakan coba lagi.',\n    errorTimeout: 'Waktu permintaan habis. Silakan coba lagi.',\n    errorNetwork: 'Tidak ada koneksi internet. Periksa jaringan Anda.',\n    errorServer: 'Server sedang sibuk. Silakan coba lagi dalam beberapa saat.',\n    errorRateLimit: 'Terlalu banyak pesan. Silakan tunggu {seconds} detik.',\n    errorInvalidResponse: 'Respons server tidak valid. Silakan hubungi dukungan.',\n\n    // File upload errors\n    fileTypeNotSupported: 'Jenis file tidak didukung: {filename}',\n    fileTooLarge: 'File terlalu besar: {filename} (maks {maxSize}MB)',\n    maxFilesExceeded: 'Maksimal {maxFiles} file diperbolehkan',\n\n    // Quick replies (default suggestions)\n    quickReply1: 'Bagaimana cara ekstraksi dokumen?',\n    quickReply2: 'Jenis file apa yang didukung?',\n    quickReply3: 'Tentang harga',\n    quickReply4: 'Hubungi dukungan',\n\n    // Accessibility labels\n    ariaOpenChat: 'Buka widget chat',\n    ariaCloseChat: 'Tutup jendela chat',\n    ariaSendMessage: 'Kirim pesan',\n    ariaMessageInput: 'Ketik pesan Anda',\n    ariaUploadFile: 'Unggah file',\n    ariaRemoveFile: 'Hapus file',\n    ariaChatWindow: 'Jendela chat',\n    ariaMessageLog: 'Pesan chat',\n  }\n};\n\n/**\n * I18n class for managing translations\n */\nexport class I18n {\n  constructor(locale = 'id') {\n    this.locale = this.isValidLocale(locale) ? locale : 'id';\n  }\n\n  /**\n   * Check if locale is valid\n   */\n  isValidLocale(locale) {\n    return Object.keys(translations).includes(locale);\n  }\n\n  /**\n   * Translate a key with optional parameter substitution\n   * @param {string} key - Translation key\n   * @param {object} params - Parameters to substitute in the translation\n   * @returns {string} Translated string\n   */\n  t(key, params = {}) {\n    let text = translations[this.locale]?.[key] || translations.en[key] || key;\n\n    // Replace parameters like {param} with actual values\n    Object.keys(params).forEach(param => {\n      const regex = new RegExp(`\\\\{${param}\\\\}`, 'g');\n      text = text.replace(regex, params[param]);\n    });\n\n    return text;\n  }\n\n  /**\n   * Change the current locale\n   * @param {string} locale - New locale (id or en)\n   */\n  setLocale(locale) {\n    if (this.isValidLocale(locale)) {\n      this.locale = locale;\n      return true;\n    }\n    console.warn(`Invalid locale: ${locale}. Keeping current locale: ${this.locale}`);\n    return false;\n  }\n\n  /**\n   * Get current locale\n   * @returns {string} Current locale\n   */\n  getLocale() {\n    return this.locale;\n  }\n\n  /**\n   * Get all available locales\n   * @returns {string[]} Array of available locale codes\n   */\n  getAvailableLocales() {\n    return Object.keys(translations);\n  }\n}\n\n// Export default instance for convenience\nexport default I18n;\n","import './style.css';\nimport { I18n } from './i18n.js';\n\n/**\n * Pindai Chat Widget - Modern, Accessible, Indonesian-focused\n * Version 2.0.0\n */\nclass PindaiChatWidget {\n  constructor(options) {\n    // Backward compatibility: support both webhookUrl and n8nUrl\n    const apiEndpoint = options.webhookUrl || options.n8nUrl;\n\n    if (!apiEndpoint) {\n      throw new Error('PindaiChatWidget: \"webhookUrl\" option is required.');\n    }\n\n    // Core configuration\n    this.webhookUrl = apiEndpoint;\n    this.mode = options.mode || 'widget';\n\n    // Internationalization\n    this.locale = options.locale || 'id'; // Default to Indonesian\n    this.i18n = new I18n(this.locale);\n\n    // UI customization\n    this.title = options.title || this.i18n.t('title');\n    this.initialMessage = options.initialMessage || this.i18n.t('initialMessage');\n    this.launcherIconUrl = options.launcherIconUrl || this.getDefaultIcon();\n\n    // Branding\n    this.logoUrl = options.logoUrl || 'https://pindai.ai/logo.png';\n    this.showLogo = options.showLogo !== false;\n    this.launcherColor = options.launcherColor || '#0066FF';\n    this.sendButtonColor = options.sendButtonColor || '#0066FF';\n    this.accentColor = options.accentColor || '#00C896';\n\n    // File upload configuration\n    this.enableFileUpload = options.enableFileUpload !== false;\n    this.allowedFileTypes = options.allowedFileTypes || [\n      'image/jpeg', 'image/png', 'image/gif', 'image/webp',\n      'application/pdf',\n      'application/msword',\n      'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n      'application/vnd.ms-excel',\n      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'\n    ];\n    this.maxFileSize = options.maxFileSize || 10 * 1024 * 1024; // 10MB\n    this.maxFiles = options.maxFiles || 5;\n    this.uploadedFiles = [];\n\n    // Notifications\n    this.enableNotifications = options.enableNotifications !== false;\n    this.enableSound = options.enableSound === true;\n    this.unreadCount = 0;\n\n    // Quick replies\n    this.showQuickReplies = options.showQuickReplies !== false;\n    this.quickReplies = options.quickReplies || [\n      this.i18n.t('quickReply1'),\n      this.i18n.t('quickReply2'),\n      this.i18n.t('quickReply3'),\n      this.i18n.t('quickReply4')\n    ];\n\n    // Message history\n    this.enableHistory = options.enableHistory !== false;\n    this.maxHistoryItems = options.maxHistoryItems || 50;\n    this.historyKey = `pindai-chat-history-${this.webhookUrl}`;\n    this.stateKey = `pindai-chat-state-${this.webhookUrl}`;\n\n    // Error handling & retry logic\n    this.maxRetries = options.maxRetries || 3;\n    this.retryDelay = options.retryDelay || 1000;\n    this.requestTimeout = options.requestTimeout || 30000;\n\n    // Rate limiting\n    this.rateLimit = options.rateLimit || 5;\n    this.rateLimitWindow = options.rateLimitWindow || 60000;\n    this.messageTimes = [];\n\n    // DOM references\n    this.container = null;\n    this.launcher = null;\n    this.chatWindow = null;\n    this.messageList = null;\n    this.input = null;\n    this.button = null;\n    this.closeButton = null;\n\n    // State\n    this.sessionId = `web-session-${Date.now()}-${Math.random()}`;\n    this.isLoading = false;\n    this.isOpen = false;\n    this.isOnline = navigator.onLine;\n\n    // Initialize\n    this.loadState();\n    this.setupOfflineDetection();\n\n    if (this.mode === 'fullscreen') {\n      this.initChatWindow();\n    } else {\n      this.initLauncher();\n    }\n  }\n\n  /**\n   * Initialize launcher button\n   */\n  initLauncher() {\n    this.launcher = document.createElement('div');\n    this.launcher.className = 'n8n-chat-launcher';\n    this.launcher.style.backgroundColor = this.launcherColor;\n    this.launcher.setAttribute('role', 'button');\n    this.launcher.setAttribute('aria-label', this.i18n.t('ariaOpenChat'));\n    this.launcher.setAttribute('tabindex', '0');\n    this.launcher.innerHTML = `\n      <img src=\"${this.launcherIconUrl}\" alt=\"\">\n      <span class=\"n8n-chat-unread-badge\" style=\"display: none;\">0</span>\n    `;\n    document.body.appendChild(this.launcher);\n\n    this.launcher.addEventListener('click', () => this.toggleChatWindow());\n    this.launcher.addEventListener('keydown', (e) => {\n      if (e.key === 'Enter' || e.key === ' ') {\n        e.preventDefault();\n        this.toggleChatWindow();\n      }\n    });\n  }\n\n  /**\n   * Initialize chat window\n   */\n  initChatWindow() {\n    this.container = document.createElement('div');\n    this.container.className = `n8n-chat-widget ${this.mode === 'fullscreen' ? 'n8n-chat-widget--fullscreen' : ''}`;\n    this.container.setAttribute('role', 'dialog');\n    this.container.setAttribute('aria-modal', 'true');\n    this.container.setAttribute('aria-label', this.title);\n\n    this.container.innerHTML = `\n      <div class=\"n8n-chat-header\">\n        <div class=\"n8n-chat-header-content\">\n          ${this.showLogo ? `<img src=\"${this.logoUrl}\" alt=\"Pindai Logo\" class=\"n8n-chat-logo\">` : ''}\n          <span class=\"n8n-chat-title\">${this.title}</span>\n        </div>\n        <button class=\"n8n-chat-close-btn\" aria-label=\"${this.i18n.t('ariaCloseChat')}\">&times;</button>\n      </div>\n      <div class=\"n8n-chat-messages\" role=\"log\" aria-live=\"polite\" aria-atomic=\"false\"></div>\n      <div class=\"n8n-chat-watermark\">\n        <span>Powered by</span>\n        <a href=\"https://pindai.ai\" target=\"_blank\" rel=\"noopener noreferrer\">Pindai.ai</a>\n      </div>\n      <div class=\"n8n-chat-input-area\">\n        ${this.enableFileUpload ? `\n          <label class=\"n8n-chat-file-upload-btn\" aria-label=\"${this.i18n.t('ariaUploadFile')}\">\n            <input type=\"file\" multiple accept=\"${this.allowedFileTypes.join(',')}\" hidden>\n            <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n              <path d=\"M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48\"/>\n            </svg>\n          </label>\n        ` : ''}\n        <input type=\"text\" placeholder=\"${this.i18n.t('placeholder')}\" aria-label=\"${this.i18n.t('ariaMessageInput')}\" />\n        <button class=\"n8n-chat-send-btn\" style=\"background-color: ${this.sendButtonColor}\" aria-label=\"${this.i18n.t('ariaSendMessage')}\">\n          <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n            <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n            <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n          </svg>\n        </button>\n      </div>\n      ${this.enableFileUpload ? '<div class=\"n8n-chat-file-preview\" style=\"display: none;\"></div>' : ''}\n    `;\n\n    if (this.mode === 'widget') {\n      document.body.appendChild(this.container);\n    } else {\n      document.body.innerHTML = '';\n      document.body.appendChild(this.container);\n      document.body.style.margin = '0';\n    }\n\n    // Get DOM references\n    this.messageList = this.container.querySelector('.n8n-chat-messages');\n    this.input = this.container.querySelector('input[type=\"text\"]');\n    this.button = this.container.querySelector('.n8n-chat-send-btn');\n    this.closeButton = this.container.querySelector('.n8n-chat-close-btn');\n\n    // Event listeners\n    this.button.addEventListener('click', (e) => {\n      e.preventDefault();\n      this.sendMessage();\n    });\n\n    this.input.addEventListener('keypress', (e) => {\n      if (e.key === 'Enter') {\n        e.preventDefault();\n        this.sendMessage();\n      }\n    });\n\n    if (this.mode === 'fullscreen') {\n      this.closeButton.style.display = 'none';\n    } else {\n      this.closeButton.addEventListener('click', () => this.toggleChatWindow());\n    }\n\n    // File upload handler\n    if (this.enableFileUpload) {\n      const fileInput = this.container.querySelector('input[type=\"file\"]');\n      fileInput.addEventListener('change', (e) => this.handleFileSelect(e));\n    }\n\n    // Setup keyboard navigation\n    this.setupKeyboardNavigation();\n\n    // Load history and show initial message\n    this.loadHistory();\n    if (this.messageList.children.length === 0) {\n      this.addMessage(this.initialMessage, 'ai');\n    }\n  }\n\n  /**\n   * Toggle chat window open/close\n   */\n  toggleChatWindow() {\n    if (!this.isOpen) {\n      if (!this.container) {\n        this.initChatWindow();\n      }\n\n      setTimeout(() => {\n        this.container.classList.add('n8n-chat-widget--open');\n        if (this.launcher) {\n          this.launcher.classList.add('n8n-chat-launcher--hidden');\n        }\n        this.input.focus();\n        this.clearUnreadCount();\n      }, 10);\n    } else {\n      this.container.classList.remove('n8n-chat-widget--open');\n      if (this.launcher) {\n        this.launcher.classList.remove('n8n-chat-launcher--hidden');\n      }\n    }\n    this.isOpen = !this.isOpen;\n    this.saveState();\n  }\n\n  /**\n   * Get default chat icon\n   */\n  getDefaultIcon() {\n    const svgIcon = `\n      <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n        <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n      </svg>\n    `;\n    return `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(svgIcon)}`;\n  }\n\n  /**\n   * Format timestamp for display\n   */\n  formatTimestamp(date) {\n    const now = new Date();\n    const diff = now - date;\n\n    if (diff < 60000) {\n      return this.i18n.t('justNow');\n    }\n    if (diff < 3600000) {\n      const minutes = Math.floor(diff / 60000);\n      return this.i18n.t('minutesAgo', { minutes });\n    }\n\n    return date.toLocaleTimeString(this.locale === 'id' ? 'id-ID' : 'en-US', {\n      hour: '2-digit',\n      minute: '2-digit'\n    });\n  }\n\n  /**\n   * Add message to chat\n   */\n  addMessage(text, sender, timestamp = new Date()) {\n    const messageBubble = document.createElement('div');\n    messageBubble.className = `n8n-chat-bubble n8n-chat-${sender}-message`;\n\n    const textNode = document.createElement('div');\n    textNode.className = 'n8n-chat-message-text';\n    textNode.textContent = text;\n\n    const timeNode = document.createElement('div');\n    timeNode.className = 'n8n-chat-message-timestamp';\n    timeNode.textContent = this.formatTimestamp(timestamp);\n    timeNode.setAttribute('data-timestamp', timestamp.toISOString());\n\n    messageBubble.appendChild(textNode);\n    messageBubble.appendChild(timeNode);\n    this.messageList.appendChild(messageBubble);\n\n    this.messageList.scrollTop = this.messageList.scrollHeight;\n\n    // Save to history\n    this.saveToHistory(text, sender, timestamp);\n\n    // Increment unread if chat closed and AI message\n    if (!this.isOpen && sender === 'ai') {\n      this.incrementUnread();\n    }\n  }\n\n  /**\n   * Show/hide typing indicator\n   */\n  showTypingIndicator(show) {\n    let indicator = this.messageList.querySelector('.n8n-chat-typing-indicator');\n    if (show) {\n      if (!indicator) {\n        indicator = document.createElement('div');\n        indicator.className = 'n8n-chat-bubble n8n-chat-ai-message n8n-chat-typing-indicator';\n        indicator.innerHTML = '<span></span><span></span><span></span>';\n        indicator.setAttribute('aria-label', this.i18n.t('typingIndicator'));\n        this.messageList.appendChild(indicator);\n        this.messageList.scrollTop = this.messageList.scrollHeight;\n      }\n    } else {\n      if (indicator) {\n        indicator.remove();\n      }\n    }\n  }\n\n  /**\n   * Handle file selection\n   */\n  handleFileSelect(event) {\n    const files = Array.from(event.target.files);\n\n    files.forEach(file => {\n      // Check file type\n      if (!this.allowedFileTypes.includes(file.type)) {\n        this.addMessage(\n          this.i18n.t('fileTypeNotSupported', { filename: file.name }),\n          'ai'\n        );\n        return;\n      }\n\n      // Check file size\n      if (file.size > this.maxFileSize) {\n        const maxSizeMB = this.maxFileSize / 1024 / 1024;\n        this.addMessage(\n          this.i18n.t('fileTooLarge', { filename: file.name, maxSize: maxSizeMB }),\n          'ai'\n        );\n        return;\n      }\n\n      // Check max files\n      if (this.uploadedFiles.length >= this.maxFiles) {\n        this.addMessage(\n          this.i18n.t('maxFilesExceeded', { maxFiles: this.maxFiles }),\n          'ai'\n        );\n        return;\n      }\n\n      this.uploadedFiles.push(file);\n      this.renderFilePreview(file);\n    });\n\n    event.target.value = ''; // Reset input\n  }\n\n  /**\n   * Render file preview\n   */\n  renderFilePreview(file) {\n    const preview = this.container.querySelector('.n8n-chat-file-preview');\n    if (!preview) return;\n\n    preview.style.display = 'flex';\n\n    const fileItem = document.createElement('div');\n    fileItem.className = 'n8n-chat-file-item';\n    fileItem.innerHTML = `\n      <span class=\"n8n-chat-file-name\">${file.name}</span>\n      <button class=\"n8n-chat-file-remove\" data-file=\"${file.name}\" aria-label=\"${this.i18n.t('ariaRemoveFile')}\">&times;</button>\n    `;\n\n    const removeBtn = fileItem.querySelector('.n8n-chat-file-remove');\n    removeBtn.addEventListener('click', () => {\n      this.uploadedFiles = this.uploadedFiles.filter(f => f.name !== file.name);\n      fileItem.remove();\n      if (this.uploadedFiles.length === 0) {\n        preview.style.display = 'none';\n      }\n    });\n\n    preview.appendChild(fileItem);\n  }\n\n  /**\n   * Send message with files\n   */\n  async sendMessage() {\n    const messageText = this.input.value.trim();\n    if ((!messageText && this.uploadedFiles.length === 0) || this.isLoading) return;\n\n    // Check rate limit\n    try {\n      this.checkRateLimit();\n    } catch (error) {\n      this.addMessage(error.message, 'ai');\n      return;\n    }\n\n    // Check online status\n    if (!this.isOnline) {\n      this.addMessage(this.i18n.t('connectionLost'), 'ai');\n      return;\n    }\n\n    this.isLoading = true;\n    this.button.disabled = true;\n    this.input.disabled = true;\n\n    if (messageText) {\n      this.addMessage(messageText, 'user');\n    }\n\n    this.input.value = '';\n    this.showTypingIndicator(true);\n\n    try {\n      const response = await this.sendMessageWithRetry(messageText, this.uploadedFiles);\n      this.addMessage(response, 'ai');\n\n      // Show quick replies after AI response\n      if (this.showQuickReplies && this.quickReplies.length > 0) {\n        this.renderQuickReplies();\n      }\n    } catch (error) {\n      const errorMessage = this.getErrorMessage(error);\n      this.addMessage(errorMessage, 'ai');\n    } finally {\n      this.isLoading = false;\n      this.button.disabled = false;\n      this.input.disabled = false;\n      this.showTypingIndicator(false);\n      this.input.focus();\n\n      // Clear uploaded files\n      if (this.uploadedFiles.length > 0) {\n        this.uploadedFiles = [];\n        const preview = this.container.querySelector('.n8n-chat-file-preview');\n        if (preview) {\n          preview.innerHTML = '';\n          preview.style.display = 'none';\n        }\n      }\n    }\n  }\n\n  /**\n   * Send message with retry logic\n   */\n  async sendMessageWithRetry(messageText, files = [], retryCount = 0) {\n    try {\n      const controller = new AbortController();\n      const timeoutId = setTimeout(() => controller.abort(), this.requestTimeout);\n\n      const formData = new FormData();\n      formData.append('sessionId', this.sessionId);\n      formData.append('message', messageText);\n\n      // Append files\n      files.forEach((file, index) => {\n        formData.append(`file${index}`, file);\n      });\n\n      const response = await fetch(this.webhookUrl, {\n        method: 'POST',\n        body: formData,\n        signal: controller.signal\n      });\n\n      clearTimeout(timeoutId);\n\n      if (!response.ok) {\n        // Retry on 5xx errors\n        if (response.status >= 500 && retryCount < this.maxRetries) {\n          await this.delay(this.retryDelay * (retryCount + 1));\n          return this.sendMessageWithRetry(messageText, files, retryCount + 1);\n        }\n\n        const errorData = await response.json().catch(() => ({}));\n        throw new Error(errorData.message || `Network error: ${response.statusText}`);\n      }\n\n      const data = await response.json();\n      if (!data.response) {\n        throw new Error(this.i18n.t('errorInvalidResponse'));\n      }\n\n      return data.response;\n\n    } catch (error) {\n      if (error.name === 'AbortError') {\n        throw new Error(this.i18n.t('errorTimeout'));\n      }\n\n      // Retry on network errors\n      if (error.message.includes('NetworkError') && retryCount < this.maxRetries) {\n        await this.delay(this.retryDelay * (retryCount + 1));\n        return this.sendMessageWithRetry(messageText, files, retryCount + 1);\n      }\n\n      throw error;\n    }\n  }\n\n  /**\n   * Delay helper\n   */\n  delay(ms) {\n    return new Promise(resolve => setTimeout(resolve, ms));\n  }\n\n  /**\n   * Get user-friendly error message\n   */\n  getErrorMessage(error) {\n    if (error.message.includes('timeout') || error.message.includes('Timeout')) {\n      return this.i18n.t('errorTimeout');\n    }\n    if (error.message.includes('NetworkError') || error.message.includes('Failed to fetch')) {\n      return this.i18n.t('errorNetwork');\n    }\n    if (error.message.includes('500') || error.message.includes('503')) {\n      return this.i18n.t('errorServer');\n    }\n    return this.i18n.t('errorGeneric');\n  }\n\n  /**\n   * Check rate limit\n   */\n  checkRateLimit() {\n    const now = Date.now();\n    this.messageTimes = this.messageTimes.filter(\n      time => now - time < this.rateLimitWindow\n    );\n\n    if (this.messageTimes.length >= this.rateLimit) {\n      const oldestTime = this.messageTimes[0];\n      const waitTime = Math.ceil((this.rateLimitWindow - (now - oldestTime)) / 1000);\n      throw new Error(this.i18n.t('errorRateLimit', { seconds: waitTime }));\n    }\n\n    this.messageTimes.push(now);\n  }\n\n  /**\n   * Render quick reply buttons\n   */\n  renderQuickReplies(replies = this.quickReplies) {\n    if (!this.showQuickReplies || replies.length === 0) return;\n\n    // Remove existing quick replies\n    const existingReplies = this.messageList.querySelector('.n8n-chat-quick-replies');\n    if (existingReplies) existingReplies.remove();\n\n    const repliesContainer = document.createElement('div');\n    repliesContainer.className = 'n8n-chat-quick-replies';\n\n    replies.forEach(reply => {\n      const button = document.createElement('button');\n      button.className = 'n8n-chat-quick-reply-btn';\n      button.textContent = reply;\n      button.addEventListener('click', () => {\n        this.input.value = reply;\n        this.sendMessage();\n        repliesContainer.remove();\n      });\n      repliesContainer.appendChild(button);\n    });\n\n    this.messageList.appendChild(repliesContainer);\n    this.messageList.scrollTop = this.messageList.scrollHeight;\n  }\n\n  /**\n   * Notification badge management\n   */\n  incrementUnread() {\n    if (!this.isOpen) {\n      this.unreadCount++;\n      this.updateUnreadBadge();\n    }\n  }\n\n  updateUnreadBadge() {\n    if (!this.launcher) return;\n    const badge = this.launcher.querySelector('.n8n-chat-unread-badge');\n    if (badge) {\n      badge.textContent = this.unreadCount;\n      badge.style.display = this.unreadCount > 0 ? 'flex' : 'none';\n    }\n  }\n\n  clearUnreadCount() {\n    this.unreadCount = 0;\n    this.updateUnreadBadge();\n  }\n\n  /**\n   * Message history persistence\n   */\n  loadHistory() {\n    if (!this.enableHistory) return;\n\n    try {\n      const stored = localStorage.getItem(this.historyKey);\n      if (!stored) return;\n\n      const history = JSON.parse(stored);\n      history.forEach(item => {\n        this.addMessageWithoutSaving(item.text, item.sender, new Date(item.timestamp));\n      });\n    } catch (error) {\n      console.warn('Failed to load chat history:', error);\n    }\n  }\n\n  addMessageWithoutSaving(text, sender, timestamp) {\n    const messageBubble = document.createElement('div');\n    messageBubble.className = `n8n-chat-bubble n8n-chat-${sender}-message`;\n\n    const textNode = document.createElement('div');\n    textNode.className = 'n8n-chat-message-text';\n    textNode.textContent = text;\n\n    const timeNode = document.createElement('div');\n    timeNode.className = 'n8n-chat-message-timestamp';\n    timeNode.textContent = this.formatTimestamp(timestamp);\n    timeNode.setAttribute('data-timestamp', timestamp.toISOString());\n\n    messageBubble.appendChild(textNode);\n    messageBubble.appendChild(timeNode);\n    this.messageList.appendChild(messageBubble);\n\n    this.messageList.scrollTop = this.messageList.scrollHeight;\n  }\n\n  saveToHistory(text, sender, timestamp = new Date()) {\n    if (!this.enableHistory) return;\n\n    try {\n      const stored = localStorage.getItem(this.historyKey);\n      let history = stored ? JSON.parse(stored) : [];\n\n      history.push({\n        text,\n        sender,\n        timestamp: timestamp.toISOString()\n      });\n\n      // Keep only last N messages\n      if (history.length > this.maxHistoryItems) {\n        history = history.slice(-this.maxHistoryItems);\n      }\n\n      localStorage.setItem(this.historyKey, JSON.stringify(history));\n    } catch (error) {\n      console.warn('Failed to save chat history:', error);\n    }\n  }\n\n  /**\n   * State persistence\n   */\n  loadState() {\n    try {\n      const stored = localStorage.getItem(this.stateKey);\n      if (stored) {\n        // State loaded but not used for auto-open\n        // User needs to explicitly open the chat\n      }\n    } catch (error) {\n      console.warn('Failed to load chat state:', error);\n    }\n  }\n\n  saveState() {\n    try {\n      localStorage.setItem(this.stateKey, JSON.stringify({\n        isOpen: this.isOpen,\n        timestamp: new Date().toISOString()\n      }));\n    } catch (error) {\n      console.warn('Failed to save chat state:', error);\n    }\n  }\n\n  /**\n   * Offline detection\n   */\n  setupOfflineDetection() {\n    window.addEventListener('online', () => {\n      this.isOnline = true;\n      this.updateOnlineStatus();\n    });\n\n    window.addEventListener('offline', () => {\n      this.isOnline = false;\n      this.updateOnlineStatus();\n    });\n  }\n\n  updateOnlineStatus() {\n    if (!this.container) return;\n\n    const statusBar = this.container.querySelector('.n8n-chat-offline-indicator');\n    if (!this.isOnline && !statusBar) {\n      const indicator = document.createElement('div');\n      indicator.className = 'n8n-chat-offline-indicator';\n      indicator.innerHTML = `\n        <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n          <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\n          <path d=\"M16.72 11.06A10.94 10.94 0 0 1 19 12.55\"></path>\n          <path d=\"M5 12.55a10.94 10.94 0 0 1 5.17-2.39\"></path>\n          <path d=\"M10.71 5.05A16 16 0 0 1 22.58 9\"></path>\n          <path d=\"M1.42 9a15.91 15.91 0 0 1 4.7-2.88\"></path>\n          <path d=\"M8.53 16.11a6 6 0 0 1 6.95 0\"></path>\n          <line x1=\"12\" y1=\"20\" x2=\"12.01\" y2=\"20\"></line>\n        </svg>\n        <span>${this.i18n.t('offline')}</span>\n      `;\n      this.container.insertBefore(indicator, this.messageList);\n    } else if (this.isOnline && statusBar) {\n      statusBar.remove();\n    }\n\n    // Update button state\n    if (this.button) {\n      this.button.disabled = !this.isOnline || this.isLoading;\n    }\n  }\n\n  /**\n   * Keyboard navigation setup\n   */\n  setupKeyboardNavigation() {\n    // ESC to close widget\n    document.addEventListener('keydown', (e) => {\n      if (e.key === 'Escape' && this.isOpen && this.mode === 'widget') {\n        this.toggleChatWindow();\n      }\n    });\n\n    // Tab trap within modal\n    this.container.addEventListener('keydown', (e) => {\n      if (e.key === 'Tab') {\n        const focusableElements = this.container.querySelectorAll(\n          'button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n        );\n        const firstElement = focusableElements[0];\n        const lastElement = focusableElements[focusableElements.length - 1];\n\n        if (e.shiftKey && document.activeElement === firstElement) {\n          e.preventDefault();\n          lastElement.focus();\n        } else if (!e.shiftKey && document.activeElement === lastElement) {\n          e.preventDefault();\n          firstElement.focus();\n        }\n      }\n    });\n  }\n}\n\n// Export both class names for backward compatibility\nwindow.PindaiChatWidget = {\n  init: (options) => {\n    if (!document.querySelector('.n8n-chat-widget') && !document.querySelector('.n8n-chat-launcher')) {\n      return new PindaiChatWidget(options);\n    }\n  }\n};\n\n// Backward compatibility with old name\nwindow.N8nChatWidget = window.PindaiChatWidget;\n"]}