guideai-app 0.3.1 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"GuideAI.js","mappings":"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","sources":["webpack://GuideAI/webpack/universalModuleDefinition","webpack://GuideAI/./src/styles/GuideAI.styles.ts","webpack://GuideAI/./src/utils/messageStorage.ts","webpack://GuideAI/./src/utils/constants.ts","webpack://GuideAI/external umd {\"commonjs\":\"react\",\"commonjs2\":\"react\",\"amd\":\"React\",\"root\":\"React\"}","webpack://GuideAI/./src/utils/api.ts","webpack://GuideAI/./src/GuideAI.tsx","webpack://GuideAI/./src/utils/ui.ts","webpack://GuideAI/./src/components/TranscriptBox.tsx","webpack://GuideAI/./src/components/Onboarding.tsx","webpack://GuideAI/./src/components/WelcomeBubble.tsx","webpack://GuideAI/./src/metric/event-listner.tsx","webpack://GuideAI/./src/utils/highlight.ts","webpack://GuideAI/./src/metric/metadata-tracker.tsx","webpack://GuideAI/./src/metric/index.tsx","webpack://GuideAI/webpack/bootstrap","webpack://GuideAI/webpack/startup"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"react\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"React\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"GuideAI\"] = factory(require(\"react\"));\n\telse\n\t\troot[\"GuideAI\"] = factory(root[\"React\"]);\n})(this, (__WEBPACK_EXTERNAL_MODULE__156__) => {\nreturn ","export const guideAIStyles = `\n.guideai-main-ui {\n position: relative;\n}\n\n.guideai-main-controls {\n display: flex;\n align-items: center;\n gap: 12px;\n position: relative;\n}\n\n.guideai-welcome-bubble {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n background: #0066ff;\n color: white;\n padding: 10px 16px;\n border-radius: 20px;\n font-size: 14px;\n white-space: normal;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n animation: bubble-pulse 2s infinite;\n max-width: 280px;\n min-width: 200px;\n text-align: center;\n line-height: 1.3;\n}\n\n.guideai-welcome-bubble.above {\n bottom: calc(100% + 10px);\n}\n\n.guideai-welcome-bubble.below {\n top: calc(100% + 10px);\n}\n\n.guideai-welcome-bubble.above::after {\n content: '';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-top: 8px solid #0066ff;\n}\n\n.guideai-welcome-bubble.below::after {\n content: '';\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-bottom: 8px solid #0066ff;\n}\n\n@keyframes bubble-pulse {\n 0% { transform: translateX(-50%) scale(1); }\n 50% { transform: translateX(-50%) scale(1.05); }\n 100% { transform: translateX(-50%) scale(1); }\n}\n\n.guideai-icon-wrapper {\n width: 50px;\n height: 50px;\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: rgba(255, 255, 255, 0.9);\n border: 2px solid transparent;\n border-radius: 50%;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.guideai-icon-wrapper:not(.initializing):hover {\n transform: scale(1.1);\n}\n\n.guideai-icon-wrapper.initializing {\n background-color: rgba(255, 255, 255, 0.9);\n box-shadow: 0 0 0 2px rgba(128, 128, 128, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);\n animation: guideai-spin 1.5s linear infinite;\n opacity: 0.7;\n cursor: default;\n}\n\n.guideai-icon-wrapper.recording {\n background-color: rgba(255, 255, 255, 0.9);\n box-shadow: 0 0 0 2px rgba(255, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);\n animation: guideai-pulse 1s infinite alternate;\n}\n\n.guideai-icon-wrapper.processing {\n background-color: rgba(255, 255, 255, 0.9);\n box-shadow: 0 0 0 2px rgba(255, 165, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);\n animation: guideai-spin 1s linear infinite;\n}\n\n.guideai-icon-wrapper.playing {\n background-color: rgba(255, 255, 255, 0.9);\n box-shadow: 0 0 0 2px rgba(0, 128, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);\n}\n\n@keyframes guideai-pulse {\n 0% { transform: scale(1); }\n 100% { transform: scale(1.05); }\n}\n\n@keyframes guideai-spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\n@keyframes click-ripple-animation {\n 0% { transform: translate(-50%, -50%) scale(0); opacity: 1; }\n 50% { transform: translate(-50%, -50%) scale(1.2); opacity: 0.6; }\n 100% { transform: translate(-50%, -50%) scale(2.5); opacity: 0; }\n}\n\n@keyframes click-dot-animation {\n 0% { transform: translate(-50%, -50%) scale(0); opacity: 1; }\n 60% { transform: translate(-50%, -50%) scale(1); opacity: 1; }\n 100% { transform: translate(-50%, -50%) scale(1); opacity: 0; }\n}\n\n@keyframes cursor-jiggle {\n 0% { transform: translate(-50%, 0) scale(1); }\n 25% { transform: translate(-50%, -5px) scale(1.1); }\n 50% { transform: translate(-50%, 0) scale(1); }\n 75% { transform: translate(-50%, 5px) scale(1.1); }\n 100% { transform: translate(-50%, 0) scale(1); filter: drop-shadow(0 0 8px #0066ff); }\n}\n\n.guideai-icon {\n width: 60%;\n height: 60%;\n min-width: 16px;\n min-height: 16px;\n max-width: 40px;\n max-height: 40px;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n}\n\n.guideai-icon.initializing {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><path fill=\"%23808080\" d=\"M304 48c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-48 368c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm208-208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zM96 256c0-26.51-21.49-48-48-48S0 229.49 0 256s21.49 48 48 48 48-21.49 48-48zm12.922 99.078c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.491-48-48-48zm294.156 0c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.49-48-48-48zM108.922 60.922c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.491-48-48-48z\"/></svg>');\n}\n\n.guideai-icon.microphone {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 352 512\"><path fill=\"%230000FF\" d=\"M176 352c53.02 0 96-42.98 96-96V96c0-53.02-42.98-96-96-96S80 42.98 80 96v160c0 53.02 42.98 96 96 96zm160-160h-16c-8.84 0-16 7.16-16 16v48c0 74.8-64.49 134.82-140.79 127.38C96.71 376.89 48 317.11 48 250.3V208c0-8.84-7.16-16-16-16H16c-8.84 0-16 7.16-16 16v40.16c0 89.64 63.97 169.55 152 181.69V464H96c-8.84 0-16 7.16-16 16v16c0 8.84 7.16 16 16 16h160c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16h-56v-33.77C285.71 418.47 352 344.9 352 256v-48c0-8.84-7.16-16-16-16z\"/></svg>');\n}\n\n.guideai-icon.recording {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><circle cx=\"256\" cy=\"256\" r=\"128\" fill=\"%23FF0000\"/><circle cx=\"256\" cy=\"256\" r=\"200\" stroke=\"%23FF0000\" stroke-width=\"20\" fill=\"none\"/></svg>');\n}\n\n.guideai-icon.processing {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><path fill=\"%23FFA500\" d=\"M304 48c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-48 368c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm208-208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zM96 256c0-26.51-21.49-48-48-48S0 229.49 0 256s21.49 48 48 48 48-21.49 48-48zm12.922 99.078c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.491-48-48-48zm294.156 0c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.49-48-48-48zM108.922 60.922c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.491-48-48-48z\"/></svg>');\n}\n\n.guideai-icon.playing {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"%23008000\" d=\"M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z\"/></svg>');\n}\n\n.guideai-icon.text-mode {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"%230066ff\" d=\"M20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h4l4 4 4-4h4c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM7 10v2h2v-2H7zm6 2h-2v-2h2v2zm4 0h-2v-2h2v2z\"/></svg>');\n}\n\n.guideai-icon.voice-mode {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 352 512\"><path fill=\"%23008000\" d=\"M176 352c53.02 0 96-42.98 96-96V96c0-53.02-42.98-96-96-96S80 42.98 80 96v160c0 53.02 42.98 96 96 96zm160-160h-16c-8.84 0-16 7.16-16 16v48c0 74.8-64.49 134.82-140.79 127.38C96.71 376.89 48 317.11 48 250.3V208c0-8.84-7.16-16-16-16H16c-8.84 0-16 7.16-16 16v40.16c0 89.64 63.97 169.55 152 181.69V464H96c-8.84 0-16 7.16-16 16v16c0 8.84 7.16 16 16 16h160c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16h-56v-33.77C285.71 418.47 352 344.9 352 256v-48c0-8.84-7.16-16-16-16z\"/></svg>');\n}\n\n\n/* Onboarding styles */\n.guideai-onboarding {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n background: white;\n border-radius: 12px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n width: 300px;\n max-width: 90vw;\n z-index: 1002;\n animation: onboarding-fade-in 0.3s ease-out;\n}\n\n.guideai-onboarding.above {\n bottom: calc(100% + 15px);\n}\n\n.guideai-onboarding.below {\n top: calc(100% + 15px);\n}\n\n.guideai-onboarding.above::after {\n content: '';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-top: 8px solid white;\n filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));\n}\n\n.guideai-onboarding.below::after {\n content: '';\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-bottom: 8px solid white;\n filter: drop-shadow(0 -2px 4px rgba(0, 0, 0, 0.1));\n}\n\n@keyframes onboarding-fade-in {\n from { opacity: 0; transform: translateX(-50%) translateY(-10px); }\n to { opacity: 1; transform: translateX(-50%) translateY(0); }\n}\n\n.guideai-onboarding-content {\n padding: 16px;\n position: relative;\n}\n\n.guideai-onboarding-close {\n position: absolute;\n top: 10px;\n right: 10px;\n background: none;\n border: none;\n font-size: 20px;\n cursor: pointer;\n color: #999;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n}\n\n.guideai-onboarding-close:hover {\n background: #f5f5f5;\n color: #333;\n}\n\n.guideai-onboarding-step {\n text-align: center;\n margin-bottom: 12px;\n}\n\n.guideai-onboarding-icon {\n font-size: 32px;\n margin-bottom: 8px;\n display: inline-block;\n}\n\n.guideai-onboarding-step h3 {\n margin: 0 0 8px;\n font-size: 16px;\n color: #333;\n font-weight: 600;\n}\n\n.guideai-onboarding-step p {\n margin: 0;\n font-size: 13px;\n color: #666;\n line-height: 1.4;\n}\n\n.guideai-onboarding-dots {\n display: flex;\n justify-content: center;\n margin: 12px 0;\n}\n\n.guideai-onboarding-dots .dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #ddd;\n margin: 0 4px;\n transition: all 0.3s ease;\n}\n\n.guideai-onboarding-dots .dot.active {\n background: #0066ff;\n transform: scale(1.2);\n}\n\n.guideai-onboarding-next {\n display: block;\n width: 100%;\n padding: 10px;\n background: #0066ff;\n color: white;\n border: none;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.2s ease;\n}\n\n.guideai-onboarding-next:hover {\n background: #0055cc;\n}\n\n/* Transcript Box Styles */\n.guideai-transcript-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: transparent;\n display: flex;\n justify-content: flex-end;\n align-items: flex-end;\n padding-bottom: 40px;\n padding-right: 40px;\n z-index: 10000;\n animation: transcript-fade-in 0.3s ease-out;\n pointer-events: none;\n}\n\n.guideai-transcript-box {\n background: rgba(40, 44, 52, 0.85);\n backdrop-filter: blur(20px);\n -webkit-backdrop-filter: blur(20px);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 16px;\n box-shadow: \n 0 8px 32px rgba(0, 0, 0, 0.3),\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n width: 280px;\n max-height: 280px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: transcript-slide-up 0.4s ease-out;\n pointer-events: auto;\n margin-right: 60px;\n position: relative;\n}\n\n.guideai-transcript-box::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 1px;\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);\n border-radius: 16px 16px 0 0;\n}\n\n\n\n.guideai-transcript-messages {\n flex: 1;\n overflow-y: auto;\n padding: 8px 12px;\n max-height: 200px;\n}\n\n.guideai-transcript-messages::-webkit-scrollbar {\n width: 6px;\n}\n\n.guideai-transcript-messages::-webkit-scrollbar-track {\n background: rgba(0, 0, 0, 0.05);\n border-radius: 3px;\n}\n\n.guideai-transcript-messages::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.2);\n border-radius: 3px;\n}\n\n.guideai-transcript-messages::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.3);\n}\n\n.guideai-transcript-empty {\n text-align: center;\n padding: 20px 12px;\n color: rgba(255, 255, 255, 0.6);\n}\n\n.guideai-transcript-empty-icon {\n font-size: 24px;\n margin-bottom: 8px;\n opacity: 0.5;\n}\n\n.guideai-transcript-empty p {\n margin: 0;\n font-size: 11px;\n color: rgba(255, 255, 255, 0.6);\n}\n\n.guideai-transcript-message {\n margin-bottom: 8px;\n animation: message-fade-in 0.3s ease-out;\n}\n\n.guideai-transcript-message.human {\n text-align: right;\n}\n\n.guideai-transcript-message.guideai {\n text-align: left;\n}\n\n.guideai-transcript-message-content {\n display: inline-block;\n max-width: 85%;\n padding: 6px 10px;\n border-radius: 12px;\n position: relative;\n}\n\n.guideai-transcript-message.human .guideai-transcript-message-content {\n background: rgba(255, 255, 255, 0.15);\n color: rgba(255, 255, 255, 0.95);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-bottom-right-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n\n.guideai-transcript-message.guideai .guideai-transcript-message-content {\n background: rgba(0, 0, 0, 0.1);\n color: rgba(255, 255, 255, 0.9);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-bottom-left-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n\n.guideai-transcript-message-sender {\n font-size: 9px;\n font-weight: 600;\n margin-bottom: 2px;\n opacity: 0.8;\n}\n\n.guideai-transcript-message-text {\n font-size: 11px;\n line-height: 1.3;\n word-wrap: break-word;\n}\n\n.guideai-transcript-message-time {\n font-size: 8px;\n opacity: 0.6;\n margin-top: 2px;\n}\n\n\n\n@keyframes transcript-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@keyframes transcript-slide-up {\n from { \n opacity: 0; \n transform: translateX(40px) scale(0.95); \n }\n to { \n opacity: 1; \n transform: translateX(0) scale(1); \n }\n}\n\n@keyframes message-fade-in {\n from { \n opacity: 0; \n transform: translateY(10px); \n }\n to { \n opacity: 1; \n transform: translateY(0); \n }\n}\n\n/* Transcript Toggle Button Styles - positioned at top of transcript area */\n.guideai-transcript-toggle-button {\n position: fixed;\n bottom: 60px;\n right: 40px;\n width: 36px;\n height: 36px;\n background: rgba(40, 44, 52, 0.9);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);\n transition: all 0.2s ease;\n z-index: 10001;\n font-size: 14px;\n padding: 0;\n color: rgba(255, 255, 255, 0.9);\n animation: toggle-fade-in 0.3s ease-out;\n}\n\n.guideai-transcript-toggle-button:hover {\n background: rgba(40, 44, 52, 1);\n transform: scale(1.1);\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);\n}\n\n.guideai-transcript-toggle-button:active {\n transform: scale(0.95);\n}\n\n.guideai-transcript-toggle-icon {\n display: inline-block;\n transition: all 0.2s ease;\n filter: none;\n}\n\n/* Position transcript toggle button based on transcript position */\n.guideai-transcript-overlay {\n pointer-events: none;\n}\n\n.guideai-transcript-toggle-button {\n pointer-events: auto;\n}\n\n/* Input Options Container - Two Stage Layout */\n.guideai-input-options {\n display: flex;\n align-items: center;\n gap: 12px;\n position: relative;\n animation: options-slide-in 0.4s ease-out;\n}\n\n@keyframes options-slide-in {\n 0% {\n opacity: 0;\n transform: scale(0.8);\n }\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n/* Individual Input Option Button */\n.guideai-input-option {\n width: 50px;\n height: 50px;\n background: rgba(255, 255, 255, 0.9);\n border: 2px solid rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n transition: all 0.3s ease;\n font-size: 18px;\n padding: 0;\n position: relative;\n}\n\n.guideai-input-option:hover:not(:disabled) {\n background: rgba(255, 255, 255, 1);\n transform: scale(1.1);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);\n}\n\n.guideai-input-option:active:not(:disabled) {\n transform: scale(0.95);\n}\n\n.guideai-input-option:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n}\n\n/* Voice Option Specific Styling */\n.guideai-input-option.voice-option {\n background: linear-gradient(135deg, rgba(76, 175, 80, 0.1), rgba(139, 195, 74, 0.1));\n border-color: rgba(76, 175, 80, 0.3);\n}\n\n.guideai-input-option.voice-option:hover:not(:disabled) {\n background: linear-gradient(135deg, rgba(76, 175, 80, 0.2), rgba(139, 195, 74, 0.2));\n border-color: rgba(76, 175, 80, 0.5);\n}\n\n/* Text Option Specific Styling */\n.guideai-input-option.text-option {\n background: linear-gradient(135deg, rgba(33, 150, 243, 0.1), rgba(63, 81, 181, 0.1));\n border-color: rgba(33, 150, 243, 0.3);\n}\n\n.guideai-input-option.text-option:hover:not(:disabled) {\n background: linear-gradient(135deg, rgba(33, 150, 243, 0.2), rgba(63, 81, 181, 0.2));\n border-color: rgba(33, 150, 243, 0.5);\n}\n\n.guideai-input-option-icon {\n display: inline-block;\n transition: all 0.2s ease;\n filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1));\n}\n\n/* Text Input integrated into Transcript Box */\n.guideai-transcript-text-input {\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n padding: 12px;\n display: flex;\n gap: 8px;\n align-items: flex-end;\n background: rgba(0, 0, 0, 0.02);\n border-radius: 0 0 16px 16px;\n animation: text-input-fade-in 0.3s ease-out;\n}\n\n.guideai-transcript-input-field {\n flex: 1;\n background: rgba(255, 255, 255, 0.15);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 8px;\n padding: 8px 12px;\n color: rgba(255, 255, 255, 0.95);\n font-size: 12px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n resize: none;\n outline: none;\n transition: all 0.2s ease;\n min-height: 32px;\n}\n\n.guideai-transcript-input-field::placeholder {\n color: rgba(255, 255, 255, 0.6);\n}\n\n.guideai-transcript-input-field:focus {\n border-color: rgba(255, 255, 255, 0.4);\n background: rgba(255, 255, 255, 0.2);\n box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.2);\n}\n\n.guideai-transcript-send-button {\n background: rgba(255, 255, 255, 0.15);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 6px;\n padding: 6px 10px;\n color: rgba(255, 255, 255, 0.9);\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 36px;\n height: 32px;\n}\n\n.guideai-transcript-send-button:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.25);\n border-color: rgba(255, 255, 255, 0.3);\n transform: translateY(-1px);\n}\n\n.guideai-transcript-send-button:active:not(:disabled) {\n transform: translateY(0);\n}\n\n.guideai-transcript-send-button:disabled {\n background: rgba(255, 255, 255, 0.05);\n border-color: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.4);\n cursor: not-allowed;\n transform: none;\n}\n\n.guideai-transcript-send-icon {\n font-size: 11px;\n}\n\n/* Animation for text input appearance */\n@keyframes text-input-fade-in {\n from { \n opacity: 0; \n transform: translateY(10px); \n }\n to { \n opacity: 1; \n transform: translateY(0); \n }\n}\n\n@keyframes toggle-fade-in {\n from { \n opacity: 0; \n transform: scale(0.8); \n }\n to { \n opacity: 1; \n transform: scale(1); \n }\n}\n\n\n`; ","// Storage data structures for conversation persistence\nexport interface StoredMessage {\n content: string;\n sender: 'GUIDEAI' | 'HUMAN';\n timestamp: number;\n}\n\nexport interface StoredConversation {\n conversationId: string;\n messages: StoredMessage[];\n timestamp: number;\n organizationKey: string;\n}\n\nexport const CONVERSATION_STORAGE_KEY = 'guideai_conversation';\nexport const CONVERSATION_EXPIRY_MINUTES = 30;\nexport const MAX_STORED_MESSAGES = 100; // Increased to keep more conversation history\n\nexport const isLocalStorageAvailable = (): boolean => {\n try {\n const testKey = '__storage_test__';\n localStorage.setItem(testKey, testKey);\n localStorage.removeItem(testKey);\n return true;\n } catch (e) {\n return false;\n }\n};\n\nconst isValidConversation = (data: any): data is StoredConversation => {\n return (\n data &&\n typeof data === 'object' &&\n typeof data.conversationId === 'string' &&\n Array.isArray(data.messages) &&\n typeof data.timestamp === 'number' &&\n typeof data.organizationKey === 'string' &&\n data.messages.every((msg: any) => (\n typeof msg === 'object' &&\n typeof msg.content === 'string' &&\n (msg.sender === 'HUMAN' || msg.sender === 'GUIDEAI') &&\n typeof msg.timestamp === 'number'\n ))\n );\n};\n\nexport const isConversationExpired = (conversation: StoredConversation): boolean => {\n const expiryTime = CONVERSATION_EXPIRY_MINUTES * 60 * 1000; // convert to milliseconds\n const now = Date.now();\n return (now - conversation.timestamp) > expiryTime;\n};\n\nconst handleStorageError = (error: unknown, operation: string): void => {\n console.error(`Storage error during ${operation}:`, error);\n \n // Check if it's a quota exceeded error\n if (error instanceof DOMException && \n (error.name === 'QuotaExceededError' || \n error.name === 'NS_ERROR_DOM_QUOTA_REACHED')) {\n \n // Try to free up space by removing oldest messages instead of clearing everything\n try {\n const conversation = loadConversationFromStorage();\n if (conversation && conversation.messages.length > 5) {\n // Remove oldest 5 messages\n conversation.messages = conversation.messages.slice(5);\n saveConversationToStorage(conversation);\n console.warn('Storage quota exceeded. Removed oldest 5 messages to free space.');\n } else if (conversation) {\n // If less than 5 messages, clear everything\n clearConversationStorage();\n console.warn('Storage quota exceeded. Cleared conversation data.');\n }\n } catch (cleanupError) {\n console.error('Failed to clean up storage:', cleanupError);\n }\n }\n};\n\nexport const saveConversationToStorage = (conversation: StoredConversation): void => {\n if (!isLocalStorageAvailable()) {\n console.warn('localStorage is not available. Conversation persistence disabled.');\n return;\n }\n \n try {\n // Limit to last MAX_STORED_MESSAGES\n if (conversation.messages.length > MAX_STORED_MESSAGES) {\n conversation.messages = conversation.messages.slice(-MAX_STORED_MESSAGES);\n }\n \n // Update timestamp\n conversation.timestamp = Date.now();\n \n localStorage.setItem(CONVERSATION_STORAGE_KEY, JSON.stringify(conversation));\n } catch (error) {\n handleStorageError(error, 'save');\n }\n};\n\nexport const loadConversationFromStorage = (): StoredConversation | null => {\n if (!isLocalStorageAvailable()) {\n console.warn('localStorage is not available. Conversation persistence disabled.');\n return null;\n }\n \n try {\n const storedData = localStorage.getItem(CONVERSATION_STORAGE_KEY);\n if (!storedData) return null;\n \n const parsedData = JSON.parse(storedData);\n \n // Validate the data structure\n if (!isValidConversation(parsedData)) {\n console.warn('Corrupted conversation data found. Clearing storage.');\n clearConversationStorage();\n return null;\n }\n \n return parsedData;\n } catch (error) {\n handleStorageError(error, 'load');\n // Clear corrupted data on any parsing errors\n clearConversationStorage();\n return null;\n }\n};\n\nexport const clearConversationStorage = (): void => {\n if (!isLocalStorageAvailable()) {\n return;\n }\n \n try {\n localStorage.removeItem(CONVERSATION_STORAGE_KEY);\n } catch (error) {\n handleStorageError(error, 'clear');\n }\n};\n\nexport const addMessageToStorage = (message: StoredMessage, conversationId: string, organizationKey: string): void => {\n if (!isLocalStorageAvailable()) {\n console.warn('localStorage is not available. Message persistence disabled.');\n return;\n }\n \n try {\n let conversation = loadConversationFromStorage();\n \n if (!conversation) {\n conversation = {\n conversationId,\n messages: [],\n timestamp: Date.now(),\n organizationKey\n };\n }\n \n // Check for duplicate messages to prevent adding the same message twice\n const isDuplicate = conversation.messages.some(existingMsg => \n existingMsg.content === message.content && \n existingMsg.sender === message.sender &&\n Math.abs(existingMsg.timestamp - message.timestamp) < 5000 // Within 5 seconds\n );\n \n if (!isDuplicate) {\n conversation.messages.push(message);\n conversation.conversationId = conversationId;\n conversation.organizationKey = organizationKey;\n \n saveConversationToStorage(conversation);\n } else {\n console.log('Duplicate message detected, skipping:', message.content.substring(0, 50));\n }\n } catch (error) {\n console.error('Error adding message to storage:', error);\n }\n};\n\nexport const checkForStoredConversation = (currentOrganizationKey: string): {\n shouldRestore: boolean;\n conversationId: string | null;\n messages: StoredMessage[] | null;\n} => {\n const storedConversation = loadConversationFromStorage();\n \n if (!storedConversation) {\n return { shouldRestore: false, conversationId: null, messages: null };\n }\n \n // Check if conversation is expired - if so, clear it automatically\n if (isConversationExpired(storedConversation)) {\n clearConversationStorage();\n return { shouldRestore: false, conversationId: null, messages: null };\n }\n \n // Check if organization key matches\n if (storedConversation.organizationKey !== currentOrganizationKey) {\n return { shouldRestore: false, conversationId: null, messages: null };\n }\n \n return {\n shouldRestore: true,\n conversationId: storedConversation.conversationId,\n messages: storedConversation.messages\n };\n};\n\nexport const formatConversationContext = (messages: StoredMessage[], maxMessages: number = 10): string => {\n // Take only the last N messages to avoid context length issues\n const recentMessages = messages.slice(-maxMessages);\n \n if (recentMessages.length === 0) {\n return '';\n }\n \n // Filter out very short or empty messages\n const meaningfulMessages = recentMessages.filter(msg => \n msg.content && msg.content.trim().length > 3\n );\n \n if (meaningfulMessages.length === 0) {\n return '';\n }\n \n // Format messages into a readable context string\n const formattedMessages = meaningfulMessages.map(msg => {\n const sender = msg.sender === 'HUMAN' ? 'User' : 'Assistant';\n return `${sender}: ${msg.content.trim()}`;\n }).join('\\n');\n \n return formattedMessages;\n}; ","// Default prompt for Guide AI\nexport const DEFAULT_PROMPT = `you are Guide AI.\n Your role is to answer any question directly and succinctly that a user has. NEVER DIRECTLY MENTION THE SCREENSHOT, but use its information as much as possible to target your responses.\n If nothing is asked, then your goal is to generally assist them.\n IMPORTANT: NEVER answer in more than 10 words. Always be concise and limit answers to 1 sentence maximum. Be simple and as short as possible.\n Your job is to help them get it done through asking more and more targeted specific questions.`;\n\n// WebRTC message types to ignore in logging\nexport const IGNORE_MESSAGE_TYPES = [\n \"delta\", \n \"rate_limits\", \n \"input_audio_buffer\",\n \"response.audio.done\", \n \"response.output_item\", \n \"response.content_part\", \n \"output_audio_buffer\",\n \"response.created\", \n \"session.created\",\n \"conversation.item.truncated\"\n];\n\n// API endpoints\nexport const GUIDE_AI_API_BASE = 'https://www.getguide.ai/api';\n// export const GUIDE_AI_API_BASE = 'http://localhost:3001/api';\nexport const OPENAI_REALTIME_BASE = 'https://api.openai.com/v1/realtime';\nexport const OPENAI_REALTIME_MODEL = \"gpt-4o-realtime-preview-2024-12-17\";\n\n// Gemini API - Note: This should be moved to environment variables in production\nexport const GEMINI_API_KEY = 'AIzaSyBiFyzjYVupLyk8BdmfWzBL1GbzX8OUdPc';\nexport const GEMINI_API_ENDPOINT = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent'; ","module.exports = __WEBPACK_EXTERNAL_MODULE__156__;","import { StoredMessage, addMessageToStorage } from './messageStorage';\nimport { GUIDE_AI_API_BASE } from './constants';\nimport { UserMetadata, MetadataUpdate } from '../types/metadata.types';\n\n// Type for the conversation creation response (now includes token and prompt)\ninterface ConversationData {\n id: string;\n ephemeralToken: string;\n prompt: string;\n}\n\n// Create a new conversation (now also returns ephemeral token + prompt)\nexport const createNewConversation = async (\n organizationKey: string,\n onError: (error: Error, context: string) => void\n): Promise<ConversationData | null> => {\n try {\n const now = new Date();\n const response = await fetch(`${GUIDE_AI_API_BASE}/initialize-session`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n organizationKey,\n userId: 'anonymous',\n date: now.toISOString().split('T')[0],\n time: now.toTimeString().split(' ')[0],\n messages: []\n })\n });\n \n if (!response.ok) {\n const errorText = await response.text().catch(() => 'No error details available');\n console.error(`Conversation creation failed with status ${response.status}:`, errorText);\n throw new Error(`Failed to create conversation: ${response.status} - ${errorText}`);\n }\n \n const conversationData = await response.json();\n console.log('Conversation created:', conversationData.id);\n return conversationData;\n } catch (error) {\n console.error('Error creating conversation:', error);\n onError(error as Error, 'Creating conversation');\n return null;\n }\n};\n\n// Log a message to the conversation via API and local storage\nexport const logMessage = async (\n content: string, \n sender: 'GUIDEAI' | 'HUMAN',\n conversationId: string | null,\n organizationKey: string,\n onError: (error: Error, context: string) => void\n): Promise<void> => {\n if (!conversationId) return;\n \n try {\n const response = await fetch(`${GUIDE_AI_API_BASE}/conversations/${conversationId}/messages`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ content, sender })\n });\n \n if (!response.ok) {\n throw new Error(`Failed to log message: ${response.status} ${response.statusText}`);\n }\n \n const message: StoredMessage = {\n content,\n sender,\n timestamp: Date.now()\n };\n \n addMessageToStorage(message, conversationId, organizationKey);\n } catch (error) {\n console.error('Error logging message:', error);\n onError(error as Error, 'Logging message');\n }\n};\n\n// Send metadata updates in batch\nexport const sendMetadataUpdates = async (\n updates: MetadataUpdate[],\n organizationKey: string,\n onError: (error: Error, context: string) => void\n): Promise<boolean> => {\n if (updates.length === 0) return true;\n\n try {\n const response = await fetch(`${GUIDE_AI_API_BASE}/metadata-updates`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n organizationKey,\n updates,\n batchTimestamp: Date.now(),\n updateCount: updates.length\n })\n });\n\n if (!response.ok) {\n throw new Error(`Failed to send metadata updates: ${response.status} ${response.statusText}`);\n }\n\n console.log(`Sent ${updates.length} metadata updates successfully`);\n return true;\n } catch (error) {\n console.error('Error sending metadata updates:', error);\n onError(error as Error, 'Sending metadata updates');\n return false;\n }\n}; ","// Import React normally, but use a helper function to handle possible duplicates\nimport React from 'react';\nimport { \n StoredMessage, \n addMessageToStorage,\n clearConversationStorage,\n checkForStoredConversation, \n formatConversationContext \n} from './utils/messageStorage';\n\n// Import our refactored modules\nimport { GuideAIProps, RecordingStatus, UseStateHook, UseEffectHook, UseRefHook, UseCallbackHook, PopupPosition } from './types/GuideAI.types';\nimport { DEFAULT_PROMPT, IGNORE_MESSAGE_TYPES, GUIDE_AI_API_BASE, OPENAI_REALTIME_BASE, OPENAI_REALTIME_MODEL, GEMINI_API_KEY, GEMINI_API_ENDPOINT } from './utils/constants';\nimport { injectStyles, calculateOptimalPosition } from './utils/ui';\nimport { highlightElement } from './utils/highlight';\nimport { createNewConversation, logMessage } from './utils/api';\nimport WelcomeBubble from './components/WelcomeBubble';\nimport Onboarding from './components/Onboarding';\nimport TranscriptBox from './components/TranscriptBox';\nimport { guideAIStyles } from './styles/GuideAI.styles';\nimport { EventTracker, UserMetadataTracker, UserMetadata } from './metric';\nimport { sendMetadataUpdates } from './utils/api';\n\n// Global flag to prevent multiple GuideAI instances from initializing simultaneously\nlet globalInitializationInProgress = false;\n\n// Get React hooks safely, avoiding duplicate React issues\nconst getReactHooks = () => {\n // Try to use the React instance from window if available (for react-scripts)\n if (typeof window !== 'undefined' && (window as any).React) {\n return {\n useState: (window as any).React.useState as UseStateHook,\n useEffect: (window as any).React.useEffect as UseEffectHook,\n useRef: (window as any).React.useRef as UseRefHook,\n useMemo: (window as any).React.useMemo,\n useCallback: (window as any).React.useCallback as UseCallbackHook\n };\n }\n // Otherwise use the imported React\n return {\n useState: React.useState,\n useEffect: React.useEffect,\n useRef: React.useRef,\n useMemo: React.useMemo,\n useCallback: React.useCallback as UseCallbackHook\n };\n};\n\nconst GuideAI = (props: GuideAIProps) => {\n const {\n organizationKey,\n position,\n onError = console.error,\n metadata: metadataOptions,\n transcript: transcriptOptions,\n input: inputOptions\n } = props;\n\n // Memoize the React hooks to ensure consistent instances\n const hooks = React.useMemo(() => getReactHooks(), []);\n\n const [status, setStatus] = hooks.useState<RecordingStatus>('idle');\n const [isClient, setIsClient] = hooks.useState(false);\n const [componentPosition] = hooks.useState(position);\n const [isHighlighting, setIsHighlighting] = hooks.useState(false);\n const [hasInteracted, setHasInteracted] = hooks.useState(false);\n const [prompt, setPrompt] = hooks.useState<string | null>(null);\n const [isSessionReady, setIsSessionReady] = hooks.useState(false);\n const [isConnecting, setIsConnecting] = hooks.useState(false);\n const [showOnboarding, setShowOnboarding] = hooks.useState(false);\n const [popupPosition, setPopupPosition] = hooks.useState<PopupPosition>('above');\n const conversationIdRef = hooks.useRef<string | null>(null);\n\n const componentRef = hooks.useRef<HTMLDivElement>(null);\n const peerConnectionRef = hooks.useRef<RTCPeerConnection | null>(null);\n const dataChannelRef = hooks.useRef<RTCDataChannel | null>(null);\n const hasCreatedConversationRef = hooks.useRef(false);\n const mediaStreamRef = hooks.useRef<MediaStream | null>(null);\n const audioElementRef = hooks.useRef<HTMLAudioElement | null>(null);\n const [ephemeralToken, setEphemeralToken] = hooks.useState<string | null>(null);\n const hasInitializedRef = hooks.useRef(false);\n const initializationInProgressRef = hooks.useRef(false);\n const isUnmountingRef = hooks.useRef(false);\n const [isConversationActive, setIsConversationActive] = hooks.useState(false);\n const [restoredMessages, setRestoredMessages] = hooks.useState<StoredMessage[]>([]);\n const [showTranscript, setShowTranscript] = hooks.useState(\n transcriptOptions?.enabled !== false // Default to true unless explicitly disabled\n );\n const [allMessages, setAllMessages] = hooks.useState<StoredMessage[]>([]);\n const [inputMode, setInputMode] = hooks.useState<'voice' | 'text'>(\n inputOptions?.defaultMode || 'voice'\n );\n const [textInput, setTextInput] = hooks.useState('');\n const [showTextInput, setShowTextInput] = hooks.useState(false);\n\n const hasAttemptedAutoStartRef = hooks.useRef(false);\n const eventTracker = hooks.useMemo(() => {\n let customerId: string | undefined;\n let organizationId: string | undefined;\n let customerType: string | undefined;\n try {\n const raw = typeof window !== 'undefined' ? localStorage.getItem('user') : null;\n if (raw) {\n const parsed = JSON.parse(raw);\n const idVal = parsed?.customer?.id;\n if (idVal != null) customerId = String(idVal);\n const orgVal = parsed?.customer.organizationId;\n if (orgVal != null) organizationId = String(orgVal);\n const typeName = parsed?.customer?.customerTypeName;\n if (typeof typeName === 'string') customerType = typeName;\n console.log(\"raw\", customerId,organizationId,customerType);\n }\n } catch (_err) {\n // ignore\n }\n return new EventTracker({ customerId, organizationId, customerType, organizationKey });\n }, [organizationKey]);\n\n const metadataTracker = hooks.useMemo(() => \n new UserMetadataTracker(organizationKey, metadataOptions?.config || {}, onError), \n [organizationKey, metadataOptions?.config, onError]\n );\n \n // ===== API & EXTERNAL CALLS =====\n \n // Call Gemini Flash API to validate and fix JSON\n const geminiFlash = async (prompt: string): Promise<string> => {\n const response = await fetch(`${GEMINI_API_ENDPOINT}?key=${GEMINI_API_KEY}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n contents: [\n {\n parts: [\n {\n text: prompt\n }\n ]\n }\n ]\n })\n });\n \n const responseJson = await response.json();\n const content = responseJson.candidates[0].content;\n const responseText = content.parts[0].text;\n return responseText;\n };\n\n // ===== COMPONENT WRAPPER FUNCTIONS =====\n \n // Wrapper functions to maintain original signatures\n const handleCreateNewConversation = async () => {\n if (hasCreatedConversationRef.current) return null;\n hasCreatedConversationRef.current = true;\n \n const conversationData = await createNewConversation(organizationKey, onError);\n if (conversationData) {\n conversationIdRef.current = conversationData.id;\n setEphemeralToken(conversationData.ephemeralToken);\n setPrompt(conversationData.prompt);\n return conversationData;\n }\n return null;\n };\n\n const handleLogMessage = async (content: string, sender: 'GUIDEAI' | 'HUMAN') => {\n await logMessage(content, sender, conversationIdRef.current, organizationKey, onError);\n \n // Add message to local state for transcript\n const newMessage: StoredMessage = {\n content,\n sender,\n timestamp: Date.now()\n };\n setAllMessages(prev => [...prev, newMessage]);\n };\n\n const handleHighlightElement = async (selector: string | string[]) => {\n return highlightElement(selector, isHighlighting, setIsHighlighting, handleLogMessage);\n };\n\n // ===== UI UTILITIES & POSITION =====\n \n // Calculate optimal position for popups based on component location\n const getOptimalPosition = hooks.useCallback((elementHeight: number = 240, spacing: number = 15): PopupPosition => {\n if (!componentRef.current) return 'above';\n \n const rect = componentRef.current.getBoundingClientRect();\n return calculateOptimalPosition(rect, elementHeight, spacing);\n }, []);\n\n // ===== WEBRTC MANAGEMENT =====\n \n const sendMessage = (message: any) => {\n if (dataChannelRef.current?.readyState === 'open') {\n // console.log('sending message', message);\n dataChannelRef.current.send(JSON.stringify(message));\n } else {\n console.error('Data channel not open, cannot send message');\n setStatus('idle');\n }\n };\n \n const cleanupWebRTC = hooks.useCallback(() => {\n if (mediaStreamRef.current) {\n // Stop tracks completely instead of just disabling them\n mediaStreamRef.current.getAudioTracks().forEach(track => {\n track.stop();\n });\n mediaStreamRef.current = null;\n }\n \n if (dataChannelRef.current) {\n dataChannelRef.current.close();\n dataChannelRef.current = null;\n }\n \n if (peerConnectionRef.current) {\n peerConnectionRef.current.close();\n peerConnectionRef.current = null;\n }\n \n if (audioElementRef.current) {\n audioElementRef.current.srcObject = null;\n }\n \n // Reset session ready state\n setIsSessionReady(false);\n }, []);\n\n const initializeWebRTC = async (audioStream: MediaStream | null): Promise<boolean> => {\n try {\n const pc = new RTCPeerConnection();\n peerConnectionRef.current = pc;\n \n // Only add audio tracks if audioStream is provided (for voice mode)\n if (audioStream) {\n audioStream.getAudioTracks().forEach(track => {\n pc.addTrack(track, audioStream);\n });\n }\n \n // Only create audio element if we have an audio stream (voice mode)\n if (audioStream && !audioElementRef.current) {\n const audioEl = document.createElement('audio');\n audioEl.autoplay = true;\n document.body.appendChild(audioEl);\n audioElementRef.current = audioEl;\n }\n \n pc.ontrack = (e) => {\n if (audioElementRef.current && e.track.kind === 'audio') {\n const stream = new MediaStream([e.track]);\n audioElementRef.current.srcObject = stream;\n }\n };\n \n const dc = pc.createDataChannel('oai-events');\n dataChannelRef.current = dc;\n \n dc.onopen = () => { \n // Configure session based on whether we have audio stream (voice vs text mode)\n const sessionConfig: any = {\n tools: [{\n type: \"function\",\n name: \"highlight\",\n description: \"Highlight specific elements on the page to guide the user's attention\",\n parameters: {\n type: \"object\",\n properties: {\n selector: {\n oneOf: [\n {\n type: \"string\",\n description: \"CSS selector or XPath for the element to highlight (e.g., '#search-bar')\"\n },\n {\n type: \"array\",\n items: {\n type: \"string\"\n },\n description: \"List of CSS selectors or XPaths to highlight in sequence (e.g., ['#first-button', '#second-button'])\"\n }\n ],\n description: \"CSS selector(s) or XPath(s) for the element(s) to highlight. Can be a single selector string or an array of selectors to process sequentially.\"\n }\n },\n required: [\"selector\"]\n }\n }],\n tool_choice: \"auto\"\n };\n\n // Only add audio-specific config if we have an audio stream\n if (audioStream) {\n sessionConfig.turn_detection = {\n type: \"semantic_vad\",\n create_response: true,\n interrupt_response: false\n };\n sessionConfig.input_audio_transcription = {\n model: \"gpt-4o-mini-transcribe\",\n language: \"en\",\n };\n }\n\n sendMessage({\n type: \"session.update\",\n session: sessionConfig\n });\n };\n \n dc.onmessage = (e) => {\n try {\n const message = JSON.parse(e.data);\n\n switch (message.type) { \n case 'session.updated':\n // console.log('session.updated', message);\n setIsSessionReady(true);\n setIsConnecting(false);\n \n // If we have restored messages, send conversation context to AI now that session is ready\n if (restoredMessages.length > 0) {\n const conversationContext = formatConversationContext(restoredMessages, 5); // Reduce to 5 messages\n \n // Send as system context instead of user input to avoid confusion\n sendMessage({\n type: \"conversation.item.create\",\n item: {\n type: \"message\",\n role: \"system\",\n content: [{\n type: \"input_text\",\n text: `This is context from a previous conversation session. The user is continuing an existing conversation. Previous context: ${conversationContext}`\n }]\n }\n });\n \n console.log('Sent conversation context with', restoredMessages.length, 'restored messages');\n }\n break;\n\n case 'session.transcript_disabled':\n if (message.text && message.text.trim()) {\n console.log('Session transcript:', message.text);\n handleLogMessage(message.text, 'HUMAN');\n }\n break;\n \n case 'conversation.item.input_audio_transcription.completed':\n if (message.transcript && message.transcript.trim()) {\n console.log('User transcript:', message.transcript);\n // Only log if it's different from the last message to avoid duplicates\n if (allMessages.length === 0 || \n allMessages[allMessages.length - 1].content !== message.transcript) {\n handleLogMessage(message.transcript, 'HUMAN');\n }\n }\n break;\n\n case 'response.audio_transcript.done':\n if (message.transcript && message.transcript.trim()) {\n console.log('Assistant message:', message.transcript);\n // Only log if it's different from the last assistant message to avoid duplicates\n const lastMessage = allMessages[allMessages.length - 1];\n if (!lastMessage || \n lastMessage.sender !== 'GUIDEAI' ||\n lastMessage.content !== message.transcript) {\n handleLogMessage(message.transcript, 'GUIDEAI');\n }\n }\n break;\n \n case \"conversation.item.created\":\n // console.log('conversation.item.created', message);\n break;\n\n case \"input_audio_buffer.speech_started\":\n // console.log('User speaking started');\n setStatus('recording');\n break;\n\n case \"input_audio_buffer.speech_stopped\":\n // console.log('User speaking stopped');\n setStatus('processing');\n break;\n\n case 'response.done':\n // console.log('response.done', message);\n for (const out of message.response.output) {\n switch (out.type) {\n case \"message\":\n // console.log('Assistant message:', out.text);\n break;\n \n case \"function_call\":\n // console.log('function_call', out);\n if (out.name === 'highlight' && out.arguments) {\n // console.log('Tool call:', out.arguments);\n try {\n let argsToUse = out.arguments;\n // Check if the JSON string is missing a closing quote\n // try {\n // console.log(\"argsToUse\", argsToUse);\n // const parsedArgs = JSON.parse(argsToUse);\n // console.log(\"parsedArgs\", parsedArgs);\n // highlightElement(parsedArgs.selector);\n // } catch (error) {\n // console.log(\"errored, argsToUse\", argsToUse);\n const prompt = `\n Validate the following JSON string and return ONLY a correct JSON object:\n Note: The selector(s) should be either a css selector or an xpath, so modify those if invalid.\n Also, [url=''] is a valid css selector, so do not modify it if it's present.\n Do not add any other text or newlines to the response.\n It should be of the following format:\n { \"selector\": \"string\" }\n or\n { \"selector\": [\"string\", ...] }\n DO NOT add any other text or newlines to the response, it should begin and end with curly braces.\n DO NOT add '''json to the response.\n The JSON string is:\n ${argsToUse}\n `\n geminiFlash(prompt).then(response => {\n response = response.replace(\"```json\", \"\").replace(\"```\", \"\").trim();\n // console.log(\"response\", response);\n const parsedArgs = JSON.parse(response);\n handleHighlightElement(parsedArgs.selector);\n }).catch(err => {\n console.error(\"Error calling Gemini:\", err);\n });\n // }\n\n\n } catch (error) {\n console.error('Error parsing function arguments:', error);\n console.log(out.arguments);\n handleLogMessage('Error parsing function arguments: ' + out.arguments, 'GUIDEAI');\n }\n }\n \n sendMessage({\n type: \"conversation.item.create\",\n item: {\n type: \"function_call_output\",\n call_id: out.call_id,\n output: JSON.stringify(true)\n }\n });\n\n sendMessage({\n type: 'response.create',\n });\n break;\n }\n }\n \n break;\n\n case \"response.function_call_arguments.delta\":\n // console.log('response.function_call_arguments.delta', message);\n break;\n\n case \"response.function_call_arguments.done\":\n // console.log('response.function_call_arguments.done', message);\n break;\n\n case \"output_audio_buffer.started\":\n setStatus('playing');\n break;\n\n case \"output_audio_buffer.stopped\":\n // console.log('output_audio_buffer.stopped');\n setStatus('recording');\n \n break;\n\n case 'error':\n if (message.error.code === 'session_expired') {\n console.error('Session expired:', message);\n setStatus('idle');\n setIsConnecting(false);\n setIsConversationActive(false);\n setEphemeralToken(null); // Clear expired token so reconnection gets fresh one\n hasCreatedConversationRef.current = false; // Allow creating new conversation\n break;\n }\n console.error('OpenAI API error:', message);\n onError(new Error(message.error.message || 'Unknown API error'), 'OpenAI API error');\n setStatus('idle');\n setIsConnecting(false);\n setIsConversationActive(false);\n setEphemeralToken(null); // Clear token in case of auth-related errors\n hasCreatedConversationRef.current = false; // Allow creating new conversation\n break;\n \n default:\n if (!IGNORE_MESSAGE_TYPES.some(fragment => message.type.includes(fragment))) {\n console.log('Unhandled:', message.type, message);\n }\n }\n } catch (error) {\n console.error('Error handling WebRTC message:', error);\n setStatus('idle');\n setIsConversationActive(false);\n }\n };\n \n // Start the session using SDP\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n \n if (!pc.localDescription || !pc.localDescription.sdp) {\n throw new Error('Failed to create local SDP offer');\n }\n \n const baseUrl = OPENAI_REALTIME_BASE;\n const model = OPENAI_REALTIME_MODEL;\n \n \n const sdpResponse = await fetch(`${baseUrl}?model=${model}`, {\n method: 'POST',\n body: pc.localDescription.sdp,\n headers: {\n Authorization: `Bearer ${ephemeralToken}`,\n 'Content-Type': 'application/sdp'\n },\n });\n \n if (!sdpResponse.ok) {\n const errorText = await sdpResponse.text().catch(() => 'No error details available');\n console.error('WebRTC connection failed with status:', sdpResponse.status);\n console.error('Error details:', errorText);\n \n // Clear token on authentication failures\n if (sdpResponse.status === 401 || sdpResponse.status === 403) {\n setEphemeralToken(null);\n }\n \n throw new Error(`Failed to connect to OpenAI WebRTC: ${sdpResponse.status} - ${errorText}`);\n }\n \n const answerSdp = await sdpResponse.text();\n \n const answer = {\n type: 'answer',\n sdp: answerSdp,\n };\n \n await pc.setRemoteDescription(answer as RTCSessionDescriptionInit);\n \n return true;\n } catch (error) {\n console.error('Error initializing WebRTC:', error);\n onError(error as Error, 'WebRTC initialization failed');\n setIsConnecting(false);\n return false;\n }\n };\n\n // ===== SESSION MANAGEMENT =====\n \n const startConversationSession = hooks.useCallback(async () => {\n try {\n setStatus('processing');\n \n if (peerConnectionRef.current && dataChannelRef.current?.readyState === 'open' && mediaStreamRef.current) {\n mediaStreamRef.current.getAudioTracks().forEach(track => {\n track.enabled = true;\n });\n setStatus('recording');\n return true;\n } else {\n cleanupWebRTC();\n \n try {\n setIsConnecting(true);\n \n // Ensure we have a valid token (get fresh one if needed)\n if (!ephemeralToken) {\n console.log('No token available, getting fresh token...');\n const conversationData = await handleCreateNewConversation();\n if (!conversationData) {\n console.error('Failed to get fresh token');\n setIsConnecting(false);\n setStatus('idle');\n return false;\n }\n }\n \n let audioStream: MediaStream | null = null;\n \n // Always attempt microphone access for voice functionality\n if (true) {\n try {\n audioStream = await navigator.mediaDevices.getUserMedia({ \n audio: {\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n channelCount: 1,\n sampleRate: 48000,\n }\n });\n mediaStreamRef.current = audioStream;\n console.log('Microphone access granted - audio tracks:', audioStream.getAudioTracks().length);\n } catch (micError) {\n console.error('Microphone access failed:', micError);\n console.log('Voice functionality will not be available - continuing with text-only mode');\n // Continue without microphone for text-only mode\n }\n }\n \n const initialized = await initializeWebRTC(audioStream);\n \n if (!initialized) {\n // Clean up if initialization fails\n if (audioStream) {\n audioStream.getAudioTracks().forEach(track => {\n track.stop();\n });\n mediaStreamRef.current = null;\n }\n setStatus('idle');\n setIsConnecting(false);\n return false;\n }\n \n // Set appropriate status based on whether we have audio\n if (audioStream) {\n setStatus('recording');\n } else {\n setStatus('idle'); // Text-only mode, no recording status needed\n }\n return true;\n } catch (error) {\n console.error('Error during conversation setup:', error);\n onError(error as Error, 'Microphone or WebRTC setup failed');\n setStatus('idle');\n setIsConnecting(false);\n return false;\n }\n }\n } catch (error) {\n setStatus('idle');\n setIsConnecting(false);\n onError(error as Error, 'Starting conversation failed');\n return false;\n }\n }, [ephemeralToken, onError]);\n\n const endConversationSession = hooks.useCallback(() => {\n if (!isClient) return;\n \n if (mediaStreamRef.current) {\n mediaStreamRef.current.getAudioTracks().forEach(track => {\n track.stop();\n });\n }\n \n cleanupWebRTC();\n setStatus('idle');\n \n // Clear localStorage when conversation is explicitly ended\n clearConversationStorage();\n \n // Reset restored messages state\n setRestoredMessages([]);\n \n // Reset auto-start flag to allow future auto-starts\n hasAttemptedAutoStartRef.current = false;\n }, [isClient]);\n\n // ===== UI EVENT HANDLERS =====\n \n const handleToggleConversation = async () => {\n if (!isClient) return;\n \n if (!hasInteracted) {\n setHasInteracted(true);\n localStorage.setItem('guideAI_hasInteracted', 'true');\n \n // Show onboarding on first interaction\n setShowOnboarding(true);\n return;\n }\n \n if (!isConversationActive) {\n const success = await startConversationSession();\n if (success) {\n setIsConversationActive(true);\n // Always show transcript when conversation starts\n if (transcriptOptions?.enabled !== false) {\n setShowTranscript(true);\n }\n // Show text input option by default (unless explicitly disabled)\n if (inputOptions?.enableTextInput !== false) {\n setShowTextInput(true);\n }\n }\n } else {\n endConversationSession();\n setIsConversationActive(false);\n // Hide transcript and text input when conversation ends\n if (transcriptOptions?.enabled !== false) {\n setShowTranscript(false);\n }\n setShowTextInput(false);\n }\n };\n\n const handleToggleTranscript = () => {\n setShowTranscript(prev => !prev);\n };\n\n const handleToggleInputMode = () => {\n setInputMode(prev => {\n const newMode = prev === 'voice' ? 'text' : 'voice';\n // Update text input visibility based on new mode\n if (newMode === 'text' && isConversationActive) {\n setShowTextInput(true);\n } else {\n setShowTextInput(false);\n }\n return newMode;\n });\n };\n\n\n\n const handleTextSubmit = async () => {\n if (!textInput.trim() || !isConversationActive) return;\n\n // Log the user's text message\n handleLogMessage(textInput.trim(), 'HUMAN');\n\n // Send text message to AI via WebRTC data channel\n if (dataChannelRef.current?.readyState === 'open') {\n const message = {\n type: \"conversation.item.create\",\n item: {\n type: \"message\",\n role: \"user\",\n content: [{\n type: \"input_text\",\n text: textInput.trim()\n }]\n }\n };\n \n dataChannelRef.current.send(JSON.stringify(message));\n\n // Trigger response generation\n const responseMessage = {\n type: \"response.create\"\n };\n dataChannelRef.current.send(JSON.stringify(responseMessage));\n }\n\n // Clear the input\n setTextInput('');\n };\n\n const handleTextKeyPress = (event: React.KeyboardEvent) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n handleTextSubmit();\n }\n };\n\n const handleOnboardingComplete = async () => {\n setShowOnboarding(false);\n \n // Start the conversation session when onboarding is completed\n const success = await startConversationSession();\n if (success) {\n setIsConversationActive(true);\n // Only auto-show transcript if enabled in options\n if (transcriptOptions?.enabled !== false) {\n setShowTranscript(true);\n }\n }\n };\n\n const handleOnboardingClose = () => {\n setShowOnboarding(false);\n };\n\n const handleCloseTranscript = () => {\n setShowTranscript(false);\n };\n\n // ===== REACT EFFECTS & LIFECYCLE ===== \n \n // CSS styles injection effect\n hooks.useEffect(() => {\n injectStyles(guideAIStyles, 'guide-ai-styles');\n }, [guideAIStyles]);\n \n // Metadata initialization effect\n hooks.useEffect(() => {\n eventTracker.initialize();\n if (metadataOptions?.initialUserData) {\n metadataTracker.updateUserInfo(metadataOptions.initialUserData);\n }\n }, [eventTracker, metadataTracker, metadataOptions?.initialUserData]);\n \n // Component initialization effect\n hooks.useEffect(() => {\n console.log('GuideAI: Component mounting - initialization started', { \n hasInitialized: hasInitializedRef.current,\n initializationInProgress: initializationInProgressRef.current,\n organizationKey,\n timestamp: Date.now()\n });\n \n // Double-check to prevent race conditions\n if (hasInitializedRef.current || initializationInProgressRef.current || isUnmountingRef.current || globalInitializationInProgress) {\n console.log('GuideAI: Already initialized, initialization in progress, unmounting, or global initialization in progress, skipping');\n return;\n }\n \n // Set flags immediately to prevent concurrent initialization\n hasInitializedRef.current = true;\n initializationInProgressRef.current = true;\n globalInitializationInProgress = true;\n \n setIsClient(true);\n setIsConnecting(true); // Show loading state during initialization\n \n // Check for stored conversation before initializing\n const { shouldRestore, conversationId, messages } = checkForStoredConversation(organizationKey);\n \n if (shouldRestore && conversationId && messages) {\n // Store the restored messages to use as context\n setRestoredMessages(messages);\n } else {\n // No valid conversation to restore\n setRestoredMessages([]);\n }\n \n // Create new conversation (gets conversation + token + prompt)\n handleCreateNewConversation().then(conversationData => {\n if (!isUnmountingRef.current) {\n setIsConnecting(false); // Hide loading state when done\n globalInitializationInProgress = false; // Release global flag\n }\n }).catch(error => {\n if (!isUnmountingRef.current) {\n setIsConnecting(false); // Hide loading state on error\n console.error('Failed to create conversation:', error);\n globalInitializationInProgress = false; // Release global flag\n }\n });\n \n const hasInteractedBefore = localStorage.getItem('guideAI_hasInteracted');\n if (!hasInteractedBefore) {\n setHasInteracted(false);\n } else {\n setHasInteracted(true);\n }\n }, [organizationKey, handleCreateNewConversation, checkForStoredConversation]);\n \n // Component cleanup effect\n hooks.useEffect(() => {\n return () => {\n console.log('GuideAI: Component unmounting - cleanup triggered', { \n hasInitialized: hasInitializedRef.current,\n initializationInProgress: initializationInProgressRef.current,\n isUnmounting: isUnmountingRef.current,\n timestamp: Date.now()\n });\n \n // Set unmounting flag to prevent any new initialization\n isUnmountingRef.current = true;\n cleanupWebRTC();\n \n if (audioElementRef.current) {\n audioElementRef.current.srcObject = null;\n audioElementRef.current.remove();\n audioElementRef.current = null;\n }\n \n // Stop event tracking on cleanup\n if (eventTracker) {\n eventTracker.stopTracking();\n }\n \n // Stop metadata tracking and sync any pending updates\n if (metadataTracker) {\n metadataTracker.destroy();\n }\n \n // Reset flags on cleanup\n hasInitializedRef.current = false;\n initializationInProgressRef.current = false;\n isUnmountingRef.current = false;\n hasAttemptedAutoStartRef.current = false;\n globalInitializationInProgress = false;\n };\n }, [cleanupWebRTC, eventTracker, metadataTracker]);\n\n // Metadata sync effect - periodically sync metadata updates to backend\n hooks.useEffect(() => {\n const syncInterval = metadataOptions?.config?.syncInterval || 30000; // 30 seconds default\n \n const syncTimer = setInterval(async () => {\n if (metadataTracker) {\n const pendingUpdates = metadataTracker.syncNow();\n if (pendingUpdates.length > 0) {\n try {\n await sendMetadataUpdates(pendingUpdates, organizationKey, onError);\n \n // Notify parent component of metadata updates if callback provided\n if (metadataOptions?.onMetadataUpdate) {\n metadataOptions.onMetadataUpdate(metadataTracker.getMetadata());\n }\n } catch (error) {\n console.error('Failed to sync metadata updates:', error);\n }\n }\n }\n }, syncInterval);\n\n return () => {\n clearInterval(syncTimer);\n };\n }, [organizationKey, metadataOptions?.config?.syncInterval, metadataOptions?.onMetadataUpdate]);\n\n // Auto-restart effect - handles reconnection when token and restored messages are ready\n hooks.useEffect(() => {\n if (ephemeralToken && restoredMessages.length > 0 && !hasAttemptedAutoStartRef.current) {\n console.log('Auto-restarting conversation with', restoredMessages.length, 'restored messages');\n hasAttemptedAutoStartRef.current = true;\n \n startConversationSession().then(success => {\n if (success) {\n setIsConversationActive(true);\n setHasInteracted(true);\n localStorage.setItem('guideAI_hasInteracted', 'true');\n }\n });\n }\n }, [ephemeralToken, restoredMessages, startConversationSession]);\n\n // Load restored messages into allMessages state\n hooks.useEffect(() => {\n if (restoredMessages.length > 0 && allMessages.length === 0) {\n setAllMessages(restoredMessages);\n }\n }, [restoredMessages, allMessages.length]);\n\n // Update popup position when needed\n hooks.useEffect(() => {\n if (showOnboarding || (!hasInteracted && ephemeralToken)) {\n // Use onboarding dimensions if onboarding is shown, otherwise welcome bubble dimensions\n const height = showOnboarding ? 240 : 50;\n const spacing = showOnboarding ? 20 : 15;\n setPopupPosition(getOptimalPosition(height, spacing));\n }\n }, [showOnboarding, hasInteracted, ephemeralToken, getOptimalPosition]);\n\n // ===== METADATA HELPER FUNCTIONS =====\n \n // Expose metadata tracking methods globally on window for external access\n hooks.useEffect(() => {\n if (typeof window !== 'undefined') {\n // Create global GuideAI metadata API\n (window as any).GuideAI = {\n ...(window as any).GuideAI,\n metadata: {\n // Track user login\n trackLogin: (additionalInfo?: Partial<UserMetadata>) => {\n metadataTracker?.trackLogin(additionalInfo);\n },\n \n // Update user information\n updateUserInfo: (userInfo: Partial<UserMetadata>) => {\n metadataTracker?.updateUserInfo(userInfo);\n },\n \n // Track custom events\n trackCustomEvent: (eventType: string, customData: Record<string, any>) => {\n metadataTracker?.trackCustomEvent(eventType, customData);\n },\n \n // Get current metadata\n getMetadata: () => {\n return metadataTracker?.getMetadata() || null;\n },\n \n // Force sync metadata now\n syncMetadata: async () => {\n if (metadataTracker) {\n const updates = metadataTracker.syncNow();\n if (updates.length > 0) {\n return await sendMetadataUpdates(updates, organizationKey, onError);\n }\n }\n return true;\n }\n },\n transcript: {\n // Toggle transcript visibility\n toggle: () => {\n setShowTranscript(prev => !prev);\n },\n \n // Show transcript\n show: () => {\n setShowTranscript(true);\n },\n \n // Hide transcript\n hide: () => {\n setShowTranscript(false);\n },\n \n // Get current transcript visibility\n isVisible: () => {\n return showTranscript;\n }\n },\n input: {\n // Toggle input mode between voice and text\n toggleMode: () => {\n handleToggleInputMode();\n },\n \n // Set input mode\n setMode: (mode: 'voice' | 'text') => {\n setInputMode(mode);\n if (mode === 'text' && inputOptions?.enableTextInput !== false && isConversationActive) {\n setShowTextInput(true);\n } else {\n setShowTextInput(false);\n }\n },\n \n // Get current input mode\n getMode: () => {\n return inputMode;\n },\n \n // Send text message programmatically\n sendText: (text: string) => {\n if (text.trim() && isConversationActive) {\n setTextInput(text);\n handleTextSubmit();\n }\n }\n }\n };\n }\n }, [organizationKey, metadataTracker, showTranscript, inputMode, isConversationActive]);\n\n if (!isClient) {\n return null;\n }\n\n // Determine if we should use fixed positioning (when position props are provided)\n const shouldUseFixedPosition = componentPosition && Object.keys(componentPosition).length > 0;\n \n // Base styles for the component\n const baseStyles: React.CSSProperties = {\n position: shouldUseFixedPosition ? 'fixed' : 'relative',\n zIndex: shouldUseFixedPosition ? 1000 : 'auto',\n ...(shouldUseFixedPosition ? componentPosition : {}),\n };\n\n return (\n <>\n <div\n ref={componentRef}\n style={baseStyles}\n >\n <div className=\"guideai-main-ui\">\n {!hasInteracted && ephemeralToken && (\n <WelcomeBubble position={popupPosition} />\n )}\n \n <Onboarding \n position={popupPosition}\n isVisible={showOnboarding}\n onComplete={handleOnboardingComplete}\n onClose={handleOnboardingClose}\n />\n \n <div className=\"guideai-main-controls\">\n <div \n className={`guideai-icon-wrapper ${isConnecting ? 'initializing' : status}`}\n onClick={isConnecting ? undefined : handleToggleConversation}\n style={isConnecting ? { cursor: 'default' } : undefined}\n title={isConnecting ? 'Initializing...' : \n status === 'idle' ? 'Click to start conversation' : \n status === 'recording' ? 'Click to end conversation' : \n status === 'processing' ? 'Processing your message...' : \n 'AI is speaking, click to end conversation'}\n >\n {isConnecting && <i className=\"guideai-icon initializing\" />}\n {!isConnecting && status === 'idle' && <i className=\"guideai-icon microphone\" />}\n {!isConnecting && status === 'recording' && <i className=\"guideai-icon recording\" />}\n {!isConnecting && status === 'processing' && <i className=\"guideai-icon processing\" />}\n {!isConnecting && status === 'playing' && <i className=\"guideai-icon playing\" />}\n </div>\n \n </div>\n \n </div>\n </div>\n \n {/* Transcript Box */}\n <TranscriptBox\n messages={allMessages}\n isVisible={showTranscript}\n onClose={handleCloseTranscript}\n showToggleButton={transcriptOptions?.showToggleButton !== false && isConversationActive}\n onToggle={handleToggleTranscript}\n showTextInput={isConversationActive && inputOptions?.enableTextInput !== false}\n textInput={textInput}\n onTextInputChange={setTextInput}\n onTextSubmit={handleTextSubmit}\n onTextKeyPress={handleTextKeyPress}\n textPlaceholder={inputOptions?.placeholder || \"Type your message...\"}\n />\n </>\n );\n};\n\nexport default GuideAI;","import { PopupPosition } from '../types/GuideAI.types';\n\n// Function to inject CSS styles into the document head\nexport const injectStyles = (css: string, id: string) => {\n if (typeof document === 'undefined') return; // SSR safety\n \n // Check if styles are already injected\n if (document.getElementById(id)) return;\n \n const styleElement = document.createElement('style');\n styleElement.id = id;\n styleElement.textContent = css;\n document.head.appendChild(styleElement);\n};\n\n// Calculate optimal position for popups based on component location\nexport const calculateOptimalPosition = (\n componentRect: DOMRect, \n elementHeight: number = 240, \n spacing: number = 15\n): PopupPosition => {\n const viewportHeight = window.innerHeight;\n \n const spaceAbove = componentRect.top;\n const spaceBelow = viewportHeight - componentRect.bottom;\n \n const canFitBelow = spaceBelow >= (elementHeight + spacing);\n const canFitAbove = spaceAbove >= (elementHeight + spacing);\n \n if (canFitBelow) {\n return 'below';\n } else if (canFitAbove) {\n return 'above';\n } else {\n return spaceBelow > spaceAbove ? 'below' : 'above';\n }\n}; ","import React from 'react';\nimport { StoredMessage } from '../utils/messageStorage';\n\ninterface TranscriptBoxProps {\n messages: StoredMessage[];\n isVisible: boolean;\n onClose: () => void;\n showToggleButton?: boolean;\n onToggle?: () => void;\n showTextInput?: boolean;\n textInput?: string;\n onTextInputChange?: (value: string) => void;\n onTextSubmit?: () => void;\n onTextKeyPress?: (event: React.KeyboardEvent) => void;\n textPlaceholder?: string;\n}\n\nconst TranscriptBox: React.FC<TranscriptBoxProps> = ({ \n messages, \n isVisible, \n onClose, \n showToggleButton = true, \n onToggle,\n showTextInput = false,\n textInput = '',\n onTextInputChange,\n onTextSubmit,\n onTextKeyPress,\n textPlaceholder = \"Type your message...\"\n}) => {\n const formatTime = (timestamp: number) => {\n return new Date(timestamp).toLocaleTimeString([], { \n hour: '2-digit', \n minute: '2-digit' \n });\n };\n\n const scrollToBottom = (element: HTMLDivElement) => {\n element.scrollTop = element.scrollHeight;\n };\n\n React.useEffect(() => {\n const transcriptContainer = document.getElementById('guideai-transcript-container');\n if (transcriptContainer) {\n scrollToBottom(transcriptContainer as HTMLDivElement);\n }\n }, [messages]);\n\n // Show toggle button if there are messages and toggle is enabled, even when transcript is hidden\n const shouldShowToggleButton = showToggleButton && messages.length > 0;\n \n // Show transcript if visible OR if text input should be shown\n const shouldShowTranscript = isVisible || showTextInput;\n \n // Don't render anything if no messages, no toggle button, and no text input\n if (messages.length === 0 && !shouldShowToggleButton && !showTextInput) return null;\n\n return (\n <div className=\"guideai-transcript-overlay\">\n {/* Toggle Button - shows even when transcript is hidden */}\n {shouldShowToggleButton && (\n <button\n className=\"guideai-transcript-toggle-button\"\n onClick={onToggle}\n title={isVisible ? 'Hide Transcript' : 'Show Transcript'}\n >\n <span className=\"guideai-transcript-toggle-icon\">\n {isVisible ? '📄' : '📋'}\n </span>\n </button>\n )}\n \n {/* Transcript Box - show when visible or when text input is needed */}\n {shouldShowTranscript && (\n <div className=\"guideai-transcript-box\">\n {/* Messages Container - only show when transcript is visible */}\n {isVisible && (\n <div \n id=\"guideai-transcript-container\"\n className=\"guideai-transcript-messages\"\n >\n {messages.length === 0 ? (\n <div className=\"guideai-transcript-empty\">\n <div className=\"guideai-transcript-empty-icon\">🎤</div>\n <p>Start a conversation to see the transcript here</p>\n </div>\n ) : (\n messages.map((message, index) => (\n <div \n key={`${message.timestamp}-${index}`}\n className={`guideai-transcript-message ${message.sender.toLowerCase()}`}\n >\n <div className=\"guideai-transcript-message-content\">\n <div className=\"guideai-transcript-message-sender\">\n {message.sender === 'HUMAN' ? 'You' : 'GuideAI'}\n </div>\n <div className=\"guideai-transcript-message-text\">\n {message.content}\n </div>\n <div className=\"guideai-transcript-message-time\">\n {formatTime(message.timestamp)}\n </div>\n </div>\n </div>\n ))\n )}\n </div>\n )}\n \n {/* Text Input - show when in text mode */}\n {showTextInput && (\n <div className=\"guideai-transcript-text-input\">\n <textarea\n className=\"guideai-transcript-input-field\"\n value={textInput}\n onChange={(e) => onTextInputChange?.(e.target.value)}\n onKeyPress={onTextKeyPress}\n placeholder={textPlaceholder}\n rows={2}\n />\n <button\n className=\"guideai-transcript-send-button\"\n onClick={onTextSubmit}\n disabled={!textInput.trim()}\n title=\"Send Message\"\n >\n <span className=\"guideai-transcript-send-icon\">📤</span>\n </button>\n </div>\n )}\n </div>\n )}\n </div>\n );\n};\n\nexport default TranscriptBox; ","import React, { useState } from 'react';\nimport { PopupPosition } from '../types/GuideAI.types';\n\ninterface OnboardingProps {\n position: PopupPosition;\n isVisible: boolean;\n onComplete: () => void; // Called when user completes onboarding and wants to start conversation\n onClose: () => void; // Called when user closes onboarding without completing\n}\n\nconst Onboarding: React.FC<OnboardingProps> = ({ position, isVisible, onComplete, onClose }) => {\n const [step, setStep] = useState(1);\n\n const handleNext = () => {\n if (step < 3) {\n setStep(step + 1);\n } else {\n // Reset step and complete onboarding\n setStep(1);\n onComplete();\n }\n };\n\n const handleClose = () => {\n // Reset step when closing\n setStep(1);\n onClose();\n };\n\n if (!isVisible) {\n return null;\n }\n\n return (\n <div className={`guideai-onboarding ${position}`}>\n <div className=\"guideai-onboarding-content\">\n <button className=\"guideai-onboarding-close\" onClick={handleClose}>×</button>\n \n {step === 1 && (\n <div className=\"guideai-onboarding-step\">\n <div className=\"guideai-onboarding-icon volume-icon\">🔊</div>\n <h3>Turn on your volume</h3>\n <p>Make sure your device's volume is turned on so you can hear Guide AI's responses.</p>\n </div>\n )}\n \n {step === 2 && (\n <div className=\"guideai-onboarding-step\">\n <div className=\"guideai-onboarding-icon mic-icon\">🎤</div>\n <h3>Allow microphone access</h3>\n <p>When prompted, click \"Allow\" to let Guide AI access your microphone.</p>\n </div>\n )}\n \n {step === 3 && (\n <div className=\"guideai-onboarding-step\">\n <div className=\"guideai-onboarding-icon ready-icon\">✅</div>\n <h3>You're all set!</h3>\n <p>Click the microphone icon to start asking questions.</p>\n </div>\n )}\n \n <div className=\"guideai-onboarding-dots\">\n <span className={`dot ${step === 1 ? 'active' : ''}`}></span>\n <span className={`dot ${step === 2 ? 'active' : ''}`}></span>\n <span className={`dot ${step === 3 ? 'active' : ''}`}></span>\n </div>\n \n <button className=\"guideai-onboarding-next\" onClick={handleNext}>\n {step < 3 ? 'Next' : 'Get Started'}\n </button>\n </div>\n </div>\n );\n};\n\nexport default Onboarding; ","import React from 'react';\nimport { PopupPosition } from '../types/GuideAI.types';\n\ninterface WelcomeBubbleProps {\n position: PopupPosition;\n}\n\nconst WelcomeBubble: React.FC<WelcomeBubbleProps> = ({ position }) => {\n return (\n <div className={`guideai-welcome-bubble ${position}`}>\n Stuck? Click here and ask me a question\n </div>\n );\n};\n\nexport default WelcomeBubble; ","// Event tracking system for GuideAI\n// Tracks click, focus, change, and submit events on all relevant elements\n\ninterface EventData {\n type: 'click' | 'focus' | 'change' | 'submit' | 'route_change';\n element?: Element;\n tagName?: string;\n className?: string;\n id?: string;\n textContent?: string;\n value?: string;\n formData?: FormData;\n timestamp: number;\n url: string;\n previousUrl?: string;\n event?: Event;\n // Customer metadata\n customerId?: string;\n customerType?: string;\n customerSegment?: string;\n // Session metadata\n sessionId?: string;\n deviceType?: 'desktop' | 'mobile' | 'tablet';\n userAgent?: string;\n screenResolution?: string;\n // Application context\n currentPage?: string;\n userRole?: string;\n organizationId?: string;\n // Geographic and timezone\n timezone?: string;\n locale?: string;\n}\n\nclass EventTracker {\n private isTracking: boolean = false;\n private eventData: EventData[] = [];\n private batchSize: number = 10; // Emit every 10 events\n private batchTimeout: number = 5000; // Emit every 5 seconds\n private batchTimer: NodeJS.Timeout | null = null;\n private pendingEvents: EventData[] = [];\n private currentUrl: string = '';\n private organizationKey?: string;\n\n // Customer metadata storage\n private customerMetadata: {\n customerId?: string;\n customerType?: string;\n customerSegment?: string;\n userRole?: string;\n organizationId?: string;\n } = {};\n\n constructor(options?: { customerId?: string; customerType?: string; organizationId?: string; organizationKey?: string; }) {\n if (options?.customerId) {\n this.customerMetadata.customerId = String(options.customerId);\n }\n if (options?.customerType) {\n this.customerMetadata.customerType = options.customerType;\n }\n if (options?.organizationId) {\n this.customerMetadata.organizationId = String(options.organizationId);\n }\n if (options?.organizationKey) {\n this.organizationKey = options.organizationKey;\n }\n // Do not auto-initialize on server; caller should invoke initialize() on client\n }\n\n\n\n // Method to set customer metadata\n public setCustomerMetadata(metadata: Partial<typeof this.customerMetadata>): void {\n // All remaining metadata is safe to collect\n this.customerMetadata = { ...this.customerMetadata, ...metadata };\n }\n\n // Method to get customer metadata\n public getCustomerMetadata(): typeof this.customerMetadata {\n return { ...this.customerMetadata };\n }\n\n // Method to clear customer metadata\n public clearCustomerMetadata(): void {\n this.customerMetadata = {};\n }\n\n public initialize(): void {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n // Start tracking when DOM is ready\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => this.startTracking());\n } else {\n this.startTracking();\n }\n }\n\n // Helper method to enrich event data with customer metadat\n private enrichEventData(baseEventData: Omit<EventData, 'customerId' | 'customerType' | 'customerSegment' | 'sessionId' | 'deviceType' | 'userAgent' | 'screenResolution' | 'currentPage' | 'userRole' | 'organizationId' | 'timezone' | 'locale'>): EventData {\n const enrichedData = {\n ...baseEventData,\n // Customer metadata\n customerId: this.customerMetadata.customerId,\n customerType: this.customerMetadata.customerType,\n customerSegment: this.customerMetadata.customerSegment,\n organizationKey: this.organizationKey,\n // Session metadata\n sessionId: this.getSessionId(),\n deviceType: this.getDeviceType(),\n userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,\n screenResolution: typeof screen !== 'undefined' ? `${screen.width}x${screen.height}` : undefined,\n // Application context\n currentPage: window.location.pathname,\n userRole: this.customerMetadata.userRole,\n organizationId: this.customerMetadata.organizationId,\n // Geographic and timezone\n timezone: typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat !== 'undefined'\n ? Intl.DateTimeFormat().resolvedOptions().timeZone\n : undefined,\n locale: navigator.language,\n };\n\n return enrichedData;\n }\n\n\n\n // Helper method to get or create session ID\n private getSessionId(): string {\n let sessionId = sessionStorage.getItem('eventTracker_sessionId');\n if (!sessionId) {\n sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n sessionStorage.setItem('eventTracker_sessionId', sessionId);\n }\n return sessionId;\n }\n\n // Helper method to detect device type\n private getDeviceType(): 'desktop' | 'mobile' | 'tablet' {\n if (typeof navigator === 'undefined') {\n return 'desktop';\n }\n const userAgent = navigator.userAgent.toLowerCase();\n if (/tablet|ipad|playbook|silk/i.test(userAgent)) {\n return 'tablet';\n }\n if (/mobile|android|iphone|ipod|blackberry|opera mini|iemobile/i.test(userAgent)) {\n return 'mobile';\n }\n return 'desktop';\n }\n\n public startTracking(): void {\n if (this.isTracking) return;\n\n this.isTracking = true;\n console.log('EventTracker: Started tracking events');\n\n // Track click events on all elements\n this.trackClickEvents();\n\n // Track focus events on focusable elements\n this.trackFocusEvents();\n\n // Track change events on form elements\n this.trackChangeEvents();\n\n // Track submit events on forms\n this.trackSubmitEvents();\n\n // Track route changes\n this.trackRouteChanges();\n }\n\n public stopTracking(): void {\n if (!this.isTracking) return;\n\n this.isTracking = false;\n console.log('EventTracker: Stopped tracking events');\n\n // Emit any pending events before stopping\n this.emitBatch();\n\n // Remove all event listeners\n document.removeEventListener('click', this.handleClick, true);\n document.removeEventListener('focus', this.handleFocus, true);\n document.removeEventListener('change', this.handleChange, true);\n document.removeEventListener('submit', this.handleSubmit, true);\n window.removeEventListener('popstate', this.handlePopstate);\n window.removeEventListener('hashchange', this.handleHashChange);\n }\n\n private trackClickEvents(): void {\n document.addEventListener('click', this.handleClick, true);\n }\n\n private trackFocusEvents(): void {\n document.addEventListener('focus', this.handleFocus, true);\n }\n\n private trackChangeEvents(): void {\n document.addEventListener('change', this.handleChange, true);\n }\n\n private trackSubmitEvents(): void {\n document.addEventListener('submit', this.handleSubmit, true);\n }\n\n private trackRouteChanges(): void {\n // Track browser back/forward navigation\n window.addEventListener('popstate', this.handlePopstate);\n\n // Track hash changes\n window.addEventListener('hashchange', this.handleHashChange);\n\n // Track History API changes (pushState, replaceState)\n this.interceptHistoryAPI();\n }\n\n private handleClick = (event: Event): void => {\n if (!this.isTracking) return;\n\n const target = event.target as Element;\n const baseEventData = {\n type: 'click' as const,\n element: target,\n tagName: target.tagName,\n className: target.className,\n id: target.id,\n textContent: target.textContent?.substring(0, 100),\n value: this.getSafeValue(target),\n timestamp: Date.now(),\n url: window.location.href,\n event: event\n };\n\n this.logEvent(baseEventData);\n };\n\n private handleFocus = (event: Event): void => {\n if (!this.isTracking) return;\n\n const target = event.target as Element;\n\n // Only track focus on focusable elements\n if (this.isFocusable(target)) {\n const baseEventData = {\n type: 'focus' as const,\n element: target,\n tagName: target.tagName,\n className: target.className,\n id: target.id,\n textContent: target.textContent?.substring(0, 100),\n value: this.getSafeValue(target),\n timestamp: Date.now(),\n url: window.location.href,\n event: event\n };\n\n this.logEvent(baseEventData);\n }\n };\n\n private handleChange = (event: Event): void => {\n if (!this.isTracking) return;\n\n const target = event.target as Element;\n\n // Only track change on form elements\n if (this.isFormElement(target)) {\n const baseEventData = {\n type: 'change' as const,\n element: target,\n tagName: target.tagName,\n className: target.className,\n id: target.id,\n textContent: target.textContent?.substring(0, 100),\n value: this.getSafeValue(target),\n timestamp: Date.now(),\n url: window.location.href,\n event: event\n };\n\n this.logEvent(baseEventData);\n }\n };\n\n private handleSubmit = (event: Event): void => {\n if (!this.isTracking) return;\n\n const target = event.target as Element;\n\n // Only track submit on form elements\n if (target.tagName === 'FORM') {\n const form = target as HTMLFormElement;\n const formData = new FormData(form);\n\n const baseEventData = {\n type: 'submit' as const,\n element: target,\n tagName: target.tagName,\n className: target.className,\n id: target.id,\n textContent: target.textContent?.substring(0, 100),\n formData: formData,\n timestamp: Date.now(),\n url: window.location.href,\n event: event\n };\n\n this.logEvent(baseEventData);\n }\n };\n\n private handlePopstate = (event: PopStateEvent): void => {\n if (!this.isTracking) return;\n\n const baseEventData = {\n type: 'route_change' as const,\n timestamp: Date.now(),\n url: window.location.href,\n previousUrl: this.getPreviousUrl(),\n event: event\n };\n\n this.logEvent(baseEventData);\n };\n\n private handleHashChange = (event: HashChangeEvent): void => {\n if (!this.isTracking) return;\n\n const baseEventData = {\n type: 'route_change' as const,\n timestamp: Date.now(),\n url: window.location.href,\n previousUrl: event.oldURL,\n event: event\n };\n\n this.logEvent(baseEventData);\n };\n\n private interceptHistoryAPI(): void {\n const originalPushState = history.pushState;\n const originalReplaceState = history.replaceState;\n\n // Store the current URL before interception\n this.currentUrl = window.location.href;\n\n // Intercept pushState\n history.pushState = (...args) => {\n const previousUrl = this.currentUrl;\n const result = originalPushState.apply(history, args);\n this.currentUrl = window.location.href;\n\n if (this.isTracking) {\n const baseEventData = {\n type: 'route_change' as const,\n timestamp: Date.now(),\n url: window.location.href,\n previousUrl: previousUrl\n };\n this.logEvent(baseEventData);\n }\n\n return result;\n };\n\n // Intercept replaceState\n history.replaceState = (...args) => {\n const previousUrl = this.currentUrl;\n const result = originalReplaceState.apply(history, args);\n this.currentUrl = window.location.href;\n\n if (this.isTracking) {\n const baseEventData = {\n type: 'route_change' as const,\n timestamp: Date.now(),\n url: window.location.href,\n previousUrl: previousUrl\n };\n this.logEvent(baseEventData);\n }\n\n return result;\n };\n }\n\n private getPreviousUrl(): string {\n return this.currentUrl || window.location.href;\n }\n\n private getSafeValue(element: Element): string | undefined {\n const tagName = element.tagName.toLowerCase();\n const inputElement = element as HTMLInputElement;\n const selectElement = element as HTMLSelectElement;\n\n // Only collect values for elements that are typically useful for targeting\n switch (tagName) {\n case 'button':\n return inputElement.value || inputElement.textContent?.trim();\n\n case 'select':\n return `${selectElement.name || ''}|${selectElement.type || ''}|${selectElement.selectedIndex || 0}`;\n\n case 'textarea':\n return inputElement.name || inputElement.type || '';\n\n case 'input':\n const inputType = inputElement.type;\n // Only collect value for button-like input types\n if (inputType === 'submit' || inputType === 'button' || inputType === 'reset') {\n return `${inputElement.name || ''}|${inputType}|${inputElement.value || ''}`;\n }\n // For other input types, only collect name and type, not the actual value\n return `${inputElement.name || ''}|${inputType}`;\n\n default:\n return undefined;\n }\n }\n\n private isFocusable(element: Element): boolean {\n const focusableSelectors = [\n 'input:not([type=\"hidden\"])',\n 'select',\n 'textarea',\n 'button',\n 'a[href]',\n 'area[href]',\n 'iframe',\n 'object',\n 'embed',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]'\n ];\n\n return focusableSelectors.some(selector => element.matches(selector));\n }\n\n private isFormElement(element: Element): boolean {\n const formElementTags = ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON'];\n return formElementTags.includes(element.tagName);\n }\n\n private logEvent(baseEventData: Omit<EventData, 'customerType' | 'customerSegment' | 'sessionId' | 'deviceType' | 'currentPage' | 'userRole' | 'locale'>): void {\n // Enrich the event data with customer metadata\n const enrichedEventData = this.enrichEventData(baseEventData);\n\n // Store event data for historical access\n this.eventData.push(enrichedEventData);\n\n // Add to pending batch\n this.pendingEvents.push(enrichedEventData);\n\n // Check if we should emit based on batch size\n if (this.pendingEvents.length >= this.batchSize) {\n this.emitBatch();\n } else {\n // Start or reset the timeout for time-based emission\n this.startBatchTimer();\n }\n }\n\n private startBatchTimer(): void {\n // Clear existing timer\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n }\n\n // Start new timer\n this.batchTimer = setTimeout(() => {\n this.emitBatch();\n }, this.batchTimeout);\n }\n\n private emitBatch(): void {\n if (this.pendingEvents.length === 0) return;\n\n // Create batch payload\n const batchPayload = {\n events: [...this.pendingEvents],\n batchSize: this.pendingEvents.length,\n timestamp: Date.now(),\n\n };\n\n // Console log the batch (for now)\n console.log('EventTracker Batch:', batchPayload);\n\n // Emit custom event for metadata tracking integration\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent('guideai:event_batch', {\n detail: batchPayload\n }));\n }\n\n\n\n // Clear pending events\n this.pendingEvents = [];\n\n // Clear timer\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n }\n\n public getEventData(): EventData[] {\n return [...this.eventData];\n }\n\n public clearEventData(): void {\n this.eventData = [];\n }\n\n public getEventDataByType(type: EventData['type']): EventData[] {\n return this.eventData.filter(event => event.type === type);\n }\n\n public getEventDataByElement(tagName: string): EventData[] {\n return this.eventData.filter(event => event.tagName === tagName.toUpperCase());\n }\n\n public getEventDataByUrl(url: string): EventData[] {\n return this.eventData.filter(event => event.url.includes(url));\n }\n\n public emitPendingEvents(): void {\n this.emitBatch();\n }\n\n public setBatchConfig(batchSize: number, batchTimeout: number): void {\n this.batchSize = batchSize;\n this.batchTimeout = batchTimeout;\n }\n\n public getPendingEventsCount(): number {\n return this.pendingEvents.length;\n }\n\n // Customer analytics methods\n public getCustomerAnalytics(): {\n totalEvents: number;\n eventsByCustomer: Record<string, number>;\n eventsByType: Record<string, number>;\n eventsByPage: Record<string, number>;\n eventsByDevice: Record<string, number>;\n sessionDuration: number;\n lastActivity: number;\n } {\n const now = Date.now();\n const sessionStart = this.getSessionStartTime();\n const sessionDuration = now - sessionStart;\n\n const analytics = {\n totalEvents: this.eventData.length,\n eventsByCustomer: {} as Record<string, number>,\n eventsByType: {} as Record<string, number>,\n eventsByPage: {} as Record<string, number>,\n eventsByDevice: {} as Record<string, number>,\n sessionDuration,\n lastActivity: this.eventData.length > 0 ? this.eventData[this.eventData.length - 1].timestamp : now\n };\n\n // Group events by customer\n this.eventData.forEach(event => {\n if (event.customerId) {\n analytics.eventsByCustomer[event.customerId] = (analytics.eventsByCustomer[event.customerId] || 0) + 1;\n }\n\n // Group events by type\n analytics.eventsByType[event.type] = (analytics.eventsByType[event.type] || 0) + 1;\n\n // Group events by page\n if (event.currentPage) {\n analytics.eventsByPage[event.currentPage] = (analytics.eventsByPage[event.currentPage] || 0) + 1;\n }\n\n // Group events by device\n if (event.deviceType) {\n analytics.eventsByDevice[event.deviceType] = (analytics.eventsByDevice[event.deviceType] || 0) + 1;\n }\n });\n\n return analytics;\n }\n\n // Get session start time\n private getSessionStartTime(): number {\n const sessionStart = sessionStorage.getItem('eventTracker_sessionStart');\n if (!sessionStart) {\n const startTime = Date.now();\n sessionStorage.setItem('eventTracker_sessionStart', startTime.toString());\n return startTime;\n }\n return parseInt(sessionStart, 10);\n }\n\n // Method to identify customer from DOM or context\n public identifyCustomerFromContext(): void {\n // Try to find customer information from the current page context\n // This could be from meta tags, data attributes, or other DOM elements\n\n\n\n // Check for user role in meta tags\n const userRoleMeta = document.querySelector('meta[name=\"user-role\"]');\n if (userRoleMeta) {\n this.setCustomerMetadata({ userRole: userRoleMeta.getAttribute('content') || undefined });\n }\n\n\n\n // Try to infer customer type from URL or page context\n const pathname = window.location.pathname;\n if (pathname.includes('/admin/')) {\n this.setCustomerMetadata({ customerType: 'admin' });\n } else if (pathname.includes('/agent/')) {\n this.setCustomerMetadata({ customerType: 'agent' });\n } else if (pathname.includes('/business/')) {\n this.setCustomerMetadata({ customerType: 'business' });\n } else if (pathname.includes('/individual/')) {\n this.setCustomerMetadata({ customerType: 'individual' });\n }\n }\n\n // Method to set customer metadata from external source (e.g., authentication system)\n public setCustomerFromAuth(authData: {\n id?: string;\n role?: string;\n customerType?: 'individual' | 'business' | 'agent' | 'admin';\n customerSegment?: string;\n }): void {\n this.setCustomerMetadata({\n userRole: authData.role,\n customerType: authData.customerType,\n customerSegment: authData.customerSegment\n });\n }\n\n\n}\n\nexport default EventTracker;\nexport type { EventData };\n\n// Export customer metadata types for external use\nexport interface CustomerMetadata {\n customerId?: string;\n customerType?: 'individual' | 'business' | 'agent' | 'admin';\n customerSegment?: string;\n userRole?: string;\n}\n\nexport interface CustomerAnalytics {\n totalEvents: number;\n eventsByCustomer: Record<string, number>;\n eventsByType: Record<string, number>;\n eventsByPage: Record<string, number>;\n eventsByDevice: Record<string, number>;\n sessionDuration: number;\n lastActivity: number;\n}\n","// Create click effects and dispatch click event on an element\nexport const clickElement = async (element: Element, rect: DOMRect): Promise<void> => {\n return new Promise<void>((resolve) => {\n setTimeout(() => {\n const clickEffectContainer = document.createElement('div');\n clickEffectContainer.style.cssText = `\n position: fixed;\n left: ${rect.left + rect.width / 2}px;\n top: ${rect.top + rect.height / 2}px;\n width: 60px;\n height: 60px;\n z-index: 1000;\n pointer-events: none;\n transform: translate(-50%, -50%);\n `;\n document.body.appendChild(clickEffectContainer);\n \n for (let j = 0; j < 3; j++) {\n const clickRipple = document.createElement('div');\n clickRipple.style.cssText = `\n position: absolute;\n left: 50%;\n top: 50%;\n width: 40px;\n height: 40px;\n border: 2px solid rgba(0, 102, 255, ${0.7 - (j * 0.2)});\n border-radius: 50%;\n transform: translate(-50%, -50%) scale(0);\n opacity: 1;\n animation: click-ripple-animation 0.8s ease-out ${j * 0.15}s forwards;\n box-shadow: 0 0 8px rgba(0, 102, 255, 0.4);\n `;\n clickEffectContainer.appendChild(clickRipple);\n }\n \n const clickDot = document.createElement('div');\n clickDot.style.cssText = `\n position: absolute;\n left: 50%;\n top: 50%;\n width: 12px;\n height: 12px;\n background: rgba(0, 102, 255, 0.9);\n border-radius: 50%;\n transform: translate(-50%, -50%) scale(0);\n animation: click-dot-animation 0.4s ease-out forwards;\n box-shadow: 0 0 5px rgba(0, 102, 255, 0.8);\n `;\n clickEffectContainer.appendChild(clickDot);\n \n const clickEvent = new MouseEvent('click', {\n view: window,\n bubbles: true,\n cancelable: true,\n });\n\n // Check for clickable subelements (links, buttons, inputs)\n const clickableElements = element.querySelectorAll('a, button, input[type=\"button\"], input[type=\"submit\"]');\n const clickableElement = clickableElements.length > 0 ? clickableElements[0] as HTMLElement : element as HTMLElement;\n console.log('Clicking element:', clickableElement);\n clickableElement.dispatchEvent(clickEvent);\n\n const originalBoxShadow = clickableElement.style.boxShadow;\n const originalTransition = clickableElement.style.transition;\n const originalZIndex = clickableElement.style.zIndex;\n\n clickableElement.style.transition = 'all 0.3s ease-out';\n clickableElement.style.boxShadow = '0 0 0 2px rgba(0, 102, 255, 0.5), 0 0 10px rgba(0, 102, 255, 0.3)';\n clickableElement.style.zIndex = '999';\n\n setTimeout(() => {\n clickableElement.style.boxShadow = originalBoxShadow;\n clickableElement.style.transition = originalTransition;\n clickableElement.style.zIndex = originalZIndex;\n\n clickEffectContainer.remove(); \n resolve();\n }, 1000);\n\n }, 1500);\n });\n};\n\n// Highlight elements on the page with animated cursor and click effects\nexport const highlightElement = async (\n selector: string | string[],\n isHighlighting: boolean,\n setIsHighlighting: (highlighting: boolean) => void,\n logMessage: (content: string, sender: 'GUIDEAI' | 'HUMAN') => void\n): Promise<boolean> => {\n if (isHighlighting) return false;\n \n const selectors = Array.isArray(selector) ? selector : [selector];\n if (selectors.length === 0) return false;\n \n console.log('Moving cursor to elements:', selectors);\n \n let cursorElement: HTMLElement | null = null;\n try {\n setIsHighlighting(true);\n \n for (let i = 0; i < selectors.length; i++) {\n const currentSelector = selectors[i];\n \n if (i > 0) {\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n \n let element;\n if (currentSelector.startsWith('//')) {\n const node = document.evaluate(currentSelector, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;\n if (!(node instanceof Element)) {\n console.log('XPath returned a non-Element node:', currentSelector);\n console.log(node);\n logMessage('XPath returned a non-Element node: ' + currentSelector, 'GUIDEAI');\n break;\n }\n element = node as Element;\n } else {\n element = document.querySelector(currentSelector);\n }\n \n if (!element) {\n console.log('Element not found:', currentSelector);\n logMessage('Element not found: ' + currentSelector, 'GUIDEAI');\n break;\n }\n \n const rect = element.getBoundingClientRect();\n \n // Create cursor if it's the first element, or reuse existing cursor\n if (!cursorElement) {\n cursorElement = document.createElement('div');\n cursorElement.id = 'guide-ai-cursor';\n \n const blueCursorSvg = `\n <svg width=\"100%\" height=\"100%\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill=\"#0066ff\" d=\"M7,2l12,11.2l-5.8,0.5l3.3,7.3l-2.2,1l-3.2-7.4L7,18.5V2\" />\n </svg>\n `;\n \n cursorElement.innerHTML = blueCursorSvg;\n cursorElement.style.cssText = `\n position: fixed;\n width: 64px;\n height: 64px;\n pointer-events: none;\n z-index: 9999;\n transition: all 0.8s ease-in-out;\n transform: translate(-50%, 0);\n filter: drop-shadow(0 0 4px rgba(0, 102, 255, 0.8));\n `;\n \n document.body.appendChild(cursorElement);\n \n // First element starts from center of viewport\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n cursorElement.style.left = `${viewportWidth / 2}px`;\n cursorElement.style.top = `${viewportHeight / 2}px`;\n }\n \n // Force reflow to ensure transition works\n cursorElement!.offsetHeight;\n \n await new Promise<void>(resolve => {\n setTimeout(() => {\n cursorElement!.style.left = `${rect.left + rect.width / 2}px`;\n cursorElement!.style.top = `${rect.top + rect.height / 2 - 10}px`;\n \n setTimeout(() => {\n cursorElement!.style.animation = 'cursor-jiggle 0.5s ease-in-out infinite';\n resolve();\n }, 800);\n }, 100);\n });\n \n await clickElement(element, rect);\n }\n\n setTimeout(() => {\n cursorElement?.remove();\n setIsHighlighting(false);\n }, 1000);\n \n return true;\n } catch (error) {\n console.error('Error moving cursor:', error);\n cursorElement?.remove();\n setIsHighlighting(false);\n return false;\n }\n}; ","// User metadata tracking system for GuideAI\n// Tracks user visits, logins, and other metadata for Overproof integration\n\nimport { \n UserMetadata, \n MetadataConfig, \n MetadataStorageData, \n MetadataEvent, \n MetadataEventType,\n MetadataUpdate \n} from '../types/metadata.types';\nimport { sendMetadataUpdates } from '../utils/api';\n\nconst METADATA_STORAGE_KEY = 'guideai_user_metadata';\nconst METADATA_VERSION = '1.0.0';\n\nclass UserMetadataTracker {\n private config: Required<MetadataConfig>;\n private metadata: UserMetadata;\n private syncTimer: NodeJS.Timeout | null = null;\n private pendingUpdates: MetadataUpdate[] = [];\n private isInitialized: boolean = false;\n private onError?: (error: Error, context: string) => void;\n\n constructor(organizationKey: string, config: MetadataConfig = {}, onError?: (error: Error, context: string) => void) {\n this.config = {\n trackVisits: true,\n trackLogins: true,\n syncInterval: 30000, // 30 seconds\n storage: 'localStorage',\n customFields: [],\n collectBrowserInfo: true,\n collectUserAgent: true,\n ...config\n };\n\n this.metadata = {\n organizationKey,\n visitCount: 0,\n loginCount: 0\n };\n \n this.onError = onError;\n\n this.init();\n }\n\n private init(): void {\n if (this.isInitialized) return;\n\n // Load existing metadata from storage\n this.loadMetadata();\n\n // Collect browser info if enabled\n if (this.config.collectBrowserInfo) {\n this.collectBrowserInfo();\n }\n\n // Track initial visit if enabled\n if (this.config.trackVisits) {\n this.trackVisit();\n }\n\n // Start sync timer\n this.startSyncTimer();\n\n // Listen for EventTracker events to detect user interactions\n this.setupEventTrackerIntegration();\n\n this.isInitialized = true;\n console.log('UserMetadataTracker: Initialized', this.metadata);\n }\n\n public updateUserInfo(userInfo: Partial<UserMetadata>): void {\n const timestamp = Date.now();\n \n // Update metadata\n this.metadata = {\n ...this.metadata,\n ...userInfo,\n lastVisit: timestamp\n };\n\n // Add to pending updates\n this.pendingUpdates.push({\n type: 'user_info',\n timestamp,\n data: userInfo\n });\n\n // Save to storage\n this.saveMetadata();\n\n console.log('UserMetadataTracker: User info updated', userInfo);\n }\n\n public trackLogin(additionalInfo?: Partial<UserMetadata>): void {\n if (!this.config.trackLogins) return;\n\n const timestamp = Date.now();\n \n this.metadata = {\n ...this.metadata,\n ...additionalInfo,\n loginCount: (this.metadata.loginCount || 0) + 1,\n lastLogin: timestamp,\n lastVisit: timestamp\n };\n\n this.pendingUpdates.push({\n type: 'login',\n timestamp,\n data: {\n loginCount: this.metadata.loginCount,\n lastLogin: timestamp,\n ...additionalInfo\n }\n });\n\n this.saveMetadata();\n console.log('UserMetadataTracker: Login tracked', this.metadata.loginCount);\n }\n\n public trackVisit(): void {\n if (!this.config.trackVisits) return;\n\n const timestamp = Date.now();\n const isFirstVisit = !this.metadata.firstVisit;\n\n this.metadata = {\n ...this.metadata,\n firstVisit: this.metadata.firstVisit || timestamp,\n lastVisit: timestamp,\n visitCount: (this.metadata.visitCount || 0) + 1\n };\n\n this.pendingUpdates.push({\n type: 'visit',\n timestamp,\n data: {\n firstVisit: this.metadata.firstVisit,\n lastVisit: this.metadata.lastVisit,\n visitCount: this.metadata.visitCount\n }\n });\n\n this.saveMetadata();\n \n console.log(`UserMetadataTracker: ${isFirstVisit ? 'First' : 'Return'} visit tracked`, {\n visitCount: this.metadata.visitCount,\n firstVisit: this.metadata.firstVisit,\n lastVisit: this.metadata.lastVisit\n });\n }\n\n public trackCustomEvent(eventType: string, customData: Record<string, any>): void {\n const timestamp = Date.now();\n\n // Update custom fields if they're in the config\n const customFields = { ...this.metadata.customFields };\n for (const [key, value] of Object.entries(customData)) {\n if (this.config.customFields.includes(key)) {\n customFields[key] = value;\n }\n }\n\n this.metadata = {\n ...this.metadata,\n customFields,\n lastVisit: timestamp\n };\n\n this.pendingUpdates.push({\n type: 'custom',\n timestamp,\n data: { customFields }\n });\n\n this.saveMetadata();\n console.log('UserMetadataTracker: Custom event tracked', eventType, customData);\n }\n\n public getMetadata(): UserMetadata {\n return { ...this.metadata };\n }\n\n public getPendingUpdates(): MetadataUpdate[] {\n return [...this.pendingUpdates];\n }\n\n public clearPendingUpdates(): void {\n this.pendingUpdates = [];\n }\n\n public syncNow(): MetadataUpdate[] {\n const updates = [...this.pendingUpdates];\n this.clearPendingUpdates();\n return updates;\n }\n\n private loadMetadata(): void {\n try {\n const storageData = this.getFromStorage();\n if (storageData && storageData.metadata) {\n // Merge stored metadata with current metadata\n this.metadata = {\n ...this.metadata,\n ...storageData.metadata\n };\n console.log('UserMetadataTracker: Loaded metadata from storage', this.metadata);\n }\n } catch (error) {\n console.warn('UserMetadataTracker: Failed to load metadata from storage', error);\n // Clear corrupted data\n this.clearStorage();\n }\n }\n\n private saveMetadata(): void {\n try {\n const storageData: MetadataStorageData = {\n metadata: this.metadata,\n lastUpdated: Date.now(),\n version: METADATA_VERSION\n };\n\n this.setToStorage(storageData);\n } catch (error) {\n console.warn('UserMetadataTracker: Failed to save metadata to storage', error);\n }\n }\n\n private collectBrowserInfo(): void {\n if (typeof window === 'undefined') return;\n\n const userAgent = navigator.userAgent;\n const browserInfo = this.parseBrowserInfo(userAgent);\n\n this.metadata = {\n ...this.metadata,\n userAgent: this.config.collectUserAgent ? userAgent : undefined,\n browserInfo\n };\n }\n\n private parseBrowserInfo(userAgent: string): UserMetadata['browserInfo'] {\n // Simple browser detection - could be enhanced with a proper library\n let name = 'Unknown';\n let version = 'Unknown';\n let platform = 'Unknown';\n\n // Detect browser\n if (userAgent.includes('Chrome') && !userAgent.includes('Edg')) {\n name = 'Chrome';\n const match = userAgent.match(/Chrome\\/([0-9.]+)/);\n version = match ? match[1] : 'Unknown';\n } else if (userAgent.includes('Firefox')) {\n name = 'Firefox';\n const match = userAgent.match(/Firefox\\/([0-9.]+)/);\n version = match ? match[1] : 'Unknown';\n } else if (userAgent.includes('Safari') && !userAgent.includes('Chrome')) {\n name = 'Safari';\n const match = userAgent.match(/Version\\/([0-9.]+)/);\n version = match ? match[1] : 'Unknown';\n } else if (userAgent.includes('Edg')) {\n name = 'Edge';\n const match = userAgent.match(/Edg\\/([0-9.]+)/);\n version = match ? match[1] : 'Unknown';\n }\n\n // Detect platform\n if (userAgent.includes('Win')) platform = 'Windows';\n else if (userAgent.includes('Mac')) platform = 'macOS';\n else if (userAgent.includes('Linux')) platform = 'Linux';\n else if (userAgent.includes('Android')) platform = 'Android';\n else if (userAgent.includes('iOS')) platform = 'iOS';\n\n return { name, version, platform };\n }\n\n private startSyncTimer(): void {\n if (this.syncTimer) return;\n\n this.syncTimer = setInterval(() => {\n if (this.pendingUpdates.length > 0) {\n this.emitPendingUpdates();\n }\n }, this.config.syncInterval);\n }\n\n private setupEventTrackerIntegration(): void {\n if (typeof window === 'undefined') return;\n\n // Listen for EventTracker batches to detect user interactions\n const handleEventBatch = (event: Event) => {\n const customEvent = event as CustomEvent;\n const batchData = customEvent.detail;\n if (batchData && batchData.events) {\n // Look for login-related events (form submissions, clicks on login buttons, etc.)\n const hasLoginEvent = batchData.events.some((evt: any) => \n evt.type === 'submit' || \n (evt.type === 'click' && (\n evt.textContent?.toLowerCase().includes('login') ||\n evt.textContent?.toLowerCase().includes('sign in') ||\n evt.className?.toLowerCase().includes('login') ||\n evt.id?.toLowerCase().includes('login')\n ))\n );\n\n if (hasLoginEvent) {\n console.log('UserMetadataTracker: Detected potential login event from EventTracker');\n // Note: We don't automatically track login here as it requires explicit confirmation\n // This is just for detecting potential login scenarios\n }\n\n // Track general user activity\n const timestamp = Date.now();\n this.metadata = {\n ...this.metadata,\n lastVisit: timestamp\n };\n }\n };\n\n window.addEventListener('guideai:event_batch', handleEventBatch);\n \n // Store the listener for cleanup\n (this as any)._eventTrackerListener = handleEventBatch;\n }\n\n private stopSyncTimer(): void {\n if (this.syncTimer) {\n clearInterval(this.syncTimer);\n this.syncTimer = null;\n }\n }\n\n private async emitPendingUpdates(): Promise<void> {\n if (this.pendingUpdates.length === 0) return;\n\n const updates = [...this.pendingUpdates];\n \n // Emit the updates (integrate with existing event system)\n console.log('UserMetadataTracker: Emitting metadata updates', {\n updateCount: updates.length,\n updates,\n currentMetadata: this.metadata\n });\n\n // Send to backend API\n try {\n if (this.onError) {\n await sendMetadataUpdates(updates, this.metadata.organizationKey, this.onError);\n }\n \n // Clear pending updates after successful emission\n this.clearPendingUpdates();\n } catch (error) {\n console.warn('UserMetadataTracker: Failed to send metadata updates, will retry later', error);\n // Don't clear pending updates so they can be retried\n }\n }\n\n private getFromStorage(): MetadataStorageData | null {\n try {\n const key = `${METADATA_STORAGE_KEY}_${this.metadata.organizationKey}`;\n let data: string | null = null;\n\n switch (this.config.storage) {\n case 'localStorage':\n data = typeof window !== 'undefined' ? localStorage.getItem(key) : null;\n break;\n case 'sessionStorage':\n data = typeof window !== 'undefined' ? sessionStorage.getItem(key) : null;\n break;\n case 'memory':\n // For memory storage, we don't persist across sessions\n return null;\n }\n\n return data ? JSON.parse(data) : null;\n } catch (error) {\n console.warn('UserMetadataTracker: Error reading from storage', error);\n return null;\n }\n }\n\n private setToStorage(data: MetadataStorageData): void {\n try {\n const key = `${METADATA_STORAGE_KEY}_${this.metadata.organizationKey}`;\n const serialized = JSON.stringify(data);\n\n switch (this.config.storage) {\n case 'localStorage':\n if (typeof window !== 'undefined') {\n localStorage.setItem(key, serialized);\n }\n break;\n case 'sessionStorage':\n if (typeof window !== 'undefined') {\n sessionStorage.setItem(key, serialized);\n }\n break;\n case 'memory':\n // For memory storage, we don't persist\n break;\n }\n } catch (error) {\n console.warn('UserMetadataTracker: Error writing to storage', error);\n }\n }\n\n private clearStorage(): void {\n try {\n const key = `${METADATA_STORAGE_KEY}_${this.metadata.organizationKey}`;\n\n switch (this.config.storage) {\n case 'localStorage':\n if (typeof window !== 'undefined') {\n localStorage.removeItem(key);\n }\n break;\n case 'sessionStorage':\n if (typeof window !== 'undefined') {\n sessionStorage.removeItem(key);\n }\n break;\n case 'memory':\n // Nothing to clear for memory storage\n break;\n }\n } catch (error) {\n console.warn('UserMetadataTracker: Error clearing storage', error);\n }\n }\n\n public destroy(): void {\n // Emit any pending updates before destroying\n this.emitPendingUpdates();\n \n // Stop sync timer\n this.stopSyncTimer();\n \n // Remove event listener\n if (typeof window !== 'undefined' && (this as any)._eventTrackerListener) {\n window.removeEventListener('guideai:event_batch', (this as any)._eventTrackerListener);\n }\n \n // Clear state\n this.isInitialized = false;\n this.pendingUpdates = [];\n \n console.log('UserMetadataTracker: Destroyed');\n }\n}\n\nexport default UserMetadataTracker;\nexport type { UserMetadata, MetadataConfig, MetadataUpdate };\n","// Metric exports\nexport { default as EventTracker } from './event-listner';\nexport type { EventData } from './event-listner';\nexport { default as UserMetadataTracker } from './metadata-tracker';\nexport type { UserMetadata, MetadataConfig, MetadataUpdate } from './metadata-tracker';","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(258);\n"],"names":["root","factory","exports","module","require","define","amd","this","__WEBPACK_EXTERNAL_MODULE__156__","guideAIStyles","CONVERSATION_STORAGE_KEY","CONVERSATION_EXPIRY_MINUTES","MAX_STORED_MESSAGES","isLocalStorageAvailable","testKey","localStorage","setItem","removeItem","e","isConversationExpired","conversation","expiryTime","Date","now","timestamp","handleStorageError","error","operation","console","DOMException","name","loadConversationFromStorage","messages","length","slice","saveConversationToStorage","warn","clearConversationStorage","cleanupError","JSON","stringify","storedData","getItem","parsedData","parse","data","conversationId","Array","isArray","organizationKey","every","msg","content","sender","addMessageToStorage","message","some","existingMsg","Math","abs","log","substring","push","checkForStoredConversation","currentOrganizationKey","storedConversation","shouldRestore","formatConversationContext","maxMessages","recentMessages","meaningfulMessages","filter","trim","map","join","DEFAULT_PROMPT","IGNORE_MESSAGE_TYPES","GUIDE_AI_API_BASE","OPENAI_REALTIME_BASE","OPENAI_REALTIME_MODEL","GEMINI_API_KEY","GEMINI_API_ENDPOINT","createNewConversation","onError","fetch","method","headers","body","userId","date","toISOString","split","time","toTimeString","response","ok","text","catch","errorText","status","Error","json","conversationData","id","logMessage","statusText","sendMetadataUpdates","updates","batchTimestamp","updateCount","globalInitializationInProgress","props","position","metadataOptions","transcriptOptions","inputOptions","hooks","useMemo","window","React","useState","useEffect","useRef","useCallback","setStatus","isClient","setIsClient","componentPosition","isHighlighting","setIsHighlighting","hasInteracted","setHasInteracted","setPrompt","setIsSessionReady","isConnecting","setIsConnecting","showOnboarding","setShowOnboarding","popupPosition","setPopupPosition","conversationIdRef","componentRef","peerConnectionRef","dataChannelRef","hasCreatedConversationRef","mediaStreamRef","audioElementRef","ephemeralToken","setEphemeralToken","hasInitializedRef","initializationInProgressRef","isUnmountingRef","isConversationActive","setIsConversationActive","restoredMessages","setRestoredMessages","enabled","showTranscript","setShowTranscript","allMessages","setAllMessages","defaultMode","inputMode","setInputMode","textInput","setTextInput","setShowTextInput","hasAttemptedAutoStartRef","eventTracker","customerId","organizationId","customerType","raw","parsed","idVal","customer","String","orgVal","typeName","customerTypeName","_err","EventTracker","metadataTracker","UserMetadataTracker","config","geminiFlash","prompt","contents","parts","responseJson","candidates","handleCreateNewConversation","current","handleLogMessage","newMessage","prev","getOptimalPosition","elementHeight","spacing","rect","getBoundingClientRect","calculateOptimalPosition","sendMessage","readyState","send","cleanupWebRTC","getAudioTracks","forEach","track","stop","close","srcObject","initializeWebRTC","audioStream","RTCPeerConnection","addTrack","audioEl","document","createElement","autoplay","appendChild","ontrack","kind","stream","MediaStream","dc","createDataChannel","onopen","sessionConfig","tools","type","description","parameters","properties","selector","oneOf","items","required","tool_choice","turn_detection","create_response","interrupt_response","input_audio_transcription","model","language","session","onmessage","conversationContext","item","role","transcript","lastMessage","output","out","arguments","argsToUse","then","replace","parsedArgs","highlightElement","err","call_id","code","fragment","includes","createOffer","offer","setLocalDescription","localDescription","sdp","baseUrl","Authorization","sdpResponse","answerSdp","answer","setRemoteDescription","startConversationSession","navigator","mediaDevices","getUserMedia","audio","echoCancellation","noiseSuppression","autoGainControl","channelCount","sampleRate","endConversationSession","handleTextSubmit","responseMessage","injectStyles","initialize","initialUserData","updateUserInfo","hasInitialized","initializationInProgress","hasInteractedBefore","isUnmounting","remove","stopTracking","destroy","syncInterval","syncTimer","setInterval","pendingUpdates","syncNow","onMetadataUpdate","getMetadata","clearInterval","success","GuideAI","metadata","trackLogin","additionalInfo","userInfo","trackCustomEvent","eventType","customData","syncMetadata","toggle","show","hide","isVisible","input","toggleMode","newMode","setMode","mode","enableTextInput","getMode","sendText","shouldUseFixedPosition","Object","keys","baseStyles","zIndex","ref","style","className","onComplete","onClose","onClick","undefined","cursor","title","showToggleButton","onToggle","showTextInput","onTextInputChange","onTextSubmit","onTextKeyPress","event","key","shiftKey","preventDefault","textPlaceholder","placeholder","css","getElementById","styleElement","textContent","head","componentRect","viewportHeight","innerHeight","spaceAbove","top","spaceBelow","bottom","element","transcriptContainer","scrollTop","scrollHeight","shouldShowToggleButton","shouldShowTranscript","index","toLowerCase","toLocaleTimeString","hour","minute","value","onChange","target","onKeyPress","rows","disabled","step","setStep","options","isTracking","eventData","batchSize","batchTimeout","batchTimer","pendingEvents","currentUrl","customerMetadata","handleClick","baseEventData","tagName","getSafeValue","url","location","href","logEvent","handleFocus","isFocusable","handleChange","isFormElement","handleSubmit","formData","FormData","handlePopstate","previousUrl","getPreviousUrl","handleHashChange","oldURL","setCustomerMetadata","getCustomerMetadata","clearCustomerMetadata","addEventListener","startTracking","enrichEventData","customerSegment","sessionId","getSessionId","deviceType","getDeviceType","userAgent","screenResolution","screen","width","height","currentPage","pathname","userRole","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","locale","sessionStorage","random","toString","substr","test","trackClickEvents","trackFocusEvents","trackChangeEvents","trackSubmitEvents","trackRouteChanges","emitBatch","removeEventListener","interceptHistoryAPI","originalPushState","history","pushState","originalReplaceState","replaceState","result","apply","args","inputElement","selectElement","selectedIndex","inputType","matches","enrichedEventData","startBatchTimer","clearTimeout","setTimeout","batchPayload","events","dispatchEvent","CustomEvent","detail","getEventData","clearEventData","getEventDataByType","getEventDataByElement","toUpperCase","getEventDataByUrl","emitPendingEvents","setBatchConfig","getPendingEventsCount","getCustomerAnalytics","sessionDuration","getSessionStartTime","analytics","totalEvents","eventsByCustomer","eventsByType","eventsByPage","eventsByDevice","lastActivity","sessionStart","startTime","parseInt","identifyCustomerFromContext","userRoleMeta","querySelector","getAttribute","setCustomerFromAuth","authData","clickElement","Promise","resolve","clickEffectContainer","cssText","left","j","clickRipple","clickDot","clickEvent","MouseEvent","view","bubbles","cancelable","clickableElements","querySelectorAll","clickableElement","originalBoxShadow","boxShadow","originalTransition","transition","originalZIndex","selectors","cursorElement","i","currentSelector","startsWith","node","evaluate","XPathResult","FIRST_ORDERED_NODE_TYPE","singleNodeValue","Element","innerHTML","viewportWidth","innerWidth","offsetHeight","animation","METADATA_STORAGE_KEY","isInitialized","trackVisits","trackLogins","storage","customFields","collectBrowserInfo","collectUserAgent","visitCount","loginCount","init","loadMetadata","trackVisit","startSyncTimer","setupEventTrackerIntegration","lastVisit","saveMetadata","lastLogin","isFirstVisit","firstVisit","entries","getPendingUpdates","clearPendingUpdates","storageData","getFromStorage","clearStorage","lastUpdated","version","setToStorage","browserInfo","parseBrowserInfo","platform","match","emitPendingUpdates","handleEventBatch","batchData","evt","_eventTrackerListener","stopSyncTimer","currentMetadata","serialized","default","__webpack_module_cache__","__webpack_exports__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","call"],"sourceRoot":""}
1
+ {"version":3,"file":"GuideAI.js","mappings":"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","sources":["webpack://GuideAI/webpack/universalModuleDefinition","webpack://GuideAI/./src/styles/GuideAI.styles.ts","webpack://GuideAI/./src/utils/messageStorage.ts","webpack://GuideAI/./src/utils/constants.ts","webpack://GuideAI/external umd {\"commonjs\":\"react\",\"commonjs2\":\"react\",\"amd\":\"React\",\"root\":\"React\"}","webpack://GuideAI/./src/utils/api.ts","webpack://GuideAI/./src/GuideAI.tsx","webpack://GuideAI/./src/utils/ui.ts","webpack://GuideAI/./src/components/TranscriptBox.tsx","webpack://GuideAI/./src/components/Onboarding.tsx","webpack://GuideAI/./src/components/WelcomeBubble.tsx","webpack://GuideAI/./src/metric/event-listner.tsx","webpack://GuideAI/./src/utils/highlight.ts","webpack://GuideAI/./src/metric/metadata-tracker.tsx","webpack://GuideAI/./src/metric/index.tsx","webpack://GuideAI/webpack/bootstrap","webpack://GuideAI/webpack/startup"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"react\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"React\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"GuideAI\"] = factory(require(\"react\"));\n\telse\n\t\troot[\"GuideAI\"] = factory(root[\"React\"]);\n})(this, (__WEBPACK_EXTERNAL_MODULE__156__) => {\nreturn ","export const guideAIStyles = `\n.guideai-main-ui {\n position: relative;\n}\n\n.guideai-main-controls {\n display: flex;\n align-items: center;\n gap: 12px;\n position: relative;\n}\n\n.guideai-welcome-bubble {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n background: #0066ff;\n color: white;\n padding: 10px 16px;\n border-radius: 20px;\n font-size: 14px;\n white-space: normal;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n animation: bubble-pulse 2s infinite;\n max-width: 280px;\n min-width: 200px;\n text-align: center;\n line-height: 1.3;\n}\n\n.guideai-welcome-bubble.above {\n bottom: calc(100% + 10px);\n}\n\n.guideai-welcome-bubble.below {\n top: calc(100% + 10px);\n}\n\n.guideai-welcome-bubble.above::after {\n content: '';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-top: 8px solid #0066ff;\n}\n\n.guideai-welcome-bubble.below::after {\n content: '';\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-bottom: 8px solid #0066ff;\n}\n\n@keyframes bubble-pulse {\n 0% { transform: translateX(-50%) scale(1); }\n 50% { transform: translateX(-50%) scale(1.05); }\n 100% { transform: translateX(-50%) scale(1); }\n}\n\n.guideai-icon-wrapper {\n width: 50px;\n height: 50px;\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: rgba(255, 255, 255, 0.9);\n border: 2px solid transparent;\n border-radius: 50%;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.guideai-icon-wrapper:not(.initializing):hover {\n transform: scale(1.1);\n}\n\n.guideai-icon-wrapper.initializing {\n background-color: rgba(255, 255, 255, 0.9);\n box-shadow: 0 0 0 2px rgba(128, 128, 128, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);\n animation: guideai-spin 1.5s linear infinite;\n opacity: 0.7;\n cursor: default;\n}\n\n.guideai-icon-wrapper.recording {\n background-color: rgba(255, 255, 255, 0.9);\n box-shadow: 0 0 0 2px rgba(255, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);\n animation: guideai-pulse 1s infinite alternate;\n}\n\n.guideai-icon-wrapper.processing {\n background-color: rgba(255, 255, 255, 0.9);\n box-shadow: 0 0 0 2px rgba(255, 165, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);\n animation: guideai-spin 1s linear infinite;\n}\n\n.guideai-icon-wrapper.playing {\n background-color: rgba(255, 255, 255, 0.9);\n box-shadow: 0 0 0 2px rgba(0, 128, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);\n}\n\n@keyframes guideai-pulse {\n 0% { transform: scale(1); }\n 100% { transform: scale(1.05); }\n}\n\n@keyframes guideai-spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\n@keyframes click-ripple-animation {\n 0% { transform: translate(-50%, -50%) scale(0); opacity: 1; }\n 50% { transform: translate(-50%, -50%) scale(1.2); opacity: 0.6; }\n 100% { transform: translate(-50%, -50%) scale(2.5); opacity: 0; }\n}\n\n@keyframes click-dot-animation {\n 0% { transform: translate(-50%, -50%) scale(0); opacity: 1; }\n 60% { transform: translate(-50%, -50%) scale(1); opacity: 1; }\n 100% { transform: translate(-50%, -50%) scale(1); opacity: 0; }\n}\n\n@keyframes cursor-jiggle {\n 0% { transform: translate(-50%, 0) scale(1); }\n 25% { transform: translate(-50%, -5px) scale(1.1); }\n 50% { transform: translate(-50%, 0) scale(1); }\n 75% { transform: translate(-50%, 5px) scale(1.1); }\n 100% { transform: translate(-50%, 0) scale(1); filter: drop-shadow(0 0 8px #0066ff); }\n}\n\n.guideai-icon {\n width: 60%;\n height: 60%;\n min-width: 16px;\n min-height: 16px;\n max-width: 40px;\n max-height: 40px;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n}\n\n.guideai-icon.initializing {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><path fill=\"%23808080\" d=\"M304 48c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-48 368c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm208-208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zM96 256c0-26.51-21.49-48-48-48S0 229.49 0 256s21.49 48 48 48 48-21.49 48-48zm12.922 99.078c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.491-48-48-48zm294.156 0c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.49-48-48-48zM108.922 60.922c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.491-48-48-48z\"/></svg>');\n}\n\n.guideai-icon.microphone {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 352 512\"><path fill=\"%230000FF\" d=\"M176 352c53.02 0 96-42.98 96-96V96c0-53.02-42.98-96-96-96S80 42.98 80 96v160c0 53.02 42.98 96 96 96zm160-160h-16c-8.84 0-16 7.16-16 16v48c0 74.8-64.49 134.82-140.79 127.38C96.71 376.89 48 317.11 48 250.3V208c0-8.84-7.16-16-16-16H16c-8.84 0-16 7.16-16 16v40.16c0 89.64 63.97 169.55 152 181.69V464H96c-8.84 0-16 7.16-16 16v16c0 8.84 7.16 16 16 16h160c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16h-56v-33.77C285.71 418.47 352 344.9 352 256v-48c0-8.84-7.16-16-16-16z\"/></svg>');\n}\n\n.guideai-icon.recording {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><circle cx=\"256\" cy=\"256\" r=\"128\" fill=\"%23FF0000\"/><circle cx=\"256\" cy=\"256\" r=\"200\" stroke=\"%23FF0000\" stroke-width=\"20\" fill=\"none\"/></svg>');\n}\n\n.guideai-icon.processing {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><path fill=\"%23FFA500\" d=\"M304 48c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-48 368c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm208-208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zM96 256c0-26.51-21.49-48-48-48S0 229.49 0 256s21.49 48 48 48 48-21.49 48-48zm12.922 99.078c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.491-48-48-48zm294.156 0c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.49-48-48-48zM108.922 60.922c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.491-48-48-48z\"/></svg>');\n}\n\n.guideai-icon.playing {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"%23008000\" d=\"M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z\"/></svg>');\n}\n\n.guideai-icon.text-mode {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"%230066ff\" d=\"M20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h4l4 4 4-4h4c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM7 10v2h2v-2H7zm6 2h-2v-2h2v2zm4 0h-2v-2h2v2z\"/></svg>');\n}\n\n.guideai-icon.voice-mode {\n background-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 352 512\"><path fill=\"%23008000\" d=\"M176 352c53.02 0 96-42.98 96-96V96c0-53.02-42.98-96-96-96S80 42.98 80 96v160c0 53.02 42.98 96 96 96zm160-160h-16c-8.84 0-16 7.16-16 16v48c0 74.8-64.49 134.82-140.79 127.38C96.71 376.89 48 317.11 48 250.3V208c0-8.84-7.16-16-16-16H16c-8.84 0-16 7.16-16 16v40.16c0 89.64 63.97 169.55 152 181.69V464H96c-8.84 0-16 7.16-16 16v16c0 8.84 7.16 16 16 16h160c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16h-56v-33.77C285.71 418.47 352 344.9 352 256v-48c0-8.84-7.16-16-16-16z\"/></svg>');\n}\n\n\n/* Onboarding styles */\n.guideai-onboarding {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n background: white;\n border-radius: 12px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n width: 300px;\n max-width: 90vw;\n z-index: 1002;\n animation: onboarding-fade-in 0.3s ease-out;\n}\n\n.guideai-onboarding.above {\n bottom: calc(100% + 15px);\n}\n\n.guideai-onboarding.below {\n top: calc(100% + 15px);\n}\n\n.guideai-onboarding.above::after {\n content: '';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-top: 8px solid white;\n filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));\n}\n\n.guideai-onboarding.below::after {\n content: '';\n position: absolute;\n bottom: 100%;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-bottom: 8px solid white;\n filter: drop-shadow(0 -2px 4px rgba(0, 0, 0, 0.1));\n}\n\n@keyframes onboarding-fade-in {\n from { opacity: 0; transform: translateX(-50%) translateY(-10px); }\n to { opacity: 1; transform: translateX(-50%) translateY(0); }\n}\n\n.guideai-onboarding-content {\n padding: 16px;\n position: relative;\n}\n\n.guideai-onboarding-close {\n position: absolute;\n top: 10px;\n right: 10px;\n background: none;\n border: none;\n font-size: 20px;\n cursor: pointer;\n color: #999;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n}\n\n.guideai-onboarding-close:hover {\n background: #f5f5f5;\n color: #333;\n}\n\n.guideai-onboarding-step {\n text-align: center;\n margin-bottom: 12px;\n}\n\n.guideai-onboarding-icon {\n font-size: 32px;\n margin-bottom: 8px;\n display: inline-block;\n}\n\n.guideai-onboarding-step h3 {\n margin: 0 0 8px;\n font-size: 16px;\n color: #333;\n font-weight: 600;\n}\n\n.guideai-onboarding-step p {\n margin: 0;\n font-size: 13px;\n color: #666;\n line-height: 1.4;\n}\n\n.guideai-onboarding-dots {\n display: flex;\n justify-content: center;\n margin: 12px 0;\n}\n\n.guideai-onboarding-dots .dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #ddd;\n margin: 0 4px;\n transition: all 0.3s ease;\n}\n\n.guideai-onboarding-dots .dot.active {\n background: #0066ff;\n transform: scale(1.2);\n}\n\n.guideai-onboarding-next {\n display: block;\n width: 100%;\n padding: 10px;\n background: #0066ff;\n color: white;\n border: none;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.2s ease;\n}\n\n.guideai-onboarding-next:hover {\n background: #0055cc;\n}\n\n/* Transcript Box Styles */\n.guideai-transcript-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: transparent;\n display: flex;\n justify-content: flex-end;\n align-items: flex-end;\n padding-bottom: 40px;\n padding-right: 40px;\n z-index: 10000;\n animation: transcript-fade-in 0.3s ease-out;\n pointer-events: none;\n}\n\n.guideai-transcript-box {\n background: rgba(40, 44, 52, 0.85);\n backdrop-filter: blur(20px);\n -webkit-backdrop-filter: blur(20px);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 16px;\n box-shadow: \n 0 8px 32px rgba(0, 0, 0, 0.3),\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n width: 280px;\n max-height: 280px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: transcript-slide-up 0.4s ease-out;\n pointer-events: auto;\n margin-right: 60px;\n position: relative;\n}\n\n.guideai-transcript-box::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 1px;\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);\n border-radius: 16px 16px 0 0;\n}\n\n\n\n.guideai-transcript-messages {\n flex: 1;\n overflow-y: auto;\n padding: 8px 12px;\n max-height: 200px;\n}\n\n.guideai-transcript-messages::-webkit-scrollbar {\n width: 6px;\n}\n\n.guideai-transcript-messages::-webkit-scrollbar-track {\n background: rgba(0, 0, 0, 0.05);\n border-radius: 3px;\n}\n\n.guideai-transcript-messages::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.2);\n border-radius: 3px;\n}\n\n.guideai-transcript-messages::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.3);\n}\n\n.guideai-transcript-empty {\n text-align: center;\n padding: 20px 12px;\n color: rgba(255, 255, 255, 0.6);\n}\n\n.guideai-transcript-empty-icon {\n font-size: 24px;\n margin-bottom: 8px;\n opacity: 0.5;\n}\n\n.guideai-transcript-empty p {\n margin: 0;\n font-size: 11px;\n color: rgba(255, 255, 255, 0.6);\n}\n\n.guideai-transcript-message {\n margin-bottom: 8px;\n animation: message-fade-in 0.3s ease-out;\n}\n\n.guideai-transcript-message.human {\n text-align: right;\n}\n\n.guideai-transcript-message.guideai {\n text-align: left;\n}\n\n.guideai-transcript-message-content {\n display: inline-block;\n max-width: 85%;\n padding: 6px 10px;\n border-radius: 12px;\n position: relative;\n}\n\n.guideai-transcript-message.human .guideai-transcript-message-content {\n background: rgba(255, 255, 255, 0.15);\n color: rgba(255, 255, 255, 0.95);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-bottom-right-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n\n.guideai-transcript-message.guideai .guideai-transcript-message-content {\n background: rgba(0, 0, 0, 0.1);\n color: rgba(255, 255, 255, 0.9);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-bottom-left-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n\n.guideai-transcript-message-sender {\n font-size: 9px;\n font-weight: 600;\n margin-bottom: 2px;\n opacity: 0.8;\n}\n\n.guideai-transcript-message-text {\n font-size: 11px;\n line-height: 1.3;\n word-wrap: break-word;\n}\n\n.guideai-transcript-message-time {\n font-size: 8px;\n opacity: 0.6;\n margin-top: 2px;\n}\n\n\n\n@keyframes transcript-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@keyframes transcript-slide-up {\n from { \n opacity: 0; \n transform: translateX(40px) scale(0.95); \n }\n to { \n opacity: 1; \n transform: translateX(0) scale(1); \n }\n}\n\n@keyframes message-fade-in {\n from { \n opacity: 0; \n transform: translateY(10px); \n }\n to { \n opacity: 1; \n transform: translateY(0); \n }\n}\n\n/* Transcript Toggle Button Styles - positioned at top of transcript area */\n.guideai-transcript-toggle-button {\n position: fixed;\n bottom: 60px;\n right: 40px;\n width: 36px;\n height: 36px;\n background: rgba(40, 44, 52, 0.9);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);\n transition: all 0.2s ease;\n z-index: 10001;\n font-size: 14px;\n padding: 0;\n color: rgba(255, 255, 255, 0.9);\n animation: toggle-fade-in 0.3s ease-out;\n}\n\n.guideai-transcript-toggle-button:hover {\n background: rgba(40, 44, 52, 1);\n transform: scale(1.1);\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);\n}\n\n.guideai-transcript-toggle-button:active {\n transform: scale(0.95);\n}\n\n.guideai-transcript-toggle-icon {\n display: inline-block;\n transition: all 0.2s ease;\n filter: none;\n}\n\n/* Position transcript toggle button based on transcript position */\n.guideai-transcript-overlay {\n pointer-events: none;\n}\n\n.guideai-transcript-toggle-button {\n pointer-events: auto;\n}\n\n/* Input Options Container - Two Stage Layout */\n.guideai-input-options {\n display: flex;\n align-items: center;\n gap: 12px;\n position: relative;\n animation: options-slide-in 0.4s ease-out;\n}\n\n@keyframes options-slide-in {\n 0% {\n opacity: 0;\n transform: scale(0.8);\n }\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n/* Individual Input Option Button */\n.guideai-input-option {\n width: 50px;\n height: 50px;\n background: rgba(255, 255, 255, 0.9);\n border: 2px solid rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n transition: all 0.3s ease;\n font-size: 18px;\n padding: 0;\n position: relative;\n}\n\n.guideai-input-option:hover:not(:disabled) {\n background: rgba(255, 255, 255, 1);\n transform: scale(1.1);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);\n}\n\n.guideai-input-option:active:not(:disabled) {\n transform: scale(0.95);\n}\n\n.guideai-input-option:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n}\n\n/* Voice Option Specific Styling */\n.guideai-input-option.voice-option {\n background: linear-gradient(135deg, rgba(76, 175, 80, 0.1), rgba(139, 195, 74, 0.1));\n border-color: rgba(76, 175, 80, 0.3);\n}\n\n.guideai-input-option.voice-option:hover:not(:disabled) {\n background: linear-gradient(135deg, rgba(76, 175, 80, 0.2), rgba(139, 195, 74, 0.2));\n border-color: rgba(76, 175, 80, 0.5);\n}\n\n/* Text Option Specific Styling */\n.guideai-input-option.text-option {\n background: linear-gradient(135deg, rgba(33, 150, 243, 0.1), rgba(63, 81, 181, 0.1));\n border-color: rgba(33, 150, 243, 0.3);\n}\n\n.guideai-input-option.text-option:hover:not(:disabled) {\n background: linear-gradient(135deg, rgba(33, 150, 243, 0.2), rgba(63, 81, 181, 0.2));\n border-color: rgba(33, 150, 243, 0.5);\n}\n\n.guideai-input-option-icon {\n display: inline-block;\n transition: all 0.2s ease;\n filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1));\n}\n\n/* Text Input integrated into Transcript Box */\n.guideai-transcript-text-input {\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n padding: 12px;\n display: flex;\n gap: 8px;\n align-items: flex-end;\n background: rgba(0, 0, 0, 0.02);\n border-radius: 0 0 16px 16px;\n animation: text-input-fade-in 0.3s ease-out;\n}\n\n.guideai-transcript-input-field {\n flex: 1;\n background: rgba(255, 255, 255, 0.15);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 8px;\n padding: 8px 12px;\n color: rgba(255, 255, 255, 0.95);\n font-size: 12px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n resize: none;\n outline: none;\n transition: all 0.2s ease;\n min-height: 32px;\n}\n\n.guideai-transcript-input-field::placeholder {\n color: rgba(255, 255, 255, 0.6);\n}\n\n.guideai-transcript-input-field:focus {\n border-color: rgba(255, 255, 255, 0.4);\n background: rgba(255, 255, 255, 0.2);\n box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.2);\n}\n\n.guideai-transcript-send-button {\n background: rgba(255, 255, 255, 0.15);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 6px;\n padding: 6px 10px;\n color: rgba(255, 255, 255, 0.9);\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 36px;\n height: 32px;\n}\n\n.guideai-transcript-send-button:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.25);\n border-color: rgba(255, 255, 255, 0.3);\n transform: translateY(-1px);\n}\n\n.guideai-transcript-send-button:active:not(:disabled) {\n transform: translateY(0);\n}\n\n.guideai-transcript-send-button:disabled {\n background: rgba(255, 255, 255, 0.05);\n border-color: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.4);\n cursor: not-allowed;\n transform: none;\n}\n\n.guideai-transcript-send-icon {\n font-size: 11px;\n}\n\n/* Animation for text input appearance */\n@keyframes text-input-fade-in {\n from { \n opacity: 0; \n transform: translateY(10px); \n }\n to { \n opacity: 1; \n transform: translateY(0); \n }\n}\n\n@keyframes toggle-fade-in {\n from { \n opacity: 0; \n transform: scale(0.8); \n }\n to { \n opacity: 1; \n transform: scale(1); \n }\n}\n\n\n`; ","// Storage data structures for conversation persistence\nexport interface StoredMessage {\n content: string;\n sender: 'GUIDEAI' | 'HUMAN';\n timestamp: number;\n}\n\nexport interface StoredConversation {\n conversationId: string;\n messages: StoredMessage[];\n timestamp: number;\n organizationKey: string;\n}\n\nexport const CONVERSATION_STORAGE_KEY = 'guideai_conversation';\nexport const CONVERSATION_EXPIRY_MINUTES = 30;\nexport const MAX_STORED_MESSAGES = 100; // Increased to keep more conversation history\n\nexport const isLocalStorageAvailable = (): boolean => {\n try {\n const testKey = '__storage_test__';\n localStorage.setItem(testKey, testKey);\n localStorage.removeItem(testKey);\n return true;\n } catch (e) {\n return false;\n }\n};\n\nconst isValidConversation = (data: any): data is StoredConversation => {\n return (\n data &&\n typeof data === 'object' &&\n typeof data.conversationId === 'string' &&\n Array.isArray(data.messages) &&\n typeof data.timestamp === 'number' &&\n typeof data.organizationKey === 'string' &&\n data.messages.every((msg: any) => (\n typeof msg === 'object' &&\n typeof msg.content === 'string' &&\n (msg.sender === 'HUMAN' || msg.sender === 'GUIDEAI') &&\n typeof msg.timestamp === 'number'\n ))\n );\n};\n\nexport const isConversationExpired = (conversation: StoredConversation): boolean => {\n const expiryTime = CONVERSATION_EXPIRY_MINUTES * 60 * 1000; // convert to milliseconds\n const now = Date.now();\n return (now - conversation.timestamp) > expiryTime;\n};\n\nconst handleStorageError = (error: unknown, operation: string): void => {\n console.error(`Storage error during ${operation}:`, error);\n \n // Check if it's a quota exceeded error\n if (error instanceof DOMException && \n (error.name === 'QuotaExceededError' || \n error.name === 'NS_ERROR_DOM_QUOTA_REACHED')) {\n \n // Try to free up space by removing oldest messages instead of clearing everything\n try {\n const conversation = loadConversationFromStorage();\n if (conversation && conversation.messages.length > 5) {\n // Remove oldest 5 messages\n conversation.messages = conversation.messages.slice(5);\n saveConversationToStorage(conversation);\n console.warn('Storage quota exceeded. Removed oldest 5 messages to free space.');\n } else if (conversation) {\n // If less than 5 messages, clear everything\n clearConversationStorage();\n console.warn('Storage quota exceeded. Cleared conversation data.');\n }\n } catch (cleanupError) {\n console.error('Failed to clean up storage:', cleanupError);\n }\n }\n};\n\nexport const saveConversationToStorage = (conversation: StoredConversation): void => {\n if (!isLocalStorageAvailable()) {\n console.warn('localStorage is not available. Conversation persistence disabled.');\n return;\n }\n \n try {\n // Limit to last MAX_STORED_MESSAGES\n if (conversation.messages.length > MAX_STORED_MESSAGES) {\n conversation.messages = conversation.messages.slice(-MAX_STORED_MESSAGES);\n }\n \n // Update timestamp\n conversation.timestamp = Date.now();\n \n localStorage.setItem(CONVERSATION_STORAGE_KEY, JSON.stringify(conversation));\n } catch (error) {\n handleStorageError(error, 'save');\n }\n};\n\nexport const loadConversationFromStorage = (): StoredConversation | null => {\n if (!isLocalStorageAvailable()) {\n console.warn('localStorage is not available. Conversation persistence disabled.');\n return null;\n }\n \n try {\n const storedData = localStorage.getItem(CONVERSATION_STORAGE_KEY);\n if (!storedData) return null;\n \n const parsedData = JSON.parse(storedData);\n \n // Validate the data structure\n if (!isValidConversation(parsedData)) {\n console.warn('Corrupted conversation data found. Clearing storage.');\n clearConversationStorage();\n return null;\n }\n \n return parsedData;\n } catch (error) {\n handleStorageError(error, 'load');\n // Clear corrupted data on any parsing errors\n clearConversationStorage();\n return null;\n }\n};\n\nexport const clearConversationStorage = (): void => {\n if (!isLocalStorageAvailable()) {\n return;\n }\n \n try {\n localStorage.removeItem(CONVERSATION_STORAGE_KEY);\n } catch (error) {\n handleStorageError(error, 'clear');\n }\n};\n\nexport const addMessageToStorage = (message: StoredMessage, conversationId: string, organizationKey: string): void => {\n if (!isLocalStorageAvailable()) {\n console.warn('localStorage is not available. Message persistence disabled.');\n return;\n }\n \n try {\n let conversation = loadConversationFromStorage();\n \n if (!conversation) {\n conversation = {\n conversationId,\n messages: [],\n timestamp: Date.now(),\n organizationKey\n };\n }\n \n // Check for duplicate messages to prevent adding the same message twice\n const isDuplicate = conversation.messages.some(existingMsg => \n existingMsg.content === message.content && \n existingMsg.sender === message.sender &&\n Math.abs(existingMsg.timestamp - message.timestamp) < 5000 // Within 5 seconds\n );\n \n if (!isDuplicate) {\n conversation.messages.push(message);\n conversation.conversationId = conversationId;\n conversation.organizationKey = organizationKey;\n \n saveConversationToStorage(conversation);\n } else {\n console.log('Duplicate message detected, skipping:', message.content.substring(0, 50));\n }\n } catch (error) {\n console.error('Error adding message to storage:', error);\n }\n};\n\nexport const checkForStoredConversation = (currentOrganizationKey: string): {\n shouldRestore: boolean;\n conversationId: string | null;\n messages: StoredMessage[] | null;\n} => {\n const storedConversation = loadConversationFromStorage();\n \n if (!storedConversation) {\n return { shouldRestore: false, conversationId: null, messages: null };\n }\n \n // Check if conversation is expired - if so, clear it automatically\n if (isConversationExpired(storedConversation)) {\n clearConversationStorage();\n return { shouldRestore: false, conversationId: null, messages: null };\n }\n \n // Check if organization key matches\n if (storedConversation.organizationKey !== currentOrganizationKey) {\n return { shouldRestore: false, conversationId: null, messages: null };\n }\n \n return {\n shouldRestore: true,\n conversationId: storedConversation.conversationId,\n messages: storedConversation.messages\n };\n};\n\nexport const formatConversationContext = (messages: StoredMessage[], maxMessages: number = 10): string => {\n // Take only the last N messages to avoid context length issues\n const recentMessages = messages.slice(-maxMessages);\n \n if (recentMessages.length === 0) {\n return '';\n }\n \n // Filter out very short or empty messages\n const meaningfulMessages = recentMessages.filter(msg => \n msg.content && msg.content.trim().length > 3\n );\n \n if (meaningfulMessages.length === 0) {\n return '';\n }\n \n // Format messages into a readable context string\n const formattedMessages = meaningfulMessages.map(msg => {\n const sender = msg.sender === 'HUMAN' ? 'User' : 'Assistant';\n return `${sender}: ${msg.content.trim()}`;\n }).join('\\n');\n \n return formattedMessages;\n}; ","// Default prompt for Guide AI\nexport const DEFAULT_PROMPT = `you are Guide AI.\n Your role is to answer any question directly and succinctly that a user has. NEVER DIRECTLY MENTION THE SCREENSHOT, but use its information as much as possible to target your responses.\n If nothing is asked, then your goal is to generally assist them.\n IMPORTANT: NEVER answer in more than 10 words. Always be concise and limit answers to 1 sentence maximum. Be simple and as short as possible.\n Your job is to help them get it done through asking more and more targeted specific questions.`;\n\n// WebRTC message types to ignore in logging\nexport const IGNORE_MESSAGE_TYPES = [\n \"delta\", \n \"rate_limits\", \n \"input_audio_buffer\",\n \"response.audio.done\", \n \"response.output_item\", \n \"response.content_part\", \n \"output_audio_buffer\",\n \"response.created\", \n \"session.created\",\n \"conversation.item.truncated\"\n];\n\n// API endpoints\nexport const GUIDE_AI_API_BASE = 'https://www.getguide.ai/api';\nexport const OPENAI_REALTIME_BASE = 'https://api.openai.com/v1/realtime';\nexport const OPENAI_REALTIME_MODEL = \"gpt-4o-realtime-preview-2024-12-17\";\n\n// Gemini API - Note: This should be moved to environment variables in production\nexport const GEMINI_API_KEY = 'AIzaSyBiFyzjYVupLyk8BdmfWzBL1GbzX8OUdPc';\nexport const GEMINI_API_ENDPOINT = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent'; ","module.exports = __WEBPACK_EXTERNAL_MODULE__156__;","import { StoredMessage, addMessageToStorage } from './messageStorage';\nimport { GUIDE_AI_API_BASE } from './constants';\nimport { UserMetadata, MetadataUpdate } from '../types/metadata.types';\n\n// Type for the conversation creation response (now includes token and prompt)\ninterface ConversationData {\n id: string;\n ephemeralToken: string;\n prompt: string;\n}\n\n// Create a new conversation (now also returns ephemeral token + prompt)\nexport const createNewConversation = async (\n organizationKey: string,\n onError: (error: Error, context: string) => void\n): Promise<ConversationData | null> => {\n try {\n const now = new Date();\n const response = await fetch(`${GUIDE_AI_API_BASE}/initialize-session`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n organizationKey,\n userId: 'anonymous',\n date: now.toISOString().split('T')[0],\n time: now.toTimeString().split(' ')[0],\n messages: []\n })\n });\n \n if (!response.ok) {\n const errorText = await response.text().catch(() => 'No error details available');\n console.error(`Conversation creation failed with status ${response.status}:`, errorText);\n throw new Error(`Failed to create conversation: ${response.status} - ${errorText}`);\n }\n \n const conversationData = await response.json();\n console.log('Conversation created:', conversationData.id);\n return conversationData;\n } catch (error) {\n console.error('Error creating conversation:', error);\n onError(error as Error, 'Creating conversation');\n return null;\n }\n};\n\n// Log a message to the conversation via API and local storage\nexport const logMessage = async (\n content: string, \n sender: 'GUIDEAI' | 'HUMAN',\n conversationId: string | null,\n organizationKey: string,\n onError: (error: Error, context: string) => void\n): Promise<void> => {\n if (!conversationId) return;\n \n try {\n const response = await fetch(`${GUIDE_AI_API_BASE}/conversations/${conversationId}/messages`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({ content, sender })\n });\n \n if (!response.ok) {\n throw new Error(`Failed to log message: ${response.status} ${response.statusText}`);\n }\n \n const message: StoredMessage = {\n content,\n sender,\n timestamp: Date.now()\n };\n \n addMessageToStorage(message, conversationId, organizationKey);\n } catch (error) {\n console.error('Error logging message:', error);\n onError(error as Error, 'Logging message');\n }\n};\n\n// Send metadata updates in batch\nexport const sendMetadataUpdates = async (\n updates: MetadataUpdate[],\n organizationKey: string,\n onError: (error: Error, context: string) => void\n): Promise<boolean> => {\n if (updates.length === 0) return true;\n\n try {\n const response = await fetch(`${GUIDE_AI_API_BASE}/metadata-updates`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n organizationKey,\n updates,\n batchTimestamp: Date.now(),\n updateCount: updates.length\n })\n });\n\n if (!response.ok) {\n throw new Error(`Failed to send metadata updates: ${response.status} ${response.statusText}`);\n }\n\n console.log(`Sent ${updates.length} metadata updates successfully`);\n return true;\n } catch (error) {\n console.error('Error sending metadata updates:', error);\n onError(error as Error, 'Sending metadata updates');\n return false;\n }\n}; ","// Import React normally, but use a helper function to handle possible duplicates\nimport React from 'react';\nimport { \n StoredMessage, \n clearConversationStorage,\n checkForStoredConversation, \n formatConversationContext \n} from './utils/messageStorage';\n\n// Import our refactored modules\nimport { GuideAIProps, RecordingStatus, UseStateHook, UseEffectHook, UseRefHook, UseCallbackHook, PopupPosition } from './types/GuideAI.types';\nimport { DEFAULT_PROMPT, IGNORE_MESSAGE_TYPES, OPENAI_REALTIME_BASE, OPENAI_REALTIME_MODEL, GEMINI_API_KEY, GEMINI_API_ENDPOINT } from './utils/constants';\nimport { injectStyles, calculateOptimalPosition } from './utils/ui';\nimport { highlightElement } from './utils/highlight';\nimport { createNewConversation, logMessage } from './utils/api';\nimport WelcomeBubble from './components/WelcomeBubble';\nimport Onboarding from './components/Onboarding';\nimport TranscriptBox from './components/TranscriptBox';\nimport { guideAIStyles } from './styles/GuideAI.styles';\nimport { EventTracker, UserMetadataTracker, UserMetadata } from './metric';\nimport { sendMetadataUpdates } from './utils/api';\n\n// Get React hooks safely, avoiding duplicate React issues - moved outside component\nconst getReactHooks = () => {\n // Try to use the React instance from window if available (for react-scripts)\n if (typeof window !== 'undefined' && (window as any).React) {\n return {\n useState: (window as any).React.useState as UseStateHook,\n useEffect: (window as any).React.useEffect as UseEffectHook,\n useRef: (window as any).React.useRef as UseRefHook,\n useMemo: (window as any).React.useMemo,\n useCallback: (window as any).React.useCallback as UseCallbackHook\n };\n }\n // Otherwise use the imported React\n return {\n useState: React.useState,\n useEffect: React.useEffect,\n useRef: React.useRef,\n useMemo: React.useMemo,\n useCallback: React.useCallback as UseCallbackHook\n };\n};\n\n// Cache the hooks to ensure consistent instances across renders\nconst cachedHooks = getReactHooks();\n\nconst GuideAIComponent = (props: GuideAIProps) => {\n const {\n organizationKey,\n position,\n onError = console.error,\n metadata: metadataOptions,\n transcript: transcriptOptions,\n input: inputOptions\n } = props;\n\n // Use cached hooks to ensure consistent instances\n const hooks = cachedHooks;\n\n const [status, setStatus] = hooks.useState<RecordingStatus>('idle');\n const [isClient, setIsClient] = hooks.useState(false);\n\n const [isHighlighting, setIsHighlighting] = hooks.useState(false);\n const [hasInteracted, setHasInteracted] = hooks.useState(false);\n const [prompt, setPrompt] = hooks.useState<string | null>(null);\n const [isSessionReady, setIsSessionReady] = hooks.useState(false);\n const [isConnecting, setIsConnecting] = hooks.useState(false);\n const [showOnboarding, setShowOnboarding] = hooks.useState(false);\n const [popupPosition, setPopupPosition] = hooks.useState<PopupPosition>('above');\n const conversationIdRef = hooks.useRef<string | null>(null);\n\n const componentRef = hooks.useRef<HTMLDivElement>(null);\n const peerConnectionRef = hooks.useRef<RTCPeerConnection | null>(null);\n const dataChannelRef = hooks.useRef<RTCDataChannel | null>(null);\n const hasCreatedConversationRef = hooks.useRef(false);\n const mediaStreamRef = hooks.useRef<MediaStream | null>(null);\n const audioElementRef = hooks.useRef<HTMLAudioElement | null>(null);\n const [ephemeralToken, setEphemeralToken] = hooks.useState<string | null>(null);\n const hasInitializedRef = hooks.useRef(false);\n const isUnmountingRef = hooks.useRef(false);\n const [isConversationActive, setIsConversationActive] = hooks.useState(false);\n const [restoredMessages, setRestoredMessages] = hooks.useState<StoredMessage[]>([]);\n const [showTranscript, setShowTranscript] = hooks.useState(\n transcriptOptions?.enabled !== false // Default to true unless explicitly disabled\n );\n const [allMessages, setAllMessages] = hooks.useState<StoredMessage[]>([]);\n const [inputMode, setInputMode] = hooks.useState<'voice' | 'text'>(\n inputOptions?.defaultMode || 'voice'\n );\n const [textInput, setTextInput] = hooks.useState('');\n const [showTextInput, setShowTextInput] = hooks.useState(false);\n\n const hasAttemptedAutoStartRef = hooks.useRef(false);\n const initializationAttemptedRef = hooks.useRef(false);\n\n\n\n // ===== METADATA AND EVENT TRACKING =====\n \n // Create event tracker - memoized to prevent recreation\n const eventTracker = hooks.useMemo(() => {\n const customerId = metadataOptions?.initialUserData?.userId || 'anonymous';\n const organizationId = metadataOptions?.initialUserData?.organizationKey || 'default';\n const customerType = metadataOptions?.initialUserData?.userType || 'user';\n \n return new EventTracker({ customerId, organizationId, customerType, organizationKey });\n }, [organizationKey]); // Only depend on organizationKey\n\n // Create metadata tracker - memoized to prevent recreation\n const metadataTracker = hooks.useMemo(() => \n new UserMetadataTracker(organizationKey, metadataOptions?.config || {}), \n [organizationKey] // Remove onError and metadataOptions?.config from dependencies\n );\n \n // ===== API & EXTERNAL CALLS =====\n \n // Call Gemini Flash API to validate and fix JSON\n const geminiFlash = async (prompt: string): Promise<string> => {\n const response = await fetch(`${GEMINI_API_ENDPOINT}?key=${GEMINI_API_KEY}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n contents: [\n {\n parts: [\n {\n text: prompt\n }\n ]\n }\n ]\n })\n });\n \n const responseJson = await response.json();\n const content = responseJson.candidates[0].content;\n const responseText = content.parts[0].text;\n return responseText;\n };\n\n // ===== COMPONENT WRAPPER FUNCTIONS =====\n \n // Wrapper functions to maintain original signatures\n const handleCreateNewConversation = hooks.useCallback(async () => {\n if (hasCreatedConversationRef.current) return null;\n hasCreatedConversationRef.current = true;\n \n const conversationData = await createNewConversation(organizationKey, onError);\n if (conversationData) {\n conversationIdRef.current = conversationData.id;\n setEphemeralToken(conversationData.ephemeralToken);\n setPrompt(conversationData.prompt);\n return conversationData;\n }\n return null;\n }, [organizationKey]); // Removed onError from dependencies to prevent re-creation\n\n const handleLogMessage = hooks.useCallback(async (content: string, sender: 'GUIDEAI' | 'HUMAN') => {\n await logMessage(content, sender, conversationIdRef.current, organizationKey, onError);\n \n // Check if this exact message already exists to prevent duplicates\n setAllMessages(prev => {\n const lastMessage = prev[prev.length - 1];\n if (lastMessage && \n lastMessage.content === content && \n lastMessage.sender === sender) {\n // Message already exists, don't add duplicate\n return prev;\n }\n \n // Add message to local state for transcript\n const newMessage: StoredMessage = {\n content,\n sender,\n timestamp: Date.now()\n };\n return [...prev, newMessage];\n });\n }, [organizationKey]); // Removed onError from dependencies to prevent re-creation\n\n const handleHighlightElement = hooks.useCallback(async (selector: string | string[]) => {\n return highlightElement(selector, isHighlighting, setIsHighlighting, handleLogMessage);\n }, [isHighlighting, handleLogMessage]);\n\n // ===== UI UTILITIES & POSITION =====\n \n // Calculate optimal position for popups based on component location\n const getOptimalPosition = hooks.useCallback((elementHeight: number = 240, spacing: number = 15): PopupPosition => {\n if (!componentRef.current) return 'above';\n \n const rect = componentRef.current.getBoundingClientRect();\n return calculateOptimalPosition(rect, elementHeight, spacing);\n }, []);\n\n // ===== WEBRTC MANAGEMENT =====\n \n const sendMessage = (message: any) => {\n if (dataChannelRef.current?.readyState === 'open') {\n // console.log('sending message', message);\n dataChannelRef.current.send(JSON.stringify(message));\n } else {\n console.error('Data channel not open, cannot send message');\n setStatus('idle');\n }\n };\n \n const cleanupWebRTC = hooks.useCallback(() => {\n if (mediaStreamRef.current) {\n // Stop tracks completely instead of just disabling them\n mediaStreamRef.current.getAudioTracks().forEach(track => {\n track.stop();\n });\n mediaStreamRef.current = null;\n }\n \n if (dataChannelRef.current) {\n dataChannelRef.current.close();\n dataChannelRef.current = null;\n }\n \n if (peerConnectionRef.current) {\n peerConnectionRef.current.close();\n peerConnectionRef.current = null;\n }\n \n if (audioElementRef.current) {\n audioElementRef.current.srcObject = null;\n }\n \n // Reset session ready state\n setIsSessionReady(false);\n }, []);\n\n const initializeWebRTC = async (audioStream: MediaStream | null): Promise<boolean> => {\n try {\n const pc = new RTCPeerConnection();\n peerConnectionRef.current = pc;\n \n // Only add audio tracks if audioStream is provided (for voice mode)\n if (audioStream) {\n audioStream.getAudioTracks().forEach(track => {\n pc.addTrack(track, audioStream);\n });\n }\n \n // Only create audio element if we have an audio stream (voice mode)\n if (audioStream && !audioElementRef.current) {\n const audioEl = document.createElement('audio');\n audioEl.autoplay = true;\n document.body.appendChild(audioEl);\n audioElementRef.current = audioEl;\n }\n \n pc.ontrack = (e) => {\n if (audioElementRef.current && e.track.kind === 'audio') {\n const stream = new MediaStream([e.track]);\n audioElementRef.current.srcObject = stream;\n }\n };\n \n const dc = pc.createDataChannel('oai-events');\n dataChannelRef.current = dc;\n \n dc.onopen = () => { \n // Configure session based on whether we have audio stream (voice vs text mode)\n const sessionConfig: any = {\n tools: [{\n type: \"function\",\n name: \"highlight\",\n description: \"Highlight specific elements on the page to guide the user's attention\",\n parameters: {\n type: \"object\",\n properties: {\n selector: {\n oneOf: [\n {\n type: \"string\",\n description: \"CSS selector or XPath for the element to highlight (e.g., '#search-bar')\"\n },\n {\n type: \"array\",\n items: {\n type: \"string\"\n },\n description: \"List of CSS selectors or XPaths to highlight in sequence (e.g., ['#first-button', '#second-button'])\"\n }\n ],\n description: \"CSS selector(s) or XPath(s) for the element(s) to highlight. Can be a single selector string or an array of selectors to process sequentially.\"\n }\n },\n required: [\"selector\"]\n }\n }],\n tool_choice: \"auto\"\n };\n\n // Only add audio-specific config if we have an audio stream\n if (audioStream) {\n sessionConfig.turn_detection = {\n type: \"semantic_vad\",\n create_response: true,\n interrupt_response: false\n };\n sessionConfig.input_audio_transcription = {\n model: \"gpt-4o-mini-transcribe\",\n language: \"en\",\n };\n }\n\n sendMessage({\n type: \"session.update\",\n session: sessionConfig\n });\n };\n \n dc.onmessage = (e) => {\n try {\n const message = JSON.parse(e.data);\n\n switch (message.type) { \n case 'session.updated':\n // console.log('session.updated', message);\n setIsSessionReady(true);\n setIsConnecting(false);\n \n // If we have restored messages, send conversation context to AI now that session is ready\n if (restoredMessages.length > 0) {\n const conversationContext = formatConversationContext(restoredMessages, 5); // Reduce to 5 messages\n \n // Send as system context instead of user input to avoid confusion\n sendMessage({\n type: \"conversation.item.create\",\n item: {\n type: \"message\",\n role: \"system\",\n content: [{\n type: \"input_text\",\n text: `This is context from a previous conversation session. The user is continuing an existing conversation. Previous context: ${conversationContext}`\n }]\n }\n });\n \n console.log('Sent conversation context with', restoredMessages.length, 'restored messages');\n }\n break;\n\n case 'session.transcript_disabled':\n if (message.text && message.text.trim()) {\n console.log('Session transcript:', message.text);\n handleLogMessage(message.text, 'HUMAN');\n }\n break;\n \n case 'conversation.item.input_audio_transcription.completed':\n if (message.transcript && message.transcript.trim()) {\n console.log('User transcript:', message.transcript);\n // Only log if it's different from the last message to avoid duplicates\n if (allMessages.length === 0 || \n allMessages[allMessages.length - 1].content !== message.transcript) {\n handleLogMessage(message.transcript, 'HUMAN');\n }\n }\n break;\n\n case 'response.audio_transcript.done':\n if (message.transcript && message.transcript.trim()) {\n console.log('Assistant message:', message.transcript);\n // Only log if it's different from the last assistant message to avoid duplicates\n const lastMessage = allMessages[allMessages.length - 1];\n if (!lastMessage || \n lastMessage.sender !== 'GUIDEAI' ||\n lastMessage.content !== message.transcript) {\n handleLogMessage(message.transcript, 'GUIDEAI');\n }\n }\n break;\n \n case \"conversation.item.created\":\n // console.log('conversation.item.created', message);\n break;\n\n case \"input_audio_buffer.speech_started\":\n // console.log('User speaking started');\n setStatus('recording');\n break;\n\n case \"input_audio_buffer.speech_stopped\":\n // console.log('User speaking stopped');\n setStatus('processing');\n break;\n\n case 'response.done':\n // console.log('response.done', message);\n for (const out of message.response.output) {\n switch (out.type) {\n case \"message\":\n // console.log('Assistant message:', out.text);\n break;\n \n case \"function_call\":\n // console.log('function_call', out);\n if (out.name === 'highlight' && out.arguments) {\n // console.log('Tool call:', out.arguments);\n try {\n let argsToUse = out.arguments;\n // Check if the JSON string is missing a closing quote\n // try {\n // console.log(\"argsToUse\", argsToUse);\n // const parsedArgs = JSON.parse(argsToUse);\n // console.log(\"parsedArgs\", parsedArgs);\n // highlightElement(parsedArgs.selector);\n // } catch (error) {\n // console.log(\"errored, argsToUse\", argsToUse);\n const prompt = `\n Validate the following JSON string and return ONLY a correct JSON object:\n Note: The selector(s) should be either a css selector or an xpath, so modify those if invalid.\n Also, [url=''] is a valid css selector, so do not modify it if it's present.\n Do not add any other text or newlines to the response.\n It should be of the following format:\n { \"selector\": \"string\" }\n or\n { \"selector\": [\"string\", ...] }\n DO NOT add any other text or newlines to the response, it should begin and end with curly braces.\n DO NOT add '''json to the response.\n The JSON string is:\n ${argsToUse}\n `\n geminiFlash(prompt).then(response => {\n response = response.replace(\"```json\", \"\").replace(\"```\", \"\").trim();\n // console.log(\"response\", response);\n const parsedArgs = JSON.parse(response);\n handleHighlightElement(parsedArgs.selector);\n }).catch(err => {\n console.error(\"Error calling Gemini:\", err);\n });\n // }\n\n\n } catch (error) {\n console.error('Error parsing function arguments:', error);\n console.log(out.arguments);\n handleLogMessage('Error parsing function arguments: ' + out.arguments, 'GUIDEAI');\n }\n }\n \n sendMessage({\n type: \"conversation.item.create\",\n item: {\n type: \"function_call_output\",\n call_id: out.call_id,\n output: JSON.stringify(true)\n }\n });\n\n sendMessage({\n type: 'response.create',\n });\n break;\n }\n }\n \n break;\n\n case \"response.function_call_arguments.delta\":\n // console.log('response.function_call_arguments.delta', message);\n break;\n\n case \"response.function_call_arguments.done\":\n // console.log('response.function_call_arguments.done', message);\n break;\n\n case \"output_audio_buffer.started\":\n setStatus('playing');\n break;\n\n case \"output_audio_buffer.stopped\":\n // console.log('output_audio_buffer.stopped');\n setStatus('recording');\n \n break;\n\n case 'error':\n if (message.error.code === 'session_expired') {\n console.error('Session expired:', message);\n // Batch state updates to prevent mounting/unmounting loops\n setTimeout(() => {\n setStatus('idle');\n setIsConnecting(false);\n setIsConversationActive(false);\n setEphemeralToken(null); // Clear expired token so reconnection gets fresh one\n hasCreatedConversationRef.current = false; // Allow creating new conversation\n }, 0);\n break;\n }\n console.error('OpenAI API error:', message);\n onError(new Error(message.error.message || 'Unknown API error'), 'OpenAI API error');\n // Batch state updates to prevent mounting/unmounting loops\n setTimeout(() => {\n setStatus('idle');\n setIsConnecting(false);\n setIsConversationActive(false);\n setEphemeralToken(null); // Clear token in case of auth-related errors\n hasCreatedConversationRef.current = false; // Allow creating new conversation\n }, 0);\n break;\n \n default:\n if (!IGNORE_MESSAGE_TYPES.some(fragment => message.type.includes(fragment))) {\n console.log('Unhandled:', message.type, message);\n }\n }\n } catch (error) {\n console.error('Error handling WebRTC message:', error);\n // Batch state updates to prevent mounting/unmounting loops\n setTimeout(() => {\n setStatus('idle');\n setIsConversationActive(false);\n }, 0);\n }\n };\n \n // Start the session using SDP\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n \n if (!pc.localDescription || !pc.localDescription.sdp) {\n throw new Error('Failed to create local SDP offer');\n }\n \n const baseUrl = OPENAI_REALTIME_BASE;\n const model = OPENAI_REALTIME_MODEL;\n \n \n const sdpResponse = await fetch(`${baseUrl}?model=${model}`, {\n method: 'POST',\n body: pc.localDescription.sdp,\n headers: {\n Authorization: `Bearer ${ephemeralToken}`,\n 'Content-Type': 'application/sdp'\n },\n });\n \n if (!sdpResponse.ok) {\n const errorText = await sdpResponse.text().catch(() => 'No error details available');\n console.error('WebRTC connection failed with status:', sdpResponse.status);\n console.error('Error details:', errorText);\n \n // Clear token on authentication failures\n if (sdpResponse.status === 401 || sdpResponse.status === 403) {\n setEphemeralToken(null);\n }\n \n throw new Error(`Failed to connect to OpenAI WebRTC: ${sdpResponse.status} - ${errorText}`);\n }\n \n const answerSdp = await sdpResponse.text();\n \n const answer = {\n type: 'answer',\n sdp: answerSdp,\n };\n \n await pc.setRemoteDescription(answer as RTCSessionDescriptionInit);\n \n return true;\n } catch (error) {\n console.error('Error initializing WebRTC:', error);\n onError(error as Error, 'WebRTC initialization failed');\n setIsConnecting(false);\n return false;\n }\n };\n\n // ===== SESSION MANAGEMENT =====\n \n const startConversationSession = hooks.useCallback(async () => {\n try {\n setStatus('processing');\n \n if (peerConnectionRef.current && dataChannelRef.current?.readyState === 'open' && mediaStreamRef.current) {\n mediaStreamRef.current.getAudioTracks().forEach(track => {\n track.enabled = true;\n });\n setStatus('recording');\n return true;\n } else {\n cleanupWebRTC();\n \n try {\n setIsConnecting(true);\n \n // Ensure we have a valid token (get fresh one if needed)\n if (!ephemeralToken) {\n console.log('No token available, getting fresh token...');\n const conversationData = await handleCreateNewConversation();\n if (!conversationData) {\n console.error('Failed to get fresh token');\n setIsConnecting(false);\n setStatus('idle');\n return false;\n }\n }\n \n let audioStream: MediaStream | null = null;\n \n // Always attempt microphone access for voice functionality\n if (true) {\n try {\n audioStream = await navigator.mediaDevices.getUserMedia({ \n audio: {\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n channelCount: 1,\n sampleRate: 48000,\n }\n });\n mediaStreamRef.current = audioStream;\n console.log('Microphone access granted - audio tracks:', audioStream.getAudioTracks().length);\n } catch (micError) {\n console.error('Microphone access failed:', micError);\n console.log('Voice functionality will not be available - continuing with text-only mode');\n // Continue without microphone for text-only mode\n }\n }\n \n const initialized = await initializeWebRTC(audioStream);\n \n if (!initialized) {\n // Clean up if initialization fails\n if (audioStream) {\n audioStream.getAudioTracks().forEach(track => {\n track.stop();\n });\n mediaStreamRef.current = null;\n }\n setStatus('idle');\n setIsConnecting(false);\n return false;\n }\n \n // Set appropriate status based on whether we have audio\n if (audioStream) {\n setStatus('recording');\n } else {\n setStatus('idle'); // Text-only mode, no recording status needed\n }\n return true;\n } catch (error) {\n console.error('Error during conversation setup:', error);\n onError(error as Error, 'Microphone or WebRTC setup failed');\n setStatus('idle');\n setIsConnecting(false);\n return false;\n }\n }\n } catch (error) {\n setStatus('idle');\n setIsConnecting(false);\n onError(error as Error, 'Starting conversation failed');\n return false;\n }\n }, [ephemeralToken]); // Remove onError from dependencies to prevent re-creation\n\n const endConversationSession = hooks.useCallback(() => {\n if (!isClient) return;\n \n if (mediaStreamRef.current) {\n mediaStreamRef.current.getAudioTracks().forEach(track => {\n track.stop();\n });\n }\n \n cleanupWebRTC();\n setStatus('idle');\n \n // Clear localStorage when conversation is explicitly ended\n clearConversationStorage();\n \n // Reset restored messages state\n setRestoredMessages([]);\n \n // Reset auto-start flag to allow future auto-starts\n hasAttemptedAutoStartRef.current = false;\n }, [isClient]);\n\n // ===== UI EVENT HANDLERS =====\n \n const handleToggleConversation = async () => {\n if (!isClient) return;\n \n if (!hasInteracted) {\n setHasInteracted(true);\n localStorage.setItem('guideAI_hasInteracted', 'true');\n \n // Show onboarding on first interaction\n setShowOnboarding(true);\n return;\n }\n \n if (!isConversationActive) {\n const success = await startConversationSession();\n if (success) {\n setIsConversationActive(true);\n // Always show transcript when conversation starts\n if (transcriptOptions?.enabled !== false) {\n setShowTranscript(true);\n }\n // Show text input option by default (unless explicitly disabled)\n if (inputOptions?.enableTextInput !== false) {\n setShowTextInput(true);\n }\n }\n } else {\n endConversationSession();\n setIsConversationActive(false);\n // Hide transcript and text input when conversation ends\n if (transcriptOptions?.enabled !== false) {\n setShowTranscript(false);\n }\n setShowTextInput(false);\n }\n };\n\n const handleToggleTranscript = () => {\n setShowTranscript(prev => !prev);\n };\n\n const handleToggleInputMode = () => {\n setInputMode(prev => {\n const newMode = prev === 'voice' ? 'text' : 'voice';\n // Update text input visibility based on new mode\n if (newMode === 'text' && isConversationActive) {\n setShowTextInput(true);\n } else {\n setShowTextInput(false);\n }\n return newMode;\n });\n };\n\n\n\n const handleTextSubmit = async () => {\n if (!textInput.trim() || !isConversationActive) return;\n\n // Log the user's text message to console (matching voice input behavior)\n console.log('User transcript:', textInput.trim());\n \n // Log the user's text message\n handleLogMessage(textInput.trim(), 'HUMAN');\n\n // Send text message to AI via WebRTC data channel\n if (dataChannelRef.current?.readyState === 'open') {\n const message = {\n type: \"conversation.item.create\",\n item: {\n type: \"message\",\n role: \"user\",\n content: [{\n type: \"input_text\",\n text: textInput.trim()\n }]\n }\n };\n \n dataChannelRef.current.send(JSON.stringify(message));\n\n // Trigger response generation\n const responseMessage = {\n type: \"response.create\"\n };\n dataChannelRef.current.send(JSON.stringify(responseMessage));\n }\n\n // Clear the input\n setTextInput('');\n };\n\n const handleTextKeyPress = (event: React.KeyboardEvent) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n handleTextSubmit();\n }\n };\n\n const handleOnboardingComplete = async () => {\n setShowOnboarding(false);\n \n // Start the conversation session when onboarding is completed\n const success = await startConversationSession();\n if (success) {\n setIsConversationActive(true);\n // Only auto-show transcript if enabled in options\n if (transcriptOptions?.enabled !== false) {\n setShowTranscript(true);\n }\n }\n };\n\n const handleOnboardingClose = () => {\n setShowOnboarding(false);\n };\n\n const handleCloseTranscript = () => {\n setShowTranscript(false);\n };\n\n // ===== REACT EFFECTS & LIFECYCLE ===== \n \n // CSS styles injection effect\n hooks.useEffect(() => {\n console.log('GuideAI: Injecting styles...', { guideAIStyles: !!guideAIStyles });\n injectStyles(guideAIStyles, 'guide-ai-styles');\n \n // Debug: Check if styles were actually injected\n setTimeout(() => {\n const styleElement = document.getElementById('guide-ai-styles');\n console.log('GuideAI: Styles injection check:', { \n styleElement: !!styleElement, \n styleContent: styleElement?.textContent?.substring(0, 100) \n });\n }, 100);\n }, [guideAIStyles]);\n \n // Metadata initialization effect - EventTracker now auto-initializes\n hooks.useEffect(() => {\n console.log('GuideAI: Metadata initialization effect triggered', {\n metadataTracker: !!metadataTracker,\n metadataOptions: !!metadataOptions,\n initialUserData: metadataOptions?.initialUserData\n });\n \n // Initialize UserMetadataTracker\n try {\n metadataTracker.init();\n console.log('GuideAI: UserMetadataTracker.init() called successfully');\n } catch (error) {\n console.error('GuideAI: Failed to initialize UserMetadataTracker:', error);\n }\n \n if (metadataOptions?.initialUserData) {\n try {\n metadataTracker.updateUserInfo(metadataOptions.initialUserData);\n console.log('GuideAI: Initial user data updated successfully');\n } catch (error) {\n console.error('GuideAI: Failed to update initial user data:', error);\n }\n }\n }, [metadataTracker, metadataOptions?.initialUserData]);\n \n // Component initialization effect\n hooks.useEffect(() => {\n console.log('GuideAI: Component mounting - initialization started', { \n hasInitialized: hasInitializedRef.current,\n initializationAttempted: initializationAttemptedRef.current,\n isClient,\n organizationKey,\n timestamp: Date.now()\n });\n \n // Prevent multiple initializations\n if (hasInitializedRef.current || isUnmountingRef.current || initializationAttemptedRef.current) {\n console.log('GuideAI: Already initialized, unmounting, or initialization already attempted, skipping');\n return;\n }\n \n // Additional safeguard: check if we're in a browser environment\n if (typeof window === 'undefined') {\n console.log('GuideAI: Not in browser environment, skipping initialization');\n return;\n }\n \n try {\n // Mark that we've attempted initialization\n initializationAttemptedRef.current = true;\n \n // Set initialization flag immediately to prevent race conditions\n hasInitializedRef.current = true;\n \n // Set client flag\n setIsClient(true);\n \n // Check for stored conversation before initializing\n const { shouldRestore, conversationId, messages } = checkForStoredConversation(organizationKey);\n \n if (shouldRestore && conversationId && messages) {\n // Store the restored messages to use as context\n setRestoredMessages(messages);\n console.log('GuideAI: Restored conversation with', messages.length, 'messages');\n } else {\n // No valid conversation to restore\n setRestoredMessages([]);\n console.log('GuideAI: No conversation to restore');\n }\n \n // Create new conversation (gets conversation + token + prompt)\n handleCreateNewConversation().then(conversationData => {\n if (!isUnmountingRef.current) {\n console.log('GuideAI: Initialization completed successfully', { conversationData: !!conversationData });\n }\n }).catch(error => {\n if (!isUnmountingRef.current) {\n console.error('GuideAI: Failed to create conversation:', error);\n // Reset initialization flag on error to allow retry\n hasInitializedRef.current = false;\n initializationAttemptedRef.current = false;\n }\n });\n \n const hasInteractedBefore = localStorage.getItem('guideAI_hasInteracted');\n if (!hasInteractedBefore) {\n setHasInteracted(false);\n } else {\n setHasInteracted(true);\n }\n \n console.log('GuideAI: Initialization setup completed');\n } catch (error) {\n console.error('GuideAI: Error during initialization:', error);\n // Reset initialization flag on error\n hasInitializedRef.current = false;\n initializationAttemptedRef.current = false;\n }\n }, [organizationKey]); // Removed handleCreateNewConversation from dependencies\n \n // Component cleanup effect\n hooks.useEffect(() => {\n return () => {\n console.log('GuideAI: Component unmounting - cleanup triggered', { \n hasInitialized: hasInitializedRef.current,\n isUnmounting: isUnmountingRef.current,\n timestamp: Date.now()\n });\n \n // Set unmounting flag to prevent any new initialization\n isUnmountingRef.current = true;\n \n // Clean up WebRTC connections\n cleanupWebRTC();\n \n // Clean up audio element\n if (audioElementRef.current) {\n try {\n audioElementRef.current.srcObject = null;\n audioElementRef.current.remove();\n } catch (error) {\n console.warn('Error cleaning up audio element:', error);\n }\n audioElementRef.current = null;\n }\n \n // Stop event tracking on cleanup\n if (eventTracker) {\n try {\n eventTracker.stopTracking();\n } catch (error) {\n console.warn('Error stopping event tracker:', error);\n }\n }\n \n // Stop metadata tracking and sync any pending updates\n if (metadataTracker) {\n try {\n metadataTracker.destroy();\n } catch (error) {\n console.warn('Error destroying metadata tracker:', error);\n }\n }\n \n // Reset all flags on cleanup\n hasInitializedRef.current = false;\n isUnmountingRef.current = false;\n hasAttemptedAutoStartRef.current = false;\n hasCreatedConversationRef.current = false;\n initializationAttemptedRef.current = false;\n \n console.log('GuideAI: Cleanup completed');\n };\n }, []);\n\n // Metadata sync effect - IMPROVED WITH LONGER INTERVALS\n hooks.useEffect(() => {\n if (!metadataTracker) return;\n \n // Use improved default interval (5 minutes) but allow overrides\n const syncInterval = metadataOptions?.config?.syncInterval || 300000; // 5 minutes instead of 2 minutes\n \n const syncTimer = setInterval(async () => {\n if (metadataTracker) {\n const pendingUpdates = metadataTracker.syncNow();\n if (pendingUpdates.length > 0) {\n try {\n await sendMetadataUpdates(pendingUpdates, organizationKey, onError);\n \n // Notify parent component of metadata updates if callback provided\n if (metadataOptions?.onMetadataUpdate) {\n metadataOptions.onMetadataUpdate(metadataTracker.getMetadata());\n }\n } catch (error) {\n console.error('Failed to sync metadata updates:', error);\n // Note: Failed updates are retained in tracker for retry\n }\n }\n }\n }, syncInterval);\n\n return () => {\n clearInterval(syncTimer);\n };\n }, [organizationKey]); // Only depend on organizationKey\n\n // Auto-restart effect - TEMPORARILY DISABLED FOR TESTING\n hooks.useEffect(() => {\n // TESTING: Disable auto-restart to see if this fixes mounting/unmounting loop\n if (ephemeralToken && restoredMessages.length > 0 && !hasAttemptedAutoStartRef.current && !isConversationActive) {\n console.log('Auto-restarting conversation with', restoredMessages.length, 'restored messages');\n hasAttemptedAutoStartRef.current = true;\n \n startConversationSession().then(success => {\n if (success) {\n setIsConversationActive(true);\n setHasInteracted(true);\n localStorage.setItem('guideAI_hasInteracted', 'true');\n }\n });\n }\n }, [ephemeralToken, restoredMessages, isConversationActive]); // Add isConversationActive to prevent loops\n\n // Load restored messages into allMessages state - FIXED\n hooks.useEffect(() => {\n if (restoredMessages.length > 0 && allMessages.length === 0) {\n setAllMessages(restoredMessages);\n }\n }, [restoredMessages]); // Remove allMessages.length to prevent loops\n\n // Update popup position when needed - STABILIZED\n hooks.useEffect(() => {\n if (showOnboarding || (!hasInteracted && ephemeralToken)) {\n // Use onboarding dimensions if onboarding is shown, otherwise welcome bubble dimensions\n const height = showOnboarding ? 240 : 50;\n const spacing = showOnboarding ? 20 : 15;\n setPopupPosition(getOptimalPosition(height, spacing));\n }\n }, [showOnboarding, hasInteracted, ephemeralToken]); // Remove getOptimalPosition from dependencies\n\n // ===== TRANSCRIPT BOX PROPS MEMOIZATION =====\n \n // Memoize TranscriptBox props to prevent unnecessary re-renders\n const transcriptBoxProps = hooks.useMemo(() => ({\n messages: allMessages,\n isVisible: showTranscript,\n onClose: handleCloseTranscript,\n showToggleButton: transcriptOptions?.showToggleButton !== false && isConversationActive,\n onToggle: handleToggleTranscript,\n showTextInput: isConversationActive && inputOptions?.enableTextInput !== false,\n textInput: textInput,\n onTextInputChange: setTextInput,\n onTextSubmit: handleTextSubmit,\n onTextKeyPress: handleTextKeyPress,\n textPlaceholder: inputOptions?.placeholder || \"Type your message...\"\n }), [\n allMessages.length, // Only depend on length, not the full array\n showTranscript,\n isConversationActive,\n textInput,\n transcriptOptions?.showToggleButton,\n inputOptions?.enableTextInput,\n inputOptions?.placeholder\n ]);\n\n\n\n // ===== METADATA HELPER FUNCTIONS =====\n \n // Expose metadata tracking methods globally on window for external access - STABILIZED\n hooks.useEffect(() => {\n if (typeof window !== 'undefined') {\n // Create global GuideAI metadata API\n (window as any).GuideAI = {\n ...(window as any).GuideAI,\n metadata: {\n // Track user login\n trackLogin: (additionalInfo?: Partial<UserMetadata>) => {\n metadataTracker?.trackLogin(additionalInfo);\n },\n \n // Update user information\n updateUserInfo: (userInfo: Partial<UserMetadata>) => {\n metadataTracker?.updateUserInfo(userInfo);\n },\n \n // Track custom events\n trackCustomEvent: (eventType: string, customData: Record<string, any>) => {\n metadataTracker?.trackCustomEvent(eventType, customData);\n },\n \n // Get current metadata\n getMetadata: () => {\n return metadataTracker?.getMetadata() || null;\n },\n \n // Force sync metadata now\n syncMetadata: async () => {\n if (metadataTracker) {\n const updates = metadataTracker.syncNow();\n if (updates.length > 0) {\n return await sendMetadataUpdates(updates, organizationKey, onError);\n }\n }\n return true;\n },\n \n // Reset session visit tracking (call this when user logs in)\n resetSessionVisitTracking: () => {\n metadataTracker?.resetSessionVisitTracking();\n },\n \n // Manually track a visit (useful for login events)\n trackVisitManually: () => {\n metadataTracker?.trackVisitManually();\n }\n },\n transcript: {\n // Toggle transcript visibility\n toggle: () => {\n setShowTranscript(prev => !prev);\n },\n \n // Show transcript\n show: () => {\n setShowTranscript(true);\n },\n \n // Hide transcript\n hide: () => {\n setShowTranscript(false);\n },\n \n // Get current transcript visibility\n isVisible: () => {\n return showTranscript;\n }\n },\n input: {\n // Toggle input mode between voice and text\n toggleMode: () => {\n handleToggleInputMode();\n },\n \n // Set input mode\n setMode: (mode: 'voice' | 'text') => {\n setInputMode(mode);\n if (mode === 'text' && inputOptions?.enableTextInput !== false && isConversationActive) {\n setShowTextInput(true);\n } else {\n setShowTextInput(false);\n }\n },\n \n // Get current input mode\n getMode: () => {\n return inputMode;\n },\n \n // Send text message programmatically\n sendText: (text: string) => {\n if (text.trim() && isConversationActive) {\n setTextInput(text);\n handleTextSubmit();\n }\n }\n }\n };\n }\n }, [organizationKey]); // Only depend on organizationKey\n\n if (!isClient) {\n return null;\n }\n\n // Determine if we should use fixed positioning (when position props are provided)\n const shouldUseFixedPosition = position && Object.keys(position).length > 0;\n \n // Base styles for the component\n const baseStyles: React.CSSProperties = {\n position: shouldUseFixedPosition ? 'fixed' : 'relative',\n zIndex: shouldUseFixedPosition ? 1000 : 'auto',\n ...(shouldUseFixedPosition ? position : {}),\n };\n\n return (\n <>\n <div\n ref={componentRef}\n style={baseStyles}\n >\n <div className=\"guideai-main-ui\">\n {!hasInteracted && ephemeralToken && (\n <WelcomeBubble position={popupPosition} />\n )}\n \n <Onboarding \n position={popupPosition}\n isVisible={showOnboarding}\n onComplete={handleOnboardingComplete}\n onClose={handleOnboardingClose}\n />\n \n <div className=\"guideai-main-controls\">\n <div \n className={`guideai-icon-wrapper ${isConnecting ? 'initializing' : status}`}\n onClick={isConnecting ? undefined : handleToggleConversation}\n style={{\n ...(isConnecting ? { cursor: 'default' } : {})\n }}\n title={isConnecting ? 'Initializing...' : \n status === 'idle' ? 'Click to start conversation' : \n status === 'recording' ? 'Click to end conversation' : \n status === 'processing' ? 'Processing your message...' : \n 'AI is speaking, click to end conversation'}\n >\n {isConnecting && <i className=\"guideai-icon initializing\" />}\n {!isConnecting && status === 'idle' && <i className=\"guideai-icon microphone\" />}\n {!isConnecting && status === 'recording' && <i className=\"guideai-icon recording\" />}\n {!isConnecting && status === 'processing' && <i className=\"guideai-icon processing\" />}\n {!isConnecting && status === 'playing' && <i className=\"guideai-icon playing\" />}\n </div>\n \n </div>\n \n </div>\n </div>\n \n {/* Transcript Box */}\n <TranscriptBox {...transcriptBoxProps} />\n </>\n );\n};\n\nconst GuideAI = GuideAIComponent;\n\nexport default GuideAI;","import { PopupPosition } from '../types/GuideAI.types';\n\n// Function to inject CSS styles into the document head\nexport const injectStyles = (css: string, id: string) => {\n if (typeof document === 'undefined') return; // SSR safety\n \n // Check if styles are already injected\n if (document.getElementById(id)) return;\n \n const styleElement = document.createElement('style');\n styleElement.id = id;\n styleElement.textContent = css;\n document.head.appendChild(styleElement);\n};\n\n// Calculate optimal position for popups based on component location\nexport const calculateOptimalPosition = (\n componentRect: DOMRect, \n elementHeight: number = 240, \n spacing: number = 15\n): PopupPosition => {\n const viewportHeight = window.innerHeight;\n \n const spaceAbove = componentRect.top;\n const spaceBelow = viewportHeight - componentRect.bottom;\n \n const canFitBelow = spaceBelow >= (elementHeight + spacing);\n const canFitAbove = spaceAbove >= (elementHeight + spacing);\n \n if (canFitBelow) {\n return 'below';\n } else if (canFitAbove) {\n return 'above';\n } else {\n return spaceBelow > spaceAbove ? 'below' : 'above';\n }\n}; ","import React from 'react';\nimport { StoredMessage } from '../utils/messageStorage';\n\ninterface TranscriptBoxProps {\n messages: StoredMessage[];\n isVisible: boolean;\n onClose: () => void;\n showToggleButton?: boolean;\n onToggle?: () => void;\n showTextInput?: boolean;\n textInput?: string;\n onTextInputChange?: (value: string) => void;\n onTextSubmit?: () => void;\n onTextKeyPress?: (event: React.KeyboardEvent) => void;\n textPlaceholder?: string;\n}\n\nconst TranscriptBoxComponent: React.FC<TranscriptBoxProps> = ({ \n messages, \n isVisible, \n onClose, \n showToggleButton = true, \n onToggle,\n showTextInput = false,\n textInput = '',\n onTextInputChange,\n onTextSubmit,\n onTextKeyPress,\n textPlaceholder = \"Type your message...\"\n}) => {\n const formatTime = (timestamp: number) => {\n return new Date(timestamp).toLocaleTimeString([], { \n hour: '2-digit', \n minute: '2-digit' \n });\n };\n\n const scrollToBottom = (element: HTMLDivElement) => {\n element.scrollTop = element.scrollHeight;\n };\n\n React.useEffect(() => {\n const transcriptContainer = document.getElementById('guideai-transcript-container');\n if (transcriptContainer) {\n scrollToBottom(transcriptContainer as HTMLDivElement);\n }\n }, [messages.length]); // Only depend on length, not the full messages array\n\n // Show toggle button if there are messages and toggle is enabled, even when transcript is hidden\n const shouldShowToggleButton = showToggleButton && messages.length > 0;\n \n // Show transcript if visible OR if text input should be shown\n const shouldShowTranscript = isVisible || showTextInput;\n \n // Don't render anything if no messages, no toggle button, and no text input\n if (messages.length === 0 && !shouldShowToggleButton && !showTextInput) return null;\n\n return (\n <div className=\"guideai-transcript-overlay\">\n {/* Toggle Button - shows even when transcript is hidden */}\n {shouldShowToggleButton && (\n <button\n className=\"guideai-transcript-toggle-button\"\n onClick={onToggle}\n title={isVisible ? 'Hide Transcript' : 'Show Transcript'}\n >\n <span className=\"guideai-transcript-toggle-icon\">\n {isVisible ? '📄' : '📋'}\n </span>\n </button>\n )}\n \n {/* Transcript Box - show when visible or when text input is needed */}\n {shouldShowTranscript && (\n <div className=\"guideai-transcript-box\">\n {/* Messages Container - only show when transcript is visible */}\n {isVisible && (\n <div \n id=\"guideai-transcript-container\"\n className=\"guideai-transcript-messages\"\n >\n {messages.length === 0 ? (\n <div className=\"guideai-transcript-empty\">\n <div className=\"guideai-transcript-empty-icon\">🎤</div>\n <p>Start a conversation to see the transcript here</p>\n </div>\n ) : (\n messages.map((message, index) => (\n <div \n key={`${message.timestamp}-${index}`}\n className={`guideai-transcript-message ${message.sender.toLowerCase()}`}\n >\n <div className=\"guideai-transcript-message-content\">\n <div className=\"guideai-transcript-message-sender\">\n {message.sender === 'HUMAN' ? 'You' : 'GuideAI'}\n </div>\n <div className=\"guideai-transcript-message-text\">\n {message.content}\n </div>\n <div className=\"guideai-transcript-message-time\">\n {formatTime(message.timestamp)}\n </div>\n </div>\n </div>\n ))\n )}\n </div>\n )}\n \n {/* Text Input - show when in text mode */}\n {showTextInput && (\n <div className=\"guideai-transcript-text-input\">\n <textarea\n className=\"guideai-transcript-input-field\"\n value={textInput}\n onChange={(e) => onTextInputChange?.(e.target.value)}\n onKeyPress={onTextKeyPress}\n placeholder={textPlaceholder}\n rows={2}\n />\n <button\n className=\"guideai-transcript-send-button\"\n onClick={onTextSubmit}\n disabled={!textInput.trim()}\n title=\"Send Message\"\n >\n <span className=\"guideai-transcript-send-icon\">📤</span>\n </button>\n </div>\n )}\n </div>\n )}\n </div>\n );\n};\n\nconst TranscriptBox = React.memo(TranscriptBoxComponent, (prevProps, nextProps) => {\n // Only re-render if essential props change\n return (\n prevProps.messages.length === nextProps.messages.length &&\n prevProps.isVisible === nextProps.isVisible &&\n prevProps.showToggleButton === nextProps.showToggleButton &&\n prevProps.showTextInput === nextProps.showTextInput &&\n prevProps.textInput === nextProps.textInput &&\n prevProps.textPlaceholder === nextProps.textPlaceholder\n );\n});\n\nTranscriptBox.displayName = 'TranscriptBox';\n\nexport default TranscriptBox; ","import React, { useState } from 'react';\nimport { PopupPosition } from '../types/GuideAI.types';\n\ninterface OnboardingProps {\n position: PopupPosition;\n isVisible: boolean;\n onComplete: () => void; // Called when user completes onboarding and wants to start conversation\n onClose: () => void; // Called when user closes onboarding without completing\n}\n\nconst Onboarding: React.FC<OnboardingProps> = ({ position, isVisible, onComplete, onClose }) => {\n const [step, setStep] = useState(1);\n\n const handleNext = () => {\n if (step < 3) {\n setStep(step + 1);\n } else {\n // Reset step and complete onboarding\n setStep(1);\n onComplete();\n }\n };\n\n const handleClose = () => {\n // Reset step when closing\n setStep(1);\n onClose();\n };\n\n if (!isVisible) {\n return null;\n }\n\n return (\n <div className={`guideai-onboarding ${position}`}>\n <div className=\"guideai-onboarding-content\">\n <button className=\"guideai-onboarding-close\" onClick={handleClose}>×</button>\n \n {step === 1 && (\n <div className=\"guideai-onboarding-step\">\n <div className=\"guideai-onboarding-icon volume-icon\">🔊</div>\n <h3>Turn on your volume</h3>\n <p>Make sure your device's volume is turned on so you can hear Guide AI's responses.</p>\n </div>\n )}\n \n {step === 2 && (\n <div className=\"guideai-onboarding-step\">\n <div className=\"guideai-onboarding-icon mic-icon\">🎤</div>\n <h3>Allow microphone access</h3>\n <p>When prompted, click \"Allow\" to let Guide AI access your microphone.</p>\n </div>\n )}\n \n {step === 3 && (\n <div className=\"guideai-onboarding-step\">\n <div className=\"guideai-onboarding-icon ready-icon\">✅</div>\n <h3>You're all set!</h3>\n <p>Click the microphone icon to start asking questions.</p>\n </div>\n )}\n \n <div className=\"guideai-onboarding-dots\">\n <span className={`dot ${step === 1 ? 'active' : ''}`}></span>\n <span className={`dot ${step === 2 ? 'active' : ''}`}></span>\n <span className={`dot ${step === 3 ? 'active' : ''}`}></span>\n </div>\n \n <button className=\"guideai-onboarding-next\" onClick={handleNext}>\n {step < 3 ? 'Next' : 'Get Started'}\n </button>\n </div>\n </div>\n );\n};\n\nexport default Onboarding; ","import React from 'react';\nimport { PopupPosition } from '../types/GuideAI.types';\n\ninterface WelcomeBubbleProps {\n position: PopupPosition;\n}\n\nconst WelcomeBubble: React.FC<WelcomeBubbleProps> = ({ position }) => {\n return (\n <div className={`guideai-welcome-bubble ${position}`}>\n Stuck? Click here and ask me a question\n </div>\n );\n};\n\nexport default WelcomeBubble; ","// Event tracking system for GuideAI\n// Tracks click, focus, change, and submit events on all relevant elements\n\ninterface EventData {\n type: 'click' | 'focus' | 'change' | 'submit' | 'route_change';\n element?: Element;\n tagName?: string;\n className?: string;\n id?: string;\n textContent?: string;\n value?: string;\n formData?: FormData;\n timestamp: number;\n url: string;\n previousUrl?: string;\n event?: Event;\n // Customer metadata\n customerId?: string;\n customerType?: string;\n customerSegment?: string;\n // Session metadata\n sessionId?: string;\n deviceType?: 'desktop' | 'mobile' | 'tablet';\n userAgent?: string;\n screenResolution?: string;\n // Application context\n currentPage?: string;\n userRole?: string;\n organizationId?: string;\n // Geographic and timezone\n timezone?: string;\n locale?: string;\n}\n\nclass EventTracker {\n private isTracking: boolean = false;\n private eventData: EventData[] = [];\n private batchSize: number = 25; // Increased from 10 to 25 events\n private batchTimeout: number = 15000; // Increased from 5s to 15s\n private batchTimer: NodeJS.Timeout | null = null;\n private pendingEvents: EventData[] = [];\n private currentUrl: string = '';\n private organizationKey?: string;\n private lastEventTime: number = 0;\n private eventThrottleInterval: number = 500; // Minimum 500ms between similar events\n private lastEventsByType: Map<string, number> = new Map();\n private duplicateEventBuffer: Map<string, EventData> = new Map();\n private maxDuplicateBuffer: number = 100;\n private isInitialized: boolean = false;\n\n // Customer metadata storage\n private customerMetadata: {\n customerId?: string;\n customerType?: string;\n customerSegment?: string;\n userRole?: string;\n organizationId?: string;\n } = {};\n\n constructor(options?: { \n customerId?: string; \n customerType?: string; \n organizationId?: string; \n organizationKey?: string;\n batchSize?: number;\n batchTimeout?: number;\n eventThrottleInterval?: number;\n }) {\n if (options?.customerId) {\n this.customerMetadata.customerId = String(options.customerId);\n }\n if (options?.customerType) {\n this.customerMetadata.customerType = options.customerType;\n }\n if (options?.organizationId) {\n this.customerMetadata.organizationId = String(options.organizationId);\n }\n if (options?.organizationKey) {\n this.organizationKey = options.organizationKey;\n }\n \n // Allow customization of batching parameters\n if (options?.batchSize && options.batchSize > 0) {\n this.batchSize = options.batchSize;\n }\n if (options?.batchTimeout && options.batchTimeout > 0) {\n this.batchTimeout = options.batchTimeout;\n }\n if (options?.eventThrottleInterval && options.eventThrottleInterval >= 0) {\n this.eventThrottleInterval = options.eventThrottleInterval;\n }\n \n // Auto-initialize like UserMetadataTracker\n this.init();\n }\n\n // Auto-initialization method\n private init(): void {\n if (this.isInitialized) return;\n \n // Load existing events from localStorage\n this.loadEventsFromStorage();\n \n // Start tracking when DOM is ready\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => this.startTracking());\n } else {\n this.startTracking();\n }\n }\n \n this.isInitialized = true;\n if (process.env.NODE_ENV === 'development') {\n console.log('EventTracker: Auto-initialized and ready');\n }\n }\n\n // Load events from localStorage\n private loadEventsFromStorage(): void {\n if (typeof window === 'undefined') return;\n \n try {\n const storageKey = `guideai_events_${this.organizationKey || 'default'}`;\n const storedEvents = localStorage.getItem(storageKey);\n \n if (storedEvents) {\n const parsedEvents = JSON.parse(storedEvents);\n this.eventData = Array.isArray(parsedEvents) ? parsedEvents : [];\n if (process.env.NODE_ENV === 'development') {\n console.log('EventTracker: Loaded', this.eventData.length, 'events from localStorage');\n }\n }\n } catch (error) {\n console.warn('EventTracker: Failed to load events from localStorage', error);\n }\n }\n\n // Save events to localStorage\n private saveEventsToStorage(): void {\n if (typeof window === 'undefined') return;\n \n try {\n const storageKey = `guideai_events_${this.organizationKey || 'default'}`;\n \n // Sanitize event data before saving to localStorage to prevent circular reference errors\n const sanitizedEventData = this.eventData.map(event => this.sanitizeEventData(event));\n \n if (process.env.NODE_ENV === 'development') {\n console.log('EventTracker: saveEventsToStorage called with', this.eventData.length, 'events');\n }\n localStorage.setItem(storageKey, JSON.stringify(sanitizedEventData));\n if (process.env.NODE_ENV === 'development') {\n console.log('EventTracker: Successfully saved', sanitizedEventData.length, 'events to localStorage');\n }\n } catch (error) {\n console.warn('EventTracker: Failed to save events to localStorage', error);\n }\n }\n\n\n // Method to set customer metadata\n public setCustomerMetadata(metadata: Partial<typeof this.customerMetadata>): void {\n // All remaining metadata is safe to collect\n this.customerMetadata = { ...this.customerMetadata, ...metadata };\n }\n\n // Method to get customer metadata\n public getCustomerMetadata(): typeof this.customerMetadata {\n return { ...this.customerMetadata };\n }\n\n // Method to clear customer metadata\n public clearCustomerMetadata(): void {\n this.customerMetadata = {};\n }\n\n public initialize(): void {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n // Start tracking when DOM is ready\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => this.startTracking());\n } else {\n this.startTracking();\n }\n }\n\n // Helper method to enrich event data with customer metadata\n private enrichEventData(baseEventData: Omit<EventData, 'customerId' | 'customerType' | 'customerSegment' | 'sessionId' | 'deviceType' | 'userAgent' | 'screenResolution' | 'currentPage' | 'userRole' | 'organizationId' | 'timezone' | 'locale'>): EventData {\n // Sanitize the base event data to remove circular references\n const sanitizedBaseData = this.sanitizeEventData(baseEventData);\n \n const enrichedData = {\n ...sanitizedBaseData,\n // Customer metadata\n customerId: this.customerMetadata.customerId,\n customerType: this.customerMetadata.customerType,\n customerSegment: this.customerMetadata.customerSegment,\n organizationKey: this.organizationKey,\n // Session metadata\n sessionId: this.getSessionId(),\n deviceType: this.getDeviceType(),\n userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,\n screenResolution: typeof screen !== 'undefined' ? `${screen.width}x${screen.height}` : undefined,\n // Application context\n currentPage: window.location.pathname,\n userRole: this.customerMetadata.userRole,\n organizationId: this.customerMetadata.organizationId,\n // Geographic and timezone\n timezone: typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat !== 'undefined'\n ? Intl.DateTimeFormat().resolvedOptions().timeZone\n : undefined,\n locale: navigator.language,\n };\n\n return enrichedData;\n }\n\n // Helper method to sanitize event data and remove circular references\n private sanitizeEventData(eventData: any): any {\n const sanitized: any = {};\n \n // Copy safe primitive values\n Object.keys(eventData).forEach(key => {\n const value = eventData[key];\n \n switch (key) {\n case 'element':\n // Extract only safe element properties\n if (value && typeof value === 'object') {\n sanitized[key] = {\n tagName: value.tagName,\n id: value.id,\n className: value.className,\n textContent: value.textContent?.substring(0, 100)\n };\n }\n break;\n \n case 'event':\n // Remove event object entirely - it contains circular references\n break;\n \n case 'formData':\n // Convert FormData to plain object\n if (value instanceof FormData) {\n const formDataObj: Record<string, any> = {};\n value.forEach((val, key) => {\n formDataObj[key] = val;\n });\n sanitized[key] = formDataObj;\n } else {\n sanitized[key] = value;\n }\n break;\n \n default:\n // Copy primitive values and safe objects\n if (value !== null && \n (typeof value === 'string' || \n typeof value === 'number' || \n typeof value === 'boolean' ||\n Array.isArray(value))) {\n sanitized[key] = value;\n }\n break;\n }\n });\n \n return sanitized;\n }\n\n\n\n // Helper method to get or create session ID\n private getSessionId(): string {\n let sessionId = sessionStorage.getItem('eventTracker_sessionId');\n if (!sessionId) {\n sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n sessionStorage.setItem('eventTracker_sessionId', sessionId);\n }\n return sessionId;\n }\n\n // Helper method to detect device type\n private getDeviceType(): 'desktop' | 'mobile' | 'tablet' {\n if (typeof navigator === 'undefined') {\n return 'desktop';\n }\n const userAgent = navigator.userAgent.toLowerCase();\n if (/tablet|ipad|playbook|silk/i.test(userAgent)) {\n return 'tablet';\n }\n if (/mobile|android|iphone|ipod|blackberry|opera mini|iemobile/i.test(userAgent)) {\n return 'mobile';\n }\n return 'desktop';\n }\n\n public startTracking(): void {\n if (this.isTracking) return;\n\n this.isTracking = true;\n if (process.env.NODE_ENV === 'development') {\n console.log('EventTracker: Started tracking events');\n }\n\n // Track click events on all elements\n this.trackClickEvents();\n\n // Track focus events on focusable elements\n this.trackFocusEvents();\n\n // Track change events on form elements\n this.trackChangeEvents();\n\n // Track submit events on forms\n this.trackSubmitEvents();\n\n // Track route changes\n this.trackRouteChanges();\n }\n\n public stopTracking(): void {\n if (!this.isTracking) return;\n\n this.isTracking = false;\n if (process.env.NODE_ENV === 'development') {\n console.log('EventTracker: Stopped tracking events');\n }\n\n // Emit any pending events before stopping\n this.emitBatch();\n\n // Remove all event listeners\n document.removeEventListener('click', this.handleClick, true);\n document.removeEventListener('focus', this.handleFocus, true);\n document.removeEventListener('change', this.handleChange, true);\n document.removeEventListener('submit', this.handleSubmit, true);\n window.removeEventListener('popstate', this.handlePopstate);\n window.removeEventListener('hashchange', this.handleHashChange);\n }\n\n private trackClickEvents(): void {\n document.addEventListener('click', this.handleClick, true);\n }\n\n private trackFocusEvents(): void {\n document.addEventListener('focus', this.handleFocus, true);\n }\n\n private trackChangeEvents(): void {\n document.addEventListener('change', this.handleChange, true);\n }\n\n private trackSubmitEvents(): void {\n document.addEventListener('submit', this.handleSubmit, true);\n }\n\n private trackRouteChanges(): void {\n // Track browser back/forward navigation\n window.addEventListener('popstate', this.handlePopstate);\n\n // Track hash changes\n window.addEventListener('hashchange', this.handleHashChange);\n\n // Track History API changes (pushState, replaceState)\n this.interceptHistoryAPI();\n }\n\n private handleClick = (event: Event): void => {\n if (!this.isTracking) return;\n\n const target = event.target as Element;\n \n // Filter out clicks on non-interactive elements unless they have special attributes\n if (!this.isSignificantClickTarget(target)) {\n return;\n }\n \n const baseEventData = {\n type: 'click' as const,\n element: target,\n tagName: target.tagName,\n className: target.className,\n id: target.id,\n textContent: target.textContent?.substring(0, 100),\n value: this.getSafeValue(target),\n timestamp: Date.now(),\n url: window.location.href,\n event: event\n };\n\n this.logEvent(baseEventData);\n };\n\n private handleFocus = (event: Event): void => {\n if (!this.isTracking) return;\n\n const target = event.target as Element;\n\n // Only track focus on significant focusable elements\n if (this.isFocusable(target) && this.isSignificantFocusTarget(target)) {\n const baseEventData = {\n type: 'focus' as const,\n element: target,\n tagName: target.tagName,\n className: target.className,\n id: target.id,\n textContent: target.textContent?.substring(0, 100),\n value: this.getSafeValue(target),\n timestamp: Date.now(),\n url: window.location.href,\n event: event\n };\n\n this.logEvent(baseEventData);\n }\n };\n\n private handleChange = (event: Event): void => {\n if (!this.isTracking) return;\n\n const target = event.target as Element;\n\n // Only track change on form elements\n if (this.isFormElement(target)) {\n const baseEventData = {\n type: 'change' as const,\n element: target,\n tagName: target.tagName,\n className: target.className,\n id: target.id,\n textContent: target.textContent?.substring(0, 100),\n value: this.getSafeValue(target),\n timestamp: Date.now(),\n url: window.location.href,\n event: event\n };\n\n this.logEvent(baseEventData);\n }\n };\n\n private handleSubmit = (event: Event): void => {\n if (!this.isTracking) return;\n\n const target = event.target as Element;\n\n // Only track submit on form elements\n if (target.tagName === 'FORM') {\n const form = target as HTMLFormElement;\n const formData = new FormData(form);\n\n const baseEventData = {\n type: 'submit' as const,\n element: target,\n tagName: target.tagName,\n className: target.className,\n id: target.id,\n textContent: target.textContent?.substring(0, 100),\n formData: formData,\n timestamp: Date.now(),\n url: window.location.href,\n event: event\n };\n\n this.logEvent(baseEventData);\n }\n };\n\n private handlePopstate = (event: PopStateEvent): void => {\n if (!this.isTracking) return;\n\n const newUrl = window.location.href;\n const previousUrl = this.getPreviousUrl();\n \n // Only track if URL actually changed meaningfully\n if (this.isSignificantRouteChange(newUrl, previousUrl)) {\n const baseEventData = {\n type: 'route_change' as const,\n timestamp: Date.now(),\n url: newUrl,\n previousUrl: previousUrl,\n event: event\n };\n\n this.logEvent(baseEventData);\n this.currentUrl = newUrl; // Update current URL\n }\n };\n\n private handleHashChange = (event: HashChangeEvent): void => {\n if (!this.isTracking) return;\n\n const newUrl = window.location.href;\n const previousUrl = event.oldURL;\n \n // Only track if hash change is significant\n if (this.isSignificantRouteChange(newUrl, previousUrl)) {\n const baseEventData = {\n type: 'route_change' as const,\n timestamp: Date.now(),\n url: newUrl,\n previousUrl: previousUrl,\n event: event\n };\n\n this.logEvent(baseEventData);\n this.currentUrl = newUrl; // Update current URL\n }\n };\n\n private interceptHistoryAPI(): void {\n const originalPushState = history.pushState;\n const originalReplaceState = history.replaceState;\n\n // Store the current URL before interception\n this.currentUrl = window.location.href;\n\n // Intercept pushState\n history.pushState = (...args) => {\n const previousUrl = this.currentUrl;\n const result = originalPushState.apply(history, args);\n const newUrl = window.location.href;\n this.currentUrl = newUrl;\n\n if (this.isTracking && this.isSignificantRouteChange(newUrl, previousUrl)) {\n const baseEventData = {\n type: 'route_change' as const,\n timestamp: Date.now(),\n url: newUrl,\n previousUrl: previousUrl\n };\n this.logEvent(baseEventData);\n }\n\n return result;\n };\n\n // Intercept replaceState\n history.replaceState = (...args) => {\n const previousUrl = this.currentUrl;\n const result = originalReplaceState.apply(history, args);\n const newUrl = window.location.href;\n this.currentUrl = newUrl;\n\n if (this.isTracking && this.isSignificantRouteChange(newUrl, previousUrl)) {\n const baseEventData = {\n type: 'route_change' as const,\n timestamp: Date.now(),\n url: newUrl,\n previousUrl: previousUrl\n };\n this.logEvent(baseEventData);\n }\n\n return result;\n };\n }\n\n private getPreviousUrl(): string {\n return this.currentUrl || window.location.href;\n }\n\n private getSafeValue(element: Element): string | undefined {\n const tagName = element.tagName.toLowerCase();\n const inputElement = element as HTMLInputElement;\n const selectElement = element as HTMLSelectElement;\n\n // Only collect values for elements that are typically useful for targeting\n switch (tagName) {\n case 'button':\n return inputElement.value || inputElement.textContent?.trim();\n\n case 'select':\n return `${selectElement.name || ''}|${selectElement.type || ''}|${selectElement.selectedIndex || 0}`;\n\n case 'textarea':\n return inputElement.name || inputElement.type || '';\n\n case 'input':\n const inputType = inputElement.type;\n // Only collect value for button-like input types\n if (inputType === 'submit' || inputType === 'button' || inputType === 'reset') {\n return `${inputElement.name || ''}|${inputType}|${inputElement.value || ''}`;\n }\n // For other input types, only collect name and type, not the actual value\n return `${inputElement.name || ''}|${inputType}`;\n\n default:\n return undefined;\n }\n }\n\n private isFocusable(element: Element): boolean {\n const focusableSelectors = [\n 'input:not([type=\"hidden\"])',\n 'select',\n 'textarea',\n 'button',\n 'a[href]',\n 'area[href]',\n 'iframe',\n 'object',\n 'embed',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]'\n ];\n\n return focusableSelectors.some(selector => element.matches(selector));\n }\n\n private isFormElement(element: Element): boolean {\n const formElementTags = ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON'];\n return formElementTags.includes(element.tagName);\n }\n\n // Helper method to generate a unique key for event deduplication\n private generateEventKey(eventData: any): string {\n return `${eventData.type}_${eventData.tagName}_${eventData.id || ''}_${eventData.className || ''}_${eventData.url}`;\n }\n\n // Helper method to check if event should be throttled\n private shouldThrottleEvent(eventData: any, currentTime: number): boolean {\n const lastEventTime = this.lastEventsByType.get(eventData.type) || 0;\n return (currentTime - lastEventTime) < this.eventThrottleInterval;\n }\n\n // Helper method to check for duplicate events\n private isDuplicateEvent(eventKey: string, eventData: any): boolean {\n const existingEvent = this.duplicateEventBuffer.get(eventKey);\n if (!existingEvent) return false;\n \n // Consider events duplicate if they're within 2 seconds and have same content\n const timeDiff = eventData.timestamp - existingEvent.timestamp;\n return timeDiff < 2000 && existingEvent.textContent === eventData.textContent;\n }\n\n // Helper method to determine if click target is significant\n private isSignificantClickTarget(element: Element): boolean {\n const significantTags = ['BUTTON', 'A', 'INPUT', 'SELECT', 'TEXTAREA'];\n const interactiveRoles = ['button', 'link', 'menuitem', 'tab', 'option'];\n \n // Always track clicks on interactive elements\n if (significantTags.includes(element.tagName)) {\n return true;\n }\n \n // Track elements with interactive roles\n const role = element.getAttribute('role');\n if (role && interactiveRoles.includes(role.toLowerCase())) {\n return true;\n }\n \n // Track elements with click handlers (has onclick or data-* attributes)\n if (element.hasAttribute('onclick') || \n Array.from(element.attributes).some(attr => attr.name.startsWith('data-'))) {\n return true;\n }\n \n // Track elements with cursor pointer style\n const style = window.getComputedStyle(element);\n if (style.cursor === 'pointer') {\n return true;\n }\n \n return false;\n }\n\n // Helper method to determine if focus target is significant\n private isSignificantFocusTarget(element: Element): boolean {\n // Only track focus on form elements and elements with tabindex\n const formElements = ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON'];\n if (formElements.includes(element.tagName)) {\n return true;\n }\n \n // Track elements with positive tabindex\n const tabindex = element.getAttribute('tabindex');\n if (tabindex && parseInt(tabindex) >= 0) {\n return true;\n }\n \n return false;\n }\n\n // Helper method to determine if route change is significant\n private isSignificantRouteChange(newUrl: string, previousUrl: string): boolean {\n if (!newUrl || !previousUrl || newUrl === previousUrl) {\n return false;\n }\n \n try {\n const newUrlObj = new URL(newUrl);\n const prevUrlObj = new URL(previousUrl);\n \n // Ignore query parameter only changes\n if (newUrlObj.pathname === prevUrlObj.pathname && \n newUrlObj.hash === prevUrlObj.hash) {\n return false;\n }\n \n // Ignore small hash changes (like anchor scrolling)\n if (newUrlObj.pathname === prevUrlObj.pathname && \n Math.abs(newUrlObj.hash.length - prevUrlObj.hash.length) < 5) {\n return false;\n }\n \n return true;\n } catch (error) {\n // If URL parsing fails, consider it significant to be safe\n return true;\n }\n }\n\n private logEvent(baseEventData: Omit<EventData, 'customerType' | 'customerSegment' | 'sessionId' | 'deviceType' | 'currentPage' | 'userRole' | 'locale'>): void {\n const now = Date.now();\n const eventKey = this.generateEventKey(baseEventData);\n \n // Throttle similar events\n if (this.shouldThrottleEvent(baseEventData, now)) {\n return;\n }\n \n // Check for duplicate events\n if (this.isDuplicateEvent(eventKey, baseEventData)) {\n return;\n }\n \n // Enrich the event data with customer metadata\n const enrichedEventData = this.enrichEventData(baseEventData);\n\n // Store event data for historical access (with size limit)\n this.eventData.push(enrichedEventData);\n if (this.eventData.length > 1000) { // Limit stored events\n this.eventData = this.eventData.slice(-500); // Keep last 500\n }\n\n // Add to pending batch\n this.pendingEvents.push(enrichedEventData);\n \n // Update throttle tracking\n this.lastEventsByType.set(baseEventData.type, now);\n this.duplicateEventBuffer.set(eventKey, enrichedEventData);\n \n // Clean duplicate buffer if it gets too large\n if (this.duplicateEventBuffer.size > this.maxDuplicateBuffer) {\n const oldestKeys = Array.from(this.duplicateEventBuffer.keys()).slice(0, 50);\n oldestKeys.forEach(key => this.duplicateEventBuffer.delete(key));\n }\n\n // Save to localStorage immediately for persistence\n this.saveEventsToStorage();\n\n // Check if we should emit based on batch size\n if (this.pendingEvents.length >= this.batchSize) {\n this.emitBatch();\n } else {\n // Start or reset the timeout for time-based emission\n this.startBatchTimer();\n }\n }\n\n private startBatchTimer(): void {\n // Clear existing timer\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n }\n\n // Start new timer\n this.batchTimer = setTimeout(() => {\n this.emitBatch();\n }, this.batchTimeout);\n }\n\n private emitBatch(): void {\n if (this.pendingEvents.length === 0) return;\n\n // Create batch payload\n const batchPayload = {\n events: [...this.pendingEvents],\n batchSize: this.pendingEvents.length,\n timestamp: Date.now(),\n };\n\n // Console log the batch\n if (process.env.NODE_ENV === 'development') {\n console.log('EventTracker Batch:', batchPayload);\n }\n\n // Save events to localStorage\n this.saveEventsToStorage();\n\n // Emit custom event for metadata tracking integration\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent('guideai:event_batch', {\n detail: batchPayload\n }));\n }\n\n // Clear pending events\n this.pendingEvents = [];\n\n // Clear timer\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n }\n\n public getEventData(): EventData[] {\n return [...this.eventData];\n }\n\n public clearEventData(): void {\n this.eventData = [];\n }\n\n public getEventDataByType(type: EventData['type']): EventData[] {\n return this.eventData.filter(event => event.type === type);\n }\n\n public getEventDataByElement(tagName: string): EventData[] {\n return this.eventData.filter(event => event.tagName === tagName.toUpperCase());\n }\n\n public getEventDataByUrl(url: string): EventData[] {\n return this.eventData.filter(event => event.url.includes(url));\n }\n\n public emitPendingEvents(): void {\n this.emitBatch();\n }\n\n public setBatchConfig(batchSize: number, batchTimeout: number): void {\n this.batchSize = batchSize;\n this.batchTimeout = batchTimeout;\n }\n\n public getPendingEventsCount(): number {\n return this.pendingEvents.length;\n }\n\n // Customer analytics methods\n public getCustomerAnalytics(): {\n totalEvents: number;\n eventsByCustomer: Record<string, number>;\n eventsByType: Record<string, number>;\n eventsByPage: Record<string, number>;\n eventsByDevice: Record<string, number>;\n sessionDuration: number;\n lastActivity: number;\n } {\n const now = Date.now();\n const sessionStart = this.getSessionStartTime();\n const sessionDuration = now - sessionStart;\n\n const analytics = {\n totalEvents: this.eventData.length,\n eventsByCustomer: {} as Record<string, number>,\n eventsByType: {} as Record<string, number>,\n eventsByPage: {} as Record<string, number>,\n eventsByDevice: {} as Record<string, number>,\n sessionDuration,\n lastActivity: this.eventData.length > 0 ? this.eventData[this.eventData.length - 1].timestamp : now\n };\n\n // Group events by customer\n this.eventData.forEach(event => {\n if (event.customerId) {\n analytics.eventsByCustomer[event.customerId] = (analytics.eventsByCustomer[event.customerId] || 0) + 1;\n }\n\n // Group events by type\n analytics.eventsByType[event.type] = (analytics.eventsByType[event.type] || 0) + 1;\n\n // Group events by page\n if (event.currentPage) {\n analytics.eventsByPage[event.currentPage] = (analytics.eventsByPage[event.currentPage] || 0) + 1;\n }\n\n // Group events by device\n if (event.deviceType) {\n analytics.eventsByDevice[event.deviceType] = (analytics.eventsByDevice[event.deviceType] || 0) + 1;\n }\n });\n\n return analytics;\n }\n\n // Get session start time\n private getSessionStartTime(): number {\n const sessionStart = sessionStorage.getItem('eventTracker_sessionStart');\n if (!sessionStart) {\n const startTime = Date.now();\n sessionStorage.setItem('eventTracker_sessionStart', startTime.toString());\n return startTime;\n }\n return parseInt(sessionStart, 10);\n }\n\n // Method to identify customer from DOM or context\n public identifyCustomerFromContext(): void {\n // Try to find customer information from the current page context\n // This could be from meta tags, data attributes, or other DOM elements\n\n\n\n // Check for user role in meta tags\n const userRoleMeta = document.querySelector('meta[name=\"user-role\"]');\n if (userRoleMeta) {\n this.setCustomerMetadata({ userRole: userRoleMeta.getAttribute('content') || undefined });\n }\n\n\n\n // Try to infer customer type from URL or page context\n const pathname = window.location.pathname;\n if (pathname.includes('/admin/')) {\n this.setCustomerMetadata({ customerType: 'admin' });\n } else if (pathname.includes('/agent/')) {\n this.setCustomerMetadata({ customerType: 'agent' });\n } else if (pathname.includes('/business/')) {\n this.setCustomerMetadata({ customerType: 'business' });\n } else if (pathname.includes('/individual/')) {\n this.setCustomerMetadata({ customerType: 'individual' });\n }\n }\n\n // Method to set customer metadata from external source (e.g., authentication system)\n public setCustomerFromAuth(authData: {\n id?: string;\n role?: string;\n customerType?: 'individual' | 'business' | 'agent' | 'admin';\n customerSegment?: string;\n }): void {\n this.setCustomerMetadata({\n userRole: authData.role,\n customerType: authData.customerType,\n customerSegment: authData.customerSegment\n });\n }\n\n\n}\n\nexport default EventTracker;\nexport type { EventData };\n\n// Export customer metadata types for external use\nexport interface CustomerMetadata {\n customerId?: string;\n customerType?: 'individual' | 'business' | 'agent' | 'admin';\n customerSegment?: string;\n userRole?: string;\n}\n\nexport interface CustomerAnalytics {\n totalEvents: number;\n eventsByCustomer: Record<string, number>;\n eventsByType: Record<string, number>;\n eventsByPage: Record<string, number>;\n eventsByDevice: Record<string, number>;\n sessionDuration: number;\n lastActivity: number;\n}\n","// Create click effects and dispatch click event on an element\nexport const clickElement = async (element: Element, rect: DOMRect): Promise<void> => {\n return new Promise<void>((resolve) => {\n setTimeout(() => {\n const clickEffectContainer = document.createElement('div');\n clickEffectContainer.style.cssText = `\n position: fixed;\n left: ${rect.left + rect.width / 2}px;\n top: ${rect.top + rect.height / 2}px;\n width: 60px;\n height: 60px;\n z-index: 1000;\n pointer-events: none;\n transform: translate(-50%, -50%);\n `;\n document.body.appendChild(clickEffectContainer);\n \n for (let j = 0; j < 3; j++) {\n const clickRipple = document.createElement('div');\n clickRipple.style.cssText = `\n position: absolute;\n left: 50%;\n top: 50%;\n width: 40px;\n height: 40px;\n border: 2px solid rgba(0, 102, 255, ${0.7 - (j * 0.2)});\n border-radius: 50%;\n transform: translate(-50%, -50%) scale(0);\n opacity: 1;\n animation: click-ripple-animation 0.8s ease-out ${j * 0.15}s forwards;\n box-shadow: 0 0 8px rgba(0, 102, 255, 0.4);\n `;\n clickEffectContainer.appendChild(clickRipple);\n }\n \n const clickDot = document.createElement('div');\n clickDot.style.cssText = `\n position: absolute;\n left: 50%;\n top: 50%;\n width: 12px;\n height: 12px;\n background: rgba(0, 102, 255, 0.9);\n border-radius: 50%;\n transform: translate(-50%, -50%) scale(0);\n animation: click-dot-animation 0.4s ease-out forwards;\n box-shadow: 0 0 5px rgba(0, 102, 255, 0.8);\n `;\n clickEffectContainer.appendChild(clickDot);\n \n const clickEvent = new MouseEvent('click', {\n view: window,\n bubbles: true,\n cancelable: true,\n });\n\n // Check for clickable subelements (links, buttons, inputs)\n const clickableElements = element.querySelectorAll('a, button, input[type=\"button\"], input[type=\"submit\"]');\n const clickableElement = clickableElements.length > 0 ? clickableElements[0] as HTMLElement : element as HTMLElement;\n console.log('Clicking element:', clickableElement);\n clickableElement.dispatchEvent(clickEvent);\n\n const originalBoxShadow = clickableElement.style.boxShadow;\n const originalTransition = clickableElement.style.transition;\n const originalZIndex = clickableElement.style.zIndex;\n\n clickableElement.style.transition = 'all 0.3s ease-out';\n clickableElement.style.boxShadow = '0 0 0 2px rgba(0, 102, 255, 0.5), 0 0 10px rgba(0, 102, 255, 0.3)';\n clickableElement.style.zIndex = '999';\n\n setTimeout(() => {\n clickableElement.style.boxShadow = originalBoxShadow;\n clickableElement.style.transition = originalTransition;\n clickableElement.style.zIndex = originalZIndex;\n\n clickEffectContainer.remove(); \n resolve();\n }, 1000);\n\n }, 1500);\n });\n};\n\n// Highlight elements on the page with animated cursor and click effects\nexport const highlightElement = async (\n selector: string | string[],\n isHighlighting: boolean,\n setIsHighlighting: (highlighting: boolean) => void,\n logMessage: (content: string, sender: 'GUIDEAI' | 'HUMAN') => void\n): Promise<boolean> => {\n if (isHighlighting) return false;\n \n const selectors = Array.isArray(selector) ? selector : [selector];\n if (selectors.length === 0) return false;\n \n console.log('Moving cursor to elements:', selectors);\n \n let cursorElement: HTMLElement | null = null;\n try {\n setIsHighlighting(true);\n \n for (let i = 0; i < selectors.length; i++) {\n const currentSelector = selectors[i];\n \n if (i > 0) {\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n \n let element;\n if (currentSelector.startsWith('//')) {\n const node = document.evaluate(currentSelector, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;\n if (!(node instanceof Element)) {\n console.log('XPath returned a non-Element node:', currentSelector);\n console.log(node);\n logMessage('XPath returned a non-Element node: ' + currentSelector, 'GUIDEAI');\n break;\n }\n element = node as Element;\n } else {\n element = document.querySelector(currentSelector);\n }\n \n if (!element) {\n console.log('Element not found:', currentSelector);\n logMessage('Element not found: ' + currentSelector, 'GUIDEAI');\n break;\n }\n \n const rect = element.getBoundingClientRect();\n \n // Create cursor if it's the first element, or reuse existing cursor\n if (!cursorElement) {\n cursorElement = document.createElement('div');\n cursorElement.id = 'guide-ai-cursor';\n \n const blueCursorSvg = `\n <svg width=\"100%\" height=\"100%\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill=\"#0066ff\" d=\"M7,2l12,11.2l-5.8,0.5l3.3,7.3l-2.2,1l-3.2-7.4L7,18.5V2\" />\n </svg>\n `;\n \n cursorElement.innerHTML = blueCursorSvg;\n cursorElement.style.cssText = `\n position: fixed;\n width: 64px;\n height: 64px;\n pointer-events: none;\n z-index: 9999;\n transition: all 0.8s ease-in-out;\n transform: translate(-50%, 0);\n filter: drop-shadow(0 0 4px rgba(0, 102, 255, 0.8));\n `;\n \n document.body.appendChild(cursorElement);\n \n // First element starts from center of viewport\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n cursorElement.style.left = `${viewportWidth / 2}px`;\n cursorElement.style.top = `${viewportHeight / 2}px`;\n }\n \n // Force reflow to ensure transition works\n cursorElement!.offsetHeight;\n \n await new Promise<void>(resolve => {\n setTimeout(() => {\n cursorElement!.style.left = `${rect.left + rect.width / 2}px`;\n cursorElement!.style.top = `${rect.top + rect.height / 2 - 10}px`;\n \n setTimeout(() => {\n cursorElement!.style.animation = 'cursor-jiggle 0.5s ease-in-out infinite';\n resolve();\n }, 800);\n }, 100);\n });\n \n await clickElement(element, rect);\n }\n\n setTimeout(() => {\n cursorElement?.remove();\n setIsHighlighting(false);\n }, 1000);\n \n return true;\n } catch (error) {\n console.error('Error moving cursor:', error);\n cursorElement?.remove();\n setIsHighlighting(false);\n return false;\n }\n}; ","// User metadata tracking system for GuideAI\n// Tracks user visits, logins, and other metadata for Overproof integration\n\nimport { \n UserMetadata, \n MetadataConfig, \n MetadataStorageData, \n MetadataEvent, \n MetadataEventType,\n MetadataUpdate \n} from '../types/metadata.types';\nimport { sendMetadataUpdates } from '../utils/api';\n\nconst METADATA_STORAGE_KEY = 'guideai_user_metadata';\nconst METADATA_VERSION = '1.0.0';\nconst SESSION_VISIT_KEY = 'guideai_session_visit';\n\nclass UserMetadataTracker {\n private config: Required<MetadataConfig>;\n private metadata: UserMetadata;\n private syncTimer: NodeJS.Timeout | null = null;\n private pendingUpdates: MetadataUpdate[] = [];\n private isInitialized: boolean = false;\n private onError?: (error: Error, context: string) => void;\n private lastSyncTime: number = 0;\n private minSyncInterval: number = 60000; // Minimum 1 minute between syncs\n private lastMetadataHash: string = '';\n private pendingUpdateTypes: Set<string> = new Set();\n\n constructor(organizationKey: string, config: MetadataConfig = {}, onError?: (error: Error, context: string) => void) {\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Constructor called', { organizationKey, config });\n }\n \n this.config = {\n trackVisits: true,\n trackLogins: true,\n syncInterval: 300000, // Increased to 5 minutes instead of 30 seconds\n storage: 'localStorage',\n customFields: [],\n collectBrowserInfo: true,\n collectUserAgent: true,\n ...config\n };\n\n this.metadata = {\n organizationKey,\n visitCount: 0,\n loginCount: 0\n };\n \n this.onError = onError;\n\n // Don't call init() immediately - let the component control initialization\n // this.init();\n \n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Constructor completed', { metadata: this.metadata });\n }\n }\n\n public init(): void {\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: init() method called', { isInitialized: this.isInitialized });\n }\n \n if (this.isInitialized) {\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Already initialized, skipping');\n }\n return;\n }\n\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Starting initialization...');\n }\n\n // Load existing metadata from storage\n this.loadMetadata();\n\n // Collect browser info if enabled\n if (this.config.collectBrowserInfo) {\n this.collectBrowserInfo();\n }\n\n // Track initial visit if enabled and not already tracked this session\n if (this.config.trackVisits) {\n this.trackVisitOncePerSession();\n }\n\n // Start sync timer\n this.startSyncTimer();\n\n // Listen for EventTracker events to detect user interactions\n this.setupEventTrackerIntegration();\n\n this.isInitialized = true;\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Initialized successfully', this.metadata);\n }\n }\n\n public updateUserInfo(userInfo: Partial<UserMetadata>): void {\n const timestamp = Date.now();\n \n // Check if the update is actually different\n if (this.isDataDuplicate('user_info', userInfo)) {\n return;\n }\n \n // Update metadata\n this.metadata = {\n ...this.metadata,\n ...userInfo,\n lastVisit: timestamp\n };\n\n // Add to pending updates with deduplication\n this.addPendingUpdate({\n type: 'user_info',\n timestamp,\n data: userInfo\n });\n\n // Save to storage\n this.saveMetadata();\n\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: User info updated', userInfo);\n }\n }\n\n public trackLogin(additionalInfo?: Partial<UserMetadata>): void {\n if (!this.config.trackLogins) return;\n\n const timestamp = Date.now();\n \n // Check if this is a duplicate login event (within 30 seconds)\n const lastLoginTime = this.metadata.lastLogin || 0;\n if (timestamp - lastLoginTime < 30000) {\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Ignoring duplicate login event');\n }\n return;\n }\n \n this.metadata = {\n ...this.metadata,\n ...additionalInfo,\n loginCount: (this.metadata.loginCount || 0) + 1,\n lastLogin: timestamp,\n lastVisit: timestamp\n };\n\n this.addPendingUpdate({\n type: 'login',\n timestamp,\n data: {\n loginCount: this.metadata.loginCount,\n lastLogin: timestamp,\n ...additionalInfo\n }\n });\n\n this.saveMetadata();\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Login tracked', this.metadata.loginCount);\n }\n }\n\n private trackVisitOncePerSession(): void {\n if (!this.config.trackVisits) return;\n\n // Check if we've already tracked a visit this session\n const sessionKey = `${SESSION_VISIT_KEY}_${this.metadata.organizationKey}`;\n const hasTrackedThisSession = typeof window !== 'undefined' && sessionStorage.getItem(sessionKey);\n \n // Check if EventTracker has created a new session\n const eventTrackerSessionId = typeof window !== 'undefined' && sessionStorage.getItem('eventTracker_sessionId');\n const lastTrackedSessionId = typeof window !== 'undefined' && sessionStorage.getItem(`${SESSION_VISIT_KEY}_sessionId_${this.metadata.organizationKey}`);\n \n // If EventTracker has a new session, reset our visit tracking\n if (eventTrackerSessionId && eventTrackerSessionId !== lastTrackedSessionId) {\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: New EventTracker session detected, resetting visit tracking');\n }\n if (typeof window !== 'undefined') {\n sessionStorage.removeItem(sessionKey);\n sessionStorage.setItem(`${SESSION_VISIT_KEY}_sessionId_${this.metadata.organizationKey}`, eventTrackerSessionId);\n }\n }\n \n if (hasTrackedThisSession) {\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Visit already tracked this session, skipping');\n }\n return;\n }\n\n const timestamp = Date.now();\n const isFirstVisit = !this.metadata.firstVisit;\n\n this.metadata = {\n ...this.metadata,\n firstVisit: this.metadata.firstVisit || timestamp,\n lastVisit: timestamp,\n visitCount: (this.metadata.visitCount || 0) + 1\n };\n\n this.addPendingUpdate({\n type: 'visit',\n timestamp,\n data: {\n firstVisit: this.metadata.firstVisit,\n lastVisit: this.metadata.lastVisit,\n visitCount: this.metadata.visitCount\n }\n });\n\n // Mark that we've tracked a visit this session\n if (typeof window !== 'undefined') {\n sessionStorage.setItem(sessionKey, timestamp.toString());\n // Store the current EventTracker session ID\n const eventTrackerSessionId = sessionStorage.getItem('eventTracker_sessionId');\n if (eventTrackerSessionId) {\n sessionStorage.setItem(`${SESSION_VISIT_KEY}_sessionId_${this.metadata.organizationKey}`, eventTrackerSessionId);\n }\n }\n\n this.saveMetadata();\n \n if (process.env.NODE_ENV === 'development') {\n console.log(`UserMetadataTracker: ${isFirstVisit ? 'First' : 'Return'} visit tracked`, {\n visitCount: this.metadata.visitCount,\n firstVisit: this.metadata.firstVisit,\n lastVisit: this.metadata.lastVisit\n });\n }\n }\n\n // Legacy method - now calls the session-based version\n public trackVisit(): void {\n this.trackVisitOncePerSession();\n }\n\n // Method to reset session visit tracking (call this when user logs in)\n public resetSessionVisitTracking(): void {\n const sessionKey = `${SESSION_VISIT_KEY}_${this.metadata.organizationKey}`;\n const sessionIdKey = `${SESSION_VISIT_KEY}_sessionId_${this.metadata.organizationKey}`;\n if (typeof window !== 'undefined') {\n sessionStorage.removeItem(sessionKey);\n sessionStorage.removeItem(sessionIdKey);\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Session visit tracking reset');\n }\n }\n }\n\n // Method to manually track a visit (useful for login events)\n public trackVisitManually(): void {\n if (!this.config.trackVisits) return;\n\n const timestamp = Date.now();\n const isFirstVisit = !this.metadata.firstVisit;\n\n this.metadata = {\n ...this.metadata,\n firstVisit: this.metadata.firstVisit || timestamp,\n lastVisit: timestamp,\n visitCount: (this.metadata.visitCount || 0) + 1\n };\n\n this.addPendingUpdate({\n type: 'visit',\n timestamp,\n data: {\n firstVisit: this.metadata.firstVisit,\n lastVisit: this.metadata.lastVisit,\n visitCount: this.metadata.visitCount\n }\n });\n\n // Mark that we've tracked a visit this session\n const sessionKey = `${SESSION_VISIT_KEY}_${this.metadata.organizationKey}`;\n const sessionIdKey = `${SESSION_VISIT_KEY}_sessionId_${this.metadata.organizationKey}`;\n if (typeof window !== 'undefined') {\n sessionStorage.setItem(sessionKey, timestamp.toString());\n // Store the current EventTracker session ID\n const eventTrackerSessionId = sessionStorage.getItem('eventTracker_sessionId');\n if (eventTrackerSessionId) {\n sessionStorage.setItem(sessionIdKey, eventTrackerSessionId);\n }\n }\n\n this.saveMetadata();\n \n if (process.env.NODE_ENV === 'development') {\n console.log(`UserMetadataTracker: Manual visit tracked`, {\n visitCount: this.metadata.visitCount,\n firstVisit: this.metadata.firstVisit,\n lastVisit: this.metadata.lastVisit\n });\n }\n }\n\n public trackCustomEvent(eventType: string, customData: Record<string, any>): void {\n const timestamp = Date.now();\n\n // Update custom fields if they're in the config\n const customFields = { ...this.metadata.customFields };\n for (const [key, value] of Object.entries(customData)) {\n if (this.config.customFields.includes(key)) {\n customFields[key] = value;\n }\n }\n\n this.metadata = {\n ...this.metadata,\n customFields,\n lastVisit: timestamp\n };\n\n this.addPendingUpdate({\n type: 'custom',\n timestamp,\n data: { customFields }\n });\n\n this.saveMetadata();\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Custom event tracked', eventType, customData);\n }\n }\n\n public getMetadata(): UserMetadata {\n return { ...this.metadata };\n }\n\n public getPendingUpdates(): MetadataUpdate[] {\n return [...this.pendingUpdates];\n }\n\n public clearPendingUpdates(): void {\n this.pendingUpdates = [];\n this.pendingUpdateTypes.clear();\n }\n\n public syncNow(): MetadataUpdate[] {\n const updates = [...this.pendingUpdates];\n this.clearPendingUpdates();\n return updates;\n }\n\n private loadMetadata(): void {\n try {\n const storageData = this.getFromStorage();\n if (storageData && storageData.metadata) {\n // Merge stored metadata with current metadata\n this.metadata = {\n ...this.metadata,\n ...storageData.metadata\n };\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Loaded metadata from storage', this.metadata);\n }\n }\n } catch (error) {\n console.warn('UserMetadataTracker: Failed to load metadata from storage', error);\n // Clear corrupted data\n this.clearStorage();\n }\n }\n\n private saveMetadata(): void {\n try {\n const storageData: MetadataStorageData = {\n metadata: this.metadata,\n lastUpdated: Date.now(),\n version: METADATA_VERSION\n };\n\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: saveMetadata called with', this.metadata);\n }\n \n this.setToStorage(storageData);\n } catch (error) {\n console.warn('UserMetadataTracker: Failed to save metadata to storage', error);\n }\n }\n\n private collectBrowserInfo(): void {\n if (typeof window === 'undefined') return;\n\n const userAgent = navigator.userAgent;\n const browserInfo = this.parseBrowserInfo(userAgent);\n\n this.metadata = {\n ...this.metadata,\n userAgent: this.config.collectUserAgent ? userAgent : undefined,\n browserInfo\n };\n \n // Save the updated metadata to localStorage\n this.saveMetadata();\n }\n\n private parseBrowserInfo(userAgent: string): UserMetadata['browserInfo'] {\n // Simple browser detection - could be enhanced with a proper library\n let name = 'Unknown';\n let version = 'Unknown';\n let platform = 'Unknown';\n\n // Detect browser\n if (userAgent.includes('Chrome') && !userAgent.includes('Edg')) {\n name = 'Chrome';\n const match = userAgent.match(/Chrome\\/([0-9.]+)/);\n version = match ? match[1] : 'Unknown';\n } else if (userAgent.includes('Firefox')) {\n name = 'Firefox';\n const match = userAgent.match(/Firefox\\/([0-9.]+)/);\n version = match ? match[1] : 'Unknown';\n } else if (userAgent.includes('Safari') && !userAgent.includes('Chrome')) {\n name = 'Safari';\n const match = userAgent.match(/Version\\/([0-9.]+)/);\n version = match ? match[1] : 'Unknown';\n } else if (userAgent.includes('Edg')) {\n name = 'Edge';\n const match = userAgent.match(/Edg\\/([0-9.]+)/);\n version = match ? match[1] : 'Unknown';\n }\n\n // Detect platform\n if (userAgent.includes('Win')) platform = 'Windows';\n else if (userAgent.includes('Mac')) platform = 'macOS';\n else if (userAgent.includes('Linux')) platform = 'Linux';\n else if (userAgent.includes('Android')) platform = 'Android';\n else if (userAgent.includes('iOS')) platform = 'iOS';\n\n return { name, version, platform };\n }\n\n private startSyncTimer(): void {\n if (this.syncTimer) return;\n\n this.syncTimer = setInterval(() => {\n if (this.pendingUpdates.length > 0 && this.shouldSync()) {\n this.emitPendingUpdates();\n }\n }, this.config.syncInterval);\n }\n\n // Helper method to check if sync should occur (respects minimum interval)\n private shouldSync(): boolean {\n const now = Date.now();\n return (now - this.lastSyncTime) >= this.minSyncInterval;\n }\n\n // Helper method to add pending updates with deduplication\n private addPendingUpdate(update: MetadataUpdate): void {\n // Check if we already have a pending update of this type\n if (this.pendingUpdateTypes.has(update.type)) {\n // Replace the existing update of this type with the latest one\n this.pendingUpdates = this.pendingUpdates.filter(u => u.type !== update.type);\n }\n \n this.pendingUpdates.push(update);\n this.pendingUpdateTypes.add(update.type);\n }\n\n // Helper method to check if data is duplicate\n private isDataDuplicate(type: string, data: any): boolean {\n const currentHash = this.generateDataHash(data);\n const existingUpdate = this.pendingUpdates.find(u => u.type === type);\n \n if (existingUpdate) {\n const existingHash = this.generateDataHash(existingUpdate.data);\n return currentHash === existingHash;\n }\n \n return false;\n }\n\n // Helper method to generate a simple hash for data comparison\n private generateDataHash(data: any): string {\n return JSON.stringify(data, Object.keys(data).sort());\n }\n\n private setupEventTrackerIntegration(): void {\n if (typeof window === 'undefined') return;\n\n let lastActivityUpdate = 0;\n const activityUpdateThrottle = 60000; // Only update activity once per minute\n\n // Listen for EventTracker batches to detect user interactions\n const handleEventBatch = (event: Event) => {\n const customEvent = event as CustomEvent;\n const batchData = customEvent.detail;\n const now = Date.now();\n \n if (batchData && batchData.events) {\n // Look for login-related events (form submissions, clicks on login buttons, etc.)\n const hasLoginEvent = batchData.events.some((evt: any) => \n evt.type === 'submit' || \n (evt.type === 'click' && (\n evt.textContent?.toLowerCase().includes('login') ||\n evt.textContent?.toLowerCase().includes('sign in') ||\n evt.className?.toLowerCase().includes('login') ||\n evt.id?.toLowerCase().includes('login')\n ))\n );\n\n if (hasLoginEvent) {\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Detected potential login event from EventTracker');\n }\n // Note: We don't automatically track login here as it requires explicit confirmation\n // This is just for detecting potential login scenarios\n }\n\n // Track general user activity with throttling\n if (now - lastActivityUpdate > activityUpdateThrottle) {\n this.metadata = {\n ...this.metadata,\n lastVisit: now\n };\n lastActivityUpdate = now;\n }\n }\n };\n\n window.addEventListener('guideai:event_batch', handleEventBatch);\n \n // Store the listener for cleanup\n (this as any)._eventTrackerListener = handleEventBatch;\n }\n\n private stopSyncTimer(): void {\n if (this.syncTimer) {\n clearInterval(this.syncTimer);\n this.syncTimer = null;\n }\n }\n\n private async emitPendingUpdates(): Promise<void> {\n if (this.pendingUpdates.length === 0) return;\n\n const updates = [...this.pendingUpdates];\n this.lastSyncTime = Date.now();\n \n // Emit the updates (integrate with existing event system)\n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Emitting metadata updates', {\n updateCount: updates.length,\n updates,\n currentMetadata: this.metadata\n });\n }\n\n // Send to backend API\n try {\n if (this.onError) {\n await sendMetadataUpdates(updates, this.metadata.organizationKey, this.onError);\n }\n \n // Clear pending updates after successful emission\n this.clearPendingUpdates();\n } catch (error) {\n console.warn('UserMetadataTracker: Failed to send metadata updates, will retry later', error);\n // Don't clear pending updates so they can be retried\n }\n }\n\n private getFromStorage(): MetadataStorageData | null {\n try {\n const key = `${METADATA_STORAGE_KEY}_${this.metadata.organizationKey}`;\n let data: string | null = null;\n\n switch (this.config.storage) {\n case 'localStorage':\n data = typeof window !== 'undefined' ? localStorage.getItem(key) : null;\n break;\n case 'sessionStorage':\n data = typeof window !== 'undefined' ? sessionStorage.getItem(key) : null;\n break;\n case 'memory':\n // For memory storage, we don't persist across sessions\n return null;\n }\n\n return data ? JSON.parse(data) : null;\n } catch (error) {\n console.warn('UserMetadataTracker: Error reading from storage', error);\n return null;\n }\n }\n\n private setToStorage(data: MetadataStorageData): void {\n try {\n const key = `${METADATA_STORAGE_KEY}_${this.metadata.organizationKey}`;\n const serialized = JSON.stringify(data);\n\n switch (this.config.storage) {\n case 'localStorage':\n if (typeof window !== 'undefined') {\n localStorage.setItem(key, serialized);\n }\n break;\n case 'sessionStorage':\n if (typeof window !== 'undefined') {\n sessionStorage.setItem(key, serialized);\n }\n break;\n case 'memory':\n // For memory storage, we don't persist\n break;\n }\n } catch (error) {\n console.warn('UserMetadataTracker: Error writing to storage', error);\n }\n }\n\n private clearStorage(): void {\n try {\n const key = `${METADATA_STORAGE_KEY}_${this.metadata.organizationKey}`;\n\n switch (this.config.storage) {\n case 'localStorage':\n if (typeof window !== 'undefined') {\n localStorage.removeItem(key);\n }\n break;\n case 'sessionStorage':\n if (typeof window !== 'undefined') {\n sessionStorage.removeItem(key);\n }\n break;\n case 'memory':\n // Nothing to clear for memory storage\n break;\n }\n } catch (error) {\n console.warn('UserMetadataTracker: Error clearing storage', error);\n }\n }\n\n public destroy(): void {\n // Emit any pending updates before destroying\n this.emitPendingUpdates();\n \n // Stop sync timer\n this.stopSyncTimer();\n \n // Remove event listener\n if (typeof window !== 'undefined' && (this as any)._eventTrackerListener) {\n window.removeEventListener('guideai:event_batch', (this as any)._eventTrackerListener);\n }\n \n // Clear state\n this.isInitialized = false;\n this.pendingUpdates = [];\n \n if (process.env.NODE_ENV === 'development') {\n console.log('UserMetadataTracker: Destroyed');\n }\n }\n}\n\nexport default UserMetadataTracker;\nexport type { UserMetadata, MetadataConfig, MetadataUpdate };\n","// Metric exports\nexport { default as EventTracker } from './event-listner';\nexport type { EventData } from './event-listner';\nexport { default as UserMetadataTracker } from './metadata-tracker';\nexport type { UserMetadata, MetadataConfig, MetadataUpdate } from './metadata-tracker';","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(258);\n"],"names":["root","factory","exports","module","require","define","amd","this","__WEBPACK_EXTERNAL_MODULE__156__","guideAIStyles","CONVERSATION_STORAGE_KEY","CONVERSATION_EXPIRY_MINUTES","MAX_STORED_MESSAGES","isLocalStorageAvailable","testKey","localStorage","setItem","removeItem","e","isConversationExpired","conversation","expiryTime","Date","now","timestamp","handleStorageError","error","operation","console","DOMException","name","loadConversationFromStorage","messages","length","slice","saveConversationToStorage","warn","clearConversationStorage","cleanupError","JSON","stringify","storedData","getItem","parsedData","parse","data","conversationId","Array","isArray","organizationKey","every","msg","content","sender","addMessageToStorage","message","some","existingMsg","Math","abs","log","substring","push","checkForStoredConversation","currentOrganizationKey","storedConversation","shouldRestore","formatConversationContext","maxMessages","recentMessages","meaningfulMessages","filter","trim","map","join","DEFAULT_PROMPT","IGNORE_MESSAGE_TYPES","GUIDE_AI_API_BASE","OPENAI_REALTIME_BASE","OPENAI_REALTIME_MODEL","GEMINI_API_KEY","GEMINI_API_ENDPOINT","createNewConversation","onError","fetch","method","headers","body","userId","date","toISOString","split","time","toTimeString","response","ok","text","catch","errorText","status","Error","json","conversationData","id","logMessage","statusText","sendMetadataUpdates","updates","batchTimestamp","updateCount","cachedHooks","window","React","useState","useEffect","useRef","useMemo","useCallback","props","position","metadataOptions","transcriptOptions","inputOptions","hooks","setStatus","isClient","setIsClient","isHighlighting","setIsHighlighting","hasInteracted","setHasInteracted","setPrompt","setIsSessionReady","isConnecting","setIsConnecting","showOnboarding","setShowOnboarding","popupPosition","setPopupPosition","conversationIdRef","componentRef","peerConnectionRef","dataChannelRef","hasCreatedConversationRef","mediaStreamRef","audioElementRef","ephemeralToken","setEphemeralToken","hasInitializedRef","isUnmountingRef","isConversationActive","setIsConversationActive","restoredMessages","setRestoredMessages","enabled","showTranscript","setShowTranscript","allMessages","setAllMessages","defaultMode","inputMode","setInputMode","textInput","setTextInput","setShowTextInput","hasAttemptedAutoStartRef","initializationAttemptedRef","eventTracker","customerId","initialUserData","organizationId","customerType","userType","EventTracker","metadataTracker","UserMetadataTracker","config","geminiFlash","prompt","contents","parts","responseJson","candidates","handleCreateNewConversation","current","handleLogMessage","prev","lastMessage","newMessage","handleHighlightElement","selector","highlightElement","getOptimalPosition","elementHeight","spacing","rect","getBoundingClientRect","calculateOptimalPosition","sendMessage","readyState","send","cleanupWebRTC","getAudioTracks","forEach","track","stop","close","srcObject","initializeWebRTC","audioStream","RTCPeerConnection","addTrack","audioEl","document","createElement","autoplay","appendChild","ontrack","kind","stream","MediaStream","dc","createDataChannel","onopen","sessionConfig","tools","type","description","parameters","properties","oneOf","items","required","tool_choice","turn_detection","create_response","interrupt_response","input_audio_transcription","model","language","session","onmessage","conversationContext","item","role","transcript","output","out","arguments","argsToUse","then","replace","parsedArgs","err","call_id","code","setTimeout","fragment","includes","createOffer","offer","setLocalDescription","localDescription","sdp","baseUrl","Authorization","sdpResponse","answerSdp","answer","setRemoteDescription","startConversationSession","navigator","mediaDevices","getUserMedia","audio","echoCancellation","noiseSuppression","autoGainControl","channelCount","sampleRate","endConversationSession","handleToggleTranscript","handleTextSubmit","responseMessage","handleTextKeyPress","event","key","shiftKey","preventDefault","handleCloseTranscript","injectStyles","styleElement","getElementById","styleContent","textContent","init","updateUserInfo","hasInitialized","initializationAttempted","hasInteractedBefore","isUnmounting","remove","stopTracking","destroy","syncInterval","syncTimer","setInterval","pendingUpdates","syncNow","onMetadataUpdate","getMetadata","clearInterval","success","transcriptBoxProps","isVisible","onClose","showToggleButton","onToggle","showTextInput","enableTextInput","onTextInputChange","onTextSubmit","onTextKeyPress","textPlaceholder","placeholder","GuideAI","metadata","trackLogin","additionalInfo","userInfo","trackCustomEvent","eventType","customData","syncMetadata","resetSessionVisitTracking","trackVisitManually","toggle","show","hide","input","toggleMode","newMode","setMode","mode","getMode","sendText","shouldUseFixedPosition","Object","keys","baseStyles","zIndex","ref","style","className","onComplete","onClick","undefined","cursor","title","css","head","componentRect","viewportHeight","innerHeight","spaceAbove","top","spaceBelow","bottom","TranscriptBox","memo","element","transcriptContainer","scrollTop","scrollHeight","shouldShowToggleButton","shouldShowTranscript","index","toLowerCase","toLocaleTimeString","hour","minute","value","onChange","target","onKeyPress","rows","disabled","prevProps","nextProps","displayName","step","setStep","options","isTracking","eventData","batchSize","batchTimeout","batchTimer","pendingEvents","currentUrl","lastEventTime","eventThrottleInterval","lastEventsByType","Map","duplicateEventBuffer","maxDuplicateBuffer","isInitialized","customerMetadata","handleClick","isSignificantClickTarget","baseEventData","tagName","getSafeValue","url","location","href","logEvent","handleFocus","isFocusable","isSignificantFocusTarget","handleChange","isFormElement","handleSubmit","formData","FormData","handlePopstate","newUrl","previousUrl","getPreviousUrl","isSignificantRouteChange","handleHashChange","oldURL","String","loadEventsFromStorage","addEventListener","startTracking","storageKey","storedEvents","parsedEvents","saveEventsToStorage","sanitizedEventData","sanitizeEventData","setCustomerMetadata","getCustomerMetadata","clearCustomerMetadata","initialize","enrichEventData","sanitizedBaseData","customerSegment","sessionId","getSessionId","deviceType","getDeviceType","userAgent","screenResolution","screen","width","height","currentPage","pathname","userRole","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","locale","sanitized","val","sessionStorage","random","toString","substr","test","trackClickEvents","trackFocusEvents","trackChangeEvents","trackSubmitEvents","trackRouteChanges","emitBatch","removeEventListener","interceptHistoryAPI","originalPushState","history","pushState","originalReplaceState","replaceState","result","apply","args","inputElement","selectElement","selectedIndex","inputType","matches","generateEventKey","shouldThrottleEvent","currentTime","get","isDuplicateEvent","eventKey","existingEvent","getAttribute","hasAttribute","from","attributes","attr","startsWith","getComputedStyle","tabindex","parseInt","newUrlObj","URL","prevUrlObj","hash","enrichedEventData","set","size","delete","startBatchTimer","clearTimeout","batchPayload","events","dispatchEvent","CustomEvent","detail","getEventData","clearEventData","getEventDataByType","getEventDataByElement","toUpperCase","getEventDataByUrl","emitPendingEvents","setBatchConfig","getPendingEventsCount","getCustomerAnalytics","sessionDuration","getSessionStartTime","analytics","totalEvents","eventsByCustomer","eventsByType","eventsByPage","eventsByDevice","lastActivity","sessionStart","startTime","identifyCustomerFromContext","userRoleMeta","querySelector","setCustomerFromAuth","authData","clickElement","Promise","resolve","clickEffectContainer","cssText","left","j","clickRipple","clickDot","clickEvent","MouseEvent","view","bubbles","cancelable","clickableElements","querySelectorAll","clickableElement","originalBoxShadow","boxShadow","originalTransition","transition","originalZIndex","selectors","cursorElement","i","currentSelector","node","evaluate","XPathResult","FIRST_ORDERED_NODE_TYPE","singleNodeValue","Element","innerHTML","viewportWidth","innerWidth","offsetHeight","animation","METADATA_STORAGE_KEY","SESSION_VISIT_KEY","lastSyncTime","minSyncInterval","lastMetadataHash","pendingUpdateTypes","Set","trackVisits","trackLogins","storage","customFields","collectBrowserInfo","collectUserAgent","visitCount","loginCount","loadMetadata","trackVisitOncePerSession","startSyncTimer","setupEventTrackerIntegration","isDataDuplicate","lastVisit","addPendingUpdate","saveMetadata","lastLogin","sessionKey","hasTrackedThisSession","eventTrackerSessionId","lastTrackedSessionId","firstVisit","trackVisit","sessionIdKey","entries","getPendingUpdates","clearPendingUpdates","clear","storageData","getFromStorage","clearStorage","lastUpdated","version","setToStorage","browserInfo","parseBrowserInfo","platform","match","shouldSync","emitPendingUpdates","update","has","u","add","currentHash","generateDataHash","existingUpdate","find","sort","lastActivityUpdate","handleEventBatch","batchData","evt","_eventTrackerListener","stopSyncTimer","serialized","default","__webpack_module_cache__","__webpack_exports__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","call"],"sourceRoot":""}