@om_patel_26/chat-widget 1.0.1 → 1.0.2
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.
- package/dist/components/ChatWidget.vue.cjs.js +1 -1
- package/dist/components/ChatWidget.vue.cjs2.js +1 -1
- package/dist/components/ChatWidget.vue.cjs2.js.map +1 -1
- package/dist/components/ChatWidget.vue.esm.js +1 -1
- package/dist/components/ChatWidget.vue.esm2.js +35 -27
- package/dist/components/ChatWidget.vue.esm2.js.map +1 -1
- package/dist/core/stateManager.cjs.js +1 -1
- package/dist/core/stateManager.cjs.js.map +1 -1
- package/dist/core/stateManager.d.ts.map +1 -1
- package/dist/core/stateManager.esm.js +11 -5
- package/dist/core/stateManager.esm.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./ChatWidget.vue.cjs2.js");;/* empty css */const t=require("../_virtual/_plugin-vue_export-helper.cjs.js").default(e.default,[["__scopeId","data-v-
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./ChatWidget.vue.cjs2.js");;/* empty css */const t=require("../_virtual/_plugin-vue_export-helper.cjs.js").default(e.default,[["__scopeId","data-v-7f95b555"]]);exports.default=t;
|
|
2
2
|
//# sourceMappingURL=ChatWidget.vue.cjs.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),t=require("../composables/useChatWidget.cjs.js"),o=require("../utils/sanitize.cjs.js"),a={class:"blockspark-chat-widget"},l={class:"blockspark-welcome-header"},n={class:"blockspark-welcome-title"},c={class:"blockspark-welcome-message"},s={class:"blockspark-welcome-cta"},r={key:2,class:"blockspark-chat-window"},i={class:"blockspark-chat-header"},p={class:"blockspark-chat-header-content"},k={class:"blockspark-chat-title"},d={class:"blockspark-chat-subtitle"},m={key:0,class:"blockspark-mode-indicator"},u={key:0,class:"blockspark-mode-badge"},g={key:1,class:"blockspark-agent-info"},b={class:"blockspark-agent-name"},h={key:2,class:"blockspark-mode-badge"},y={key:0,class:"blockspark-chat-empty"},E=
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),t=require("../composables/useChatWidget.cjs.js"),o=require("../utils/sanitize.cjs.js"),a={class:"blockspark-chat-widget"},l={class:"blockspark-welcome-header"},n={class:"blockspark-welcome-title"},c={class:"blockspark-welcome-message"},s={class:"blockspark-welcome-cta"},r={key:2,class:"blockspark-chat-window"},i={class:"blockspark-chat-header"},p={class:"blockspark-chat-header-content"},k={class:"blockspark-chat-title"},d={class:"blockspark-chat-subtitle"},m={key:0,class:"blockspark-mode-indicator"},u={key:0,class:"blockspark-mode-badge"},g={key:1,class:"blockspark-agent-info"},b={class:"blockspark-agent-name"},h={key:2,class:"blockspark-mode-badge"},y={key:0,class:"blockspark-chat-empty"},E=["innerHTML"],f={key:0,class:"blockspark-chips-container"},B={key:0,class:"blockspark-chips-group"},V=["onClick"],v={key:0,class:"blockspark-chips-group"},N=["onClick"],C={class:"blockspark-message-time"},w={key:1,class:"blockspark-message blockspark-message-bot"},M={key:2,class:"blockspark-agent-typing-indicator"},S=["value","placeholder","disabled"],x=["disabled"],A=e.defineComponent({__name:"ChatWidget",props:{dfProjectId:{},dfLocation:{},dfAgentId:{},serviceAccountKey:{},accessToken:{},languageCode:{},backendBaseUrl:{},backendWsUrl:{},title:{default:"💬 BlockSpark AI Assistant"},subtitle:{default:"We're here to help"},welcomeTitle:{default:"👋 Welcome to BlockSpark"},welcomeMessage:{default:"My name is BlockSpark AI Assistant and I'll guide you."},welcomeCta:{default:"💬 Click here to start chatting!"},showWelcomePopup:{type:Boolean,default:!0},welcomePopupDelay:{default:1500},fallbackWelcomeMessage:{default:"Hello! I'm BlockSpark AI Assistant. How can I help you today?"},inputPlaceholder:{default:"Type your message..."},emptyStateMessage:{default:"Hi! I'm BlockSpark AI Assistant. How can I help you today?"},debug:{type:Boolean,default:!1}},setup(A){const I=A,{state:L,isOpen:D,messages:T,isLoading:W,error:P,chatMode:j,wsConnected:F,agentTyping:H,currentAgent:O,openChat:_,closeChat:z,sendMessage:q,toggleChat:$,setInputValue:U,clearError:K,manager:R}=t.useChatWidget(I),G=e.ref(null),J=e.ref(null),Q=e.computed(()=>I);e.watch(()=>T.value.length,()=>{e.nextTick(()=>{G.value?.scrollIntoView({behavior:"smooth"})})});const X=async()=>{await _()},Y=()=>{z()},Z=()=>{R.closeWelcomePopup()},ee=e=>{const t=e.target;U(t.value)},te=async e=>{e.preventDefault(),L.value.inputValue.trim()&&await q(L.value.inputValue)},oe=async(e,t)=>{const o=e||t||"";await q(o)},ae=e=>e.includes("👤")||e.includes("being connected")||e.includes("live support agent")||e.includes("transfer your conversation");return e.onMounted(()=>{Q.value.showWelcomePopup&&"undefined"!=typeof window&&R.initializeWelcomePopup()}),(t,A)=>(e.openBlock(),e.createElementBlock("div",a,[e.unref(L).showWelcomePopup&&!e.unref(L).isOpen?(e.openBlock(),e.createElementBlock("div",{key:0,class:"blockspark-welcome-popup",onClick:X},[e.createElementVNode("div",l,[e.createElementVNode("div",n,e.toDisplayString(Q.value.welcomeTitle),1),e.createElementVNode("button",{class:"blockspark-close-popup",onClick:e.withModifiers(Z,["stop"]),"aria-label":"Close welcome popup"}," × ")]),e.createElementVNode("div",c,e.toDisplayString(Q.value.welcomeMessage),1),e.createElementVNode("div",s,e.toDisplayString(Q.value.welcomeCta),1)])):e.createCommentVNode("",!0),e.unref(L).isOpen?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("button",{key:1,class:"blockspark-chat-toggle-btn",onClick:X,"aria-label":"Open chat"},[...A[0]||(A[0]=[e.createElementVNode("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[e.createElementVNode("path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"})],-1)])])),e.unref(L).isOpen?(e.openBlock(),e.createElementBlock("div",r,[e.createElementVNode("div",i,[e.createElementVNode("div",p,[e.createElementVNode("div",k,e.toDisplayString(Q.value.title),1),e.createElementVNode("div",d,[e.createTextVNode(e.toDisplayString(Q.value.subtitle)+" ",1),"human"===e.unref(L).chatMode?(e.openBlock(),e.createElementBlock("span",m," • "+e.toDisplayString(e.unref(F)?"🟢 Connected":"🟡 Connecting..."),1)):e.createCommentVNode("",!0)]),"human"===e.unref(L).chatMode?(e.openBlock(),e.createElementBlock("div",u," Human Support Mode ")):e.createCommentVNode("",!0),"human"===e.unref(L).chatMode?(e.openBlock(),e.createElementBlock("div",g,[A[1]||(A[1]=e.createElementVNode("span",{class:"blockspark-agent-label"},"Agent:",-1)),e.createElementVNode("span",b,e.toDisplayString(e.unref(O).name),1)])):e.createCommentVNode("",!0),"ai"===e.unref(L).chatMode?(e.openBlock(),e.createElementBlock("div",h," Bot Mode ")):e.createCommentVNode("",!0)]),e.createElementVNode("button",{class:"blockspark-chat-close-btn",onClick:Y,"aria-label":"Close chat"}," × ")]),e.createElementVNode("div",{class:"blockspark-chat-messages",ref_key:"messagesContainer",ref:J},[0===e.unref(L).messages.length?(e.openBlock(),e.createElementBlock("div",y,[A[2]||(A[2]=e.createElementVNode("div",{class:"blockspark-chat-empty-icon"},"👋",-1)),e.createElementVNode("p",null,e.toDisplayString(Q.value.emptyStateMessage),1)])):e.createCommentVNode("",!0),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(L).messages,t=>{return e.openBlock(),e.createElementBlock("div",{key:t.id,class:e.normalizeClass(["blockspark-message",`blockspark-message-${t.sender}`,{"blockspark-handoff-message":ae(t.text)}])},[e.createElementVNode("div",{class:e.normalizeClass(["blockspark-message-content",{"blockspark-handoff-content":ae(t.text)}])},[e.createElementVNode("span",{innerHTML:e.unref(o.safeLinkifyText)(t.text).replace(/\n/g,"<br>")},null,8,E)],2),t.richContent&&Array.isArray(t.richContent)&&t.richContent.length>0?(e.openBlock(),e.createElementBlock("div",f,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.richContent,(t,o)=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:o},[Array.isArray(t)?(e.openBlock(!0),e.createElementBlock(e.Fragment,{key:1},e.renderList(t,(t,a)=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:`${o}-${a}`},["chips"===t.type&&t.options?(e.openBlock(),e.createElementBlock("div",v,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.options,(t,o)=>(e.openBlock(),e.createElementBlock("button",{key:o,class:"blockspark-chip-button",type:"button",onClick:e=>oe(t.text,t.payload)},e.toDisplayString(t.text),9,N))),128))])):e.createCommentVNode("",!0)],64))),128)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},["chips"===t.type&&t.options?(e.openBlock(),e.createElementBlock("div",B,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.options,(t,o)=>(e.openBlock(),e.createElementBlock("button",{key:o,class:"blockspark-chip-button",type:"button",onClick:e=>oe(t.text,t.payload)},e.toDisplayString(t.text),9,V))),128))])):e.createCommentVNode("",!0)],64))],64))),128))])):e.createCommentVNode("",!0),e.createElementVNode("div",C,e.toDisplayString((a=t.timestamp,a.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}))),1)],2);var a}),128)),e.unref(L).isLoading?(e.openBlock(),e.createElementBlock("div",w,[...A[3]||(A[3]=[e.createElementVNode("div",{class:"blockspark-typing-indicator"},[e.createElementVNode("span"),e.createElementVNode("span"),e.createElementVNode("span")],-1)])])):e.createCommentVNode("",!0),"human"===e.unref(L).chatMode&&e.unref(H)?(e.openBlock(),e.createElementBlock("div",M,[...A[4]||(A[4]=[e.createElementVNode("span",{class:"blockspark-typing-dots"},[e.createElementVNode("span"),e.createElementVNode("span"),e.createElementVNode("span")],-1),e.createElementVNode("span",{class:"blockspark-typing-text"},"Agent is typing...",-1)])])):e.createCommentVNode("",!0),e.createElementVNode("div",{ref_key:"messagesEndRef",ref:G},null,512)],512),e.createElementVNode("form",{class:"blockspark-chat-input-form",onSubmit:e.withModifiers(te,["prevent"])},[e.createElementVNode("input",{type:"text",class:"blockspark-chat-input",value:e.unref(L).inputValue,onInput:ee,placeholder:Q.value.inputPlaceholder,disabled:e.unref(L).isLoading},null,40,S),e.createElementVNode("button",{type:"submit",class:"blockspark-chat-send-btn",disabled:!e.unref(L).inputValue.trim()||e.unref(L).isLoading},[...A[5]||(A[5]=[e.createElementVNode("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[e.createElementVNode("line",{x1:"22",y1:"2",x2:"11",y2:"13"}),e.createElementVNode("polygon",{points:"22 2 15 22 11 13 2 9 22 2"})],-1)])],8,x)],32)])):e.createCommentVNode("",!0)]))}});exports.default=A;
|
|
2
2
|
//# sourceMappingURL=ChatWidget.vue.cjs2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatWidget.vue.cjs2.js","sources":["../../src/components/ChatWidget.vue"],"sourcesContent":["<template>\n <div class=\"blockspark-chat-widget\">\n <!-- Welcome Popup -->\n <div\n v-if=\"state.showWelcomePopup && !state.isOpen\"\n class=\"blockspark-welcome-popup\"\n @click=\"handleOpenChat\"\n >\n <div class=\"blockspark-welcome-header\">\n <div class=\"blockspark-welcome-title\">{{ config.welcomeTitle }}</div>\n <button\n class=\"blockspark-close-popup\"\n @click.stop=\"handleCloseWelcomePopup\"\n aria-label=\"Close welcome popup\"\n >\n ×\n </button>\n </div>\n <div class=\"blockspark-welcome-message\">{{ config.welcomeMessage }}</div>\n <div class=\"blockspark-welcome-cta\">{{ config.welcomeCta }}</div>\n </div>\n\n <!-- Chat Toggle Button -->\n <button\n v-if=\"!state.isOpen\"\n class=\"blockspark-chat-toggle-btn\"\n @click=\"handleOpenChat\"\n aria-label=\"Open chat\"\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n </button>\n\n <!-- Chat Window -->\n <div v-if=\"state.isOpen\" class=\"blockspark-chat-window\">\n <div class=\"blockspark-chat-header\">\n <div class=\"blockspark-chat-header-content\">\n <div class=\"blockspark-chat-title\">{{ config.title }}</div>\n <div class=\"blockspark-chat-subtitle\">\n {{ config.subtitle }}\n <span v-if=\"state.chatMode === 'human'\" class=\"blockspark-mode-indicator\">\n • {{ wsConnected ? '🟢 Connected' : '🟡 Connecting...' }}\n </span>\n </div>\n <div v-if=\"state.chatMode === 'human'\" class=\"blockspark-mode-badge\">\n Human Support Mode\n </div>\n <div v-if=\"state.chatMode === 'human'\" class=\"blockspark-agent-info\">\n <span class=\"blockspark-agent-label\">Agent:</span>\n <span class=\"blockspark-agent-name\">{{ currentAgent.name }}</span>\n </div>\n <div v-if=\"state.chatMode === 'ai'\" class=\"blockspark-mode-badge\">\n Bot Mode\n </div>\n </div>\n <button\n class=\"blockspark-chat-close-btn\"\n @click=\"handleCloseChat\"\n aria-label=\"Close chat\"\n >\n ×\n </button>\n </div>\n\n <div class=\"blockspark-chat-messages\" ref=\"messagesContainer\">\n <!-- Empty State -->\n <div v-if=\"state.messages.length === 0\" class=\"blockspark-chat-empty\">\n <div class=\"blockspark-chat-empty-icon\">👋</div>\n <p>{{ config.emptyStateMessage }}</p>\n </div>\n\n <!-- Messages -->\n <div\n v-for=\"message in state.messages\"\n :key=\"message.id\"\n :class=\"['blockspark-message', `blockspark-message-${message.sender}`]\"\n >\n <div class=\"blockspark-message-content\">\n <!-- Safe HTML rendering with sanitization -->\n <span v-html=\"safeLinkifyText(message.text)\"></span>\n </div>\n\n <!-- Rich Content (Chips) -->\n <div\n v-if=\"message.richContent && Array.isArray(message.richContent) && message.richContent.length > 0\"\n class=\"blockspark-chips-container\"\n >\n <template v-for=\"(contentGroup, groupIndex) in message.richContent\" :key=\"groupIndex\">\n <template v-if=\"!Array.isArray(contentGroup)\">\n <div\n v-if=\"contentGroup.type === 'chips' && contentGroup.options\"\n class=\"blockspark-chips-group\"\n >\n <button\n v-for=\"(chip, chipIndex) in contentGroup.options\"\n :key=\"chipIndex\"\n class=\"blockspark-chip-button\"\n type=\"button\"\n @click=\"handleChipClick(chip.text, chip.payload)\"\n >\n {{ chip.text }}\n </button>\n </div>\n </template>\n <template v-else>\n <template\n v-for=\"(content, contentIndex) in contentGroup\"\n :key=\"`${groupIndex}-${contentIndex}`\"\n >\n <div\n v-if=\"content.type === 'chips' && content.options\"\n class=\"blockspark-chips-group\"\n >\n <button\n v-for=\"(chip, chipIndex) in content.options\"\n :key=\"chipIndex\"\n class=\"blockspark-chip-button\"\n type=\"button\"\n @click=\"handleChipClick(chip.text, chip.payload)\"\n >\n {{ chip.text }}\n </button>\n </div>\n </template>\n </template>\n </template>\n </div>\n\n <div class=\"blockspark-message-time\">\n {{ formatTime(message.timestamp) }}\n </div>\n </div>\n\n <!-- Loading Indicator -->\n <div v-if=\"state.isLoading\" class=\"blockspark-message blockspark-message-bot\">\n <div class=\"blockspark-typing-indicator\">\n <span></span>\n <span></span>\n <span></span>\n </div>\n </div>\n\n <!-- Agent Typing Indicator -->\n <div v-if=\"state.chatMode === 'human' && agentTyping\" class=\"blockspark-agent-typing-indicator\">\n <span class=\"blockspark-typing-dots\">\n <span></span>\n <span></span>\n <span></span>\n </span>\n <span class=\"blockspark-typing-text\">Agent is typing...</span>\n </div>\n\n <div ref=\"messagesEndRef\"></div>\n </div>\n\n <!-- Input Form -->\n <form class=\"blockspark-chat-input-form\" @submit.prevent=\"handleSubmit\">\n <input\n type=\"text\"\n class=\"blockspark-chat-input\"\n :value=\"state.inputValue\"\n @input=\"handleInput\"\n :placeholder=\"config.inputPlaceholder\"\n :disabled=\"state.isLoading\"\n />\n <button\n type=\"submit\"\n class=\"blockspark-chat-send-btn\"\n :disabled=\"!state.inputValue.trim() || state.isLoading\"\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n </button>\n </form>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted, nextTick, watch } from 'vue';\nimport { useChatWidget } from '../composables/useChatWidget';\nimport { safeLinkifyText } from '../utils/sanitize';\nimport type { WidgetConfig } from '../core/types';\n\n// Props\nconst props = withDefaults(defineProps<WidgetConfig>(), {\n title: '💬 BlockSpark AI Assistant',\n subtitle: \"We're here to help\",\n welcomeTitle: '👋 Welcome to BlockSpark',\n welcomeMessage: \"My name is BlockSpark AI Assistant and I'll guide you.\",\n welcomeCta: '💬 Click here to start chatting!',\n showWelcomePopup: true,\n welcomePopupDelay: 1500,\n fallbackWelcomeMessage: \"Hello! I'm BlockSpark AI Assistant. How can I help you today?\",\n inputPlaceholder: 'Type your message...',\n emptyStateMessage: \"Hi! I'm BlockSpark AI Assistant. How can I help you today?\",\n debug: false,\n});\n\n// Use headless composable\nconst {\n state,\n isOpen,\n messages,\n isLoading,\n error,\n chatMode,\n wsConnected,\n agentTyping,\n currentAgent,\n openChat,\n closeChat,\n sendMessage,\n toggleChat,\n setInputValue,\n clearError,\n manager,\n} = useChatWidget(props);\n\n// Refs\nconst messagesEndRef = ref<HTMLDivElement | null>(null);\nconst messagesContainer = ref<HTMLDivElement | null>(null);\n\n// Computed config (for reactivity)\nconst config = computed(() => props);\n\n// Auto-scroll to bottom when messages change\nwatch(\n () => messages.value.length,\n () => {\n nextTick(() => {\n messagesEndRef.value?.scrollIntoView({ behavior: 'smooth' });\n });\n }\n);\n\n// Handlers\nconst handleOpenChat = async () => {\n await openChat();\n};\n\nconst handleCloseChat = () => {\n closeChat();\n};\n\nconst handleCloseWelcomePopup = () => {\n manager.closeWelcomePopup();\n};\n\nconst handleInput = (event: Event) => {\n const target = event.target as HTMLInputElement;\n setInputValue(target.value);\n};\n\nconst handleSubmit = async (event: Event) => {\n event.preventDefault();\n if (state.value.inputValue.trim()) {\n await sendMessage(state.value.inputValue);\n }\n};\n\nconst handleChipClick = async (chipText: string, payload?: string) => {\n const messageToSend = chipText || payload || '';\n await sendMessage(messageToSend);\n};\n\n// Utility functions\nconst formatTime = (date: Date): string => {\n return date.toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n });\n};\n\n// Initialize welcome popup on mount (SSR-safe)\nonMounted(() => {\n if (config.value.showWelcomePopup && typeof window !== 'undefined') {\n manager.initializeWelcomePopup();\n }\n});\n</script>\n\n<style scoped>\n/* Styles are imported separately by users */\n/* This ensures SSR compatibility */\n</style>\n"],"names":["props","__props","state","isOpen","messages","isLoading","error","chatMode","wsConnected","agentTyping","currentAgent","openChat","closeChat","sendMessage","toggleChat","setInputValue","clearError","manager","useChatWidget","messagesEndRef","ref","messagesContainer","config","computed","watch","value","length","nextTick","scrollIntoView","behavior","handleOpenChat","async","handleCloseChat","handleCloseWelcomePopup","closeWelcomePopup","handleInput","event","target","handleSubmit","preventDefault","inputValue","trim","handleChipClick","chipText","payload","messageToSend","onMounted","showWelcomePopup","window","initializeWelcomePopup","_openBlock","_createElementBlock","_hoisted_1","_unref","class","onClick","_createElementVNode","_hoisted_2","_hoisted_3","_toDisplayString","welcomeTitle","_hoisted_4","welcomeMessage","_hoisted_5","welcomeCta","width","height","viewBox","fill","stroke","d","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","title","_hoisted_10","subtitle","_hoisted_11","_hoisted_12","_hoisted_13","_cache","_hoisted_14","name","_hoisted_15","_hoisted_16","emptyStateMessage","_Fragment","_renderList","message","key","id","_normalizeClass","sender","_hoisted_17","innerHTML","safeLinkifyText","text","richContent","Array","isArray","_hoisted_19","contentGroup","groupIndex","content","contentIndex","type","options","_hoisted_22","chip","chipIndex","$event","_hoisted_23","_hoisted_20","_hoisted_21","_hoisted_24","date","timestamp","toLocaleTimeString","hour","minute","_hoisted_25","_hoisted_26","onSubmit","onInput","placeholder","inputPlaceholder","disabled","x1","y1","x2","y2","points"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChatWidget.vue.cjs2.js","sources":["../../src/components/ChatWidget.vue"],"sourcesContent":["<template>\n <div class=\"blockspark-chat-widget\">\n <!-- Welcome Popup -->\n <div\n v-if=\"state.showWelcomePopup && !state.isOpen\"\n class=\"blockspark-welcome-popup\"\n @click=\"handleOpenChat\"\n >\n <div class=\"blockspark-welcome-header\">\n <div class=\"blockspark-welcome-title\">{{ config.welcomeTitle }}</div>\n <button\n class=\"blockspark-close-popup\"\n @click.stop=\"handleCloseWelcomePopup\"\n aria-label=\"Close welcome popup\"\n >\n ×\n </button>\n </div>\n <div class=\"blockspark-welcome-message\">{{ config.welcomeMessage }}</div>\n <div class=\"blockspark-welcome-cta\">{{ config.welcomeCta }}</div>\n </div>\n\n <!-- Chat Toggle Button -->\n <button\n v-if=\"!state.isOpen\"\n class=\"blockspark-chat-toggle-btn\"\n @click=\"handleOpenChat\"\n aria-label=\"Open chat\"\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n </button>\n\n <!-- Chat Window -->\n <div v-if=\"state.isOpen\" class=\"blockspark-chat-window\">\n <div class=\"blockspark-chat-header\">\n <div class=\"blockspark-chat-header-content\">\n <div class=\"blockspark-chat-title\">{{ config.title }}</div>\n <div class=\"blockspark-chat-subtitle\">\n {{ config.subtitle }}\n <span v-if=\"state.chatMode === 'human'\" class=\"blockspark-mode-indicator\">\n • {{ wsConnected ? '🟢 Connected' : '🟡 Connecting...' }}\n </span>\n </div>\n <div v-if=\"state.chatMode === 'human'\" class=\"blockspark-mode-badge\">\n Human Support Mode\n </div>\n <div v-if=\"state.chatMode === 'human'\" class=\"blockspark-agent-info\">\n <span class=\"blockspark-agent-label\">Agent:</span>\n <span class=\"blockspark-agent-name\">{{ currentAgent.name }}</span>\n </div>\n <div v-if=\"state.chatMode === 'ai'\" class=\"blockspark-mode-badge\">\n Bot Mode\n </div>\n </div>\n <button\n class=\"blockspark-chat-close-btn\"\n @click=\"handleCloseChat\"\n aria-label=\"Close chat\"\n >\n ×\n </button>\n </div>\n\n <div class=\"blockspark-chat-messages\" ref=\"messagesContainer\">\n <!-- Empty State -->\n <div v-if=\"state.messages.length === 0\" class=\"blockspark-chat-empty\">\n <div class=\"blockspark-chat-empty-icon\">👋</div>\n <p>{{ config.emptyStateMessage }}</p>\n </div>\n\n <!-- Messages -->\n <div\n v-for=\"message in state.messages\"\n :key=\"message.id\"\n :class=\"[\n 'blockspark-message', \n `blockspark-message-${message.sender}`,\n { 'blockspark-handoff-message': isHandoffMessage(message.text) }\n ]\"\n >\n <div \n class=\"blockspark-message-content\"\n :class=\"{ 'blockspark-handoff-content': isHandoffMessage(message.text) }\"\n >\n <!-- Safe HTML rendering with sanitization -->\n <!-- Preserve line breaks for better formatting -->\n <span v-html=\"safeLinkifyText(message.text).replace(/\\n/g, '<br>')\"></span>\n </div>\n\n <!-- Rich Content (Chips) -->\n <div\n v-if=\"message.richContent && Array.isArray(message.richContent) && message.richContent.length > 0\"\n class=\"blockspark-chips-container\"\n >\n <template v-for=\"(contentGroup, groupIndex) in message.richContent\" :key=\"groupIndex\">\n <template v-if=\"!Array.isArray(contentGroup)\">\n <div\n v-if=\"contentGroup.type === 'chips' && contentGroup.options\"\n class=\"blockspark-chips-group\"\n >\n <button\n v-for=\"(chip, chipIndex) in contentGroup.options\"\n :key=\"chipIndex\"\n class=\"blockspark-chip-button\"\n type=\"button\"\n @click=\"handleChipClick(chip.text, chip.payload)\"\n >\n {{ chip.text }}\n </button>\n </div>\n </template>\n <template v-else>\n <template\n v-for=\"(content, contentIndex) in contentGroup\"\n :key=\"`${groupIndex}-${contentIndex}`\"\n >\n <div\n v-if=\"content.type === 'chips' && content.options\"\n class=\"blockspark-chips-group\"\n >\n <button\n v-for=\"(chip, chipIndex) in content.options\"\n :key=\"chipIndex\"\n class=\"blockspark-chip-button\"\n type=\"button\"\n @click=\"handleChipClick(chip.text, chip.payload)\"\n >\n {{ chip.text }}\n </button>\n </div>\n </template>\n </template>\n </template>\n </div>\n\n <div class=\"blockspark-message-time\">\n {{ formatTime(message.timestamp) }}\n </div>\n </div>\n\n <!-- Loading Indicator -->\n <div v-if=\"state.isLoading\" class=\"blockspark-message blockspark-message-bot\">\n <div class=\"blockspark-typing-indicator\">\n <span></span>\n <span></span>\n <span></span>\n </div>\n </div>\n\n <!-- Agent Typing Indicator -->\n <div v-if=\"state.chatMode === 'human' && agentTyping\" class=\"blockspark-agent-typing-indicator\">\n <span class=\"blockspark-typing-dots\">\n <span></span>\n <span></span>\n <span></span>\n </span>\n <span class=\"blockspark-typing-text\">Agent is typing...</span>\n </div>\n\n <div ref=\"messagesEndRef\"></div>\n </div>\n\n <!-- Input Form -->\n <form class=\"blockspark-chat-input-form\" @submit.prevent=\"handleSubmit\">\n <input\n type=\"text\"\n class=\"blockspark-chat-input\"\n :value=\"state.inputValue\"\n @input=\"handleInput\"\n :placeholder=\"config.inputPlaceholder\"\n :disabled=\"state.isLoading\"\n />\n <button\n type=\"submit\"\n class=\"blockspark-chat-send-btn\"\n :disabled=\"!state.inputValue.trim() || state.isLoading\"\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n </button>\n </form>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted, nextTick, watch } from 'vue';\nimport { useChatWidget } from '../composables/useChatWidget';\nimport { safeLinkifyText } from '../utils/sanitize';\nimport type { WidgetConfig } from '../core/types';\n\n// Props\nconst props = withDefaults(defineProps<WidgetConfig>(), {\n title: '💬 BlockSpark AI Assistant',\n subtitle: \"We're here to help\",\n welcomeTitle: '👋 Welcome to BlockSpark',\n welcomeMessage: \"My name is BlockSpark AI Assistant and I'll guide you.\",\n welcomeCta: '💬 Click here to start chatting!',\n showWelcomePopup: true,\n welcomePopupDelay: 1500,\n fallbackWelcomeMessage: \"Hello! I'm BlockSpark AI Assistant. How can I help you today?\",\n inputPlaceholder: 'Type your message...',\n emptyStateMessage: \"Hi! I'm BlockSpark AI Assistant. How can I help you today?\",\n debug: false,\n});\n\n// Use headless composable\nconst {\n state,\n isOpen,\n messages,\n isLoading,\n error,\n chatMode,\n wsConnected,\n agentTyping,\n currentAgent,\n openChat,\n closeChat,\n sendMessage,\n toggleChat,\n setInputValue,\n clearError,\n manager,\n} = useChatWidget(props);\n\n// Refs\nconst messagesEndRef = ref<HTMLDivElement | null>(null);\nconst messagesContainer = ref<HTMLDivElement | null>(null);\n\n// Computed config (for reactivity)\nconst config = computed(() => props);\n\n// Auto-scroll to bottom when messages change\nwatch(\n () => messages.value.length,\n () => {\n nextTick(() => {\n messagesEndRef.value?.scrollIntoView({ behavior: 'smooth' });\n });\n }\n);\n\n// Handlers\nconst handleOpenChat = async () => {\n await openChat();\n};\n\nconst handleCloseChat = () => {\n closeChat();\n};\n\nconst handleCloseWelcomePopup = () => {\n manager.closeWelcomePopup();\n};\n\nconst handleInput = (event: Event) => {\n const target = event.target as HTMLInputElement;\n setInputValue(target.value);\n};\n\nconst handleSubmit = async (event: Event) => {\n event.preventDefault();\n if (state.value.inputValue.trim()) {\n await sendMessage(state.value.inputValue);\n }\n};\n\nconst handleChipClick = async (chipText: string, payload?: string) => {\n const messageToSend = chipText || payload || '';\n await sendMessage(messageToSend);\n};\n\n// Utility functions\nconst formatTime = (date: Date): string => {\n return date.toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n });\n};\n\n// Check if message is a handoff message\nconst isHandoffMessage = (text: string): boolean => {\n return text.includes('👤') || \n text.includes('being connected') || \n text.includes('live support agent') ||\n text.includes('transfer your conversation');\n};\n\n// Initialize welcome popup on mount (SSR-safe)\nonMounted(() => {\n if (config.value.showWelcomePopup && typeof window !== 'undefined') {\n manager.initializeWelcomePopup();\n }\n});\n</script>\n\n<style scoped>\n/* Styles are imported separately by users */\n/* This ensures SSR compatibility */\n</style>\n"],"names":["props","__props","state","isOpen","messages","isLoading","error","chatMode","wsConnected","agentTyping","currentAgent","openChat","closeChat","sendMessage","toggleChat","setInputValue","clearError","manager","useChatWidget","messagesEndRef","ref","messagesContainer","config","computed","watch","value","length","nextTick","scrollIntoView","behavior","handleOpenChat","async","handleCloseChat","handleCloseWelcomePopup","closeWelcomePopup","handleInput","event","target","handleSubmit","preventDefault","inputValue","trim","handleChipClick","chipText","payload","messageToSend","isHandoffMessage","text","includes","onMounted","showWelcomePopup","window","initializeWelcomePopup","_openBlock","_createElementBlock","_hoisted_1","_unref","class","onClick","_createElementVNode","_hoisted_2","_hoisted_3","_toDisplayString","welcomeTitle","_hoisted_4","welcomeMessage","_hoisted_5","welcomeCta","width","height","viewBox","fill","stroke","d","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","title","_hoisted_10","subtitle","_hoisted_11","_hoisted_12","_hoisted_13","_cache","_hoisted_14","name","_hoisted_15","_hoisted_16","emptyStateMessage","_Fragment","_renderList","message","key","id","_normalizeClass","sender","innerHTML","safeLinkifyText","replace","richContent","Array","isArray","_hoisted_18","contentGroup","groupIndex","content","contentIndex","type","options","_hoisted_21","chip","chipIndex","$event","_hoisted_22","_hoisted_19","_hoisted_20","_hoisted_23","date","timestamp","toLocaleTimeString","hour","minute","_hoisted_24","_hoisted_25","onSubmit","onInput","placeholder","inputPlaceholder","disabled","x1","y1","x2","y2","points"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _sfc_main from "./ChatWidget.vue.esm2.js";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import _export_sfc from "../_virtual/_plugin-vue_export-helper.esm.js";
|
|
4
|
-
const ChatWidget = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
4
|
+
const ChatWidget = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-7f95b555"]]);
|
|
5
5
|
export {
|
|
6
6
|
ChatWidget as default
|
|
7
7
|
};
|
|
@@ -35,33 +35,32 @@ const _hoisted_16 = {
|
|
|
35
35
|
key: 0,
|
|
36
36
|
class: "blockspark-chat-empty"
|
|
37
37
|
};
|
|
38
|
-
const _hoisted_17 =
|
|
39
|
-
const _hoisted_18 =
|
|
40
|
-
const _hoisted_19 = {
|
|
38
|
+
const _hoisted_17 = ["innerHTML"];
|
|
39
|
+
const _hoisted_18 = {
|
|
41
40
|
key: 0,
|
|
42
41
|
class: "blockspark-chips-container"
|
|
43
42
|
};
|
|
44
|
-
const
|
|
43
|
+
const _hoisted_19 = {
|
|
45
44
|
key: 0,
|
|
46
45
|
class: "blockspark-chips-group"
|
|
47
46
|
};
|
|
48
|
-
const
|
|
49
|
-
const
|
|
47
|
+
const _hoisted_20 = ["onClick"];
|
|
48
|
+
const _hoisted_21 = {
|
|
50
49
|
key: 0,
|
|
51
50
|
class: "blockspark-chips-group"
|
|
52
51
|
};
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
52
|
+
const _hoisted_22 = ["onClick"];
|
|
53
|
+
const _hoisted_23 = { class: "blockspark-message-time" };
|
|
54
|
+
const _hoisted_24 = {
|
|
56
55
|
key: 1,
|
|
57
56
|
class: "blockspark-message blockspark-message-bot"
|
|
58
57
|
};
|
|
59
|
-
const
|
|
58
|
+
const _hoisted_25 = {
|
|
60
59
|
key: 2,
|
|
61
60
|
class: "blockspark-agent-typing-indicator"
|
|
62
61
|
};
|
|
63
|
-
const
|
|
64
|
-
const
|
|
62
|
+
const _hoisted_26 = ["value", "placeholder", "disabled"];
|
|
63
|
+
const _hoisted_27 = ["disabled"];
|
|
65
64
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
66
65
|
__name: "ChatWidget",
|
|
67
66
|
props: {
|
|
@@ -145,6 +144,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
145
144
|
minute: "2-digit"
|
|
146
145
|
});
|
|
147
146
|
};
|
|
147
|
+
const isHandoffMessage = (text) => {
|
|
148
|
+
return text.includes("👤") || text.includes("being connected") || text.includes("live support agent") || text.includes("transfer your conversation");
|
|
149
|
+
};
|
|
148
150
|
onMounted(() => {
|
|
149
151
|
if (config.value.showWelcomePopup && typeof window !== "undefined") {
|
|
150
152
|
manager.initializeWelcomePopup();
|
|
@@ -220,39 +222,45 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
220
222
|
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(state).messages, (message) => {
|
|
221
223
|
return openBlock(), createElementBlock("div", {
|
|
222
224
|
key: message.id,
|
|
223
|
-
class: normalizeClass([
|
|
225
|
+
class: normalizeClass([
|
|
226
|
+
"blockspark-message",
|
|
227
|
+
`blockspark-message-${message.sender}`,
|
|
228
|
+
{ "blockspark-handoff-message": isHandoffMessage(message.text) }
|
|
229
|
+
])
|
|
224
230
|
}, [
|
|
225
|
-
createElementVNode("div",
|
|
231
|
+
createElementVNode("div", {
|
|
232
|
+
class: normalizeClass(["blockspark-message-content", { "blockspark-handoff-content": isHandoffMessage(message.text) }])
|
|
233
|
+
}, [
|
|
226
234
|
createElementVNode("span", {
|
|
227
|
-
innerHTML: unref(safeLinkifyText)(message.text)
|
|
228
|
-
}, null, 8,
|
|
229
|
-
]),
|
|
230
|
-
message.richContent && Array.isArray(message.richContent) && message.richContent.length > 0 ? (openBlock(), createElementBlock("div",
|
|
235
|
+
innerHTML: unref(safeLinkifyText)(message.text).replace(/\n/g, "<br>")
|
|
236
|
+
}, null, 8, _hoisted_17)
|
|
237
|
+
], 2),
|
|
238
|
+
message.richContent && Array.isArray(message.richContent) && message.richContent.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_18, [
|
|
231
239
|
(openBlock(true), createElementBlock(Fragment, null, renderList(message.richContent, (contentGroup, groupIndex) => {
|
|
232
240
|
return openBlock(), createElementBlock(Fragment, { key: groupIndex }, [
|
|
233
241
|
!Array.isArray(contentGroup) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
|
|
234
|
-
contentGroup.type === "chips" && contentGroup.options ? (openBlock(), createElementBlock("div",
|
|
242
|
+
contentGroup.type === "chips" && contentGroup.options ? (openBlock(), createElementBlock("div", _hoisted_19, [
|
|
235
243
|
(openBlock(true), createElementBlock(Fragment, null, renderList(contentGroup.options, (chip, chipIndex) => {
|
|
236
244
|
return openBlock(), createElementBlock("button", {
|
|
237
245
|
key: chipIndex,
|
|
238
246
|
class: "blockspark-chip-button",
|
|
239
247
|
type: "button",
|
|
240
248
|
onClick: ($event) => handleChipClick(chip.text, chip.payload)
|
|
241
|
-
}, toDisplayString(chip.text), 9,
|
|
249
|
+
}, toDisplayString(chip.text), 9, _hoisted_20);
|
|
242
250
|
}), 128))
|
|
243
251
|
])) : createCommentVNode("", true)
|
|
244
252
|
], 64)) : (openBlock(true), createElementBlock(Fragment, { key: 1 }, renderList(contentGroup, (content, contentIndex) => {
|
|
245
253
|
return openBlock(), createElementBlock(Fragment, {
|
|
246
254
|
key: `${groupIndex}-${contentIndex}`
|
|
247
255
|
}, [
|
|
248
|
-
content.type === "chips" && content.options ? (openBlock(), createElementBlock("div",
|
|
256
|
+
content.type === "chips" && content.options ? (openBlock(), createElementBlock("div", _hoisted_21, [
|
|
249
257
|
(openBlock(true), createElementBlock(Fragment, null, renderList(content.options, (chip, chipIndex) => {
|
|
250
258
|
return openBlock(), createElementBlock("button", {
|
|
251
259
|
key: chipIndex,
|
|
252
260
|
class: "blockspark-chip-button",
|
|
253
261
|
type: "button",
|
|
254
262
|
onClick: ($event) => handleChipClick(chip.text, chip.payload)
|
|
255
|
-
}, toDisplayString(chip.text), 9,
|
|
263
|
+
}, toDisplayString(chip.text), 9, _hoisted_22);
|
|
256
264
|
}), 128))
|
|
257
265
|
])) : createCommentVNode("", true)
|
|
258
266
|
], 64);
|
|
@@ -260,17 +268,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
260
268
|
], 64);
|
|
261
269
|
}), 128))
|
|
262
270
|
])) : createCommentVNode("", true),
|
|
263
|
-
createElementVNode("div",
|
|
271
|
+
createElementVNode("div", _hoisted_23, toDisplayString(formatTime(message.timestamp)), 1)
|
|
264
272
|
], 2);
|
|
265
273
|
}), 128)),
|
|
266
|
-
unref(state).isLoading ? (openBlock(), createElementBlock("div",
|
|
274
|
+
unref(state).isLoading ? (openBlock(), createElementBlock("div", _hoisted_24, [..._cache[3] || (_cache[3] = [
|
|
267
275
|
createElementVNode("div", { class: "blockspark-typing-indicator" }, [
|
|
268
276
|
createElementVNode("span"),
|
|
269
277
|
createElementVNode("span"),
|
|
270
278
|
createElementVNode("span")
|
|
271
279
|
], -1)
|
|
272
280
|
])])) : createCommentVNode("", true),
|
|
273
|
-
unref(state).chatMode === "human" && unref(agentTyping) ? (openBlock(), createElementBlock("div",
|
|
281
|
+
unref(state).chatMode === "human" && unref(agentTyping) ? (openBlock(), createElementBlock("div", _hoisted_25, [..._cache[4] || (_cache[4] = [
|
|
274
282
|
createElementVNode("span", { class: "blockspark-typing-dots" }, [
|
|
275
283
|
createElementVNode("span"),
|
|
276
284
|
createElementVNode("span"),
|
|
@@ -294,7 +302,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
294
302
|
onInput: handleInput,
|
|
295
303
|
placeholder: config.value.inputPlaceholder,
|
|
296
304
|
disabled: unref(state).isLoading
|
|
297
|
-
}, null, 40,
|
|
305
|
+
}, null, 40, _hoisted_26),
|
|
298
306
|
createElementVNode("button", {
|
|
299
307
|
type: "submit",
|
|
300
308
|
class: "blockspark-chat-send-btn",
|
|
@@ -318,7 +326,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
318
326
|
}),
|
|
319
327
|
createElementVNode("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
|
|
320
328
|
], -1)
|
|
321
|
-
])], 8,
|
|
329
|
+
])], 8, _hoisted_27)
|
|
322
330
|
], 32)
|
|
323
331
|
])) : createCommentVNode("", true)
|
|
324
332
|
]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatWidget.vue.esm2.js","sources":["../../src/components/ChatWidget.vue"],"sourcesContent":["<template>\n <div class=\"blockspark-chat-widget\">\n <!-- Welcome Popup -->\n <div\n v-if=\"state.showWelcomePopup && !state.isOpen\"\n class=\"blockspark-welcome-popup\"\n @click=\"handleOpenChat\"\n >\n <div class=\"blockspark-welcome-header\">\n <div class=\"blockspark-welcome-title\">{{ config.welcomeTitle }}</div>\n <button\n class=\"blockspark-close-popup\"\n @click.stop=\"handleCloseWelcomePopup\"\n aria-label=\"Close welcome popup\"\n >\n ×\n </button>\n </div>\n <div class=\"blockspark-welcome-message\">{{ config.welcomeMessage }}</div>\n <div class=\"blockspark-welcome-cta\">{{ config.welcomeCta }}</div>\n </div>\n\n <!-- Chat Toggle Button -->\n <button\n v-if=\"!state.isOpen\"\n class=\"blockspark-chat-toggle-btn\"\n @click=\"handleOpenChat\"\n aria-label=\"Open chat\"\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n </button>\n\n <!-- Chat Window -->\n <div v-if=\"state.isOpen\" class=\"blockspark-chat-window\">\n <div class=\"blockspark-chat-header\">\n <div class=\"blockspark-chat-header-content\">\n <div class=\"blockspark-chat-title\">{{ config.title }}</div>\n <div class=\"blockspark-chat-subtitle\">\n {{ config.subtitle }}\n <span v-if=\"state.chatMode === 'human'\" class=\"blockspark-mode-indicator\">\n • {{ wsConnected ? '🟢 Connected' : '🟡 Connecting...' }}\n </span>\n </div>\n <div v-if=\"state.chatMode === 'human'\" class=\"blockspark-mode-badge\">\n Human Support Mode\n </div>\n <div v-if=\"state.chatMode === 'human'\" class=\"blockspark-agent-info\">\n <span class=\"blockspark-agent-label\">Agent:</span>\n <span class=\"blockspark-agent-name\">{{ currentAgent.name }}</span>\n </div>\n <div v-if=\"state.chatMode === 'ai'\" class=\"blockspark-mode-badge\">\n Bot Mode\n </div>\n </div>\n <button\n class=\"blockspark-chat-close-btn\"\n @click=\"handleCloseChat\"\n aria-label=\"Close chat\"\n >\n ×\n </button>\n </div>\n\n <div class=\"blockspark-chat-messages\" ref=\"messagesContainer\">\n <!-- Empty State -->\n <div v-if=\"state.messages.length === 0\" class=\"blockspark-chat-empty\">\n <div class=\"blockspark-chat-empty-icon\">👋</div>\n <p>{{ config.emptyStateMessage }}</p>\n </div>\n\n <!-- Messages -->\n <div\n v-for=\"message in state.messages\"\n :key=\"message.id\"\n :class=\"['blockspark-message', `blockspark-message-${message.sender}`]\"\n >\n <div class=\"blockspark-message-content\">\n <!-- Safe HTML rendering with sanitization -->\n <span v-html=\"safeLinkifyText(message.text)\"></span>\n </div>\n\n <!-- Rich Content (Chips) -->\n <div\n v-if=\"message.richContent && Array.isArray(message.richContent) && message.richContent.length > 0\"\n class=\"blockspark-chips-container\"\n >\n <template v-for=\"(contentGroup, groupIndex) in message.richContent\" :key=\"groupIndex\">\n <template v-if=\"!Array.isArray(contentGroup)\">\n <div\n v-if=\"contentGroup.type === 'chips' && contentGroup.options\"\n class=\"blockspark-chips-group\"\n >\n <button\n v-for=\"(chip, chipIndex) in contentGroup.options\"\n :key=\"chipIndex\"\n class=\"blockspark-chip-button\"\n type=\"button\"\n @click=\"handleChipClick(chip.text, chip.payload)\"\n >\n {{ chip.text }}\n </button>\n </div>\n </template>\n <template v-else>\n <template\n v-for=\"(content, contentIndex) in contentGroup\"\n :key=\"`${groupIndex}-${contentIndex}`\"\n >\n <div\n v-if=\"content.type === 'chips' && content.options\"\n class=\"blockspark-chips-group\"\n >\n <button\n v-for=\"(chip, chipIndex) in content.options\"\n :key=\"chipIndex\"\n class=\"blockspark-chip-button\"\n type=\"button\"\n @click=\"handleChipClick(chip.text, chip.payload)\"\n >\n {{ chip.text }}\n </button>\n </div>\n </template>\n </template>\n </template>\n </div>\n\n <div class=\"blockspark-message-time\">\n {{ formatTime(message.timestamp) }}\n </div>\n </div>\n\n <!-- Loading Indicator -->\n <div v-if=\"state.isLoading\" class=\"blockspark-message blockspark-message-bot\">\n <div class=\"blockspark-typing-indicator\">\n <span></span>\n <span></span>\n <span></span>\n </div>\n </div>\n\n <!-- Agent Typing Indicator -->\n <div v-if=\"state.chatMode === 'human' && agentTyping\" class=\"blockspark-agent-typing-indicator\">\n <span class=\"blockspark-typing-dots\">\n <span></span>\n <span></span>\n <span></span>\n </span>\n <span class=\"blockspark-typing-text\">Agent is typing...</span>\n </div>\n\n <div ref=\"messagesEndRef\"></div>\n </div>\n\n <!-- Input Form -->\n <form class=\"blockspark-chat-input-form\" @submit.prevent=\"handleSubmit\">\n <input\n type=\"text\"\n class=\"blockspark-chat-input\"\n :value=\"state.inputValue\"\n @input=\"handleInput\"\n :placeholder=\"config.inputPlaceholder\"\n :disabled=\"state.isLoading\"\n />\n <button\n type=\"submit\"\n class=\"blockspark-chat-send-btn\"\n :disabled=\"!state.inputValue.trim() || state.isLoading\"\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n </button>\n </form>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted, nextTick, watch } from 'vue';\nimport { useChatWidget } from '../composables/useChatWidget';\nimport { safeLinkifyText } from '../utils/sanitize';\nimport type { WidgetConfig } from '../core/types';\n\n// Props\nconst props = withDefaults(defineProps<WidgetConfig>(), {\n title: '💬 BlockSpark AI Assistant',\n subtitle: \"We're here to help\",\n welcomeTitle: '👋 Welcome to BlockSpark',\n welcomeMessage: \"My name is BlockSpark AI Assistant and I'll guide you.\",\n welcomeCta: '💬 Click here to start chatting!',\n showWelcomePopup: true,\n welcomePopupDelay: 1500,\n fallbackWelcomeMessage: \"Hello! I'm BlockSpark AI Assistant. How can I help you today?\",\n inputPlaceholder: 'Type your message...',\n emptyStateMessage: \"Hi! I'm BlockSpark AI Assistant. How can I help you today?\",\n debug: false,\n});\n\n// Use headless composable\nconst {\n state,\n isOpen,\n messages,\n isLoading,\n error,\n chatMode,\n wsConnected,\n agentTyping,\n currentAgent,\n openChat,\n closeChat,\n sendMessage,\n toggleChat,\n setInputValue,\n clearError,\n manager,\n} = useChatWidget(props);\n\n// Refs\nconst messagesEndRef = ref<HTMLDivElement | null>(null);\nconst messagesContainer = ref<HTMLDivElement | null>(null);\n\n// Computed config (for reactivity)\nconst config = computed(() => props);\n\n// Auto-scroll to bottom when messages change\nwatch(\n () => messages.value.length,\n () => {\n nextTick(() => {\n messagesEndRef.value?.scrollIntoView({ behavior: 'smooth' });\n });\n }\n);\n\n// Handlers\nconst handleOpenChat = async () => {\n await openChat();\n};\n\nconst handleCloseChat = () => {\n closeChat();\n};\n\nconst handleCloseWelcomePopup = () => {\n manager.closeWelcomePopup();\n};\n\nconst handleInput = (event: Event) => {\n const target = event.target as HTMLInputElement;\n setInputValue(target.value);\n};\n\nconst handleSubmit = async (event: Event) => {\n event.preventDefault();\n if (state.value.inputValue.trim()) {\n await sendMessage(state.value.inputValue);\n }\n};\n\nconst handleChipClick = async (chipText: string, payload?: string) => {\n const messageToSend = chipText || payload || '';\n await sendMessage(messageToSend);\n};\n\n// Utility functions\nconst formatTime = (date: Date): string => {\n return date.toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n });\n};\n\n// Initialize welcome popup on mount (SSR-safe)\nonMounted(() => {\n if (config.value.showWelcomePopup && typeof window !== 'undefined') {\n manager.initializeWelcomePopup();\n }\n});\n</script>\n\n<style scoped>\n/* Styles are imported separately by users */\n/* This ensures SSR compatibility */\n</style>\n"],"names":["_openBlock","_createElementBlock","_unref","_createElementVNode","_toDisplayString","_Fragment","_renderList","_normalizeClass"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChatWidget.vue.esm2.js","sources":["../../src/components/ChatWidget.vue"],"sourcesContent":["<template>\n <div class=\"blockspark-chat-widget\">\n <!-- Welcome Popup -->\n <div\n v-if=\"state.showWelcomePopup && !state.isOpen\"\n class=\"blockspark-welcome-popup\"\n @click=\"handleOpenChat\"\n >\n <div class=\"blockspark-welcome-header\">\n <div class=\"blockspark-welcome-title\">{{ config.welcomeTitle }}</div>\n <button\n class=\"blockspark-close-popup\"\n @click.stop=\"handleCloseWelcomePopup\"\n aria-label=\"Close welcome popup\"\n >\n ×\n </button>\n </div>\n <div class=\"blockspark-welcome-message\">{{ config.welcomeMessage }}</div>\n <div class=\"blockspark-welcome-cta\">{{ config.welcomeCta }}</div>\n </div>\n\n <!-- Chat Toggle Button -->\n <button\n v-if=\"!state.isOpen\"\n class=\"blockspark-chat-toggle-btn\"\n @click=\"handleOpenChat\"\n aria-label=\"Open chat\"\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n </button>\n\n <!-- Chat Window -->\n <div v-if=\"state.isOpen\" class=\"blockspark-chat-window\">\n <div class=\"blockspark-chat-header\">\n <div class=\"blockspark-chat-header-content\">\n <div class=\"blockspark-chat-title\">{{ config.title }}</div>\n <div class=\"blockspark-chat-subtitle\">\n {{ config.subtitle }}\n <span v-if=\"state.chatMode === 'human'\" class=\"blockspark-mode-indicator\">\n • {{ wsConnected ? '🟢 Connected' : '🟡 Connecting...' }}\n </span>\n </div>\n <div v-if=\"state.chatMode === 'human'\" class=\"blockspark-mode-badge\">\n Human Support Mode\n </div>\n <div v-if=\"state.chatMode === 'human'\" class=\"blockspark-agent-info\">\n <span class=\"blockspark-agent-label\">Agent:</span>\n <span class=\"blockspark-agent-name\">{{ currentAgent.name }}</span>\n </div>\n <div v-if=\"state.chatMode === 'ai'\" class=\"blockspark-mode-badge\">\n Bot Mode\n </div>\n </div>\n <button\n class=\"blockspark-chat-close-btn\"\n @click=\"handleCloseChat\"\n aria-label=\"Close chat\"\n >\n ×\n </button>\n </div>\n\n <div class=\"blockspark-chat-messages\" ref=\"messagesContainer\">\n <!-- Empty State -->\n <div v-if=\"state.messages.length === 0\" class=\"blockspark-chat-empty\">\n <div class=\"blockspark-chat-empty-icon\">👋</div>\n <p>{{ config.emptyStateMessage }}</p>\n </div>\n\n <!-- Messages -->\n <div\n v-for=\"message in state.messages\"\n :key=\"message.id\"\n :class=\"[\n 'blockspark-message', \n `blockspark-message-${message.sender}`,\n { 'blockspark-handoff-message': isHandoffMessage(message.text) }\n ]\"\n >\n <div \n class=\"blockspark-message-content\"\n :class=\"{ 'blockspark-handoff-content': isHandoffMessage(message.text) }\"\n >\n <!-- Safe HTML rendering with sanitization -->\n <!-- Preserve line breaks for better formatting -->\n <span v-html=\"safeLinkifyText(message.text).replace(/\\n/g, '<br>')\"></span>\n </div>\n\n <!-- Rich Content (Chips) -->\n <div\n v-if=\"message.richContent && Array.isArray(message.richContent) && message.richContent.length > 0\"\n class=\"blockspark-chips-container\"\n >\n <template v-for=\"(contentGroup, groupIndex) in message.richContent\" :key=\"groupIndex\">\n <template v-if=\"!Array.isArray(contentGroup)\">\n <div\n v-if=\"contentGroup.type === 'chips' && contentGroup.options\"\n class=\"blockspark-chips-group\"\n >\n <button\n v-for=\"(chip, chipIndex) in contentGroup.options\"\n :key=\"chipIndex\"\n class=\"blockspark-chip-button\"\n type=\"button\"\n @click=\"handleChipClick(chip.text, chip.payload)\"\n >\n {{ chip.text }}\n </button>\n </div>\n </template>\n <template v-else>\n <template\n v-for=\"(content, contentIndex) in contentGroup\"\n :key=\"`${groupIndex}-${contentIndex}`\"\n >\n <div\n v-if=\"content.type === 'chips' && content.options\"\n class=\"blockspark-chips-group\"\n >\n <button\n v-for=\"(chip, chipIndex) in content.options\"\n :key=\"chipIndex\"\n class=\"blockspark-chip-button\"\n type=\"button\"\n @click=\"handleChipClick(chip.text, chip.payload)\"\n >\n {{ chip.text }}\n </button>\n </div>\n </template>\n </template>\n </template>\n </div>\n\n <div class=\"blockspark-message-time\">\n {{ formatTime(message.timestamp) }}\n </div>\n </div>\n\n <!-- Loading Indicator -->\n <div v-if=\"state.isLoading\" class=\"blockspark-message blockspark-message-bot\">\n <div class=\"blockspark-typing-indicator\">\n <span></span>\n <span></span>\n <span></span>\n </div>\n </div>\n\n <!-- Agent Typing Indicator -->\n <div v-if=\"state.chatMode === 'human' && agentTyping\" class=\"blockspark-agent-typing-indicator\">\n <span class=\"blockspark-typing-dots\">\n <span></span>\n <span></span>\n <span></span>\n </span>\n <span class=\"blockspark-typing-text\">Agent is typing...</span>\n </div>\n\n <div ref=\"messagesEndRef\"></div>\n </div>\n\n <!-- Input Form -->\n <form class=\"blockspark-chat-input-form\" @submit.prevent=\"handleSubmit\">\n <input\n type=\"text\"\n class=\"blockspark-chat-input\"\n :value=\"state.inputValue\"\n @input=\"handleInput\"\n :placeholder=\"config.inputPlaceholder\"\n :disabled=\"state.isLoading\"\n />\n <button\n type=\"submit\"\n class=\"blockspark-chat-send-btn\"\n :disabled=\"!state.inputValue.trim() || state.isLoading\"\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n </button>\n </form>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted, nextTick, watch } from 'vue';\nimport { useChatWidget } from '../composables/useChatWidget';\nimport { safeLinkifyText } from '../utils/sanitize';\nimport type { WidgetConfig } from '../core/types';\n\n// Props\nconst props = withDefaults(defineProps<WidgetConfig>(), {\n title: '💬 BlockSpark AI Assistant',\n subtitle: \"We're here to help\",\n welcomeTitle: '👋 Welcome to BlockSpark',\n welcomeMessage: \"My name is BlockSpark AI Assistant and I'll guide you.\",\n welcomeCta: '💬 Click here to start chatting!',\n showWelcomePopup: true,\n welcomePopupDelay: 1500,\n fallbackWelcomeMessage: \"Hello! I'm BlockSpark AI Assistant. How can I help you today?\",\n inputPlaceholder: 'Type your message...',\n emptyStateMessage: \"Hi! I'm BlockSpark AI Assistant. How can I help you today?\",\n debug: false,\n});\n\n// Use headless composable\nconst {\n state,\n isOpen,\n messages,\n isLoading,\n error,\n chatMode,\n wsConnected,\n agentTyping,\n currentAgent,\n openChat,\n closeChat,\n sendMessage,\n toggleChat,\n setInputValue,\n clearError,\n manager,\n} = useChatWidget(props);\n\n// Refs\nconst messagesEndRef = ref<HTMLDivElement | null>(null);\nconst messagesContainer = ref<HTMLDivElement | null>(null);\n\n// Computed config (for reactivity)\nconst config = computed(() => props);\n\n// Auto-scroll to bottom when messages change\nwatch(\n () => messages.value.length,\n () => {\n nextTick(() => {\n messagesEndRef.value?.scrollIntoView({ behavior: 'smooth' });\n });\n }\n);\n\n// Handlers\nconst handleOpenChat = async () => {\n await openChat();\n};\n\nconst handleCloseChat = () => {\n closeChat();\n};\n\nconst handleCloseWelcomePopup = () => {\n manager.closeWelcomePopup();\n};\n\nconst handleInput = (event: Event) => {\n const target = event.target as HTMLInputElement;\n setInputValue(target.value);\n};\n\nconst handleSubmit = async (event: Event) => {\n event.preventDefault();\n if (state.value.inputValue.trim()) {\n await sendMessage(state.value.inputValue);\n }\n};\n\nconst handleChipClick = async (chipText: string, payload?: string) => {\n const messageToSend = chipText || payload || '';\n await sendMessage(messageToSend);\n};\n\n// Utility functions\nconst formatTime = (date: Date): string => {\n return date.toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n });\n};\n\n// Check if message is a handoff message\nconst isHandoffMessage = (text: string): boolean => {\n return text.includes('👤') || \n text.includes('being connected') || \n text.includes('live support agent') ||\n text.includes('transfer your conversation');\n};\n\n// Initialize welcome popup on mount (SSR-safe)\nonMounted(() => {\n if (config.value.showWelcomePopup && typeof window !== 'undefined') {\n manager.initializeWelcomePopup();\n }\n});\n</script>\n\n<style scoped>\n/* Styles are imported separately by users */\n/* This ensures SSR compatibility */\n</style>\n"],"names":["_openBlock","_createElementBlock","_unref","_createElementVNode","_toDisplayString","_Fragment","_renderList","_normalizeClass"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../services/dialogflowClient.cjs.js"),t=require("../services/chatService.cjs.js"),s=require("../utils/ssr.cjs.js");exports.WidgetStateManager=class{constructor(e){this.listeners=new Set,this.chatMode="ai",this.chatId=null,this.supportSessionId=null,this.chatService=null,this.collectingUserInfo=!1,this.userInfoStep=null,this.collectedUserName="",this.collectedUserEmail="",this.collectedUserMobile="",this.wsConnected=!1,this.agentTyping=!1,this.currentAgent={name:"Agent"},this.isConnectingToAgent=!1,this.agentAccepted=!1,this.chatResolved=!1,this.historyLoaded=null,this.typingTimeout=null,this.agentTypingTimeout=null,this.config=e,this.state={isOpen:!1,showWelcomePopup:!1,messages:[],inputValue:"",isLoading:!1,error:null,sessionId:null,chatMode:"ai"},this.chatService=t.createChatService({baseUrl:this.config.backendBaseUrl||"http://localhost:8012",wsUrl:this.config.backendWsUrl||"ws://localhost:8012",debug:this.config.debug||!1});const i=s.safeLocalStorage(),a=i.getItem("blockspark_chat_mode");a&&(this.chatMode="HUMAN"===a?"human":"ai",this.state.chatMode=this.chatMode),this.chatId=i.getItem("blockspark_chat_id"),this.supportSessionId=i.getItem("blockspark_session_id")}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}getState(){return{...this.state}}setState(e){this.state={...this.state,...e},this.listeners.forEach(e=>e(this.getState()))}updateConfig(e){this.config={...this.config,...e}}async openChat(){if(this.setState({isOpen:!0}),this.state.showWelcomePopup&&this.setState({showWelcomePopup:!1}),"ai"===this.state.chatMode&&!this.state.sessionId&&this.config.dfProjectId&&this.config.dfAgentId)try{this.setState({isLoading:!0});const t={dfProjectId:this.config.dfProjectId,dfLocation:this.config.dfLocation||"us-central1",dfAgentId:this.config.dfAgentId,serviceAccountKey:this.config.serviceAccountKey,accessToken:this.config.accessToken,languageCode:this.config.languageCode||"en"},s=await e.createDialogflowSession(t);if(this.setState({sessionId:s.session_id,isLoading:!1}),s.message){const e={id:`welcome-${Date.now()}`,text:s.message,sender:"bot",timestamp:new Date,richContent:s.richContent};this.setState({messages:[e]})}}catch(t){this.setState({isLoading:!1,error:t.message||"Failed to initialize chat"});const e={id:`fallback-${Date.now()}`,text:this.config.fallbackWelcomeMessage||"Hello! How can I help you today?",sender:"bot",timestamp:new Date};this.setState({messages:[e]})}}closeChat(){this.setState({isOpen:!1})}closeWelcomePopup(){this.setState({showWelcomePopup:!1})}toggleChat(){const e=!this.state.isOpen;this.setState({isOpen:e}),e&&this.state.showWelcomePopup&&this.setState({showWelcomePopup:!1})}setInputValue(e){this.setState({inputValue:e})}clearError(){this.setState({error:null})}async sendMessage(e,s=!1){if(e.trim()&&!this.state.isLoading){if(this.collectingUserInfo){const t={id:`user-${Date.now()}`,text:e.trim(),sender:"user",timestamp:new Date};return this.setState({messages:[...this.state.messages,t],inputValue:"",isLoading:!1,error:null}),void(await this.handleUserInfoCollection(e))}if(s)this.setState({inputValue:"",isLoading:!0,error:null});else{const t={id:`user-${Date.now()}`,text:e.trim(),sender:"user",timestamp:new Date};this.setState({messages:[...this.state.messages,t],inputValue:"",isLoading:!0,error:null})}try{"human"===this.state.chatMode?await this.sendHumanMessage(e):await this.sendAIMessage(e)}catch(i){if(i instanceof t.ChatResolvedError||"ChatResolvedError"===i?.name||"chat_resolved"===i?.message)return void this.enterResolvedState(this.chatId);const e={id:`error-${Date.now()}`,text:this.config.debug?`Error: ${i.message||"Failed to send message"}`:i.message?.includes("CORS")||i.message?.includes("Failed to fetch")?"Unable to connect to Dialogflow. Please check your configuration and network.":"Sorry, I'm having trouble processing your message. Please try again.",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e],error:i.message||"Failed to send message",isLoading:!1})}}}async sendAIMessage(t){if(!this.config.dfProjectId||!this.config.dfAgentId)throw new Error("Dialogflow configuration is missing");const s={dfProjectId:this.config.dfProjectId,dfLocation:this.config.dfLocation||"us-central1",dfAgentId:this.config.dfAgentId,serviceAccountKey:this.config.serviceAccountKey,accessToken:this.config.accessToken,languageCode:this.config.languageCode||"en"};if(!this.state.sessionId){const t=await e.createDialogflowSession(s);this.setState({sessionId:t.session_id})}this.config.debug;const i=await e.sendDialogflowMessage(t,this.state.sessionId,s);if(this.config.debug,!0===i.handoff){const e={id:`bot-${Date.now()}`,text:i.response||this.config.fallbackWelcomeMessage||"No response",sender:"bot",timestamp:new Date,richContent:i.richContent};return this.setState({messages:[...this.state.messages,e],isLoading:!1}),void this.startUserInfoCollection()}const a={id:`bot-${Date.now()}`,text:i.response||this.config.fallbackWelcomeMessage||"No response",sender:"bot",timestamp:new Date,richContent:i.richContent};this.setState({messages:[...this.state.messages,a],isLoading:!1})}async sendHumanMessage(e){if(!this.chatId||!this.supportSessionId){const e={id:`error-${Date.now()}`,text:"Chat session not initialized. Please try again.",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,e],isLoading:!1})}if(!this.chatService)throw new Error("Chat service not initialized");this.chatService.sendTypingIndicator("typing_stop"),this.typingTimeout&&(clearTimeout(this.typingTimeout),this.typingTimeout=null);try{this.chatService.sendMessageViaWebSocket(e.trim())||await this.chatService.sendMessageToAgent(this.chatId,this.supportSessionId,e.trim()),this.setState({isLoading:!1})}catch(i){if(i instanceof t.ChatResolvedError||"ChatResolvedError"===i?.name||"chat_resolved"===i?.message)return void this.enterResolvedState(this.chatId);if(!(i.message?.includes("Chat not found")||i.message?.includes("unauthorized")||i.message?.includes("401")||i.message?.includes("404")))throw i;{this.config.debug,this.chatId=null,this.supportSessionId=null;const i=s.safeLocalStorage();i.removeItem("blockspark_chat_id"),i.removeItem("blockspark_session_id");try{const t=await this.chatService.startSupportChat(this.state.sessionId||null,null,null,null);this.chatId=t.chat_id,this.supportSessionId=t.session_id;const i=s.safeLocalStorage();return i.setItem("blockspark_chat_id",this.chatId),i.setItem("blockspark_session_id",this.supportSessionId),this.chatId&&this.supportSessionId&&await this.chatService.sendMessageToAgent(this.chatId,this.supportSessionId,e.trim()),void this.setState({isLoading:!1})}catch(a){if(a instanceof t.ChatResolvedError||"chat_resolved"===a?.message)return void this.enterResolvedState(this.chatId);throw a}}}}switchToHumanMode(){this.chatMode="human",this.setState({chatMode:"human"}),s.safeLocalStorage().setItem("blockspark_chat_mode","HUMAN")}switchToBotMode(){this.chatMode="ai",this.setState({chatMode:"ai"}),s.safeLocalStorage().setItem("blockspark_chat_mode","BOT")}initializeWelcomePopup(){if(!1!==this.config.showWelcomePopup){const e=this.config.welcomePopupDelay||1500;setTimeout(()=>{this.state.isOpen||this.setState({showWelcomePopup:!0})},e)}}startUserInfoCollection(){this.collectingUserInfo=!0,this.userInfoStep="name",this.collectedUserName="",this.collectedUserEmail="",this.collectedUserMobile="";const e={id:`prompt-${Date.now()}`,text:"To connect you with a human agent, I'll need some information. Please provide your name:",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e]})}async handleUserInfoCollection(e){if("name"===this.userInfoStep){const t=e.trim();this.collectedUserName=t,this.userInfoStep="email";const s={id:`prompt-${Date.now()}`,text:"Thank you! Now please provide your email address:",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,s],inputValue:""})}if("email"===this.userInfoStep){const t=e.trim();if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)){const e={id:`prompt-${Date.now()}`,text:"Please provide a valid email address:",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,e],inputValue:""})}this.collectedUserEmail=t,this.userInfoStep="mobile";const s={id:`prompt-${Date.now()}`,text:"Thank you! Now please provide your mobile number:",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,s],inputValue:""})}if("mobile"===this.userInfoStep){const t=e.trim();if(!/^[\+]?[(]?[0-9]{1,4}[)]?[-\s\.]?[(]?[0-9]{1,4}[)]?[-\s\.]?[0-9]{1,9}$/.test(t)||t.length<10){const e={id:`prompt-${Date.now()}`,text:"Please provide a valid mobile number (e.g., +1234567890):",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,e],inputValue:""})}this.collectedUserMobile=t,this.collectingUserInfo=!1,this.userInfoStep=null,await this.handleHandoff(this.collectedUserName,this.collectedUserEmail,t),this.setState({inputValue:""})}}async handleHandoff(e,t,i){if(!this.chatService)throw new Error("Chat service not initialized");try{this.isConnectingToAgent=!0;const n=this.state.sessionId,o=await this.chatService.ensureChatInitialized(this.chatId,this.supportSessionId,n||null,e||null,t||null,i||null);if(!o||!o.chat_id)throw new Error("Failed to initialize chat session");const c=o.chat_id,h=o.session_id;if(c!==this.chatId){this.chatId=c,this.supportSessionId=h;const e=s.safeLocalStorage();e.setItem("blockspark_chat_id",this.chatId),e.setItem("blockspark_session_id",this.supportSessionId),this.config.debug}try{await this.chatService.requestHandoff(c,h,"Customer requested human agent",n||null,e||null,t||null,i||null),this.config.debug}catch(a){if(!(a.message?.includes("Invalid chat_id")||a.message?.includes("Chat not found")||a.message?.includes("unauthorized")||a.message?.includes("400")||a.message?.includes("401")||a.message?.includes("404")||a.message?.includes("expired")))throw a;{this.config.debug,this.chatId=null,this.supportSessionId=null;const a=s.safeLocalStorage();a.removeItem("blockspark_chat_id"),a.removeItem("blockspark_session_id");const o=await this.chatService.startSupportChat(n||null,e||null,t||null,i||null);if(!o||!o.chat_id)throw new Error("Failed to re-initialize chat session");this.chatId=o.chat_id,this.supportSessionId=o.session_id;const c=s.safeLocalStorage();c.setItem("blockspark_chat_id",this.chatId),c.setItem("blockspark_session_id",this.supportSessionId),await this.chatService.requestHandoff(this.chatId,this.supportSessionId,"Customer requested human agent",n||null,e||null,t||null,i||null),this.config.debug}}this.switchToHumanMode(),this.chatResolved=!1,this.agentAccepted=!1;const r={id:`connecting-${Date.now()}`,text:"Connecting you to a human agent...",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,r]}),c&&h&&this.chatService.connectWebSocket(c,h,e=>{this.handleWebSocketMessage(e)},e=>{this.wsConnected=e}),this.isConnectingToAgent=!1}catch(n){const e={id:`error-${Date.now()}`,text:this.config.debug?`Handoff error: ${n.message}`:"Failed to connect to agent. Please try again.",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e]}),this.isConnectingToAgent=!1}}handleWebSocketMessage(e){switch(e.type){case"message":if(e.content&&("agent"===e.sender_type||!e.sender_type)){const t={id:e.id||`agent-${Date.now()}`,text:e.content,sender:"agent",timestamp:new Date(e.timestamp||Date.now())};new Set(this.state.messages.map(e=>e.id)).has(t.id)||this.setState({messages:[...this.state.messages,t]}),this.agentTyping=!1,this.agentTypingTimeout&&(clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=null)}break;case"typing_start":"agent"===e.sender_type&&(this.agentTyping=!0,this.agentTypingTimeout&&clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=setTimeout(()=>{this.agentTyping=!1},3e3));break;case"typing_stop":"agent"===e.sender_type&&(this.agentTyping=!1,this.agentTypingTimeout&&(clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=null));break;case"agent_changed":if(e.to_agent){this.currentAgent={id:e.to_agent_id,name:e.to_agent};const t={id:`system-${Date.now()}`,text:e.from_agent?`Chat has been transferred from ${e.from_agent} to ${e.to_agent}`:`Chat has been transferred to ${e.to_agent}`,sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,t]})}break;case"agent_accepted":this.agentAccepted=!0,this.isConnectingToAgent=!1;const t={id:e.id||`agent-accepted-${Date.now()}`,text:"You can chat now, the agent has accepted your request.",sender:"bot",timestamp:e.timestamp?new Date(e.timestamp):new Date};new Set(this.state.messages.map(e=>e.id)).has(t.id)||this.setState({messages:[...this.state.messages,t]}),e.to_agent&&(this.currentAgent={name:e.to_agent,id:e.to_agent_id});break;case"chat_resolved":case"chat_ended":this.enterResolvedState(e.chat_id||null);break;case"chat_info":"active"===e.status?(this.isConnectingToAgent=!1,this.agentAccepted=!0):"resolved"!==e.status&&"ended"!==e.status||this.enterResolvedState(e.chat_id||null),e.agent_id&&(this.currentAgent={...this.currentAgent,id:e.agent_id});break;case"error":const s={id:`error-${Date.now()}`,text:e.error||"An error occurred. Please try again.",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,s]})}}enterResolvedState(t){this.chatResolved=!0,this.isConnectingToAgent=!1,this.agentAccepted=!1,this.agentTyping=!1,this.agentTypingTimeout&&(clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=null),this.chatService&&this.chatService.disconnectWebSocket(),this.chatId=null,this.supportSessionId=null;const i=s.safeLocalStorage();i.removeItem("blockspark_chat_id"),i.removeItem("blockspark_session_id");const a={id:`resolved-${Date.now()}`,text:"Thank you for contacting us!",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,a]}),setTimeout(async()=>{if(this.switchToBotMode(),this.chatResolved=!1,this.setState({messages:[],sessionId:null}),this.collectingUserInfo=!1,this.userInfoStep=null,this.collectedUserName="",this.collectedUserEmail="",this.collectedUserMobile="",this.config.dfProjectId&&this.config.dfAgentId&&this.state.isOpen)try{this.setState({isLoading:!0});const t={dfProjectId:this.config.dfProjectId,dfLocation:this.config.dfLocation||"us-central1",dfAgentId:this.config.dfAgentId,serviceAccountKey:this.config.serviceAccountKey,accessToken:this.config.accessToken,languageCode:this.config.languageCode||"en"},s=await e.createDialogflowSession(t);if(this.setState({sessionId:s.session_id,isLoading:!1}),s.message){const e={id:`welcome-${Date.now()}`,text:s.message,sender:"bot",timestamp:new Date,richContent:s.richContent};this.setState({messages:[e]})}}catch(t){this.setState({isLoading:!1,error:t.message||"Failed to initialize chat"});const e={id:`fallback-${Date.now()}`,text:this.config.fallbackWelcomeMessage||"Hello! How can I help you today?",sender:"bot",timestamp:new Date};this.setState({messages:[e]})}},2e3)}async loadMessageHistory(e=!1){if(this.chatService&&this.chatId&&this.supportSessionId)try{if(this.chatId&&this.supportSessionId){const t=(await this.chatService.loadMessageHistory(this.chatId,this.supportSessionId)).map(e=>({id:e.id||`history-${Date.now()}-${Math.random()}`,text:e.content,sender:"agent"===e.sender_type?"agent":"user",timestamp:new Date(e.timestamp)}));if(e){const e=new Set(this.state.messages.map(e=>e.id)),s=t.filter(t=>!e.has(t.id)),i=[...this.state.messages,...s].sort((e,t)=>e.timestamp.getTime()-t.timestamp.getTime());this.setState({messages:i})}else this.setState({messages:t})}}catch(t){if(this.config.debug){const e={id:`error-${Date.now()}`,text:`Failed to load chat history: ${t.message}`,sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e]})}}}getAdditionalState(){return{wsConnected:this.wsConnected,agentTyping:this.agentTyping,currentAgent:this.currentAgent,isConnectingToAgent:this.isConnectingToAgent,agentAccepted:this.agentAccepted,chatResolved:this.chatResolved}}destroy(){this.typingTimeout&&clearTimeout(this.typingTimeout),this.agentTypingTimeout&&clearTimeout(this.agentTypingTimeout),this.chatService&&this.chatService.disconnectWebSocket(),this.listeners.clear()}};
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../services/dialogflowClient.cjs.js"),t=require("../services/chatService.cjs.js"),s=require("../utils/ssr.cjs.js");exports.WidgetStateManager=class{constructor(e){this.listeners=new Set,this.chatMode="ai",this.chatId=null,this.supportSessionId=null,this.chatService=null,this.collectingUserInfo=!1,this.userInfoStep=null,this.collectedUserName="",this.collectedUserEmail="",this.collectedUserMobile="",this.wsConnected=!1,this.agentTyping=!1,this.currentAgent={name:"Agent"},this.isConnectingToAgent=!1,this.agentAccepted=!1,this.chatResolved=!1,this.historyLoaded=null,this.typingTimeout=null,this.agentTypingTimeout=null,this.config=e,this.state={isOpen:!1,showWelcomePopup:!1,messages:[],inputValue:"",isLoading:!1,error:null,sessionId:null,chatMode:"ai"},this.chatService=t.createChatService({baseUrl:this.config.backendBaseUrl||"http://localhost:8012",wsUrl:this.config.backendWsUrl||"ws://localhost:8012",debug:this.config.debug||!1});const i=s.safeLocalStorage(),a=i.getItem("blockspark_chat_mode");a&&(this.chatMode="HUMAN"===a?"human":"ai",this.state.chatMode=this.chatMode),this.chatId=i.getItem("blockspark_chat_id"),this.supportSessionId=i.getItem("blockspark_session_id")}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}getState(){return{...this.state}}setState(e){this.state={...this.state,...e},this.listeners.forEach(e=>e(this.getState()))}updateConfig(e){this.config={...this.config,...e}}async openChat(){if(this.setState({isOpen:!0}),this.state.showWelcomePopup&&this.setState({showWelcomePopup:!1}),"ai"===this.state.chatMode&&!this.state.sessionId&&this.config.dfProjectId&&this.config.dfAgentId)try{this.setState({isLoading:!0});const t={dfProjectId:this.config.dfProjectId,dfLocation:this.config.dfLocation||"us-central1",dfAgentId:this.config.dfAgentId,serviceAccountKey:this.config.serviceAccountKey,accessToken:this.config.accessToken,languageCode:this.config.languageCode||"en"},s=await e.createDialogflowSession(t);if(this.setState({sessionId:s.session_id,isLoading:!1}),s.message){const e={id:`welcome-${Date.now()}`,text:s.message,sender:"bot",timestamp:new Date,richContent:s.richContent};this.setState({messages:[e]})}}catch(t){this.setState({isLoading:!1,error:t.message||"Failed to initialize chat"});const e={id:`fallback-${Date.now()}`,text:this.config.fallbackWelcomeMessage||"Hello! How can I help you today?",sender:"bot",timestamp:new Date};this.setState({messages:[e]})}}closeChat(){this.setState({isOpen:!1})}closeWelcomePopup(){this.setState({showWelcomePopup:!1})}toggleChat(){const e=!this.state.isOpen;this.setState({isOpen:e}),e&&this.state.showWelcomePopup&&this.setState({showWelcomePopup:!1})}setInputValue(e){this.setState({inputValue:e})}clearError(){this.setState({error:null})}async sendMessage(e,s=!1){if(e.trim()&&!this.state.isLoading){if(this.collectingUserInfo){const t={id:`user-${Date.now()}`,text:e.trim(),sender:"user",timestamp:new Date};return this.setState({messages:[...this.state.messages,t],inputValue:"",isLoading:!1,error:null}),void(await this.handleUserInfoCollection(e))}if(s)this.setState({inputValue:"",isLoading:!0,error:null});else{const t={id:`user-${Date.now()}`,text:e.trim(),sender:"user",timestamp:new Date};this.setState({messages:[...this.state.messages,t],inputValue:"",isLoading:!0,error:null})}try{"human"===this.state.chatMode?await this.sendHumanMessage(e):await this.sendAIMessage(e)}catch(i){if(i instanceof t.ChatResolvedError||"ChatResolvedError"===i?.name||"chat_resolved"===i?.message)return void this.enterResolvedState(this.chatId);const e={id:`error-${Date.now()}`,text:this.config.debug?`Error: ${i.message||"Failed to send message"}`:i.message?.includes("CORS")||i.message?.includes("Failed to fetch")?"Unable to connect to Dialogflow. Please check your configuration and network.":"Sorry, I'm having trouble processing your message. Please try again.",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e],error:i.message||"Failed to send message",isLoading:!1})}}}async sendAIMessage(t){if(!this.config.dfProjectId||!this.config.dfAgentId)throw new Error("Dialogflow configuration is missing");const s={dfProjectId:this.config.dfProjectId,dfLocation:this.config.dfLocation||"us-central1",dfAgentId:this.config.dfAgentId,serviceAccountKey:this.config.serviceAccountKey,accessToken:this.config.accessToken,languageCode:this.config.languageCode||"en"};if(!this.state.sessionId){const t=await e.createDialogflowSession(s);this.setState({sessionId:t.session_id})}this.config.debug;const i=await e.sendDialogflowMessage(t,this.state.sessionId,s);if(this.config.debug,!0===i.handoff){const e={id:`bot-${Date.now()}`,text:i.response||this.config.fallbackWelcomeMessage||"No response",sender:"bot",timestamp:new Date,richContent:i.richContent};return this.setState({messages:[...this.state.messages,e],isLoading:!1}),void this.startUserInfoCollection()}const a={id:`bot-${Date.now()}`,text:i.response||this.config.fallbackWelcomeMessage||"No response",sender:"bot",timestamp:new Date,richContent:i.richContent};this.setState({messages:[...this.state.messages,a],isLoading:!1})}async sendHumanMessage(e){if(!this.chatId||!this.supportSessionId){const e={id:`error-${Date.now()}`,text:"Chat session not initialized. Please try again.",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,e],isLoading:!1})}if(!this.chatService)throw new Error("Chat service not initialized");this.chatService.sendTypingIndicator("typing_stop"),this.typingTimeout&&(clearTimeout(this.typingTimeout),this.typingTimeout=null);try{this.chatService.sendMessageViaWebSocket(e.trim())||await this.chatService.sendMessageToAgent(this.chatId,this.supportSessionId,e.trim()),this.setState({isLoading:!1})}catch(i){if(i instanceof t.ChatResolvedError||"ChatResolvedError"===i?.name||"chat_resolved"===i?.message)return void this.enterResolvedState(this.chatId);if(!(i.message?.includes("Chat not found")||i.message?.includes("unauthorized")||i.message?.includes("401")||i.message?.includes("404")))throw i;{this.config.debug,this.chatId=null,this.supportSessionId=null;const i=s.safeLocalStorage();i.removeItem("blockspark_chat_id"),i.removeItem("blockspark_session_id");try{const t=await this.chatService.startSupportChat(this.state.sessionId||null,null,null,null);this.chatId=t.chat_id,this.supportSessionId=t.session_id;const i=s.safeLocalStorage();return i.setItem("blockspark_chat_id",this.chatId),i.setItem("blockspark_session_id",this.supportSessionId),this.chatId&&this.supportSessionId&&await this.chatService.sendMessageToAgent(this.chatId,this.supportSessionId,e.trim()),void this.setState({isLoading:!1})}catch(a){if(a instanceof t.ChatResolvedError||"chat_resolved"===a?.message)return void this.enterResolvedState(this.chatId);throw a}}}}switchToHumanMode(){this.chatMode="human",this.setState({chatMode:"human"}),s.safeLocalStorage().setItem("blockspark_chat_mode","HUMAN")}switchToBotMode(){this.chatMode="ai",this.setState({chatMode:"ai"}),s.safeLocalStorage().setItem("blockspark_chat_mode","BOT")}initializeWelcomePopup(){if(!1!==this.config.showWelcomePopup){const e=this.config.welcomePopupDelay||1500;setTimeout(()=>{this.state.isOpen||this.setState({showWelcomePopup:!0})},e)}}startUserInfoCollection(){this.collectingUserInfo=!0,this.userInfoStep="name",this.collectedUserName="",this.collectedUserEmail="",this.collectedUserMobile="";const e={id:`handoff-${Date.now()}`,text:"👤 You're being connected to a live support agent. Please wait while we transfer your conversation...",sender:"bot",timestamp:new Date},t={id:`prompt-${Date.now()}`,text:"To connect you with a human agent, I'll need some information.\n\nPlease provide your name:",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e,t]})}async handleUserInfoCollection(e){if("name"===this.userInfoStep){const t=e.trim();this.collectedUserName=t,this.userInfoStep="email";const s={id:`prompt-${Date.now()}`,text:"✅ Thank you! Now please provide your email address:",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,s],inputValue:""})}if("email"===this.userInfoStep){const t=e.trim();if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)){const e={id:`prompt-${Date.now()}`,text:"Please provide a valid email address:",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,e],inputValue:""})}this.collectedUserEmail=t,this.userInfoStep="mobile";const s={id:`prompt-${Date.now()}`,text:"✅ Thank you! Now please provide your mobile number:",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,s],inputValue:""})}if("mobile"===this.userInfoStep){const t=e.trim();if(!/^[\+]?[(]?[0-9]{1,4}[)]?[-\s\.]?[(]?[0-9]{1,4}[)]?[-\s\.]?[0-9]{1,9}$/.test(t)||t.length<10){const e={id:`prompt-${Date.now()}`,text:"Please provide a valid mobile number (e.g., +1234567890):",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,e],inputValue:""})}this.collectedUserMobile=t,this.collectingUserInfo=!1,this.userInfoStep=null,await this.handleHandoff(this.collectedUserName,this.collectedUserEmail,t),this.setState({inputValue:""})}}async handleHandoff(e,t,i){if(!this.chatService)throw new Error("Chat service not initialized");try{this.isConnectingToAgent=!0;const n=this.state.sessionId,o=await this.chatService.ensureChatInitialized(this.chatId,this.supportSessionId,n||null,e||null,t||null,i||null);if(!o||!o.chat_id)throw new Error("Failed to initialize chat session");const c=o.chat_id,h=o.session_id;if(c!==this.chatId){this.chatId=c,this.supportSessionId=h;const e=s.safeLocalStorage();e.setItem("blockspark_chat_id",this.chatId),e.setItem("blockspark_session_id",this.supportSessionId),this.config.debug}try{await this.chatService.requestHandoff(c,h,"Customer requested human agent",n||null,e||null,t||null,i||null),this.config.debug}catch(a){if(!(a.message?.includes("Invalid chat_id")||a.message?.includes("Chat not found")||a.message?.includes("unauthorized")||a.message?.includes("400")||a.message?.includes("401")||a.message?.includes("404")||a.message?.includes("expired")))throw a;{this.config.debug,this.chatId=null,this.supportSessionId=null;const a=s.safeLocalStorage();a.removeItem("blockspark_chat_id"),a.removeItem("blockspark_session_id");const o=await this.chatService.startSupportChat(n||null,e||null,t||null,i||null);if(!o||!o.chat_id)throw new Error("Failed to re-initialize chat session");this.chatId=o.chat_id,this.supportSessionId=o.session_id;const c=s.safeLocalStorage();c.setItem("blockspark_chat_id",this.chatId),c.setItem("blockspark_session_id",this.supportSessionId),await this.chatService.requestHandoff(this.chatId,this.supportSessionId,"Customer requested human agent",n||null,e||null,t||null,i||null),this.config.debug}}this.switchToHumanMode(),this.chatResolved=!1,this.agentAccepted=!1;const r={id:`connecting-${Date.now()}`,text:"🔄 Connecting you to a human agent...",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,r]}),c&&h&&this.chatService.connectWebSocket(c,h,e=>{this.handleWebSocketMessage(e)},e=>{this.wsConnected=e}),this.isConnectingToAgent=!1}catch(n){const e={id:`error-${Date.now()}`,text:this.config.debug?`Handoff error: ${n.message}`:"Failed to connect to agent. Please try again.",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e]}),this.isConnectingToAgent=!1}}handleWebSocketMessage(e){switch(e.type){case"message":if(e.content&&("agent"===e.sender_type||!e.sender_type)){const t={id:e.id||`agent-${Date.now()}`,text:e.content,sender:"agent",timestamp:new Date(e.timestamp||Date.now())};new Set(this.state.messages.map(e=>e.id)).has(t.id)||this.setState({messages:[...this.state.messages,t]}),this.agentTyping=!1,this.agentTypingTimeout&&(clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=null)}break;case"typing_start":"agent"===e.sender_type&&(this.agentTyping=!0,this.agentTypingTimeout&&clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=setTimeout(()=>{this.agentTyping=!1},3e3));break;case"typing_stop":"agent"===e.sender_type&&(this.agentTyping=!1,this.agentTypingTimeout&&(clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=null));break;case"agent_changed":if(e.to_agent){this.currentAgent={id:e.to_agent_id,name:e.to_agent};const t={id:`system-${Date.now()}`,text:e.from_agent?`Chat has been transferred from ${e.from_agent} to ${e.to_agent}`:`Chat has been transferred to ${e.to_agent}`,sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,t]})}break;case"agent_accepted":this.agentAccepted=!0,this.isConnectingToAgent=!1;const t={id:e.id||`agent-accepted-${Date.now()}`,text:"You can chat now, the agent has accepted your request.",sender:"bot",timestamp:e.timestamp?new Date(e.timestamp):new Date};new Set(this.state.messages.map(e=>e.id)).has(t.id)||this.setState({messages:[...this.state.messages,t]}),e.to_agent&&(this.currentAgent={name:e.to_agent,id:e.to_agent_id});break;case"chat_resolved":case"chat_ended":this.enterResolvedState(e.chat_id||null);break;case"chat_info":"active"===e.status?(this.isConnectingToAgent=!1,this.agentAccepted=!0):"resolved"!==e.status&&"ended"!==e.status||this.enterResolvedState(e.chat_id||null),e.agent_id&&(this.currentAgent={...this.currentAgent,id:e.agent_id});break;case"error":const s={id:`error-${Date.now()}`,text:e.error||"An error occurred. Please try again.",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,s]})}}enterResolvedState(t){this.chatResolved=!0,this.isConnectingToAgent=!1,this.agentAccepted=!1,this.agentTyping=!1,this.agentTypingTimeout&&(clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=null),this.chatService&&this.chatService.disconnectWebSocket(),this.chatId=null,this.supportSessionId=null;const i=s.safeLocalStorage();i.removeItem("blockspark_chat_id"),i.removeItem("blockspark_session_id");const a={id:`resolved-${Date.now()}`,text:"Thank you for contacting us!",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,a]}),setTimeout(async()=>{if(this.switchToBotMode(),this.chatResolved=!1,this.setState({messages:[],sessionId:null}),this.collectingUserInfo=!1,this.userInfoStep=null,this.collectedUserName="",this.collectedUserEmail="",this.collectedUserMobile="",this.config.dfProjectId&&this.config.dfAgentId&&this.state.isOpen)try{this.setState({isLoading:!0});const t={dfProjectId:this.config.dfProjectId,dfLocation:this.config.dfLocation||"us-central1",dfAgentId:this.config.dfAgentId,serviceAccountKey:this.config.serviceAccountKey,accessToken:this.config.accessToken,languageCode:this.config.languageCode||"en"},s=await e.createDialogflowSession(t);if(this.setState({sessionId:s.session_id,isLoading:!1}),s.message){const e={id:`welcome-${Date.now()}`,text:s.message,sender:"bot",timestamp:new Date,richContent:s.richContent};this.setState({messages:[e]})}}catch(t){this.setState({isLoading:!1,error:t.message||"Failed to initialize chat"});const e={id:`fallback-${Date.now()}`,text:this.config.fallbackWelcomeMessage||"Hello! How can I help you today?",sender:"bot",timestamp:new Date};this.setState({messages:[e]})}},2e3)}async loadMessageHistory(e=!1){if(this.chatService&&this.chatId&&this.supportSessionId)try{if(this.chatId&&this.supportSessionId){const t=(await this.chatService.loadMessageHistory(this.chatId,this.supportSessionId)).map(e=>({id:e.id||`history-${Date.now()}-${Math.random()}`,text:e.content,sender:"agent"===e.sender_type?"agent":"user",timestamp:new Date(e.timestamp)}));if(e){const e=new Set(this.state.messages.map(e=>e.id)),s=t.filter(t=>!e.has(t.id)),i=[...this.state.messages,...s].sort((e,t)=>e.timestamp.getTime()-t.timestamp.getTime());this.setState({messages:i})}else this.setState({messages:t})}}catch(t){if(this.config.debug){const e={id:`error-${Date.now()}`,text:`Failed to load chat history: ${t.message}`,sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e]})}}}getAdditionalState(){return{wsConnected:this.wsConnected,agentTyping:this.agentTyping,currentAgent:this.currentAgent,isConnectingToAgent:this.isConnectingToAgent,agentAccepted:this.agentAccepted,chatResolved:this.chatResolved}}destroy(){this.typingTimeout&&clearTimeout(this.typingTimeout),this.agentTypingTimeout&&clearTimeout(this.agentTypingTimeout),this.chatService&&this.chatService.disconnectWebSocket(),this.listeners.clear()}};
|
|
2
2
|
//# sourceMappingURL=stateManager.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stateManager.cjs.js","sources":["../../src/core/stateManager.ts"],"sourcesContent":["/**\n * State Manager - Framework Agnostic\n * Manages widget state independently of framework\n */\n\nimport type { WidgetState, WidgetConfig, ChatMessage } from './types';\nimport {\n createDialogflowSession,\n sendDialogflowMessage,\n type DialogflowConfig,\n} from '../services/dialogflowClient';\nimport { \n createChatService, \n ChatResolvedError,\n type WebSocketMessage\n} from '../services/chatService';\nimport { safeLocalStorage } from '../utils/ssr';\n\nexport class WidgetStateManager {\n private state: WidgetState;\n private config: WidgetConfig;\n private listeners: Set<(state: WidgetState) => void> = new Set();\n private chatMode: 'ai' | 'human' = 'ai';\n private chatId: string | null = null;\n private supportSessionId: string | null = null;\n private chatService: ReturnType<typeof createChatService> | null = null;\n \n // User info collection for handoff\n private collectingUserInfo: boolean = false;\n private userInfoStep: 'name' | 'email' | 'mobile' | null = null;\n private collectedUserName: string = '';\n private collectedUserEmail: string = '';\n private collectedUserMobile: string = '';\n \n // Additional state for human support\n private wsConnected: boolean = false;\n private agentTyping: boolean = false;\n private currentAgent: { name: string; id?: string } = { name: 'Agent' };\n private isConnectingToAgent: boolean = false;\n private agentAccepted: boolean = false;\n private chatResolved: boolean = false;\n private historyLoaded: string | null = null;\n \n // Typing timeout refs (stored as class properties since we can't use refs)\n private typingTimeout: NodeJS.Timeout | null = null;\n private agentTypingTimeout: NodeJS.Timeout | null = null;\n\n constructor(config: WidgetConfig) {\n this.config = config;\n this.state = {\n isOpen: false,\n showWelcomePopup: false,\n messages: [],\n inputValue: '',\n isLoading: false,\n error: null,\n sessionId: null,\n chatMode: 'ai',\n };\n \n // Initialize ChatService\n this.chatService = createChatService({\n baseUrl: this.config.backendBaseUrl || 'http://localhost:8012',\n wsUrl: this.config.backendWsUrl || 'ws://localhost:8012',\n debug: this.config.debug || false,\n });\n \n // Load chat mode and chat IDs from localStorage if available (SSR-safe)\n const storage = safeLocalStorage();\n const savedMode = storage.getItem('blockspark_chat_mode');\n if (savedMode) {\n this.chatMode = savedMode === 'HUMAN' ? 'human' : 'ai';\n this.state.chatMode = this.chatMode;\n }\n \n this.chatId = storage.getItem('blockspark_chat_id');\n this.supportSessionId = storage.getItem('blockspark_session_id');\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(listener: (state: WidgetState) => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Get current state\n */\n getState(): WidgetState {\n return { ...this.state };\n }\n\n /**\n * Update state and notify listeners\n */\n private setState(updates: Partial<WidgetState>): void {\n this.state = { ...this.state, ...updates };\n this.listeners.forEach(listener => listener(this.getState()));\n }\n\n /**\n * Update configuration\n */\n updateConfig(config: Partial<WidgetConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Open chat\n */\n async openChat(): Promise<void> {\n this.setState({ isOpen: true });\n if (this.state.showWelcomePopup) {\n this.setState({ showWelcomePopup: false });\n }\n \n // Initialize Dialogflow session when chat opens (if in AI mode and no session exists)\n if (this.state.chatMode === 'ai' && !this.state.sessionId && this.config.dfProjectId && this.config.dfAgentId) {\n try {\n this.setState({ isLoading: true });\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n \n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ \n sessionId: session.session_id,\n isLoading: false,\n });\n \n // Add welcome message from Dialogflow if available\n if (session.message) {\n const welcomeMessage: ChatMessage = {\n id: `welcome-${Date.now()}`,\n text: session.message,\n sender: 'bot',\n timestamp: new Date(),\n richContent: session.richContent,\n };\n this.setState({\n messages: [welcomeMessage],\n });\n }\n } catch (error: any) {\n console.error('Error initializing Dialogflow session:', error);\n this.setState({ \n isLoading: false,\n error: error.message || 'Failed to initialize chat',\n });\n \n // Show fallback welcome message\n const fallbackMessage: ChatMessage = {\n id: `fallback-${Date.now()}`,\n text: this.config.fallbackWelcomeMessage || 'Hello! How can I help you today?',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [fallbackMessage],\n });\n }\n }\n }\n\n /**\n * Close chat\n */\n closeChat(): void {\n this.setState({ isOpen: false });\n }\n\n /**\n * Close welcome popup\n */\n closeWelcomePopup(): void {\n this.setState({ showWelcomePopup: false });\n }\n\n /**\n * Toggle chat\n */\n toggleChat(): void {\n const willBeOpen = !this.state.isOpen;\n this.setState({ isOpen: willBeOpen });\n if (willBeOpen && this.state.showWelcomePopup) {\n this.setState({ showWelcomePopup: false });\n }\n }\n\n /**\n * Set input value\n */\n setInputValue(value: string): void {\n this.setState({ inputValue: value });\n }\n\n /**\n * Clear error\n */\n clearError(): void {\n this.setState({ error: null });\n }\n\n /**\n * Send message\n */\n async sendMessage(text: string, skipUserMessage: boolean = false): Promise<void> {\n if (!text.trim() || this.state.isLoading) {\n return;\n }\n\n // Handle user info collection for handoff\n if (this.collectingUserInfo) {\n // Add user message first so it appears in chat\n const userMessage: ChatMessage = {\n id: `user-${Date.now()}`,\n text: text.trim(),\n sender: 'user',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, userMessage],\n inputValue: '',\n isLoading: false,\n error: null,\n });\n \n // Then handle the info collection\n await this.handleUserInfoCollection(text);\n return;\n }\n\n // Add user message unless skipped (e.g., when chip button already added it)\n if (!skipUserMessage) {\n const userMessage: ChatMessage = {\n id: `user-${Date.now()}`,\n text: text.trim(),\n sender: 'user',\n timestamp: new Date(),\n };\n\n this.setState({\n messages: [...this.state.messages, userMessage],\n inputValue: '',\n isLoading: true,\n error: null,\n });\n } else {\n this.setState({\n inputValue: '',\n isLoading: true,\n error: null,\n });\n }\n\n try {\n if (this.state.chatMode === 'human') {\n // Human support mode\n await this.sendHumanMessage(text);\n } else {\n // AI mode (Dialogflow)\n await this.sendAIMessage(text);\n }\n } catch (error: any) {\n console.error('Error sending message:', error);\n \n // chat_resolved is a normal terminal condition, not an error\n if (error instanceof ChatResolvedError || error?.name === 'ChatResolvedError' || error?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n \n // Add error message to chat\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: this.config.debug \n ? `Error: ${error.message || 'Failed to send message'}`\n : error.message?.includes('CORS') || error.message?.includes('Failed to fetch')\n ? 'Unable to connect to Dialogflow. Please check your configuration and network.'\n : 'Sorry, I\\'m having trouble processing your message. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n \n this.setState({\n messages: [...this.state.messages, errorMessage],\n error: error.message || 'Failed to send message',\n isLoading: false,\n });\n }\n }\n\n /**\n * Send message to Dialogflow\n */\n private async sendAIMessage(text: string): Promise<void> {\n if (!this.config.dfProjectId || !this.config.dfAgentId) {\n throw new Error('Dialogflow configuration is missing');\n }\n\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId!,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId!,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n\n // Create session if needed\n if (!this.state.sessionId) {\n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ sessionId: session.session_id });\n }\n\n // Send message (correct parameter order: message, sessionId, config)\n if (this.config.debug) {\n console.log('Sending message to Dialogflow:', {\n message: text,\n sessionId: this.state.sessionId,\n hasConfig: !!dialogflowConfig,\n });\n }\n \n const response = await sendDialogflowMessage(\n text,\n this.state.sessionId!,\n dialogflowConfig\n );\n\n if (this.config.debug) {\n console.log('Dialogflow response:', {\n response: response.response,\n hasRichContent: !!response.richContent,\n richContent: response.richContent,\n });\n }\n\n // Check for handoff\n if (response.handoff === true) {\n // Add bot response first\n const botMessage: ChatMessage = {\n id: `bot-${Date.now()}`,\n text: response.response || this.config.fallbackWelcomeMessage || 'No response',\n sender: 'bot',\n timestamp: new Date(),\n richContent: response.richContent,\n };\n this.setState({\n messages: [...this.state.messages, botMessage],\n isLoading: false,\n });\n \n // Start collecting user info for handoff\n this.startUserInfoCollection();\n return;\n }\n \n const botMessage: ChatMessage = {\n id: `bot-${Date.now()}`,\n text: response.response || this.config.fallbackWelcomeMessage || 'No response',\n sender: 'bot',\n timestamp: new Date(),\n richContent: response.richContent,\n };\n\n this.setState({\n messages: [...this.state.messages, botMessage],\n isLoading: false,\n });\n }\n\n /**\n * Send message to human support\n */\n private async sendHumanMessage(text: string): Promise<void> {\n if (!this.chatId || !this.supportSessionId) {\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: 'Chat session not initialized. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n isLoading: false,\n });\n return;\n }\n\n if (!this.chatService) {\n throw new Error('Chat service not initialized');\n }\n\n // Send typing_stop before sending message\n this.chatService.sendTypingIndicator('typing_stop');\n if (this.typingTimeout) {\n clearTimeout(this.typingTimeout);\n this.typingTimeout = null;\n }\n\n try {\n // Try WebSocket first, fallback to REST API\n const sentViaWs = this.chatService.sendMessageViaWebSocket(text.trim());\n \n if (!sentViaWs) {\n // Fallback to REST API\n await this.chatService.sendMessageToAgent(this.chatId, this.supportSessionId, text.trim());\n }\n \n this.setState({ isLoading: false });\n } catch (error: any) {\n // chat_resolved is a normal terminal condition, not an error\n if (error instanceof ChatResolvedError || error?.name === 'ChatResolvedError' || error?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n\n // Handle 401/404 - clear chat_id and reinitialize\n if (error.message?.includes('Chat not found') ||\n error.message?.includes('unauthorized') ||\n error.message?.includes('401') ||\n error.message?.includes('404')) {\n if (this.config.debug) {\n console.log('⚠️ Chat expired. Re-initializing...');\n }\n \n // Clear chat_id\n this.chatId = null;\n this.supportSessionId = null;\n const storage = safeLocalStorage();\n storage.removeItem('blockspark_chat_id');\n storage.removeItem('blockspark_session_id');\n \n // Try to reinitialize chat\n try {\n const newSession = await this.chatService.startSupportChat(\n this.state.sessionId || null,\n null,\n null,\n null\n );\n this.chatId = newSession.chat_id;\n this.supportSessionId = newSession.session_id;\n const storage1 = safeLocalStorage();\n storage1.setItem('blockspark_chat_id', this.chatId);\n storage1.setItem('blockspark_session_id', this.supportSessionId);\n \n // Retry sending message\n if (this.chatId && this.supportSessionId) {\n await this.chatService.sendMessageToAgent(\n this.chatId,\n this.supportSessionId,\n text.trim()\n );\n }\n this.setState({ isLoading: false });\n return;\n } catch (retryError: any) {\n if (retryError instanceof ChatResolvedError || retryError?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n throw retryError;\n }\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Switch to human mode\n */\n switchToHumanMode(): void {\n this.chatMode = 'human';\n this.setState({ chatMode: 'human' });\n safeLocalStorage().setItem('blockspark_chat_mode', 'HUMAN');\n }\n\n /**\n * Switch to AI mode\n */\n switchToBotMode(): void {\n this.chatMode = 'ai';\n this.setState({ chatMode: 'ai' });\n safeLocalStorage().setItem('blockspark_chat_mode', 'BOT');\n }\n\n /**\n * Initialize welcome popup\n */\n initializeWelcomePopup(): void {\n if (this.config.showWelcomePopup !== false) {\n const delay = this.config.welcomePopupDelay || 1500;\n setTimeout(() => {\n if (!this.state.isOpen) {\n this.setState({ showWelcomePopup: true });\n }\n }, delay);\n }\n }\n\n /**\n * Start user info collection for handoff\n */\n private startUserInfoCollection(): void {\n this.collectingUserInfo = true;\n this.userInfoStep = 'name';\n this.collectedUserName = '';\n this.collectedUserEmail = '';\n this.collectedUserMobile = '';\n \n // Ask for name\n const namePrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'To connect you with a human agent, I\\'ll need some information. Please provide your name:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, namePrompt],\n });\n }\n\n /**\n * Handle user info collection\n */\n private async handleUserInfoCollection(text: string): Promise<void> {\n if (this.userInfoStep === 'name') {\n // Save name and ask for email\n const name = text.trim();\n this.collectedUserName = name;\n this.userInfoStep = 'email';\n \n // Ask for email\n const emailPrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Thank you! Now please provide your email address:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, emailPrompt],\n inputValue: '',\n });\n return;\n } else if (this.userInfoStep === 'email') {\n // Validate email format\n const email = text.trim();\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n \n if (!emailRegex.test(email)) {\n // Invalid email, ask again\n const invalidEmailMessage: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Please provide a valid email address:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, invalidEmailMessage],\n inputValue: '',\n });\n return;\n }\n \n // Save email and ask for mobile\n this.collectedUserEmail = email;\n this.userInfoStep = 'mobile';\n \n // Ask for mobile\n const mobilePrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Thank you! Now please provide your mobile number:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, mobilePrompt],\n inputValue: '',\n });\n return;\n } else if (this.userInfoStep === 'mobile') {\n // Validate mobile format\n const mobile = text.trim();\n const mobileRegex = /^[\\+]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[0-9]{1,9}$/;\n \n if (!mobileRegex.test(mobile) || mobile.length < 10) {\n // Invalid mobile, ask again\n const invalidMobileMessage: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Please provide a valid mobile number (e.g., +1234567890):',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, invalidMobileMessage],\n inputValue: '',\n });\n return;\n }\n \n // Save mobile and proceed with handoff\n this.collectedUserMobile = mobile;\n \n // Reset collection state\n this.collectingUserInfo = false;\n this.userInfoStep = null;\n \n // Proceed with handoff using collected info\n await this.handleHandoff(this.collectedUserName, this.collectedUserEmail, mobile);\n this.setState({ inputValue: '' });\n }\n }\n\n /**\n * Handle handoff from Dialogflow to human support\n */\n async handleHandoff(customerName?: string, customerEmail?: string, customerMobile?: string): Promise<void> {\n if (!this.chatService) {\n throw new Error('Chat service not initialized');\n }\n\n try {\n this.isConnectingToAgent = true;\n \n // Get Dialogflow session ID if available\n const dialogflowSessionId = this.state.sessionId;\n \n // STEP 1: Ensure chat is initialized\n const session = await this.chatService.ensureChatInitialized(\n this.chatId,\n this.supportSessionId,\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!session || !session.chat_id) {\n throw new Error('Failed to initialize chat session');\n }\n \n const currentChatId = session.chat_id;\n const currentSupportSessionId = session.session_id;\n \n // Update state if chat was newly initialized\n if (currentChatId !== this.chatId) {\n this.chatId = currentChatId;\n this.supportSessionId = currentSupportSessionId;\n const storage = safeLocalStorage();\n storage.setItem('blockspark_chat_id', this.chatId);\n storage.setItem('blockspark_session_id', this.supportSessionId);\n if (this.config.debug) {\n console.log('✅ Chat initialized:', { chatId: currentChatId, sessionId: currentSupportSessionId });\n }\n }\n\n // STEP 2: Request handoff\n try {\n await this.chatService.requestHandoff(\n currentChatId,\n currentSupportSessionId,\n 'Customer requested human agent',\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (this.config.debug) {\n console.log('✅ Handoff requested successfully');\n }\n } catch (handoffError: any) {\n // Handle 401/404 or \"chat not found\" - clear chat_id and retry\n if (handoffError.message?.includes('Invalid chat_id') || \n handoffError.message?.includes('Chat not found') ||\n handoffError.message?.includes('unauthorized') ||\n handoffError.message?.includes('400') ||\n handoffError.message?.includes('401') ||\n handoffError.message?.includes('404') ||\n handoffError.message?.includes('expired')) {\n if (this.config.debug) {\n console.log('⚠️ Chat expired or not found. Re-initializing chat...');\n }\n \n // Clear old chat_id\n this.chatId = null;\n this.supportSessionId = null;\n const storage2 = safeLocalStorage();\n storage2.removeItem('blockspark_chat_id');\n storage2.removeItem('blockspark_session_id');\n \n // Create new chat session\n const newSession = await this.chatService.startSupportChat(\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!newSession || !newSession.chat_id) {\n throw new Error('Failed to re-initialize chat session');\n }\n \n this.chatId = newSession.chat_id;\n this.supportSessionId = newSession.session_id;\n const storage4 = safeLocalStorage();\n storage4.setItem('blockspark_chat_id', this.chatId);\n storage4.setItem('blockspark_session_id', this.supportSessionId);\n \n // Retry handoff with new chat_id\n await this.chatService.requestHandoff(\n this.chatId,\n this.supportSessionId,\n 'Customer requested human agent',\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (this.config.debug) {\n console.log('✅ Handoff requested successfully after retry');\n }\n } else {\n throw handoffError;\n }\n }\n\n // Switch to human mode\n this.switchToHumanMode();\n this.chatResolved = false;\n this.agentAccepted = false;\n\n // Add connecting message\n const connectingMessage: ChatMessage = {\n id: `connecting-${Date.now()}`,\n text: 'Connecting you to a human agent...',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, connectingMessage],\n });\n\n // Connect WebSocket with handlers\n if (currentChatId && currentSupportSessionId) {\n this.chatService.connectWebSocket(\n currentChatId,\n currentSupportSessionId,\n (message: WebSocketMessage) => {\n this.handleWebSocketMessage(message);\n },\n (connected: boolean) => {\n this.wsConnected = connected;\n }\n );\n }\n \n this.isConnectingToAgent = false;\n } catch (error: any) {\n console.error('Error handling handoff:', error);\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: this.config.debug\n ? `Handoff error: ${error.message}`\n : 'Failed to connect to agent. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n this.isConnectingToAgent = false;\n }\n }\n\n /**\n * Handle WebSocket messages\n */\n private handleWebSocketMessage(message: WebSocketMessage): void {\n switch (message.type) {\n case 'message':\n if (message.content) {\n // Only display messages from agent\n if (message.sender_type === 'agent' || !message.sender_type) {\n const agentMessage: ChatMessage = {\n id: message.id || `agent-${Date.now()}`,\n text: message.content,\n sender: 'agent',\n timestamp: new Date(message.timestamp || Date.now()),\n };\n \n // Avoid duplicate messages\n const existingIds = new Set(this.state.messages.map(m => m.id));\n if (!existingIds.has(agentMessage.id)) {\n this.setState({\n messages: [...this.state.messages, agentMessage],\n });\n }\n \n // Hide typing indicator when message received\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n }\n }\n break;\n\n case 'typing_start':\n if (message.sender_type === 'agent') {\n this.agentTyping = true;\n // Auto-hide after 3 seconds if no message received\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n }\n this.agentTypingTimeout = setTimeout(() => {\n this.agentTyping = false;\n }, 3000);\n }\n break;\n\n case 'typing_stop':\n if (message.sender_type === 'agent') {\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n }\n break;\n\n case 'agent_changed':\n if (message.to_agent) {\n this.currentAgent = {\n id: message.to_agent_id,\n name: message.to_agent,\n };\n\n // Add system message to chat\n const systemMessage: ChatMessage = {\n id: `system-${Date.now()}`,\n text: message.from_agent\n ? `Chat has been transferred from ${message.from_agent} to ${message.to_agent}`\n : `Chat has been transferred to ${message.to_agent}`,\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, systemMessage],\n });\n }\n break;\n\n case 'agent_accepted':\n this.agentAccepted = true;\n this.isConnectingToAgent = false;\n const acceptedMessage: ChatMessage = {\n id: message.id || `agent-accepted-${Date.now()}`,\n text: 'You can chat now, the agent has accepted your request.',\n sender: 'bot',\n timestamp: message.timestamp ? new Date(message.timestamp) : new Date(),\n };\n const existingIds = new Set(this.state.messages.map(m => m.id));\n if (!existingIds.has(acceptedMessage.id)) {\n this.setState({\n messages: [...this.state.messages, acceptedMessage],\n });\n }\n if (message.to_agent) {\n this.currentAgent = {\n name: message.to_agent,\n id: message.to_agent_id,\n };\n }\n break;\n\n case 'chat_resolved':\n case 'chat_ended':\n this.enterResolvedState(message.chat_id || null);\n break;\n\n case 'chat_info':\n if (message.status === 'active') {\n this.isConnectingToAgent = false;\n this.agentAccepted = true;\n } else if (message.status === 'resolved' || message.status === 'ended') {\n this.enterResolvedState(message.chat_id || null);\n }\n if (message.agent_id) {\n this.currentAgent = {\n ...this.currentAgent,\n id: message.agent_id,\n };\n }\n break;\n\n case 'error':\n console.error('WebSocket error:', message.error);\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: message.error || 'An error occurred. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n break;\n }\n }\n\n /**\n * Enter resolved state\n */\n private enterResolvedState(resolvedChatId?: string | null): void {\n this.chatResolved = true;\n this.isConnectingToAgent = false;\n this.agentAccepted = false;\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n\n // Stop WS + prevent any reuse of the old chat_id\n if (this.chatService) {\n this.chatService.disconnectWebSocket();\n }\n this.chatId = null;\n this.supportSessionId = null;\n const storage = safeLocalStorage();\n storage.removeItem('blockspark_chat_id');\n storage.removeItem('blockspark_session_id');\n \n // Add thank you message before reset\n const thankYouMessage: ChatMessage = {\n id: `resolved-${Date.now()}`,\n text: 'Thank you for contacting us!',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, thankYouMessage],\n });\n \n // Automatically reset to BOT mode after showing thank you message\n setTimeout(async () => {\n this.switchToBotMode();\n this.chatResolved = false;\n this.setState({\n messages: [],\n sessionId: null, // Clear session ID to force recreation\n });\n this.collectingUserInfo = false;\n this.userInfoStep = null;\n this.collectedUserName = '';\n this.collectedUserEmail = '';\n this.collectedUserMobile = '';\n \n // Recreate Dialogflow session to start fresh\n if (this.config.dfProjectId && this.config.dfAgentId && this.state.isOpen) {\n try {\n this.setState({ isLoading: true });\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n \n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ \n sessionId: session.session_id,\n isLoading: false,\n });\n \n // Add welcome message from Dialogflow if available\n if (session.message) {\n const welcomeMessage: ChatMessage = {\n id: `welcome-${Date.now()}`,\n text: session.message,\n sender: 'bot',\n timestamp: new Date(),\n richContent: session.richContent,\n };\n this.setState({\n messages: [welcomeMessage],\n });\n }\n } catch (error: any) {\n console.error('Error recreating Dialogflow session after handoff:', error);\n this.setState({ \n isLoading: false,\n error: error.message || 'Failed to initialize chat',\n });\n \n // Show fallback welcome message\n const fallbackMessage: ChatMessage = {\n id: `fallback-${Date.now()}`,\n text: this.config.fallbackWelcomeMessage || 'Hello! How can I help you today?',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [fallbackMessage],\n });\n }\n }\n }, 2000);\n }\n\n /**\n * Load message history\n */\n async loadMessageHistory(preserveExisting: boolean = false): Promise<void> {\n if (!this.chatService || !this.chatId || !this.supportSessionId) {\n return;\n }\n\n try {\n if (this.chatId && this.supportSessionId) {\n const history = await this.chatService.loadMessageHistory(this.chatId, this.supportSessionId);\n \n const historyMessages: ChatMessage[] = history.map((msg: any) => ({\n id: msg.id || `history-${Date.now()}-${Math.random()}`,\n text: msg.content,\n sender: msg.sender_type === 'agent' ? 'agent' : 'user',\n timestamp: new Date(msg.timestamp),\n }));\n\n if (preserveExisting) {\n // Merge with existing messages, avoiding duplicates\n const existingIds = new Set(this.state.messages.map(m => m.id));\n const newMessages = historyMessages.filter(m => !existingIds.has(m.id));\n \n // Combine existing messages with new history messages\n // Sort by timestamp to maintain chronological order\n const combined = [...this.state.messages, ...newMessages].sort((a, b) => \n a.timestamp.getTime() - b.timestamp.getTime()\n );\n \n this.setState({\n messages: combined,\n });\n } else {\n // Replace all messages\n this.setState({\n messages: historyMessages,\n });\n }\n }\n } catch (error: any) {\n console.error('Error loading message history:', error);\n if (this.config.debug) {\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: `Failed to load chat history: ${error.message}`,\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n }\n }\n }\n\n /**\n * Get additional state for UI (not in WidgetState but needed by components)\n */\n getAdditionalState() {\n return {\n wsConnected: this.wsConnected,\n agentTyping: this.agentTyping,\n currentAgent: this.currentAgent,\n isConnectingToAgent: this.isConnectingToAgent,\n agentAccepted: this.agentAccepted,\n chatResolved: this.chatResolved,\n };\n }\n\n /**\n * Cleanup\n */\n destroy(): void {\n if (this.typingTimeout) {\n clearTimeout(this.typingTimeout);\n }\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n }\n if (this.chatService) {\n this.chatService.disconnectWebSocket();\n }\n this.listeners.clear();\n }\n}\n"],"names":["constructor","config","this","listeners","Set","chatMode","chatId","supportSessionId","chatService","collectingUserInfo","userInfoStep","collectedUserName","collectedUserEmail","collectedUserMobile","wsConnected","agentTyping","currentAgent","name","isConnectingToAgent","agentAccepted","chatResolved","historyLoaded","typingTimeout","agentTypingTimeout","state","isOpen","showWelcomePopup","messages","inputValue","isLoading","error","sessionId","createChatService","baseUrl","backendBaseUrl","wsUrl","backendWsUrl","debug","storage","safeLocalStorage","savedMode","getItem","subscribe","listener","add","delete","getState","setState","updates","forEach","updateConfig","openChat","dfProjectId","dfAgentId","dialogflowConfig","dfLocation","serviceAccountKey","accessToken","languageCode","session","createDialogflowSession","session_id","message","welcomeMessage","id","Date","now","text","sender","timestamp","richContent","fallbackMessage","fallbackWelcomeMessage","closeChat","closeWelcomePopup","toggleChat","willBeOpen","setInputValue","value","clearError","sendMessage","skipUserMessage","trim","userMessage","handleUserInfoCollection","sendHumanMessage","sendAIMessage","ChatResolvedError","enterResolvedState","errorMessage","includes","Error","response","sendDialogflowMessage","handoff","botMessage","startUserInfoCollection","sendTypingIndicator","clearTimeout","sendMessageViaWebSocket","sendMessageToAgent","removeItem","newSession","startSupportChat","chat_id","storage1","setItem","retryError","switchToHumanMode","switchToBotMode","initializeWelcomePopup","delay","welcomePopupDelay","setTimeout","namePrompt","emailPrompt","email","test","invalidEmailMessage","mobilePrompt","mobile","length","invalidMobileMessage","handleHandoff","customerName","customerEmail","customerMobile","dialogflowSessionId","ensureChatInitialized","currentChatId","currentSupportSessionId","requestHandoff","handoffError","storage2","storage4","connectingMessage","connectWebSocket","handleWebSocketMessage","connected","type","content","sender_type","agentMessage","map","m","has","to_agent","to_agent_id","systemMessage","from_agent","acceptedMessage","status","agent_id","resolvedChatId","disconnectWebSocket","thankYouMessage","async","loadMessageHistory","preserveExisting","historyMessages","msg","Math","random","existingIds","newMessages","filter","combined","sort","a","b","getTime","getAdditionalState","destroy","clear"],"mappings":"+OAkBO,MA6BL,WAAAA,CAAYC,GA1BZC,KAAQC,cAAmDC,IAC3DF,KAAQG,SAA2B,KACnCH,KAAQI,OAAwB,KAChCJ,KAAQK,iBAAkC,KAC1CL,KAAQM,YAA2D,KAGnEN,KAAQO,oBAA8B,EACtCP,KAAQQ,aAAmD,KAC3DR,KAAQS,kBAA4B,GACpCT,KAAQU,mBAA6B,GACrCV,KAAQW,oBAA8B,GAGtCX,KAAQY,aAAuB,EAC/BZ,KAAQa,aAAuB,EAC/Bb,KAAQc,aAA8C,CAAEC,KAAM,SAC9Df,KAAQgB,qBAA+B,EACvChB,KAAQiB,eAAyB,EACjCjB,KAAQkB,cAAwB,EAChClB,KAAQmB,cAA+B,KAGvCnB,KAAQoB,cAAuC,KAC/CpB,KAAQqB,mBAA4C,KAGlDrB,KAAKD,OAASA,EACdC,KAAKsB,MAAQ,CACXC,QAAQ,EACRC,kBAAkB,EAClBC,SAAU,GACVC,WAAY,GACZC,WAAW,EACXC,MAAO,KACPC,UAAW,KACX1B,SAAU,MAIZH,KAAKM,YAAcwB,oBAAkB,CACnCC,QAAS/B,KAAKD,OAAOiC,gBAAkB,wBACvCC,MAAOjC,KAAKD,OAAOmC,cAAgB,sBACnCC,MAAOnC,KAAKD,OAAOoC,QAAS,IAI9B,MAAMC,EAAUC,EAAAA,mBACVC,EAAYF,EAAQG,QAAQ,wBAC9BD,IACFtC,KAAKG,SAAyB,UAAdmC,EAAwB,QAAU,KAClDtC,KAAKsB,MAAMnB,SAAWH,KAAKG,UAG7BH,KAAKI,OAASgC,EAAQG,QAAQ,sBAC9BvC,KAAKK,iBAAmB+B,EAAQG,QAAQ,wBAC1C,CAKA,SAAAC,CAAUC,GAER,OADAzC,KAAKC,UAAUyC,IAAID,GACZ,KACLzC,KAAKC,UAAU0C,OAAOF,GAE1B,CAKA,QAAAG,GACE,MAAO,IAAK5C,KAAKsB,MACnB,CAKQ,QAAAuB,CAASC,GACf9C,KAAKsB,MAAQ,IAAKtB,KAAKsB,SAAUwB,GACjC9C,KAAKC,UAAU8C,QAAQN,GAAYA,EAASzC,KAAK4C,YACnD,CAKA,YAAAI,CAAajD,GACXC,KAAKD,OAAS,IAAKC,KAAKD,UAAWA,EACrC,CAKA,cAAMkD,GAOJ,GANAjD,KAAK6C,SAAS,CAAEtB,QAAQ,IACpBvB,KAAKsB,MAAME,kBACbxB,KAAK6C,SAAS,CAAErB,kBAAkB,IAIR,OAAxBxB,KAAKsB,MAAMnB,WAAsBH,KAAKsB,MAAMO,WAAa7B,KAAKD,OAAOmD,aAAelD,KAAKD,OAAOoD,UAClG,IACEnD,KAAK6C,SAAS,CAAElB,WAAW,IAC3B,MAAMyB,EAAqC,CACzCF,YAAalD,KAAKD,OAAOmD,YACzBG,WAAYrD,KAAKD,OAAOsD,YAAc,cACtCF,UAAWnD,KAAKD,OAAOoD,UACvBG,kBAAmBtD,KAAKD,OAAOuD,kBAC/BC,YAAavD,KAAKD,OAAOwD,YACzBC,aAAcxD,KAAKD,OAAOyD,cAAgB,MAGtCC,QAAgBC,EAAAA,wBAAwBN,GAO9C,GANApD,KAAK6C,SAAS,CACZhB,UAAW4B,EAAQE,WACnBhC,WAAW,IAIT8B,EAAQG,QAAS,CACnB,MAAMC,EAA8B,CAClCC,GAAI,WAAWC,KAAKC,QACpBC,KAAMR,EAAQG,QACdM,OAAQ,MACRC,cAAeJ,KACfK,YAAaX,EAAQW,aAEvBpE,KAAK6C,SAAS,CACZpB,SAAU,CAACoC,IAEf,CACF,OAASjC,GAEP5B,KAAK6C,SAAS,CACZlB,WAAW,EACXC,MAAOA,EAAMgC,SAAW,8BAI1B,MAAMS,EAA+B,CACnCP,GAAI,YAAYC,KAAKC,QACrBC,KAAMjE,KAAKD,OAAOuE,wBAA0B,mCAC5CJ,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,CAAC4C,IAEf,CAEJ,CAKA,SAAAE,GACEvE,KAAK6C,SAAS,CAAEtB,QAAQ,GAC1B,CAKA,iBAAAiD,GACExE,KAAK6C,SAAS,CAAErB,kBAAkB,GACpC,CAKA,UAAAiD,GACE,MAAMC,GAAc1E,KAAKsB,MAAMC,OAC/BvB,KAAK6C,SAAS,CAAEtB,OAAQmD,IACpBA,GAAc1E,KAAKsB,MAAME,kBAC3BxB,KAAK6C,SAAS,CAAErB,kBAAkB,GAEtC,CAKA,aAAAmD,CAAcC,GACZ5E,KAAK6C,SAAS,CAAEnB,WAAYkD,GAC9B,CAKA,UAAAC,GACE7E,KAAK6C,SAAS,CAAEjB,MAAO,MACzB,CAKA,iBAAMkD,CAAYb,EAAcc,GAA2B,GACzD,GAAKd,EAAKe,SAAUhF,KAAKsB,MAAMK,UAA/B,CAKA,GAAI3B,KAAKO,mBAAoB,CAE3B,MAAM0E,EAA2B,CAC/BnB,GAAI,QAAQC,KAAKC,QACjBC,KAAMA,EAAKe,OACXd,OAAQ,OACRC,cAAeJ,MAWjB,OATA/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUwD,GACnCvD,WAAY,GACZC,WAAW,EACXC,MAAO,kBAIH5B,KAAKkF,yBAAyBjB,GAEtC,CAGA,GAAKc,EAeH/E,KAAK6C,SAAS,CACZnB,WAAY,GACZC,WAAW,EACXC,MAAO,WAlBW,CACpB,MAAMqD,EAA2B,CAC/BnB,GAAI,QAAQC,KAAKC,QACjBC,KAAMA,EAAKe,OACXd,OAAQ,OACRC,cAAeJ,MAGjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUwD,GACnCvD,WAAY,GACZC,WAAW,EACXC,MAAO,MAEX,CAQA,IAC8B,UAAxB5B,KAAKsB,MAAMnB,eAEPH,KAAKmF,iBAAiBlB,SAGtBjE,KAAKoF,cAAcnB,EAE7B,OAASrC,GAIP,GAAIA,aAAiByD,EAAAA,mBAAqC,sBAAhBzD,GAAOb,MAAmD,kBAAnBa,GAAOgC,QAEtF,YADA5D,KAAKsF,mBAAmBtF,KAAKI,QAK/B,MAAMmF,EAA4B,CAChCzB,GAAI,SAASC,KAAKC,QAClBC,KAAMjE,KAAKD,OAAOoC,MACd,UAAUP,EAAMgC,SAAW,2BAC3BhC,EAAMgC,SAAS4B,SAAS,SAAW5D,EAAMgC,SAAS4B,SAAS,mBAC3D,gFACA,uEACJtB,OAAQ,MACRC,cAAeJ,MAGjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU8D,GACnC3D,MAAOA,EAAMgC,SAAW,yBACxBjC,WAAW,GAEf,CAhFA,CAiFF,CAKA,mBAAcyD,CAAcnB,GAC1B,IAAKjE,KAAKD,OAAOmD,cAAgBlD,KAAKD,OAAOoD,UAC3C,MAAM,IAAIsC,MAAM,uCAGlB,MAAMrC,EAAqC,CACzCF,YAAalD,KAAKD,OAAOmD,YACzBG,WAAYrD,KAAKD,OAAOsD,YAAc,cACtCF,UAAWnD,KAAKD,OAAOoD,UACvBG,kBAAmBtD,KAAKD,OAAOuD,kBAC/BC,YAAavD,KAAKD,OAAOwD,YACzBC,aAAcxD,KAAKD,OAAOyD,cAAgB,MAI5C,IAAKxD,KAAKsB,MAAMO,UAAW,CACzB,MAAM4B,QAAgBC,EAAAA,wBAAwBN,GAC9CpD,KAAK6C,SAAS,CAAEhB,UAAW4B,EAAQE,YACrC,CAGI3D,KAAKD,OAAOoC,MAQhB,MAAMuD,QAAiBC,EAAAA,sBACrB1B,EACAjE,KAAKsB,MAAMO,UACXuB,GAYF,GATIpD,KAAKD,OAAOoC,OASS,IAArBuD,EAASE,QAAkB,CAE7B,MAAMC,EAA0B,CAC9B/B,GAAI,OAAOC,KAAKC,QAChBC,KAAMyB,EAASA,UAAY1F,KAAKD,OAAOuE,wBAA0B,cACjEJ,OAAQ,MACRC,cAAeJ,KACfK,YAAasB,EAAStB,aASxB,OAPApE,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUoE,GACnClE,WAAW,SAIb3B,KAAK8F,yBAEP,CAEA,MAAMD,EAA0B,CAC9B/B,GAAI,OAAOC,KAAKC,QAChBC,KAAMyB,EAASA,UAAY1F,KAAKD,OAAOuE,wBAA0B,cACjEJ,OAAQ,MACRC,cAAeJ,KACfK,YAAasB,EAAStB,aAGxBpE,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUoE,GACnClE,WAAW,GAEf,CAKA,sBAAcwD,CAAiBlB,GAC7B,IAAKjE,KAAKI,SAAWJ,KAAKK,iBAAkB,CAC1C,MAAMkF,EAA4B,CAChCzB,GAAI,SAASC,KAAKC,QAClBC,KAAM,kDACNC,OAAQ,MACRC,cAAeJ,MAMjB,YAJA/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU8D,GACnC5D,WAAW,GAGf,CAEA,IAAK3B,KAAKM,YACR,MAAM,IAAImF,MAAM,gCAIlBzF,KAAKM,YAAYyF,oBAAoB,eACjC/F,KAAKoB,gBACP4E,aAAahG,KAAKoB,eAClBpB,KAAKoB,cAAgB,MAGvB,IAEoBpB,KAAKM,YAAY2F,wBAAwBhC,EAAKe,eAIxDhF,KAAKM,YAAY4F,mBAAmBlG,KAAKI,OAAQJ,KAAKK,iBAAkB4D,EAAKe,QAGrFhF,KAAK6C,SAAS,CAAElB,WAAW,GAC7B,OAASC,GAEP,GAAIA,aAAiByD,EAAAA,mBAAqC,sBAAhBzD,GAAOb,MAAmD,kBAAnBa,GAAOgC,QAEtF,YADA5D,KAAKsF,mBAAmBtF,KAAKI,QAK/B,KAAIwB,EAAMgC,SAAS4B,SAAS,mBACxB5D,EAAMgC,SAAS4B,SAAS,iBACxB5D,EAAMgC,SAAS4B,SAAS,QACxB5D,EAAMgC,SAAS4B,SAAS,QA4C1B,MAAM5D,EA5C4B,CAC9B5B,KAAKD,OAAOoC,MAKhBnC,KAAKI,OAAS,KACdJ,KAAKK,iBAAmB,KACxB,MAAM+B,EAAUC,EAAAA,mBAChBD,EAAQ+D,WAAW,sBACnB/D,EAAQ+D,WAAW,yBAGnB,IACE,MAAMC,QAAmBpG,KAAKM,YAAY+F,iBACxCrG,KAAKsB,MAAMO,WAAa,KACxB,KACA,KACA,MAEF7B,KAAKI,OAASgG,EAAWE,QACzBtG,KAAKK,iBAAmB+F,EAAWzC,WACnC,MAAM4C,EAAWlE,EAAAA,mBAajB,OAZAkE,EAASC,QAAQ,qBAAsBxG,KAAKI,QAC5CmG,EAASC,QAAQ,wBAAyBxG,KAAKK,kBAG3CL,KAAKI,QAAUJ,KAAKK,wBAChBL,KAAKM,YAAY4F,mBACrBlG,KAAKI,OACLJ,KAAKK,iBACL4D,EAAKe,aAGThF,KAAK6C,SAAS,CAAElB,WAAW,GAE7B,OAAS8E,GACP,GAAIA,aAAsBpB,EAAAA,mBAA6C,kBAAxBoB,GAAY7C,QAEzD,YADA5D,KAAKsF,mBAAmBtF,KAAKI,QAG/B,MAAMqG,CACR,CACF,CAGF,CACF,CAKA,iBAAAC,GACE1G,KAAKG,SAAW,QAChBH,KAAK6C,SAAS,CAAE1C,SAAU,UAC1BkC,EAAAA,mBAAmBmE,QAAQ,uBAAwB,QACrD,CAKA,eAAAG,GACE3G,KAAKG,SAAW,KAChBH,KAAK6C,SAAS,CAAE1C,SAAU,OAC1BkC,EAAAA,mBAAmBmE,QAAQ,uBAAwB,MACrD,CAKA,sBAAAI,GACE,IAAqC,IAAjC5G,KAAKD,OAAOyB,iBAA4B,CAC1C,MAAMqF,EAAQ7G,KAAKD,OAAO+G,mBAAqB,KAC/CC,WAAW,KACJ/G,KAAKsB,MAAMC,QACdvB,KAAK6C,SAAS,CAAErB,kBAAkB,KAEnCqF,EACL,CACF,CAKQ,uBAAAf,GACN9F,KAAKO,oBAAqB,EAC1BP,KAAKQ,aAAe,OACpBR,KAAKS,kBAAoB,GACzBT,KAAKU,mBAAqB,GAC1BV,KAAKW,oBAAsB,GAG3B,MAAMqG,EAA0B,CAC9BlD,GAAI,UAAUC,KAAKC,QACnBC,KAAM,2FACNC,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUuF,IAEvC,CAKA,8BAAc9B,CAAyBjB,GACrC,GAA0B,SAAtBjE,KAAKQ,aAAyB,CAEhC,MAAMO,EAAOkD,EAAKe,OAClBhF,KAAKS,kBAAoBM,EACzBf,KAAKQ,aAAe,QAGpB,MAAMyG,EAA2B,CAC/BnD,GAAI,UAAUC,KAAKC,QACnBC,KAAM,oDACNC,OAAQ,MACRC,cAAeJ,MAMjB,YAJA/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUwF,GACnCvF,WAAY,IAGhB,CAAA,GAAiC,UAAtB1B,KAAKQ,aAA0B,CAExC,MAAM0G,EAAQjD,EAAKe,OAGnB,IAFmB,6BAEHmC,KAAKD,GAAQ,CAE3B,MAAME,EAAmC,CACvCtD,GAAI,UAAUC,KAAKC,QACnBC,KAAM,wCACNC,OAAQ,MACRC,cAAeJ,MAMjB,YAJA/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU2F,GACnC1F,WAAY,IAGhB,CAGA1B,KAAKU,mBAAqBwG,EAC1BlH,KAAKQ,aAAe,SAGpB,MAAM6G,EAA4B,CAChCvD,GAAI,UAAUC,KAAKC,QACnBC,KAAM,oDACNC,OAAQ,MACRC,cAAeJ,MAMjB,YAJA/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU4F,GACnC3F,WAAY,IAGhB,CAAA,GAAiC,WAAtB1B,KAAKQ,aAA2B,CAEzC,MAAM8G,EAASrD,EAAKe,OAGpB,IAFoB,wEAEHmC,KAAKG,IAAWA,EAAOC,OAAS,GAAI,CAEnD,MAAMC,EAAoC,CACxC1D,GAAI,UAAUC,KAAKC,QACnBC,KAAM,4DACNC,OAAQ,MACRC,cAAeJ,MAMjB,YAJA/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU+F,GACnC9F,WAAY,IAGhB,CAGA1B,KAAKW,oBAAsB2G,EAG3BtH,KAAKO,oBAAqB,EAC1BP,KAAKQ,aAAe,WAGdR,KAAKyH,cAAczH,KAAKS,kBAAmBT,KAAKU,mBAAoB4G,GAC1EtH,KAAK6C,SAAS,CAAEnB,WAAY,IAC9B,CACF,CAKA,mBAAM+F,CAAcC,EAAuBC,EAAwBC,GACjE,IAAK5H,KAAKM,YACR,MAAM,IAAImF,MAAM,gCAGlB,IACEzF,KAAKgB,qBAAsB,EAG3B,MAAM6G,EAAsB7H,KAAKsB,MAAMO,UAGjC4B,QAAgBzD,KAAKM,YAAYwH,sBACrC9H,KAAKI,OACLJ,KAAKK,iBACLwH,GAAuB,KACvBH,GAAgB,KAChBC,GAAiB,KACjBC,GAAkB,MAGpB,IAAKnE,IAAYA,EAAQ6C,QACvB,MAAM,IAAIb,MAAM,qCAGlB,MAAMsC,EAAgBtE,EAAQ6C,QACxB0B,EAA0BvE,EAAQE,WAGxC,GAAIoE,IAAkB/H,KAAKI,OAAQ,CACjCJ,KAAKI,OAAS2H,EACd/H,KAAKK,iBAAmB2H,EACxB,MAAM5F,EAAUC,EAAAA,mBAChBD,EAAQoE,QAAQ,qBAAsBxG,KAAKI,QAC3CgC,EAAQoE,QAAQ,wBAAyBxG,KAAKK,kBAC1CL,KAAKD,OAAOoC,KAGlB,CAGA,UACQnC,KAAKM,YAAY2H,eACrBF,EACAC,EACA,iCACAH,GAAuB,KACvBH,GAAgB,KAChBC,GAAiB,KACjBC,GAAkB,MAGhB5H,KAAKD,OAAOoC,KAGlB,OAAS+F,GAEP,KAAIA,EAAatE,SAAS4B,SAAS,oBAC/B0C,EAAatE,SAAS4B,SAAS,mBAC/B0C,EAAatE,SAAS4B,SAAS,iBAC/B0C,EAAatE,SAAS4B,SAAS,QAC/B0C,EAAatE,SAAS4B,SAAS,QAC/B0C,EAAatE,SAAS4B,SAAS,QAC/B0C,EAAatE,SAAS4B,SAAS,YA6CjC,MAAM0C,EA7CuC,CACzClI,KAAKD,OAAOoC,MAKhBnC,KAAKI,OAAS,KACdJ,KAAKK,iBAAmB,KACxB,MAAM8H,EAAW9F,EAAAA,mBACjB8F,EAAShC,WAAW,sBACpBgC,EAAShC,WAAW,yBAGpB,MAAMC,QAAmBpG,KAAKM,YAAY+F,iBACxCwB,GAAuB,KACvBH,GAAgB,KAChBC,GAAiB,KACjBC,GAAkB,MAGpB,IAAKxB,IAAeA,EAAWE,QAC7B,MAAM,IAAIb,MAAM,wCAGlBzF,KAAKI,OAASgG,EAAWE,QACzBtG,KAAKK,iBAAmB+F,EAAWzC,WACnC,MAAMyE,EAAW/F,EAAAA,mBACjB+F,EAAS5B,QAAQ,qBAAsBxG,KAAKI,QAC5CgI,EAAS5B,QAAQ,wBAAyBxG,KAAKK,wBAGzCL,KAAKM,YAAY2H,eACrBjI,KAAKI,OACLJ,KAAKK,iBACL,iCACAwH,GAAuB,KACvBH,GAAgB,KAChBC,GAAiB,KACjBC,GAAkB,MAGhB5H,KAAKD,OAAOoC,KAGlB,CAGF,CAGAnC,KAAK0G,oBACL1G,KAAKkB,cAAe,EACpBlB,KAAKiB,eAAgB,EAGrB,MAAMoH,EAAiC,CACrCvE,GAAI,cAAcC,KAAKC,QACvBC,KAAM,qCACNC,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU4G,KAIjCN,GAAiBC,GACnBhI,KAAKM,YAAYgI,iBACfP,EACAC,EACCpE,IACC5D,KAAKuI,uBAAuB3E,IAE7B4E,IACCxI,KAAKY,YAAc4H,IAKzBxI,KAAKgB,qBAAsB,CAC7B,OAASY,GAEP,MAAM2D,EAA4B,CAChCzB,GAAI,SAASC,KAAKC,QAClBC,KAAMjE,KAAKD,OAAOoC,MACd,kBAAkBP,EAAMgC,UACxB,gDACJM,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU8D,KAErCvF,KAAKgB,qBAAsB,CAC7B,CACF,CAKQ,sBAAAuH,CAAuB3E,GAC7B,OAAQA,EAAQ6E,MACd,IAAK,UACH,GAAI7E,EAAQ8E,UAEkB,UAAxB9E,EAAQ+E,cAA4B/E,EAAQ+E,aAAa,CAC3D,MAAMC,EAA4B,CAChC9E,GAAIF,EAAQE,IAAM,SAASC,KAAKC,QAChCC,KAAML,EAAQ8E,QACdxE,OAAQ,QACRC,UAAW,IAAIJ,KAAKH,EAAQO,WAAaJ,KAAKC,QAI5B,IAAI9D,IAAIF,KAAKsB,MAAMG,SAASoH,IAAIC,GAAKA,EAAEhF,KAC1CiF,IAAIH,EAAa9E,KAChC9D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUmH,KAKvC5I,KAAKa,aAAc,EACfb,KAAKqB,qBACP2E,aAAahG,KAAKqB,oBAClBrB,KAAKqB,mBAAqB,KAE9B,CAEF,MAEF,IAAK,eACyB,UAAxBuC,EAAQ+E,cACV3I,KAAKa,aAAc,EAEfb,KAAKqB,oBACP2E,aAAahG,KAAKqB,oBAEpBrB,KAAKqB,mBAAqB0F,WAAW,KACnC/G,KAAKa,aAAc,GAClB,MAEL,MAEF,IAAK,cACyB,UAAxB+C,EAAQ+E,cACV3I,KAAKa,aAAc,EACfb,KAAKqB,qBACP2E,aAAahG,KAAKqB,oBAClBrB,KAAKqB,mBAAqB,OAG9B,MAEF,IAAK,gBACH,GAAIuC,EAAQoF,SAAU,CACpBhJ,KAAKc,aAAe,CAClBgD,GAAIF,EAAQqF,YACZlI,KAAM6C,EAAQoF,UAIhB,MAAME,EAA6B,CACjCpF,GAAI,UAAUC,KAAKC,QACnBC,KAAML,EAAQuF,WACV,kCAAkCvF,EAAQuF,iBAAiBvF,EAAQoF,WACnE,gCAAgCpF,EAAQoF,WAC5C9E,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUyH,IAEvC,CACA,MAEF,IAAK,iBACHlJ,KAAKiB,eAAgB,EACrBjB,KAAKgB,qBAAsB,EAC3B,MAAMoI,EAA+B,CACnCtF,GAAIF,EAAQE,IAAM,kBAAkBC,KAAKC,QACzCC,KAAM,yDACNC,OAAQ,MACRC,UAAWP,EAAQO,UAAY,IAAIJ,KAAKH,EAAQO,WAAa,IAAIJ,MAE/C,IAAI7D,IAAIF,KAAKsB,MAAMG,SAASoH,IAAIC,GAAKA,EAAEhF,KAC1CiF,IAAIK,EAAgBtF,KACnC9D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU2H,KAGnCxF,EAAQoF,WACVhJ,KAAKc,aAAe,CAClBC,KAAM6C,EAAQoF,SACdlF,GAAIF,EAAQqF,cAGhB,MAEF,IAAK,gBACL,IAAK,aACHjJ,KAAKsF,mBAAmB1B,EAAQ0C,SAAW,MAC3C,MAEF,IAAK,YACoB,WAAnB1C,EAAQyF,QACVrJ,KAAKgB,qBAAsB,EAC3BhB,KAAKiB,eAAgB,GACO,aAAnB2C,EAAQyF,QAA4C,UAAnBzF,EAAQyF,QAClDrJ,KAAKsF,mBAAmB1B,EAAQ0C,SAAW,MAEzC1C,EAAQ0F,WACVtJ,KAAKc,aAAe,IACfd,KAAKc,aACRgD,GAAIF,EAAQ0F,WAGhB,MAEF,IAAK,QAEH,MAAM/D,EAA4B,CAChCzB,GAAI,SAASC,KAAKC,QAClBC,KAAML,EAAQhC,OAAS,uCACvBsC,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU8D,KAI3C,CAKQ,kBAAAD,CAAmBiE,GACzBvJ,KAAKkB,cAAe,EACpBlB,KAAKgB,qBAAsB,EAC3BhB,KAAKiB,eAAgB,EACrBjB,KAAKa,aAAc,EACfb,KAAKqB,qBACP2E,aAAahG,KAAKqB,oBAClBrB,KAAKqB,mBAAqB,MAIxBrB,KAAKM,aACPN,KAAKM,YAAYkJ,sBAEnBxJ,KAAKI,OAAS,KACdJ,KAAKK,iBAAmB,KACxB,MAAM+B,EAAUC,EAAAA,mBAChBD,EAAQ+D,WAAW,sBACnB/D,EAAQ+D,WAAW,yBAGnB,MAAMsD,EAA+B,CACnC3F,GAAI,YAAYC,KAAKC,QACrBC,KAAM,+BACNC,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUgI,KAIrC1C,WAAW2C,UAcT,GAbA1J,KAAK2G,kBACL3G,KAAKkB,cAAe,EACpBlB,KAAK6C,SAAS,CACZpB,SAAU,GACVI,UAAW,OAEb7B,KAAKO,oBAAqB,EAC1BP,KAAKQ,aAAe,KACpBR,KAAKS,kBAAoB,GACzBT,KAAKU,mBAAqB,GAC1BV,KAAKW,oBAAsB,GAGvBX,KAAKD,OAAOmD,aAAelD,KAAKD,OAAOoD,WAAanD,KAAKsB,MAAMC,OACjE,IACEvB,KAAK6C,SAAS,CAAElB,WAAW,IAC3B,MAAMyB,EAAqC,CACzCF,YAAalD,KAAKD,OAAOmD,YACzBG,WAAYrD,KAAKD,OAAOsD,YAAc,cACtCF,UAAWnD,KAAKD,OAAOoD,UACvBG,kBAAmBtD,KAAKD,OAAOuD,kBAC/BC,YAAavD,KAAKD,OAAOwD,YACzBC,aAAcxD,KAAKD,OAAOyD,cAAgB,MAGtCC,QAAgBC,EAAAA,wBAAwBN,GAO9C,GANApD,KAAK6C,SAAS,CACZhB,UAAW4B,EAAQE,WACnBhC,WAAW,IAIT8B,EAAQG,QAAS,CACnB,MAAMC,EAA8B,CAClCC,GAAI,WAAWC,KAAKC,QACpBC,KAAMR,EAAQG,QACdM,OAAQ,MACRC,cAAeJ,KACfK,YAAaX,EAAQW,aAEvBpE,KAAK6C,SAAS,CACZpB,SAAU,CAACoC,IAEf,CACF,OAASjC,GAEP5B,KAAK6C,SAAS,CACZlB,WAAW,EACXC,MAAOA,EAAMgC,SAAW,8BAI1B,MAAMS,EAA+B,CACnCP,GAAI,YAAYC,KAAKC,QACrBC,KAAMjE,KAAKD,OAAOuE,wBAA0B,mCAC5CJ,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,CAAC4C,IAEf,GAED,IACL,CAKA,wBAAMsF,CAAmBC,GAA4B,GACnD,GAAK5J,KAAKM,aAAgBN,KAAKI,QAAWJ,KAAKK,iBAI/C,IACE,GAAIL,KAAKI,QAAUJ,KAAKK,iBAAkB,CACxC,MAEMwJ,SAFgB7J,KAAKM,YAAYqJ,mBAAmB3J,KAAKI,OAAQJ,KAAKK,mBAE7BwI,IAAKiB,IAAA,CAClDhG,GAAIgG,EAAIhG,IAAM,WAAWC,KAAKC,SAAS+F,KAAKC,WAC5C/F,KAAM6F,EAAIpB,QACVxE,OAA4B,UAApB4F,EAAInB,YAA0B,QAAU,OAChDxE,UAAW,IAAIJ,KAAK+F,EAAI3F,cAG1B,GAAIyF,EAAkB,CAEpB,MAAMK,EAAc,IAAI/J,IAAIF,KAAKsB,MAAMG,SAASoH,IAAIC,GAAKA,EAAEhF,KACrDoG,EAAcL,EAAgBM,OAAOrB,IAAMmB,EAAYlB,IAAID,EAAEhF,KAI7DsG,EAAW,IAAIpK,KAAKsB,MAAMG,YAAayI,GAAaG,KAAK,CAACC,EAAGC,IACjED,EAAEnG,UAAUqG,UAAYD,EAAEpG,UAAUqG,WAGtCxK,KAAK6C,SAAS,CACZpB,SAAU2I,GAEd,MAEEpK,KAAK6C,SAAS,CACZpB,SAAUoI,GAGhB,CACF,OAASjI,GAEP,GAAI5B,KAAKD,OAAOoC,MAAO,CACrB,MAAMoD,EAA4B,CAChCzB,GAAI,SAASC,KAAKC,QAClBC,KAAM,gCAAgCrC,EAAMgC,UAC5CM,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU8D,IAEvC,CACF,CACF,CAKA,kBAAAkF,GACE,MAAO,CACL7J,YAAaZ,KAAKY,YAClBC,YAAab,KAAKa,YAClBC,aAAcd,KAAKc,aACnBE,oBAAqBhB,KAAKgB,oBAC1BC,cAAejB,KAAKiB,cACpBC,aAAclB,KAAKkB,aAEvB,CAKA,OAAAwJ,GACM1K,KAAKoB,eACP4E,aAAahG,KAAKoB,eAEhBpB,KAAKqB,oBACP2E,aAAahG,KAAKqB,oBAEhBrB,KAAKM,aACPN,KAAKM,YAAYkJ,sBAEnBxJ,KAAKC,UAAU0K,OACjB"}
|
|
1
|
+
{"version":3,"file":"stateManager.cjs.js","sources":["../../src/core/stateManager.ts"],"sourcesContent":["/**\n * State Manager - Framework Agnostic\n * Manages widget state independently of framework\n */\n\nimport type { WidgetState, WidgetConfig, ChatMessage } from './types';\nimport {\n createDialogflowSession,\n sendDialogflowMessage,\n type DialogflowConfig,\n} from '../services/dialogflowClient';\nimport { \n createChatService, \n ChatResolvedError,\n type WebSocketMessage\n} from '../services/chatService';\nimport { safeLocalStorage } from '../utils/ssr';\n\nexport class WidgetStateManager {\n private state: WidgetState;\n private config: WidgetConfig;\n private listeners: Set<(state: WidgetState) => void> = new Set();\n private chatMode: 'ai' | 'human' = 'ai';\n private chatId: string | null = null;\n private supportSessionId: string | null = null;\n private chatService: ReturnType<typeof createChatService> | null = null;\n \n // User info collection for handoff\n private collectingUserInfo: boolean = false;\n private userInfoStep: 'name' | 'email' | 'mobile' | null = null;\n private collectedUserName: string = '';\n private collectedUserEmail: string = '';\n private collectedUserMobile: string = '';\n \n // Additional state for human support\n private wsConnected: boolean = false;\n private agentTyping: boolean = false;\n private currentAgent: { name: string; id?: string } = { name: 'Agent' };\n private isConnectingToAgent: boolean = false;\n private agentAccepted: boolean = false;\n private chatResolved: boolean = false;\n private historyLoaded: string | null = null;\n \n // Typing timeout refs (stored as class properties since we can't use refs)\n private typingTimeout: NodeJS.Timeout | null = null;\n private agentTypingTimeout: NodeJS.Timeout | null = null;\n\n constructor(config: WidgetConfig) {\n this.config = config;\n this.state = {\n isOpen: false,\n showWelcomePopup: false,\n messages: [],\n inputValue: '',\n isLoading: false,\n error: null,\n sessionId: null,\n chatMode: 'ai',\n };\n \n // Initialize ChatService\n this.chatService = createChatService({\n baseUrl: this.config.backendBaseUrl || 'http://localhost:8012',\n wsUrl: this.config.backendWsUrl || 'ws://localhost:8012',\n debug: this.config.debug || false,\n });\n \n // Load chat mode and chat IDs from localStorage if available (SSR-safe)\n const storage = safeLocalStorage();\n const savedMode = storage.getItem('blockspark_chat_mode');\n if (savedMode) {\n this.chatMode = savedMode === 'HUMAN' ? 'human' : 'ai';\n this.state.chatMode = this.chatMode;\n }\n \n this.chatId = storage.getItem('blockspark_chat_id');\n this.supportSessionId = storage.getItem('blockspark_session_id');\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(listener: (state: WidgetState) => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Get current state\n */\n getState(): WidgetState {\n return { ...this.state };\n }\n\n /**\n * Update state and notify listeners\n */\n private setState(updates: Partial<WidgetState>): void {\n this.state = { ...this.state, ...updates };\n this.listeners.forEach(listener => listener(this.getState()));\n }\n\n /**\n * Update configuration\n */\n updateConfig(config: Partial<WidgetConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Open chat\n */\n async openChat(): Promise<void> {\n this.setState({ isOpen: true });\n if (this.state.showWelcomePopup) {\n this.setState({ showWelcomePopup: false });\n }\n \n // Initialize Dialogflow session when chat opens (if in AI mode and no session exists)\n if (this.state.chatMode === 'ai' && !this.state.sessionId && this.config.dfProjectId && this.config.dfAgentId) {\n try {\n this.setState({ isLoading: true });\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n \n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ \n sessionId: session.session_id,\n isLoading: false,\n });\n \n // Add welcome message from Dialogflow if available\n if (session.message) {\n const welcomeMessage: ChatMessage = {\n id: `welcome-${Date.now()}`,\n text: session.message,\n sender: 'bot',\n timestamp: new Date(),\n richContent: session.richContent,\n };\n this.setState({\n messages: [welcomeMessage],\n });\n }\n } catch (error: any) {\n console.error('Error initializing Dialogflow session:', error);\n this.setState({ \n isLoading: false,\n error: error.message || 'Failed to initialize chat',\n });\n \n // Show fallback welcome message\n const fallbackMessage: ChatMessage = {\n id: `fallback-${Date.now()}`,\n text: this.config.fallbackWelcomeMessage || 'Hello! How can I help you today?',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [fallbackMessage],\n });\n }\n }\n }\n\n /**\n * Close chat\n */\n closeChat(): void {\n this.setState({ isOpen: false });\n }\n\n /**\n * Close welcome popup\n */\n closeWelcomePopup(): void {\n this.setState({ showWelcomePopup: false });\n }\n\n /**\n * Toggle chat\n */\n toggleChat(): void {\n const willBeOpen = !this.state.isOpen;\n this.setState({ isOpen: willBeOpen });\n if (willBeOpen && this.state.showWelcomePopup) {\n this.setState({ showWelcomePopup: false });\n }\n }\n\n /**\n * Set input value\n */\n setInputValue(value: string): void {\n this.setState({ inputValue: value });\n }\n\n /**\n * Clear error\n */\n clearError(): void {\n this.setState({ error: null });\n }\n\n /**\n * Send message\n */\n async sendMessage(text: string, skipUserMessage: boolean = false): Promise<void> {\n if (!text.trim() || this.state.isLoading) {\n return;\n }\n\n // Handle user info collection for handoff\n if (this.collectingUserInfo) {\n // Add user message first so it appears in chat\n const userMessage: ChatMessage = {\n id: `user-${Date.now()}`,\n text: text.trim(),\n sender: 'user',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, userMessage],\n inputValue: '',\n isLoading: false,\n error: null,\n });\n \n // Then handle the info collection\n await this.handleUserInfoCollection(text);\n return;\n }\n\n // Add user message unless skipped (e.g., when chip button already added it)\n if (!skipUserMessage) {\n const userMessage: ChatMessage = {\n id: `user-${Date.now()}`,\n text: text.trim(),\n sender: 'user',\n timestamp: new Date(),\n };\n\n this.setState({\n messages: [...this.state.messages, userMessage],\n inputValue: '',\n isLoading: true,\n error: null,\n });\n } else {\n this.setState({\n inputValue: '',\n isLoading: true,\n error: null,\n });\n }\n\n try {\n if (this.state.chatMode === 'human') {\n // Human support mode\n await this.sendHumanMessage(text);\n } else {\n // AI mode (Dialogflow)\n await this.sendAIMessage(text);\n }\n } catch (error: any) {\n console.error('Error sending message:', error);\n \n // chat_resolved is a normal terminal condition, not an error\n if (error instanceof ChatResolvedError || error?.name === 'ChatResolvedError' || error?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n \n // Add error message to chat\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: this.config.debug \n ? `Error: ${error.message || 'Failed to send message'}`\n : error.message?.includes('CORS') || error.message?.includes('Failed to fetch')\n ? 'Unable to connect to Dialogflow. Please check your configuration and network.'\n : 'Sorry, I\\'m having trouble processing your message. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n \n this.setState({\n messages: [...this.state.messages, errorMessage],\n error: error.message || 'Failed to send message',\n isLoading: false,\n });\n }\n }\n\n /**\n * Send message to Dialogflow\n */\n private async sendAIMessage(text: string): Promise<void> {\n if (!this.config.dfProjectId || !this.config.dfAgentId) {\n throw new Error('Dialogflow configuration is missing');\n }\n\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId!,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId!,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n\n // Create session if needed\n if (!this.state.sessionId) {\n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ sessionId: session.session_id });\n }\n\n // Send message (correct parameter order: message, sessionId, config)\n if (this.config.debug) {\n console.log('Sending message to Dialogflow:', {\n message: text,\n sessionId: this.state.sessionId,\n hasConfig: !!dialogflowConfig,\n });\n }\n \n const response = await sendDialogflowMessage(\n text,\n this.state.sessionId!,\n dialogflowConfig\n );\n\n if (this.config.debug) {\n console.log('Dialogflow response:', {\n response: response.response,\n hasRichContent: !!response.richContent,\n richContent: response.richContent,\n });\n }\n\n // Check for handoff\n if (response.handoff === true) {\n // Add bot response first\n const botMessage: ChatMessage = {\n id: `bot-${Date.now()}`,\n text: response.response || this.config.fallbackWelcomeMessage || 'No response',\n sender: 'bot',\n timestamp: new Date(),\n richContent: response.richContent,\n };\n this.setState({\n messages: [...this.state.messages, botMessage],\n isLoading: false,\n });\n \n // Start collecting user info for handoff\n this.startUserInfoCollection();\n return;\n }\n \n const botMessage: ChatMessage = {\n id: `bot-${Date.now()}`,\n text: response.response || this.config.fallbackWelcomeMessage || 'No response',\n sender: 'bot',\n timestamp: new Date(),\n richContent: response.richContent,\n };\n\n this.setState({\n messages: [...this.state.messages, botMessage],\n isLoading: false,\n });\n }\n\n /**\n * Send message to human support\n */\n private async sendHumanMessage(text: string): Promise<void> {\n if (!this.chatId || !this.supportSessionId) {\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: 'Chat session not initialized. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n isLoading: false,\n });\n return;\n }\n\n if (!this.chatService) {\n throw new Error('Chat service not initialized');\n }\n\n // Send typing_stop before sending message\n this.chatService.sendTypingIndicator('typing_stop');\n if (this.typingTimeout) {\n clearTimeout(this.typingTimeout);\n this.typingTimeout = null;\n }\n\n try {\n // Try WebSocket first, fallback to REST API\n const sentViaWs = this.chatService.sendMessageViaWebSocket(text.trim());\n \n if (!sentViaWs) {\n // Fallback to REST API\n await this.chatService.sendMessageToAgent(this.chatId, this.supportSessionId, text.trim());\n }\n \n this.setState({ isLoading: false });\n } catch (error: any) {\n // chat_resolved is a normal terminal condition, not an error\n if (error instanceof ChatResolvedError || error?.name === 'ChatResolvedError' || error?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n\n // Handle 401/404 - clear chat_id and reinitialize\n if (error.message?.includes('Chat not found') ||\n error.message?.includes('unauthorized') ||\n error.message?.includes('401') ||\n error.message?.includes('404')) {\n if (this.config.debug) {\n console.log('⚠️ Chat expired. Re-initializing...');\n }\n \n // Clear chat_id\n this.chatId = null;\n this.supportSessionId = null;\n const storage = safeLocalStorage();\n storage.removeItem('blockspark_chat_id');\n storage.removeItem('blockspark_session_id');\n \n // Try to reinitialize chat\n try {\n const newSession = await this.chatService.startSupportChat(\n this.state.sessionId || null,\n null,\n null,\n null\n );\n this.chatId = newSession.chat_id;\n this.supportSessionId = newSession.session_id;\n const storage1 = safeLocalStorage();\n storage1.setItem('blockspark_chat_id', this.chatId);\n storage1.setItem('blockspark_session_id', this.supportSessionId);\n \n // Retry sending message\n if (this.chatId && this.supportSessionId) {\n await this.chatService.sendMessageToAgent(\n this.chatId,\n this.supportSessionId,\n text.trim()\n );\n }\n this.setState({ isLoading: false });\n return;\n } catch (retryError: any) {\n if (retryError instanceof ChatResolvedError || retryError?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n throw retryError;\n }\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Switch to human mode\n */\n switchToHumanMode(): void {\n this.chatMode = 'human';\n this.setState({ chatMode: 'human' });\n safeLocalStorage().setItem('blockspark_chat_mode', 'HUMAN');\n }\n\n /**\n * Switch to AI mode\n */\n switchToBotMode(): void {\n this.chatMode = 'ai';\n this.setState({ chatMode: 'ai' });\n safeLocalStorage().setItem('blockspark_chat_mode', 'BOT');\n }\n\n /**\n * Initialize welcome popup\n */\n initializeWelcomePopup(): void {\n if (this.config.showWelcomePopup !== false) {\n const delay = this.config.welcomePopupDelay || 1500;\n setTimeout(() => {\n if (!this.state.isOpen) {\n this.setState({ showWelcomePopup: true });\n }\n }, delay);\n }\n }\n\n /**\n * Start user info collection for handoff\n */\n private startUserInfoCollection(): void {\n this.collectingUserInfo = true;\n this.userInfoStep = 'name';\n this.collectedUserName = '';\n this.collectedUserEmail = '';\n this.collectedUserMobile = '';\n \n // Add initial handoff message with better formatting\n const handoffMessage: ChatMessage = {\n id: `handoff-${Date.now()}`,\n text: '👤 You\\'re being connected to a live support agent. Please wait while we transfer your conversation...',\n sender: 'bot',\n timestamp: new Date(),\n };\n \n // Ask for name\n const namePrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'To connect you with a human agent, I\\'ll need some information.\\n\\nPlease provide your name:',\n sender: 'bot',\n timestamp: new Date(),\n };\n \n this.setState({\n messages: [...this.state.messages, handoffMessage, namePrompt],\n });\n }\n\n /**\n * Handle user info collection\n */\n private async handleUserInfoCollection(text: string): Promise<void> {\n if (this.userInfoStep === 'name') {\n // Save name and ask for email\n const name = text.trim();\n this.collectedUserName = name;\n this.userInfoStep = 'email';\n \n // Ask for email\n const emailPrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: '✅ Thank you! Now please provide your email address:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, emailPrompt],\n inputValue: '',\n });\n return;\n } else if (this.userInfoStep === 'email') {\n // Validate email format\n const email = text.trim();\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n \n if (!emailRegex.test(email)) {\n // Invalid email, ask again\n const invalidEmailMessage: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Please provide a valid email address:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, invalidEmailMessage],\n inputValue: '',\n });\n return;\n }\n \n // Save email and ask for mobile\n this.collectedUserEmail = email;\n this.userInfoStep = 'mobile';\n \n // Ask for mobile\n const mobilePrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: '✅ Thank you! Now please provide your mobile number:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, mobilePrompt],\n inputValue: '',\n });\n return;\n } else if (this.userInfoStep === 'mobile') {\n // Validate mobile format\n const mobile = text.trim();\n const mobileRegex = /^[\\+]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[0-9]{1,9}$/;\n \n if (!mobileRegex.test(mobile) || mobile.length < 10) {\n // Invalid mobile, ask again\n const invalidMobileMessage: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Please provide a valid mobile number (e.g., +1234567890):',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, invalidMobileMessage],\n inputValue: '',\n });\n return;\n }\n \n // Save mobile and proceed with handoff\n this.collectedUserMobile = mobile;\n \n // Reset collection state\n this.collectingUserInfo = false;\n this.userInfoStep = null;\n \n // Proceed with handoff using collected info\n await this.handleHandoff(this.collectedUserName, this.collectedUserEmail, mobile);\n this.setState({ inputValue: '' });\n }\n }\n\n /**\n * Handle handoff from Dialogflow to human support\n */\n async handleHandoff(customerName?: string, customerEmail?: string, customerMobile?: string): Promise<void> {\n if (!this.chatService) {\n throw new Error('Chat service not initialized');\n }\n\n try {\n this.isConnectingToAgent = true;\n \n // Get Dialogflow session ID if available\n const dialogflowSessionId = this.state.sessionId;\n \n // STEP 1: Ensure chat is initialized\n const session = await this.chatService.ensureChatInitialized(\n this.chatId,\n this.supportSessionId,\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!session || !session.chat_id) {\n throw new Error('Failed to initialize chat session');\n }\n \n const currentChatId = session.chat_id;\n const currentSupportSessionId = session.session_id;\n \n // Update state if chat was newly initialized\n if (currentChatId !== this.chatId) {\n this.chatId = currentChatId;\n this.supportSessionId = currentSupportSessionId;\n const storage = safeLocalStorage();\n storage.setItem('blockspark_chat_id', this.chatId);\n storage.setItem('blockspark_session_id', this.supportSessionId);\n if (this.config.debug) {\n console.log('✅ Chat initialized:', { chatId: currentChatId, sessionId: currentSupportSessionId });\n }\n }\n\n // STEP 2: Request handoff\n try {\n await this.chatService.requestHandoff(\n currentChatId,\n currentSupportSessionId,\n 'Customer requested human agent',\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (this.config.debug) {\n console.log('✅ Handoff requested successfully');\n }\n } catch (handoffError: any) {\n // Handle 401/404 or \"chat not found\" - clear chat_id and retry\n if (handoffError.message?.includes('Invalid chat_id') || \n handoffError.message?.includes('Chat not found') ||\n handoffError.message?.includes('unauthorized') ||\n handoffError.message?.includes('400') ||\n handoffError.message?.includes('401') ||\n handoffError.message?.includes('404') ||\n handoffError.message?.includes('expired')) {\n if (this.config.debug) {\n console.log('⚠️ Chat expired or not found. Re-initializing chat...');\n }\n \n // Clear old chat_id\n this.chatId = null;\n this.supportSessionId = null;\n const storage2 = safeLocalStorage();\n storage2.removeItem('blockspark_chat_id');\n storage2.removeItem('blockspark_session_id');\n \n // Create new chat session\n const newSession = await this.chatService.startSupportChat(\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!newSession || !newSession.chat_id) {\n throw new Error('Failed to re-initialize chat session');\n }\n \n this.chatId = newSession.chat_id;\n this.supportSessionId = newSession.session_id;\n const storage4 = safeLocalStorage();\n storage4.setItem('blockspark_chat_id', this.chatId);\n storage4.setItem('blockspark_session_id', this.supportSessionId);\n \n // Retry handoff with new chat_id\n await this.chatService.requestHandoff(\n this.chatId,\n this.supportSessionId,\n 'Customer requested human agent',\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (this.config.debug) {\n console.log('✅ Handoff requested successfully after retry');\n }\n } else {\n throw handoffError;\n }\n }\n\n // Switch to human mode\n this.switchToHumanMode();\n this.chatResolved = false;\n this.agentAccepted = false;\n\n // Add connecting message\n const connectingMessage: ChatMessage = {\n id: `connecting-${Date.now()}`,\n text: '🔄 Connecting you to a human agent...',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, connectingMessage],\n });\n\n // Connect WebSocket with handlers\n if (currentChatId && currentSupportSessionId) {\n this.chatService.connectWebSocket(\n currentChatId,\n currentSupportSessionId,\n (message: WebSocketMessage) => {\n this.handleWebSocketMessage(message);\n },\n (connected: boolean) => {\n this.wsConnected = connected;\n }\n );\n }\n \n this.isConnectingToAgent = false;\n } catch (error: any) {\n console.error('Error handling handoff:', error);\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: this.config.debug\n ? `Handoff error: ${error.message}`\n : 'Failed to connect to agent. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n this.isConnectingToAgent = false;\n }\n }\n\n /**\n * Handle WebSocket messages\n */\n private handleWebSocketMessage(message: WebSocketMessage): void {\n switch (message.type) {\n case 'message':\n if (message.content) {\n // Only display messages from agent\n if (message.sender_type === 'agent' || !message.sender_type) {\n const agentMessage: ChatMessage = {\n id: message.id || `agent-${Date.now()}`,\n text: message.content,\n sender: 'agent',\n timestamp: new Date(message.timestamp || Date.now()),\n };\n \n // Avoid duplicate messages\n const existingIds = new Set(this.state.messages.map(m => m.id));\n if (!existingIds.has(agentMessage.id)) {\n this.setState({\n messages: [...this.state.messages, agentMessage],\n });\n }\n \n // Hide typing indicator when message received\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n }\n }\n break;\n\n case 'typing_start':\n if (message.sender_type === 'agent') {\n this.agentTyping = true;\n // Auto-hide after 3 seconds if no message received\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n }\n this.agentTypingTimeout = setTimeout(() => {\n this.agentTyping = false;\n }, 3000);\n }\n break;\n\n case 'typing_stop':\n if (message.sender_type === 'agent') {\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n }\n break;\n\n case 'agent_changed':\n if (message.to_agent) {\n this.currentAgent = {\n id: message.to_agent_id,\n name: message.to_agent,\n };\n\n // Add system message to chat\n const systemMessage: ChatMessage = {\n id: `system-${Date.now()}`,\n text: message.from_agent\n ? `Chat has been transferred from ${message.from_agent} to ${message.to_agent}`\n : `Chat has been transferred to ${message.to_agent}`,\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, systemMessage],\n });\n }\n break;\n\n case 'agent_accepted':\n this.agentAccepted = true;\n this.isConnectingToAgent = false;\n const acceptedMessage: ChatMessage = {\n id: message.id || `agent-accepted-${Date.now()}`,\n text: 'You can chat now, the agent has accepted your request.',\n sender: 'bot',\n timestamp: message.timestamp ? new Date(message.timestamp) : new Date(),\n };\n const existingIds = new Set(this.state.messages.map(m => m.id));\n if (!existingIds.has(acceptedMessage.id)) {\n this.setState({\n messages: [...this.state.messages, acceptedMessage],\n });\n }\n if (message.to_agent) {\n this.currentAgent = {\n name: message.to_agent,\n id: message.to_agent_id,\n };\n }\n break;\n\n case 'chat_resolved':\n case 'chat_ended':\n this.enterResolvedState(message.chat_id || null);\n break;\n\n case 'chat_info':\n if (message.status === 'active') {\n this.isConnectingToAgent = false;\n this.agentAccepted = true;\n } else if (message.status === 'resolved' || message.status === 'ended') {\n this.enterResolvedState(message.chat_id || null);\n }\n if (message.agent_id) {\n this.currentAgent = {\n ...this.currentAgent,\n id: message.agent_id,\n };\n }\n break;\n\n case 'error':\n console.error('WebSocket error:', message.error);\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: message.error || 'An error occurred. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n break;\n }\n }\n\n /**\n * Enter resolved state\n */\n private enterResolvedState(resolvedChatId?: string | null): void {\n this.chatResolved = true;\n this.isConnectingToAgent = false;\n this.agentAccepted = false;\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n\n // Stop WS + prevent any reuse of the old chat_id\n if (this.chatService) {\n this.chatService.disconnectWebSocket();\n }\n this.chatId = null;\n this.supportSessionId = null;\n const storage = safeLocalStorage();\n storage.removeItem('blockspark_chat_id');\n storage.removeItem('blockspark_session_id');\n \n // Add thank you message before reset\n const thankYouMessage: ChatMessage = {\n id: `resolved-${Date.now()}`,\n text: 'Thank you for contacting us!',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, thankYouMessage],\n });\n \n // Automatically reset to BOT mode after showing thank you message\n setTimeout(async () => {\n this.switchToBotMode();\n this.chatResolved = false;\n this.setState({\n messages: [],\n sessionId: null, // Clear session ID to force recreation\n });\n this.collectingUserInfo = false;\n this.userInfoStep = null;\n this.collectedUserName = '';\n this.collectedUserEmail = '';\n this.collectedUserMobile = '';\n \n // Recreate Dialogflow session to start fresh\n if (this.config.dfProjectId && this.config.dfAgentId && this.state.isOpen) {\n try {\n this.setState({ isLoading: true });\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n \n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ \n sessionId: session.session_id,\n isLoading: false,\n });\n \n // Add welcome message from Dialogflow if available\n if (session.message) {\n const welcomeMessage: ChatMessage = {\n id: `welcome-${Date.now()}`,\n text: session.message,\n sender: 'bot',\n timestamp: new Date(),\n richContent: session.richContent,\n };\n this.setState({\n messages: [welcomeMessage],\n });\n }\n } catch (error: any) {\n console.error('Error recreating Dialogflow session after handoff:', error);\n this.setState({ \n isLoading: false,\n error: error.message || 'Failed to initialize chat',\n });\n \n // Show fallback welcome message\n const fallbackMessage: ChatMessage = {\n id: `fallback-${Date.now()}`,\n text: this.config.fallbackWelcomeMessage || 'Hello! How can I help you today?',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [fallbackMessage],\n });\n }\n }\n }, 2000);\n }\n\n /**\n * Load message history\n */\n async loadMessageHistory(preserveExisting: boolean = false): Promise<void> {\n if (!this.chatService || !this.chatId || !this.supportSessionId) {\n return;\n }\n\n try {\n if (this.chatId && this.supportSessionId) {\n const history = await this.chatService.loadMessageHistory(this.chatId, this.supportSessionId);\n \n const historyMessages: ChatMessage[] = history.map((msg: any) => ({\n id: msg.id || `history-${Date.now()}-${Math.random()}`,\n text: msg.content,\n sender: msg.sender_type === 'agent' ? 'agent' : 'user',\n timestamp: new Date(msg.timestamp),\n }));\n\n if (preserveExisting) {\n // Merge with existing messages, avoiding duplicates\n const existingIds = new Set(this.state.messages.map(m => m.id));\n const newMessages = historyMessages.filter(m => !existingIds.has(m.id));\n \n // Combine existing messages with new history messages\n // Sort by timestamp to maintain chronological order\n const combined = [...this.state.messages, ...newMessages].sort((a, b) => \n a.timestamp.getTime() - b.timestamp.getTime()\n );\n \n this.setState({\n messages: combined,\n });\n } else {\n // Replace all messages\n this.setState({\n messages: historyMessages,\n });\n }\n }\n } catch (error: any) {\n console.error('Error loading message history:', error);\n if (this.config.debug) {\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: `Failed to load chat history: ${error.message}`,\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n }\n }\n }\n\n /**\n * Get additional state for UI (not in WidgetState but needed by components)\n */\n getAdditionalState() {\n return {\n wsConnected: this.wsConnected,\n agentTyping: this.agentTyping,\n currentAgent: this.currentAgent,\n isConnectingToAgent: this.isConnectingToAgent,\n agentAccepted: this.agentAccepted,\n chatResolved: this.chatResolved,\n };\n }\n\n /**\n * Cleanup\n */\n destroy(): void {\n if (this.typingTimeout) {\n clearTimeout(this.typingTimeout);\n }\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n }\n if (this.chatService) {\n this.chatService.disconnectWebSocket();\n }\n this.listeners.clear();\n }\n}\n"],"names":["constructor","config","this","listeners","Set","chatMode","chatId","supportSessionId","chatService","collectingUserInfo","userInfoStep","collectedUserName","collectedUserEmail","collectedUserMobile","wsConnected","agentTyping","currentAgent","name","isConnectingToAgent","agentAccepted","chatResolved","historyLoaded","typingTimeout","agentTypingTimeout","state","isOpen","showWelcomePopup","messages","inputValue","isLoading","error","sessionId","createChatService","baseUrl","backendBaseUrl","wsUrl","backendWsUrl","debug","storage","safeLocalStorage","savedMode","getItem","subscribe","listener","add","delete","getState","setState","updates","forEach","updateConfig","openChat","dfProjectId","dfAgentId","dialogflowConfig","dfLocation","serviceAccountKey","accessToken","languageCode","session","createDialogflowSession","session_id","message","welcomeMessage","id","Date","now","text","sender","timestamp","richContent","fallbackMessage","fallbackWelcomeMessage","closeChat","closeWelcomePopup","toggleChat","willBeOpen","setInputValue","value","clearError","sendMessage","skipUserMessage","trim","userMessage","handleUserInfoCollection","sendHumanMessage","sendAIMessage","ChatResolvedError","enterResolvedState","errorMessage","includes","Error","response","sendDialogflowMessage","handoff","botMessage","startUserInfoCollection","sendTypingIndicator","clearTimeout","sendMessageViaWebSocket","sendMessageToAgent","removeItem","newSession","startSupportChat","chat_id","storage1","setItem","retryError","switchToHumanMode","switchToBotMode","initializeWelcomePopup","delay","welcomePopupDelay","setTimeout","handoffMessage","namePrompt","emailPrompt","email","test","invalidEmailMessage","mobilePrompt","mobile","length","invalidMobileMessage","handleHandoff","customerName","customerEmail","customerMobile","dialogflowSessionId","ensureChatInitialized","currentChatId","currentSupportSessionId","requestHandoff","handoffError","storage2","storage4","connectingMessage","connectWebSocket","handleWebSocketMessage","connected","type","content","sender_type","agentMessage","map","m","has","to_agent","to_agent_id","systemMessage","from_agent","acceptedMessage","status","agent_id","resolvedChatId","disconnectWebSocket","thankYouMessage","async","loadMessageHistory","preserveExisting","historyMessages","msg","Math","random","existingIds","newMessages","filter","combined","sort","a","b","getTime","getAdditionalState","destroy","clear"],"mappings":"+OAkBO,MA6BL,WAAAA,CAAYC,GA1BZC,KAAQC,cAAmDC,IAC3DF,KAAQG,SAA2B,KACnCH,KAAQI,OAAwB,KAChCJ,KAAQK,iBAAkC,KAC1CL,KAAQM,YAA2D,KAGnEN,KAAQO,oBAA8B,EACtCP,KAAQQ,aAAmD,KAC3DR,KAAQS,kBAA4B,GACpCT,KAAQU,mBAA6B,GACrCV,KAAQW,oBAA8B,GAGtCX,KAAQY,aAAuB,EAC/BZ,KAAQa,aAAuB,EAC/Bb,KAAQc,aAA8C,CAAEC,KAAM,SAC9Df,KAAQgB,qBAA+B,EACvChB,KAAQiB,eAAyB,EACjCjB,KAAQkB,cAAwB,EAChClB,KAAQmB,cAA+B,KAGvCnB,KAAQoB,cAAuC,KAC/CpB,KAAQqB,mBAA4C,KAGlDrB,KAAKD,OAASA,EACdC,KAAKsB,MAAQ,CACXC,QAAQ,EACRC,kBAAkB,EAClBC,SAAU,GACVC,WAAY,GACZC,WAAW,EACXC,MAAO,KACPC,UAAW,KACX1B,SAAU,MAIZH,KAAKM,YAAcwB,oBAAkB,CACnCC,QAAS/B,KAAKD,OAAOiC,gBAAkB,wBACvCC,MAAOjC,KAAKD,OAAOmC,cAAgB,sBACnCC,MAAOnC,KAAKD,OAAOoC,QAAS,IAI9B,MAAMC,EAAUC,EAAAA,mBACVC,EAAYF,EAAQG,QAAQ,wBAC9BD,IACFtC,KAAKG,SAAyB,UAAdmC,EAAwB,QAAU,KAClDtC,KAAKsB,MAAMnB,SAAWH,KAAKG,UAG7BH,KAAKI,OAASgC,EAAQG,QAAQ,sBAC9BvC,KAAKK,iBAAmB+B,EAAQG,QAAQ,wBAC1C,CAKA,SAAAC,CAAUC,GAER,OADAzC,KAAKC,UAAUyC,IAAID,GACZ,KACLzC,KAAKC,UAAU0C,OAAOF,GAE1B,CAKA,QAAAG,GACE,MAAO,IAAK5C,KAAKsB,MACnB,CAKQ,QAAAuB,CAASC,GACf9C,KAAKsB,MAAQ,IAAKtB,KAAKsB,SAAUwB,GACjC9C,KAAKC,UAAU8C,QAAQN,GAAYA,EAASzC,KAAK4C,YACnD,CAKA,YAAAI,CAAajD,GACXC,KAAKD,OAAS,IAAKC,KAAKD,UAAWA,EACrC,CAKA,cAAMkD,GAOJ,GANAjD,KAAK6C,SAAS,CAAEtB,QAAQ,IACpBvB,KAAKsB,MAAME,kBACbxB,KAAK6C,SAAS,CAAErB,kBAAkB,IAIR,OAAxBxB,KAAKsB,MAAMnB,WAAsBH,KAAKsB,MAAMO,WAAa7B,KAAKD,OAAOmD,aAAelD,KAAKD,OAAOoD,UAClG,IACEnD,KAAK6C,SAAS,CAAElB,WAAW,IAC3B,MAAMyB,EAAqC,CACzCF,YAAalD,KAAKD,OAAOmD,YACzBG,WAAYrD,KAAKD,OAAOsD,YAAc,cACtCF,UAAWnD,KAAKD,OAAOoD,UACvBG,kBAAmBtD,KAAKD,OAAOuD,kBAC/BC,YAAavD,KAAKD,OAAOwD,YACzBC,aAAcxD,KAAKD,OAAOyD,cAAgB,MAGtCC,QAAgBC,EAAAA,wBAAwBN,GAO9C,GANApD,KAAK6C,SAAS,CACZhB,UAAW4B,EAAQE,WACnBhC,WAAW,IAIT8B,EAAQG,QAAS,CACnB,MAAMC,EAA8B,CAClCC,GAAI,WAAWC,KAAKC,QACpBC,KAAMR,EAAQG,QACdM,OAAQ,MACRC,cAAeJ,KACfK,YAAaX,EAAQW,aAEvBpE,KAAK6C,SAAS,CACZpB,SAAU,CAACoC,IAEf,CACF,OAASjC,GAEP5B,KAAK6C,SAAS,CACZlB,WAAW,EACXC,MAAOA,EAAMgC,SAAW,8BAI1B,MAAMS,EAA+B,CACnCP,GAAI,YAAYC,KAAKC,QACrBC,KAAMjE,KAAKD,OAAOuE,wBAA0B,mCAC5CJ,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,CAAC4C,IAEf,CAEJ,CAKA,SAAAE,GACEvE,KAAK6C,SAAS,CAAEtB,QAAQ,GAC1B,CAKA,iBAAAiD,GACExE,KAAK6C,SAAS,CAAErB,kBAAkB,GACpC,CAKA,UAAAiD,GACE,MAAMC,GAAc1E,KAAKsB,MAAMC,OAC/BvB,KAAK6C,SAAS,CAAEtB,OAAQmD,IACpBA,GAAc1E,KAAKsB,MAAME,kBAC3BxB,KAAK6C,SAAS,CAAErB,kBAAkB,GAEtC,CAKA,aAAAmD,CAAcC,GACZ5E,KAAK6C,SAAS,CAAEnB,WAAYkD,GAC9B,CAKA,UAAAC,GACE7E,KAAK6C,SAAS,CAAEjB,MAAO,MACzB,CAKA,iBAAMkD,CAAYb,EAAcc,GAA2B,GACzD,GAAKd,EAAKe,SAAUhF,KAAKsB,MAAMK,UAA/B,CAKA,GAAI3B,KAAKO,mBAAoB,CAE3B,MAAM0E,EAA2B,CAC/BnB,GAAI,QAAQC,KAAKC,QACjBC,KAAMA,EAAKe,OACXd,OAAQ,OACRC,cAAeJ,MAWjB,OATA/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUwD,GACnCvD,WAAY,GACZC,WAAW,EACXC,MAAO,kBAIH5B,KAAKkF,yBAAyBjB,GAEtC,CAGA,GAAKc,EAeH/E,KAAK6C,SAAS,CACZnB,WAAY,GACZC,WAAW,EACXC,MAAO,WAlBW,CACpB,MAAMqD,EAA2B,CAC/BnB,GAAI,QAAQC,KAAKC,QACjBC,KAAMA,EAAKe,OACXd,OAAQ,OACRC,cAAeJ,MAGjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUwD,GACnCvD,WAAY,GACZC,WAAW,EACXC,MAAO,MAEX,CAQA,IAC8B,UAAxB5B,KAAKsB,MAAMnB,eAEPH,KAAKmF,iBAAiBlB,SAGtBjE,KAAKoF,cAAcnB,EAE7B,OAASrC,GAIP,GAAIA,aAAiByD,EAAAA,mBAAqC,sBAAhBzD,GAAOb,MAAmD,kBAAnBa,GAAOgC,QAEtF,YADA5D,KAAKsF,mBAAmBtF,KAAKI,QAK/B,MAAMmF,EAA4B,CAChCzB,GAAI,SAASC,KAAKC,QAClBC,KAAMjE,KAAKD,OAAOoC,MACd,UAAUP,EAAMgC,SAAW,2BAC3BhC,EAAMgC,SAAS4B,SAAS,SAAW5D,EAAMgC,SAAS4B,SAAS,mBAC3D,gFACA,uEACJtB,OAAQ,MACRC,cAAeJ,MAGjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU8D,GACnC3D,MAAOA,EAAMgC,SAAW,yBACxBjC,WAAW,GAEf,CAhFA,CAiFF,CAKA,mBAAcyD,CAAcnB,GAC1B,IAAKjE,KAAKD,OAAOmD,cAAgBlD,KAAKD,OAAOoD,UAC3C,MAAM,IAAIsC,MAAM,uCAGlB,MAAMrC,EAAqC,CACzCF,YAAalD,KAAKD,OAAOmD,YACzBG,WAAYrD,KAAKD,OAAOsD,YAAc,cACtCF,UAAWnD,KAAKD,OAAOoD,UACvBG,kBAAmBtD,KAAKD,OAAOuD,kBAC/BC,YAAavD,KAAKD,OAAOwD,YACzBC,aAAcxD,KAAKD,OAAOyD,cAAgB,MAI5C,IAAKxD,KAAKsB,MAAMO,UAAW,CACzB,MAAM4B,QAAgBC,EAAAA,wBAAwBN,GAC9CpD,KAAK6C,SAAS,CAAEhB,UAAW4B,EAAQE,YACrC,CAGI3D,KAAKD,OAAOoC,MAQhB,MAAMuD,QAAiBC,EAAAA,sBACrB1B,EACAjE,KAAKsB,MAAMO,UACXuB,GAYF,GATIpD,KAAKD,OAAOoC,OASS,IAArBuD,EAASE,QAAkB,CAE7B,MAAMC,EAA0B,CAC9B/B,GAAI,OAAOC,KAAKC,QAChBC,KAAMyB,EAASA,UAAY1F,KAAKD,OAAOuE,wBAA0B,cACjEJ,OAAQ,MACRC,cAAeJ,KACfK,YAAasB,EAAStB,aASxB,OAPApE,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUoE,GACnClE,WAAW,SAIb3B,KAAK8F,yBAEP,CAEA,MAAMD,EAA0B,CAC9B/B,GAAI,OAAOC,KAAKC,QAChBC,KAAMyB,EAASA,UAAY1F,KAAKD,OAAOuE,wBAA0B,cACjEJ,OAAQ,MACRC,cAAeJ,KACfK,YAAasB,EAAStB,aAGxBpE,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUoE,GACnClE,WAAW,GAEf,CAKA,sBAAcwD,CAAiBlB,GAC7B,IAAKjE,KAAKI,SAAWJ,KAAKK,iBAAkB,CAC1C,MAAMkF,EAA4B,CAChCzB,GAAI,SAASC,KAAKC,QAClBC,KAAM,kDACNC,OAAQ,MACRC,cAAeJ,MAMjB,YAJA/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU8D,GACnC5D,WAAW,GAGf,CAEA,IAAK3B,KAAKM,YACR,MAAM,IAAImF,MAAM,gCAIlBzF,KAAKM,YAAYyF,oBAAoB,eACjC/F,KAAKoB,gBACP4E,aAAahG,KAAKoB,eAClBpB,KAAKoB,cAAgB,MAGvB,IAEoBpB,KAAKM,YAAY2F,wBAAwBhC,EAAKe,eAIxDhF,KAAKM,YAAY4F,mBAAmBlG,KAAKI,OAAQJ,KAAKK,iBAAkB4D,EAAKe,QAGrFhF,KAAK6C,SAAS,CAAElB,WAAW,GAC7B,OAASC,GAEP,GAAIA,aAAiByD,EAAAA,mBAAqC,sBAAhBzD,GAAOb,MAAmD,kBAAnBa,GAAOgC,QAEtF,YADA5D,KAAKsF,mBAAmBtF,KAAKI,QAK/B,KAAIwB,EAAMgC,SAAS4B,SAAS,mBACxB5D,EAAMgC,SAAS4B,SAAS,iBACxB5D,EAAMgC,SAAS4B,SAAS,QACxB5D,EAAMgC,SAAS4B,SAAS,QA4C1B,MAAM5D,EA5C4B,CAC9B5B,KAAKD,OAAOoC,MAKhBnC,KAAKI,OAAS,KACdJ,KAAKK,iBAAmB,KACxB,MAAM+B,EAAUC,EAAAA,mBAChBD,EAAQ+D,WAAW,sBACnB/D,EAAQ+D,WAAW,yBAGnB,IACE,MAAMC,QAAmBpG,KAAKM,YAAY+F,iBACxCrG,KAAKsB,MAAMO,WAAa,KACxB,KACA,KACA,MAEF7B,KAAKI,OAASgG,EAAWE,QACzBtG,KAAKK,iBAAmB+F,EAAWzC,WACnC,MAAM4C,EAAWlE,EAAAA,mBAajB,OAZAkE,EAASC,QAAQ,qBAAsBxG,KAAKI,QAC5CmG,EAASC,QAAQ,wBAAyBxG,KAAKK,kBAG3CL,KAAKI,QAAUJ,KAAKK,wBAChBL,KAAKM,YAAY4F,mBACrBlG,KAAKI,OACLJ,KAAKK,iBACL4D,EAAKe,aAGThF,KAAK6C,SAAS,CAAElB,WAAW,GAE7B,OAAS8E,GACP,GAAIA,aAAsBpB,EAAAA,mBAA6C,kBAAxBoB,GAAY7C,QAEzD,YADA5D,KAAKsF,mBAAmBtF,KAAKI,QAG/B,MAAMqG,CACR,CACF,CAGF,CACF,CAKA,iBAAAC,GACE1G,KAAKG,SAAW,QAChBH,KAAK6C,SAAS,CAAE1C,SAAU,UAC1BkC,EAAAA,mBAAmBmE,QAAQ,uBAAwB,QACrD,CAKA,eAAAG,GACE3G,KAAKG,SAAW,KAChBH,KAAK6C,SAAS,CAAE1C,SAAU,OAC1BkC,EAAAA,mBAAmBmE,QAAQ,uBAAwB,MACrD,CAKA,sBAAAI,GACE,IAAqC,IAAjC5G,KAAKD,OAAOyB,iBAA4B,CAC1C,MAAMqF,EAAQ7G,KAAKD,OAAO+G,mBAAqB,KAC/CC,WAAW,KACJ/G,KAAKsB,MAAMC,QACdvB,KAAK6C,SAAS,CAAErB,kBAAkB,KAEnCqF,EACL,CACF,CAKQ,uBAAAf,GACN9F,KAAKO,oBAAqB,EAC1BP,KAAKQ,aAAe,OACpBR,KAAKS,kBAAoB,GACzBT,KAAKU,mBAAqB,GAC1BV,KAAKW,oBAAsB,GAG3B,MAAMqG,EAA8B,CAClClD,GAAI,WAAWC,KAAKC,QACpBC,KAAM,wGACNC,OAAQ,MACRC,cAAeJ,MAIXkD,EAA0B,CAC9BnD,GAAI,UAAUC,KAAKC,QACnBC,KAAM,8FACNC,OAAQ,MACRC,cAAeJ,MAGjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUuF,EAAgBC,IAEvD,CAKA,8BAAc/B,CAAyBjB,GACrC,GAA0B,SAAtBjE,KAAKQ,aAAyB,CAEhC,MAAMO,EAAOkD,EAAKe,OAClBhF,KAAKS,kBAAoBM,EACzBf,KAAKQ,aAAe,QAGpB,MAAM0G,EAA2B,CAC/BpD,GAAI,UAAUC,KAAKC,QACnBC,KAAM,sDACNC,OAAQ,MACRC,cAAeJ,MAMjB,YAJA/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUyF,GACnCxF,WAAY,IAGhB,CAAA,GAAiC,UAAtB1B,KAAKQ,aAA0B,CAExC,MAAM2G,EAAQlD,EAAKe,OAGnB,IAFmB,6BAEHoC,KAAKD,GAAQ,CAE3B,MAAME,EAAmC,CACvCvD,GAAI,UAAUC,KAAKC,QACnBC,KAAM,wCACNC,OAAQ,MACRC,cAAeJ,MAMjB,YAJA/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU4F,GACnC3F,WAAY,IAGhB,CAGA1B,KAAKU,mBAAqByG,EAC1BnH,KAAKQ,aAAe,SAGpB,MAAM8G,EAA4B,CAChCxD,GAAI,UAAUC,KAAKC,QACnBC,KAAM,sDACNC,OAAQ,MACRC,cAAeJ,MAMjB,YAJA/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU6F,GACnC5F,WAAY,IAGhB,CAAA,GAAiC,WAAtB1B,KAAKQ,aAA2B,CAEzC,MAAM+G,EAAStD,EAAKe,OAGpB,IAFoB,wEAEHoC,KAAKG,IAAWA,EAAOC,OAAS,GAAI,CAEnD,MAAMC,EAAoC,CACxC3D,GAAI,UAAUC,KAAKC,QACnBC,KAAM,4DACNC,OAAQ,MACRC,cAAeJ,MAMjB,YAJA/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUgG,GACnC/F,WAAY,IAGhB,CAGA1B,KAAKW,oBAAsB4G,EAG3BvH,KAAKO,oBAAqB,EAC1BP,KAAKQ,aAAe,WAGdR,KAAK0H,cAAc1H,KAAKS,kBAAmBT,KAAKU,mBAAoB6G,GAC1EvH,KAAK6C,SAAS,CAAEnB,WAAY,IAC9B,CACF,CAKA,mBAAMgG,CAAcC,EAAuBC,EAAwBC,GACjE,IAAK7H,KAAKM,YACR,MAAM,IAAImF,MAAM,gCAGlB,IACEzF,KAAKgB,qBAAsB,EAG3B,MAAM8G,EAAsB9H,KAAKsB,MAAMO,UAGjC4B,QAAgBzD,KAAKM,YAAYyH,sBACrC/H,KAAKI,OACLJ,KAAKK,iBACLyH,GAAuB,KACvBH,GAAgB,KAChBC,GAAiB,KACjBC,GAAkB,MAGpB,IAAKpE,IAAYA,EAAQ6C,QACvB,MAAM,IAAIb,MAAM,qCAGlB,MAAMuC,EAAgBvE,EAAQ6C,QACxB2B,EAA0BxE,EAAQE,WAGxC,GAAIqE,IAAkBhI,KAAKI,OAAQ,CACjCJ,KAAKI,OAAS4H,EACdhI,KAAKK,iBAAmB4H,EACxB,MAAM7F,EAAUC,EAAAA,mBAChBD,EAAQoE,QAAQ,qBAAsBxG,KAAKI,QAC3CgC,EAAQoE,QAAQ,wBAAyBxG,KAAKK,kBAC1CL,KAAKD,OAAOoC,KAGlB,CAGA,UACQnC,KAAKM,YAAY4H,eACrBF,EACAC,EACA,iCACAH,GAAuB,KACvBH,GAAgB,KAChBC,GAAiB,KACjBC,GAAkB,MAGhB7H,KAAKD,OAAOoC,KAGlB,OAASgG,GAEP,KAAIA,EAAavE,SAAS4B,SAAS,oBAC/B2C,EAAavE,SAAS4B,SAAS,mBAC/B2C,EAAavE,SAAS4B,SAAS,iBAC/B2C,EAAavE,SAAS4B,SAAS,QAC/B2C,EAAavE,SAAS4B,SAAS,QAC/B2C,EAAavE,SAAS4B,SAAS,QAC/B2C,EAAavE,SAAS4B,SAAS,YA6CjC,MAAM2C,EA7CuC,CACzCnI,KAAKD,OAAOoC,MAKhBnC,KAAKI,OAAS,KACdJ,KAAKK,iBAAmB,KACxB,MAAM+H,EAAW/F,EAAAA,mBACjB+F,EAASjC,WAAW,sBACpBiC,EAASjC,WAAW,yBAGpB,MAAMC,QAAmBpG,KAAKM,YAAY+F,iBACxCyB,GAAuB,KACvBH,GAAgB,KAChBC,GAAiB,KACjBC,GAAkB,MAGpB,IAAKzB,IAAeA,EAAWE,QAC7B,MAAM,IAAIb,MAAM,wCAGlBzF,KAAKI,OAASgG,EAAWE,QACzBtG,KAAKK,iBAAmB+F,EAAWzC,WACnC,MAAM0E,EAAWhG,EAAAA,mBACjBgG,EAAS7B,QAAQ,qBAAsBxG,KAAKI,QAC5CiI,EAAS7B,QAAQ,wBAAyBxG,KAAKK,wBAGzCL,KAAKM,YAAY4H,eACrBlI,KAAKI,OACLJ,KAAKK,iBACL,iCACAyH,GAAuB,KACvBH,GAAgB,KAChBC,GAAiB,KACjBC,GAAkB,MAGhB7H,KAAKD,OAAOoC,KAGlB,CAGF,CAGAnC,KAAK0G,oBACL1G,KAAKkB,cAAe,EACpBlB,KAAKiB,eAAgB,EAGrB,MAAMqH,EAAiC,CACrCxE,GAAI,cAAcC,KAAKC,QACvBC,KAAM,wCACNC,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU6G,KAIjCN,GAAiBC,GACnBjI,KAAKM,YAAYiI,iBACfP,EACAC,EACCrE,IACC5D,KAAKwI,uBAAuB5E,IAE7B6E,IACCzI,KAAKY,YAAc6H,IAKzBzI,KAAKgB,qBAAsB,CAC7B,OAASY,GAEP,MAAM2D,EAA4B,CAChCzB,GAAI,SAASC,KAAKC,QAClBC,KAAMjE,KAAKD,OAAOoC,MACd,kBAAkBP,EAAMgC,UACxB,gDACJM,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU8D,KAErCvF,KAAKgB,qBAAsB,CAC7B,CACF,CAKQ,sBAAAwH,CAAuB5E,GAC7B,OAAQA,EAAQ8E,MACd,IAAK,UACH,GAAI9E,EAAQ+E,UAEkB,UAAxB/E,EAAQgF,cAA4BhF,EAAQgF,aAAa,CAC3D,MAAMC,EAA4B,CAChC/E,GAAIF,EAAQE,IAAM,SAASC,KAAKC,QAChCC,KAAML,EAAQ+E,QACdzE,OAAQ,QACRC,UAAW,IAAIJ,KAAKH,EAAQO,WAAaJ,KAAKC,QAI5B,IAAI9D,IAAIF,KAAKsB,MAAMG,SAASqH,IAAIC,GAAKA,EAAEjF,KAC1CkF,IAAIH,EAAa/E,KAChC9D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUoH,KAKvC7I,KAAKa,aAAc,EACfb,KAAKqB,qBACP2E,aAAahG,KAAKqB,oBAClBrB,KAAKqB,mBAAqB,KAE9B,CAEF,MAEF,IAAK,eACyB,UAAxBuC,EAAQgF,cACV5I,KAAKa,aAAc,EAEfb,KAAKqB,oBACP2E,aAAahG,KAAKqB,oBAEpBrB,KAAKqB,mBAAqB0F,WAAW,KACnC/G,KAAKa,aAAc,GAClB,MAEL,MAEF,IAAK,cACyB,UAAxB+C,EAAQgF,cACV5I,KAAKa,aAAc,EACfb,KAAKqB,qBACP2E,aAAahG,KAAKqB,oBAClBrB,KAAKqB,mBAAqB,OAG9B,MAEF,IAAK,gBACH,GAAIuC,EAAQqF,SAAU,CACpBjJ,KAAKc,aAAe,CAClBgD,GAAIF,EAAQsF,YACZnI,KAAM6C,EAAQqF,UAIhB,MAAME,EAA6B,CACjCrF,GAAI,UAAUC,KAAKC,QACnBC,KAAML,EAAQwF,WACV,kCAAkCxF,EAAQwF,iBAAiBxF,EAAQqF,WACnE,gCAAgCrF,EAAQqF,WAC5C/E,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU0H,IAEvC,CACA,MAEF,IAAK,iBACHnJ,KAAKiB,eAAgB,EACrBjB,KAAKgB,qBAAsB,EAC3B,MAAMqI,EAA+B,CACnCvF,GAAIF,EAAQE,IAAM,kBAAkBC,KAAKC,QACzCC,KAAM,yDACNC,OAAQ,MACRC,UAAWP,EAAQO,UAAY,IAAIJ,KAAKH,EAAQO,WAAa,IAAIJ,MAE/C,IAAI7D,IAAIF,KAAKsB,MAAMG,SAASqH,IAAIC,GAAKA,EAAEjF,KAC1CkF,IAAIK,EAAgBvF,KACnC9D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU4H,KAGnCzF,EAAQqF,WACVjJ,KAAKc,aAAe,CAClBC,KAAM6C,EAAQqF,SACdnF,GAAIF,EAAQsF,cAGhB,MAEF,IAAK,gBACL,IAAK,aACHlJ,KAAKsF,mBAAmB1B,EAAQ0C,SAAW,MAC3C,MAEF,IAAK,YACoB,WAAnB1C,EAAQ0F,QACVtJ,KAAKgB,qBAAsB,EAC3BhB,KAAKiB,eAAgB,GACO,aAAnB2C,EAAQ0F,QAA4C,UAAnB1F,EAAQ0F,QAClDtJ,KAAKsF,mBAAmB1B,EAAQ0C,SAAW,MAEzC1C,EAAQ2F,WACVvJ,KAAKc,aAAe,IACfd,KAAKc,aACRgD,GAAIF,EAAQ2F,WAGhB,MAEF,IAAK,QAEH,MAAMhE,EAA4B,CAChCzB,GAAI,SAASC,KAAKC,QAClBC,KAAML,EAAQhC,OAAS,uCACvBsC,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU8D,KAI3C,CAKQ,kBAAAD,CAAmBkE,GACzBxJ,KAAKkB,cAAe,EACpBlB,KAAKgB,qBAAsB,EAC3BhB,KAAKiB,eAAgB,EACrBjB,KAAKa,aAAc,EACfb,KAAKqB,qBACP2E,aAAahG,KAAKqB,oBAClBrB,KAAKqB,mBAAqB,MAIxBrB,KAAKM,aACPN,KAAKM,YAAYmJ,sBAEnBzJ,KAAKI,OAAS,KACdJ,KAAKK,iBAAmB,KACxB,MAAM+B,EAAUC,EAAAA,mBAChBD,EAAQ+D,WAAW,sBACnB/D,EAAQ+D,WAAW,yBAGnB,MAAMuD,EAA+B,CACnC5F,GAAI,YAAYC,KAAKC,QACrBC,KAAM,+BACNC,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAUiI,KAIrC3C,WAAW4C,UAcT,GAbA3J,KAAK2G,kBACL3G,KAAKkB,cAAe,EACpBlB,KAAK6C,SAAS,CACZpB,SAAU,GACVI,UAAW,OAEb7B,KAAKO,oBAAqB,EAC1BP,KAAKQ,aAAe,KACpBR,KAAKS,kBAAoB,GACzBT,KAAKU,mBAAqB,GAC1BV,KAAKW,oBAAsB,GAGvBX,KAAKD,OAAOmD,aAAelD,KAAKD,OAAOoD,WAAanD,KAAKsB,MAAMC,OACjE,IACEvB,KAAK6C,SAAS,CAAElB,WAAW,IAC3B,MAAMyB,EAAqC,CACzCF,YAAalD,KAAKD,OAAOmD,YACzBG,WAAYrD,KAAKD,OAAOsD,YAAc,cACtCF,UAAWnD,KAAKD,OAAOoD,UACvBG,kBAAmBtD,KAAKD,OAAOuD,kBAC/BC,YAAavD,KAAKD,OAAOwD,YACzBC,aAAcxD,KAAKD,OAAOyD,cAAgB,MAGtCC,QAAgBC,EAAAA,wBAAwBN,GAO9C,GANApD,KAAK6C,SAAS,CACZhB,UAAW4B,EAAQE,WACnBhC,WAAW,IAIT8B,EAAQG,QAAS,CACnB,MAAMC,EAA8B,CAClCC,GAAI,WAAWC,KAAKC,QACpBC,KAAMR,EAAQG,QACdM,OAAQ,MACRC,cAAeJ,KACfK,YAAaX,EAAQW,aAEvBpE,KAAK6C,SAAS,CACZpB,SAAU,CAACoC,IAEf,CACF,OAASjC,GAEP5B,KAAK6C,SAAS,CACZlB,WAAW,EACXC,MAAOA,EAAMgC,SAAW,8BAI1B,MAAMS,EAA+B,CACnCP,GAAI,YAAYC,KAAKC,QACrBC,KAAMjE,KAAKD,OAAOuE,wBAA0B,mCAC5CJ,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,CAAC4C,IAEf,GAED,IACL,CAKA,wBAAMuF,CAAmBC,GAA4B,GACnD,GAAK7J,KAAKM,aAAgBN,KAAKI,QAAWJ,KAAKK,iBAI/C,IACE,GAAIL,KAAKI,QAAUJ,KAAKK,iBAAkB,CACxC,MAEMyJ,SAFgB9J,KAAKM,YAAYsJ,mBAAmB5J,KAAKI,OAAQJ,KAAKK,mBAE7ByI,IAAKiB,IAAA,CAClDjG,GAAIiG,EAAIjG,IAAM,WAAWC,KAAKC,SAASgG,KAAKC,WAC5ChG,KAAM8F,EAAIpB,QACVzE,OAA4B,UAApB6F,EAAInB,YAA0B,QAAU,OAChDzE,UAAW,IAAIJ,KAAKgG,EAAI5F,cAG1B,GAAI0F,EAAkB,CAEpB,MAAMK,EAAc,IAAIhK,IAAIF,KAAKsB,MAAMG,SAASqH,IAAIC,GAAKA,EAAEjF,KACrDqG,EAAcL,EAAgBM,OAAOrB,IAAMmB,EAAYlB,IAAID,EAAEjF,KAI7DuG,EAAW,IAAIrK,KAAKsB,MAAMG,YAAa0I,GAAaG,KAAK,CAACC,EAAGC,IACjED,EAAEpG,UAAUsG,UAAYD,EAAErG,UAAUsG,WAGtCzK,KAAK6C,SAAS,CACZpB,SAAU4I,GAEd,MAEErK,KAAK6C,SAAS,CACZpB,SAAUqI,GAGhB,CACF,OAASlI,GAEP,GAAI5B,KAAKD,OAAOoC,MAAO,CACrB,MAAMoD,EAA4B,CAChCzB,GAAI,SAASC,KAAKC,QAClBC,KAAM,gCAAgCrC,EAAMgC,UAC5CM,OAAQ,MACRC,cAAeJ,MAEjB/D,KAAK6C,SAAS,CACZpB,SAAU,IAAIzB,KAAKsB,MAAMG,SAAU8D,IAEvC,CACF,CACF,CAKA,kBAAAmF,GACE,MAAO,CACL9J,YAAaZ,KAAKY,YAClBC,YAAab,KAAKa,YAClBC,aAAcd,KAAKc,aACnBE,oBAAqBhB,KAAKgB,oBAC1BC,cAAejB,KAAKiB,cACpBC,aAAclB,KAAKkB,aAEvB,CAKA,OAAAyJ,GACM3K,KAAKoB,eACP4E,aAAahG,KAAKoB,eAEhBpB,KAAKqB,oBACP2E,aAAahG,KAAKqB,oBAEhBrB,KAAKM,aACPN,KAAKM,YAAYmJ,sBAEnBzJ,KAAKC,UAAU2K,OACjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stateManager.d.ts","sourceRoot":"","sources":["../../src/core/stateManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAe,MAAM,SAAS,CAAC;AAatE,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAAgD;IACjE,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,WAAW,CAAqD;IAGxE,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,YAAY,CAA4C;IAChE,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,kBAAkB,CAAc;IACxC,OAAO,CAAC,mBAAmB,CAAc;IAGzC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,YAAY,CAAoD;IACxE,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,aAAa,CAAuB;IAG5C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,kBAAkB,CAA+B;gBAE7C,MAAM,EAAE,YAAY;IAgChC;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI;IAO7D;;OAEG;IACH,QAAQ,IAAI,WAAW;IAIvB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAKhB;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI;IAIjD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA2D/B;;OAEG;IACH,SAAS,IAAI,IAAI;IAIjB;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAIzB;;OAEG;IACH,UAAU,IAAI,IAAI;IAQlB;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIlC;;OAEG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAsFhF;;OAEG;YACW,aAAa;IA6E3B;;OAEG;YACW,gBAAgB;IAgG9B;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAMzB;;OAEG;IACH,eAAe,IAAI,IAAI;IAMvB;;OAEG;IACH,sBAAsB,IAAI,IAAI;IAW9B;;OAEG;IACH,OAAO,CAAC,uBAAuB;
|
|
1
|
+
{"version":3,"file":"stateManager.d.ts","sourceRoot":"","sources":["../../src/core/stateManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAe,MAAM,SAAS,CAAC;AAatE,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAAgD;IACjE,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,WAAW,CAAqD;IAGxE,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,YAAY,CAA4C;IAChE,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,kBAAkB,CAAc;IACxC,OAAO,CAAC,mBAAmB,CAAc;IAGzC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,YAAY,CAAoD;IACxE,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,aAAa,CAAuB;IAG5C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,kBAAkB,CAA+B;gBAE7C,MAAM,EAAE,YAAY;IAgChC;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI;IAO7D;;OAEG;IACH,QAAQ,IAAI,WAAW;IAIvB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAKhB;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI;IAIjD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA2D/B;;OAEG;IACH,SAAS,IAAI,IAAI;IAIjB;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAIzB;;OAEG;IACH,UAAU,IAAI,IAAI;IAQlB;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIlC;;OAEG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAsFhF;;OAEG;YACW,aAAa;IA6E3B;;OAEG;YACW,gBAAgB;IAgG9B;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAMzB;;OAEG;IACH,eAAe,IAAI,IAAI;IAMvB;;OAEG;IACH,sBAAsB,IAAI,IAAI;IAW9B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IA4B/B;;OAEG;YACW,wBAAwB;IAwFtC;;OAEG;IACG,aAAa,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgK1G;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAsI9B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAmG1B;;OAEG;IACG,kBAAkB,CAAC,gBAAgB,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAqD1E;;OAEG;IACH,kBAAkB;;;;kBAliCY,MAAM;iBAAO,MAAM;;;;;;IA6iCjD;;OAEG;IACH,OAAO,IAAI,IAAI;CAYhB"}
|
|
@@ -412,14 +412,20 @@ class WidgetStateManager {
|
|
|
412
412
|
this.collectedUserName = "";
|
|
413
413
|
this.collectedUserEmail = "";
|
|
414
414
|
this.collectedUserMobile = "";
|
|
415
|
+
const handoffMessage = {
|
|
416
|
+
id: `handoff-${Date.now()}`,
|
|
417
|
+
text: "👤 You're being connected to a live support agent. Please wait while we transfer your conversation...",
|
|
418
|
+
sender: "bot",
|
|
419
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
420
|
+
};
|
|
415
421
|
const namePrompt = {
|
|
416
422
|
id: `prompt-${Date.now()}`,
|
|
417
|
-
text: "To connect you with a human agent, I'll need some information
|
|
423
|
+
text: "To connect you with a human agent, I'll need some information.\n\nPlease provide your name:",
|
|
418
424
|
sender: "bot",
|
|
419
425
|
timestamp: /* @__PURE__ */ new Date()
|
|
420
426
|
};
|
|
421
427
|
this.setState({
|
|
422
|
-
messages: [...this.state.messages, namePrompt]
|
|
428
|
+
messages: [...this.state.messages, handoffMessage, namePrompt]
|
|
423
429
|
});
|
|
424
430
|
}
|
|
425
431
|
/**
|
|
@@ -432,7 +438,7 @@ class WidgetStateManager {
|
|
|
432
438
|
this.userInfoStep = "email";
|
|
433
439
|
const emailPrompt = {
|
|
434
440
|
id: `prompt-${Date.now()}`,
|
|
435
|
-
text: "Thank you! Now please provide your email address:",
|
|
441
|
+
text: "✅ Thank you! Now please provide your email address:",
|
|
436
442
|
sender: "bot",
|
|
437
443
|
timestamp: /* @__PURE__ */ new Date()
|
|
438
444
|
};
|
|
@@ -461,7 +467,7 @@ class WidgetStateManager {
|
|
|
461
467
|
this.userInfoStep = "mobile";
|
|
462
468
|
const mobilePrompt = {
|
|
463
469
|
id: `prompt-${Date.now()}`,
|
|
464
|
-
text: "Thank you! Now please provide your mobile number:",
|
|
470
|
+
text: "✅ Thank you! Now please provide your mobile number:",
|
|
465
471
|
sender: "bot",
|
|
466
472
|
timestamp: /* @__PURE__ */ new Date()
|
|
467
473
|
};
|
|
@@ -584,7 +590,7 @@ class WidgetStateManager {
|
|
|
584
590
|
this.agentAccepted = false;
|
|
585
591
|
const connectingMessage = {
|
|
586
592
|
id: `connecting-${Date.now()}`,
|
|
587
|
-
text: "Connecting you to a human agent...",
|
|
593
|
+
text: "🔄 Connecting you to a human agent...",
|
|
588
594
|
sender: "bot",
|
|
589
595
|
timestamp: /* @__PURE__ */ new Date()
|
|
590
596
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stateManager.esm.js","sources":["../../src/core/stateManager.ts"],"sourcesContent":["/**\n * State Manager - Framework Agnostic\n * Manages widget state independently of framework\n */\n\nimport type { WidgetState, WidgetConfig, ChatMessage } from './types';\nimport {\n createDialogflowSession,\n sendDialogflowMessage,\n type DialogflowConfig,\n} from '../services/dialogflowClient';\nimport { \n createChatService, \n ChatResolvedError,\n type WebSocketMessage\n} from '../services/chatService';\nimport { safeLocalStorage } from '../utils/ssr';\n\nexport class WidgetStateManager {\n private state: WidgetState;\n private config: WidgetConfig;\n private listeners: Set<(state: WidgetState) => void> = new Set();\n private chatMode: 'ai' | 'human' = 'ai';\n private chatId: string | null = null;\n private supportSessionId: string | null = null;\n private chatService: ReturnType<typeof createChatService> | null = null;\n \n // User info collection for handoff\n private collectingUserInfo: boolean = false;\n private userInfoStep: 'name' | 'email' | 'mobile' | null = null;\n private collectedUserName: string = '';\n private collectedUserEmail: string = '';\n private collectedUserMobile: string = '';\n \n // Additional state for human support\n private wsConnected: boolean = false;\n private agentTyping: boolean = false;\n private currentAgent: { name: string; id?: string } = { name: 'Agent' };\n private isConnectingToAgent: boolean = false;\n private agentAccepted: boolean = false;\n private chatResolved: boolean = false;\n private historyLoaded: string | null = null;\n \n // Typing timeout refs (stored as class properties since we can't use refs)\n private typingTimeout: NodeJS.Timeout | null = null;\n private agentTypingTimeout: NodeJS.Timeout | null = null;\n\n constructor(config: WidgetConfig) {\n this.config = config;\n this.state = {\n isOpen: false,\n showWelcomePopup: false,\n messages: [],\n inputValue: '',\n isLoading: false,\n error: null,\n sessionId: null,\n chatMode: 'ai',\n };\n \n // Initialize ChatService\n this.chatService = createChatService({\n baseUrl: this.config.backendBaseUrl || 'http://localhost:8012',\n wsUrl: this.config.backendWsUrl || 'ws://localhost:8012',\n debug: this.config.debug || false,\n });\n \n // Load chat mode and chat IDs from localStorage if available (SSR-safe)\n const storage = safeLocalStorage();\n const savedMode = storage.getItem('blockspark_chat_mode');\n if (savedMode) {\n this.chatMode = savedMode === 'HUMAN' ? 'human' : 'ai';\n this.state.chatMode = this.chatMode;\n }\n \n this.chatId = storage.getItem('blockspark_chat_id');\n this.supportSessionId = storage.getItem('blockspark_session_id');\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(listener: (state: WidgetState) => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Get current state\n */\n getState(): WidgetState {\n return { ...this.state };\n }\n\n /**\n * Update state and notify listeners\n */\n private setState(updates: Partial<WidgetState>): void {\n this.state = { ...this.state, ...updates };\n this.listeners.forEach(listener => listener(this.getState()));\n }\n\n /**\n * Update configuration\n */\n updateConfig(config: Partial<WidgetConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Open chat\n */\n async openChat(): Promise<void> {\n this.setState({ isOpen: true });\n if (this.state.showWelcomePopup) {\n this.setState({ showWelcomePopup: false });\n }\n \n // Initialize Dialogflow session when chat opens (if in AI mode and no session exists)\n if (this.state.chatMode === 'ai' && !this.state.sessionId && this.config.dfProjectId && this.config.dfAgentId) {\n try {\n this.setState({ isLoading: true });\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n \n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ \n sessionId: session.session_id,\n isLoading: false,\n });\n \n // Add welcome message from Dialogflow if available\n if (session.message) {\n const welcomeMessage: ChatMessage = {\n id: `welcome-${Date.now()}`,\n text: session.message,\n sender: 'bot',\n timestamp: new Date(),\n richContent: session.richContent,\n };\n this.setState({\n messages: [welcomeMessage],\n });\n }\n } catch (error: any) {\n console.error('Error initializing Dialogflow session:', error);\n this.setState({ \n isLoading: false,\n error: error.message || 'Failed to initialize chat',\n });\n \n // Show fallback welcome message\n const fallbackMessage: ChatMessage = {\n id: `fallback-${Date.now()}`,\n text: this.config.fallbackWelcomeMessage || 'Hello! How can I help you today?',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [fallbackMessage],\n });\n }\n }\n }\n\n /**\n * Close chat\n */\n closeChat(): void {\n this.setState({ isOpen: false });\n }\n\n /**\n * Close welcome popup\n */\n closeWelcomePopup(): void {\n this.setState({ showWelcomePopup: false });\n }\n\n /**\n * Toggle chat\n */\n toggleChat(): void {\n const willBeOpen = !this.state.isOpen;\n this.setState({ isOpen: willBeOpen });\n if (willBeOpen && this.state.showWelcomePopup) {\n this.setState({ showWelcomePopup: false });\n }\n }\n\n /**\n * Set input value\n */\n setInputValue(value: string): void {\n this.setState({ inputValue: value });\n }\n\n /**\n * Clear error\n */\n clearError(): void {\n this.setState({ error: null });\n }\n\n /**\n * Send message\n */\n async sendMessage(text: string, skipUserMessage: boolean = false): Promise<void> {\n if (!text.trim() || this.state.isLoading) {\n return;\n }\n\n // Handle user info collection for handoff\n if (this.collectingUserInfo) {\n // Add user message first so it appears in chat\n const userMessage: ChatMessage = {\n id: `user-${Date.now()}`,\n text: text.trim(),\n sender: 'user',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, userMessage],\n inputValue: '',\n isLoading: false,\n error: null,\n });\n \n // Then handle the info collection\n await this.handleUserInfoCollection(text);\n return;\n }\n\n // Add user message unless skipped (e.g., when chip button already added it)\n if (!skipUserMessage) {\n const userMessage: ChatMessage = {\n id: `user-${Date.now()}`,\n text: text.trim(),\n sender: 'user',\n timestamp: new Date(),\n };\n\n this.setState({\n messages: [...this.state.messages, userMessage],\n inputValue: '',\n isLoading: true,\n error: null,\n });\n } else {\n this.setState({\n inputValue: '',\n isLoading: true,\n error: null,\n });\n }\n\n try {\n if (this.state.chatMode === 'human') {\n // Human support mode\n await this.sendHumanMessage(text);\n } else {\n // AI mode (Dialogflow)\n await this.sendAIMessage(text);\n }\n } catch (error: any) {\n console.error('Error sending message:', error);\n \n // chat_resolved is a normal terminal condition, not an error\n if (error instanceof ChatResolvedError || error?.name === 'ChatResolvedError' || error?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n \n // Add error message to chat\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: this.config.debug \n ? `Error: ${error.message || 'Failed to send message'}`\n : error.message?.includes('CORS') || error.message?.includes('Failed to fetch')\n ? 'Unable to connect to Dialogflow. Please check your configuration and network.'\n : 'Sorry, I\\'m having trouble processing your message. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n \n this.setState({\n messages: [...this.state.messages, errorMessage],\n error: error.message || 'Failed to send message',\n isLoading: false,\n });\n }\n }\n\n /**\n * Send message to Dialogflow\n */\n private async sendAIMessage(text: string): Promise<void> {\n if (!this.config.dfProjectId || !this.config.dfAgentId) {\n throw new Error('Dialogflow configuration is missing');\n }\n\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId!,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId!,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n\n // Create session if needed\n if (!this.state.sessionId) {\n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ sessionId: session.session_id });\n }\n\n // Send message (correct parameter order: message, sessionId, config)\n if (this.config.debug) {\n console.log('Sending message to Dialogflow:', {\n message: text,\n sessionId: this.state.sessionId,\n hasConfig: !!dialogflowConfig,\n });\n }\n \n const response = await sendDialogflowMessage(\n text,\n this.state.sessionId!,\n dialogflowConfig\n );\n\n if (this.config.debug) {\n console.log('Dialogflow response:', {\n response: response.response,\n hasRichContent: !!response.richContent,\n richContent: response.richContent,\n });\n }\n\n // Check for handoff\n if (response.handoff === true) {\n // Add bot response first\n const botMessage: ChatMessage = {\n id: `bot-${Date.now()}`,\n text: response.response || this.config.fallbackWelcomeMessage || 'No response',\n sender: 'bot',\n timestamp: new Date(),\n richContent: response.richContent,\n };\n this.setState({\n messages: [...this.state.messages, botMessage],\n isLoading: false,\n });\n \n // Start collecting user info for handoff\n this.startUserInfoCollection();\n return;\n }\n \n const botMessage: ChatMessage = {\n id: `bot-${Date.now()}`,\n text: response.response || this.config.fallbackWelcomeMessage || 'No response',\n sender: 'bot',\n timestamp: new Date(),\n richContent: response.richContent,\n };\n\n this.setState({\n messages: [...this.state.messages, botMessage],\n isLoading: false,\n });\n }\n\n /**\n * Send message to human support\n */\n private async sendHumanMessage(text: string): Promise<void> {\n if (!this.chatId || !this.supportSessionId) {\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: 'Chat session not initialized. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n isLoading: false,\n });\n return;\n }\n\n if (!this.chatService) {\n throw new Error('Chat service not initialized');\n }\n\n // Send typing_stop before sending message\n this.chatService.sendTypingIndicator('typing_stop');\n if (this.typingTimeout) {\n clearTimeout(this.typingTimeout);\n this.typingTimeout = null;\n }\n\n try {\n // Try WebSocket first, fallback to REST API\n const sentViaWs = this.chatService.sendMessageViaWebSocket(text.trim());\n \n if (!sentViaWs) {\n // Fallback to REST API\n await this.chatService.sendMessageToAgent(this.chatId, this.supportSessionId, text.trim());\n }\n \n this.setState({ isLoading: false });\n } catch (error: any) {\n // chat_resolved is a normal terminal condition, not an error\n if (error instanceof ChatResolvedError || error?.name === 'ChatResolvedError' || error?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n\n // Handle 401/404 - clear chat_id and reinitialize\n if (error.message?.includes('Chat not found') ||\n error.message?.includes('unauthorized') ||\n error.message?.includes('401') ||\n error.message?.includes('404')) {\n if (this.config.debug) {\n console.log('⚠️ Chat expired. Re-initializing...');\n }\n \n // Clear chat_id\n this.chatId = null;\n this.supportSessionId = null;\n const storage = safeLocalStorage();\n storage.removeItem('blockspark_chat_id');\n storage.removeItem('blockspark_session_id');\n \n // Try to reinitialize chat\n try {\n const newSession = await this.chatService.startSupportChat(\n this.state.sessionId || null,\n null,\n null,\n null\n );\n this.chatId = newSession.chat_id;\n this.supportSessionId = newSession.session_id;\n const storage1 = safeLocalStorage();\n storage1.setItem('blockspark_chat_id', this.chatId);\n storage1.setItem('blockspark_session_id', this.supportSessionId);\n \n // Retry sending message\n if (this.chatId && this.supportSessionId) {\n await this.chatService.sendMessageToAgent(\n this.chatId,\n this.supportSessionId,\n text.trim()\n );\n }\n this.setState({ isLoading: false });\n return;\n } catch (retryError: any) {\n if (retryError instanceof ChatResolvedError || retryError?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n throw retryError;\n }\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Switch to human mode\n */\n switchToHumanMode(): void {\n this.chatMode = 'human';\n this.setState({ chatMode: 'human' });\n safeLocalStorage().setItem('blockspark_chat_mode', 'HUMAN');\n }\n\n /**\n * Switch to AI mode\n */\n switchToBotMode(): void {\n this.chatMode = 'ai';\n this.setState({ chatMode: 'ai' });\n safeLocalStorage().setItem('blockspark_chat_mode', 'BOT');\n }\n\n /**\n * Initialize welcome popup\n */\n initializeWelcomePopup(): void {\n if (this.config.showWelcomePopup !== false) {\n const delay = this.config.welcomePopupDelay || 1500;\n setTimeout(() => {\n if (!this.state.isOpen) {\n this.setState({ showWelcomePopup: true });\n }\n }, delay);\n }\n }\n\n /**\n * Start user info collection for handoff\n */\n private startUserInfoCollection(): void {\n this.collectingUserInfo = true;\n this.userInfoStep = 'name';\n this.collectedUserName = '';\n this.collectedUserEmail = '';\n this.collectedUserMobile = '';\n \n // Ask for name\n const namePrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'To connect you with a human agent, I\\'ll need some information. Please provide your name:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, namePrompt],\n });\n }\n\n /**\n * Handle user info collection\n */\n private async handleUserInfoCollection(text: string): Promise<void> {\n if (this.userInfoStep === 'name') {\n // Save name and ask for email\n const name = text.trim();\n this.collectedUserName = name;\n this.userInfoStep = 'email';\n \n // Ask for email\n const emailPrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Thank you! Now please provide your email address:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, emailPrompt],\n inputValue: '',\n });\n return;\n } else if (this.userInfoStep === 'email') {\n // Validate email format\n const email = text.trim();\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n \n if (!emailRegex.test(email)) {\n // Invalid email, ask again\n const invalidEmailMessage: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Please provide a valid email address:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, invalidEmailMessage],\n inputValue: '',\n });\n return;\n }\n \n // Save email and ask for mobile\n this.collectedUserEmail = email;\n this.userInfoStep = 'mobile';\n \n // Ask for mobile\n const mobilePrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Thank you! Now please provide your mobile number:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, mobilePrompt],\n inputValue: '',\n });\n return;\n } else if (this.userInfoStep === 'mobile') {\n // Validate mobile format\n const mobile = text.trim();\n const mobileRegex = /^[\\+]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[0-9]{1,9}$/;\n \n if (!mobileRegex.test(mobile) || mobile.length < 10) {\n // Invalid mobile, ask again\n const invalidMobileMessage: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Please provide a valid mobile number (e.g., +1234567890):',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, invalidMobileMessage],\n inputValue: '',\n });\n return;\n }\n \n // Save mobile and proceed with handoff\n this.collectedUserMobile = mobile;\n \n // Reset collection state\n this.collectingUserInfo = false;\n this.userInfoStep = null;\n \n // Proceed with handoff using collected info\n await this.handleHandoff(this.collectedUserName, this.collectedUserEmail, mobile);\n this.setState({ inputValue: '' });\n }\n }\n\n /**\n * Handle handoff from Dialogflow to human support\n */\n async handleHandoff(customerName?: string, customerEmail?: string, customerMobile?: string): Promise<void> {\n if (!this.chatService) {\n throw new Error('Chat service not initialized');\n }\n\n try {\n this.isConnectingToAgent = true;\n \n // Get Dialogflow session ID if available\n const dialogflowSessionId = this.state.sessionId;\n \n // STEP 1: Ensure chat is initialized\n const session = await this.chatService.ensureChatInitialized(\n this.chatId,\n this.supportSessionId,\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!session || !session.chat_id) {\n throw new Error('Failed to initialize chat session');\n }\n \n const currentChatId = session.chat_id;\n const currentSupportSessionId = session.session_id;\n \n // Update state if chat was newly initialized\n if (currentChatId !== this.chatId) {\n this.chatId = currentChatId;\n this.supportSessionId = currentSupportSessionId;\n const storage = safeLocalStorage();\n storage.setItem('blockspark_chat_id', this.chatId);\n storage.setItem('blockspark_session_id', this.supportSessionId);\n if (this.config.debug) {\n console.log('✅ Chat initialized:', { chatId: currentChatId, sessionId: currentSupportSessionId });\n }\n }\n\n // STEP 2: Request handoff\n try {\n await this.chatService.requestHandoff(\n currentChatId,\n currentSupportSessionId,\n 'Customer requested human agent',\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (this.config.debug) {\n console.log('✅ Handoff requested successfully');\n }\n } catch (handoffError: any) {\n // Handle 401/404 or \"chat not found\" - clear chat_id and retry\n if (handoffError.message?.includes('Invalid chat_id') || \n handoffError.message?.includes('Chat not found') ||\n handoffError.message?.includes('unauthorized') ||\n handoffError.message?.includes('400') ||\n handoffError.message?.includes('401') ||\n handoffError.message?.includes('404') ||\n handoffError.message?.includes('expired')) {\n if (this.config.debug) {\n console.log('⚠️ Chat expired or not found. Re-initializing chat...');\n }\n \n // Clear old chat_id\n this.chatId = null;\n this.supportSessionId = null;\n const storage2 = safeLocalStorage();\n storage2.removeItem('blockspark_chat_id');\n storage2.removeItem('blockspark_session_id');\n \n // Create new chat session\n const newSession = await this.chatService.startSupportChat(\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!newSession || !newSession.chat_id) {\n throw new Error('Failed to re-initialize chat session');\n }\n \n this.chatId = newSession.chat_id;\n this.supportSessionId = newSession.session_id;\n const storage4 = safeLocalStorage();\n storage4.setItem('blockspark_chat_id', this.chatId);\n storage4.setItem('blockspark_session_id', this.supportSessionId);\n \n // Retry handoff with new chat_id\n await this.chatService.requestHandoff(\n this.chatId,\n this.supportSessionId,\n 'Customer requested human agent',\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (this.config.debug) {\n console.log('✅ Handoff requested successfully after retry');\n }\n } else {\n throw handoffError;\n }\n }\n\n // Switch to human mode\n this.switchToHumanMode();\n this.chatResolved = false;\n this.agentAccepted = false;\n\n // Add connecting message\n const connectingMessage: ChatMessage = {\n id: `connecting-${Date.now()}`,\n text: 'Connecting you to a human agent...',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, connectingMessage],\n });\n\n // Connect WebSocket with handlers\n if (currentChatId && currentSupportSessionId) {\n this.chatService.connectWebSocket(\n currentChatId,\n currentSupportSessionId,\n (message: WebSocketMessage) => {\n this.handleWebSocketMessage(message);\n },\n (connected: boolean) => {\n this.wsConnected = connected;\n }\n );\n }\n \n this.isConnectingToAgent = false;\n } catch (error: any) {\n console.error('Error handling handoff:', error);\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: this.config.debug\n ? `Handoff error: ${error.message}`\n : 'Failed to connect to agent. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n this.isConnectingToAgent = false;\n }\n }\n\n /**\n * Handle WebSocket messages\n */\n private handleWebSocketMessage(message: WebSocketMessage): void {\n switch (message.type) {\n case 'message':\n if (message.content) {\n // Only display messages from agent\n if (message.sender_type === 'agent' || !message.sender_type) {\n const agentMessage: ChatMessage = {\n id: message.id || `agent-${Date.now()}`,\n text: message.content,\n sender: 'agent',\n timestamp: new Date(message.timestamp || Date.now()),\n };\n \n // Avoid duplicate messages\n const existingIds = new Set(this.state.messages.map(m => m.id));\n if (!existingIds.has(agentMessage.id)) {\n this.setState({\n messages: [...this.state.messages, agentMessage],\n });\n }\n \n // Hide typing indicator when message received\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n }\n }\n break;\n\n case 'typing_start':\n if (message.sender_type === 'agent') {\n this.agentTyping = true;\n // Auto-hide after 3 seconds if no message received\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n }\n this.agentTypingTimeout = setTimeout(() => {\n this.agentTyping = false;\n }, 3000);\n }\n break;\n\n case 'typing_stop':\n if (message.sender_type === 'agent') {\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n }\n break;\n\n case 'agent_changed':\n if (message.to_agent) {\n this.currentAgent = {\n id: message.to_agent_id,\n name: message.to_agent,\n };\n\n // Add system message to chat\n const systemMessage: ChatMessage = {\n id: `system-${Date.now()}`,\n text: message.from_agent\n ? `Chat has been transferred from ${message.from_agent} to ${message.to_agent}`\n : `Chat has been transferred to ${message.to_agent}`,\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, systemMessage],\n });\n }\n break;\n\n case 'agent_accepted':\n this.agentAccepted = true;\n this.isConnectingToAgent = false;\n const acceptedMessage: ChatMessage = {\n id: message.id || `agent-accepted-${Date.now()}`,\n text: 'You can chat now, the agent has accepted your request.',\n sender: 'bot',\n timestamp: message.timestamp ? new Date(message.timestamp) : new Date(),\n };\n const existingIds = new Set(this.state.messages.map(m => m.id));\n if (!existingIds.has(acceptedMessage.id)) {\n this.setState({\n messages: [...this.state.messages, acceptedMessage],\n });\n }\n if (message.to_agent) {\n this.currentAgent = {\n name: message.to_agent,\n id: message.to_agent_id,\n };\n }\n break;\n\n case 'chat_resolved':\n case 'chat_ended':\n this.enterResolvedState(message.chat_id || null);\n break;\n\n case 'chat_info':\n if (message.status === 'active') {\n this.isConnectingToAgent = false;\n this.agentAccepted = true;\n } else if (message.status === 'resolved' || message.status === 'ended') {\n this.enterResolvedState(message.chat_id || null);\n }\n if (message.agent_id) {\n this.currentAgent = {\n ...this.currentAgent,\n id: message.agent_id,\n };\n }\n break;\n\n case 'error':\n console.error('WebSocket error:', message.error);\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: message.error || 'An error occurred. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n break;\n }\n }\n\n /**\n * Enter resolved state\n */\n private enterResolvedState(resolvedChatId?: string | null): void {\n this.chatResolved = true;\n this.isConnectingToAgent = false;\n this.agentAccepted = false;\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n\n // Stop WS + prevent any reuse of the old chat_id\n if (this.chatService) {\n this.chatService.disconnectWebSocket();\n }\n this.chatId = null;\n this.supportSessionId = null;\n const storage = safeLocalStorage();\n storage.removeItem('blockspark_chat_id');\n storage.removeItem('blockspark_session_id');\n \n // Add thank you message before reset\n const thankYouMessage: ChatMessage = {\n id: `resolved-${Date.now()}`,\n text: 'Thank you for contacting us!',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, thankYouMessage],\n });\n \n // Automatically reset to BOT mode after showing thank you message\n setTimeout(async () => {\n this.switchToBotMode();\n this.chatResolved = false;\n this.setState({\n messages: [],\n sessionId: null, // Clear session ID to force recreation\n });\n this.collectingUserInfo = false;\n this.userInfoStep = null;\n this.collectedUserName = '';\n this.collectedUserEmail = '';\n this.collectedUserMobile = '';\n \n // Recreate Dialogflow session to start fresh\n if (this.config.dfProjectId && this.config.dfAgentId && this.state.isOpen) {\n try {\n this.setState({ isLoading: true });\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n \n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ \n sessionId: session.session_id,\n isLoading: false,\n });\n \n // Add welcome message from Dialogflow if available\n if (session.message) {\n const welcomeMessage: ChatMessage = {\n id: `welcome-${Date.now()}`,\n text: session.message,\n sender: 'bot',\n timestamp: new Date(),\n richContent: session.richContent,\n };\n this.setState({\n messages: [welcomeMessage],\n });\n }\n } catch (error: any) {\n console.error('Error recreating Dialogflow session after handoff:', error);\n this.setState({ \n isLoading: false,\n error: error.message || 'Failed to initialize chat',\n });\n \n // Show fallback welcome message\n const fallbackMessage: ChatMessage = {\n id: `fallback-${Date.now()}`,\n text: this.config.fallbackWelcomeMessage || 'Hello! How can I help you today?',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [fallbackMessage],\n });\n }\n }\n }, 2000);\n }\n\n /**\n * Load message history\n */\n async loadMessageHistory(preserveExisting: boolean = false): Promise<void> {\n if (!this.chatService || !this.chatId || !this.supportSessionId) {\n return;\n }\n\n try {\n if (this.chatId && this.supportSessionId) {\n const history = await this.chatService.loadMessageHistory(this.chatId, this.supportSessionId);\n \n const historyMessages: ChatMessage[] = history.map((msg: any) => ({\n id: msg.id || `history-${Date.now()}-${Math.random()}`,\n text: msg.content,\n sender: msg.sender_type === 'agent' ? 'agent' : 'user',\n timestamp: new Date(msg.timestamp),\n }));\n\n if (preserveExisting) {\n // Merge with existing messages, avoiding duplicates\n const existingIds = new Set(this.state.messages.map(m => m.id));\n const newMessages = historyMessages.filter(m => !existingIds.has(m.id));\n \n // Combine existing messages with new history messages\n // Sort by timestamp to maintain chronological order\n const combined = [...this.state.messages, ...newMessages].sort((a, b) => \n a.timestamp.getTime() - b.timestamp.getTime()\n );\n \n this.setState({\n messages: combined,\n });\n } else {\n // Replace all messages\n this.setState({\n messages: historyMessages,\n });\n }\n }\n } catch (error: any) {\n console.error('Error loading message history:', error);\n if (this.config.debug) {\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: `Failed to load chat history: ${error.message}`,\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n }\n }\n }\n\n /**\n * Get additional state for UI (not in WidgetState but needed by components)\n */\n getAdditionalState() {\n return {\n wsConnected: this.wsConnected,\n agentTyping: this.agentTyping,\n currentAgent: this.currentAgent,\n isConnectingToAgent: this.isConnectingToAgent,\n agentAccepted: this.agentAccepted,\n chatResolved: this.chatResolved,\n };\n }\n\n /**\n * Cleanup\n */\n destroy(): void {\n if (this.typingTimeout) {\n clearTimeout(this.typingTimeout);\n }\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n }\n if (this.chatService) {\n this.chatService.disconnectWebSocket();\n }\n this.listeners.clear();\n }\n}\n"],"names":["botMessage","existingIds"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stateManager.esm.js","sources":["../../src/core/stateManager.ts"],"sourcesContent":["/**\n * State Manager - Framework Agnostic\n * Manages widget state independently of framework\n */\n\nimport type { WidgetState, WidgetConfig, ChatMessage } from './types';\nimport {\n createDialogflowSession,\n sendDialogflowMessage,\n type DialogflowConfig,\n} from '../services/dialogflowClient';\nimport { \n createChatService, \n ChatResolvedError,\n type WebSocketMessage\n} from '../services/chatService';\nimport { safeLocalStorage } from '../utils/ssr';\n\nexport class WidgetStateManager {\n private state: WidgetState;\n private config: WidgetConfig;\n private listeners: Set<(state: WidgetState) => void> = new Set();\n private chatMode: 'ai' | 'human' = 'ai';\n private chatId: string | null = null;\n private supportSessionId: string | null = null;\n private chatService: ReturnType<typeof createChatService> | null = null;\n \n // User info collection for handoff\n private collectingUserInfo: boolean = false;\n private userInfoStep: 'name' | 'email' | 'mobile' | null = null;\n private collectedUserName: string = '';\n private collectedUserEmail: string = '';\n private collectedUserMobile: string = '';\n \n // Additional state for human support\n private wsConnected: boolean = false;\n private agentTyping: boolean = false;\n private currentAgent: { name: string; id?: string } = { name: 'Agent' };\n private isConnectingToAgent: boolean = false;\n private agentAccepted: boolean = false;\n private chatResolved: boolean = false;\n private historyLoaded: string | null = null;\n \n // Typing timeout refs (stored as class properties since we can't use refs)\n private typingTimeout: NodeJS.Timeout | null = null;\n private agentTypingTimeout: NodeJS.Timeout | null = null;\n\n constructor(config: WidgetConfig) {\n this.config = config;\n this.state = {\n isOpen: false,\n showWelcomePopup: false,\n messages: [],\n inputValue: '',\n isLoading: false,\n error: null,\n sessionId: null,\n chatMode: 'ai',\n };\n \n // Initialize ChatService\n this.chatService = createChatService({\n baseUrl: this.config.backendBaseUrl || 'http://localhost:8012',\n wsUrl: this.config.backendWsUrl || 'ws://localhost:8012',\n debug: this.config.debug || false,\n });\n \n // Load chat mode and chat IDs from localStorage if available (SSR-safe)\n const storage = safeLocalStorage();\n const savedMode = storage.getItem('blockspark_chat_mode');\n if (savedMode) {\n this.chatMode = savedMode === 'HUMAN' ? 'human' : 'ai';\n this.state.chatMode = this.chatMode;\n }\n \n this.chatId = storage.getItem('blockspark_chat_id');\n this.supportSessionId = storage.getItem('blockspark_session_id');\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(listener: (state: WidgetState) => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Get current state\n */\n getState(): WidgetState {\n return { ...this.state };\n }\n\n /**\n * Update state and notify listeners\n */\n private setState(updates: Partial<WidgetState>): void {\n this.state = { ...this.state, ...updates };\n this.listeners.forEach(listener => listener(this.getState()));\n }\n\n /**\n * Update configuration\n */\n updateConfig(config: Partial<WidgetConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Open chat\n */\n async openChat(): Promise<void> {\n this.setState({ isOpen: true });\n if (this.state.showWelcomePopup) {\n this.setState({ showWelcomePopup: false });\n }\n \n // Initialize Dialogflow session when chat opens (if in AI mode and no session exists)\n if (this.state.chatMode === 'ai' && !this.state.sessionId && this.config.dfProjectId && this.config.dfAgentId) {\n try {\n this.setState({ isLoading: true });\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n \n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ \n sessionId: session.session_id,\n isLoading: false,\n });\n \n // Add welcome message from Dialogflow if available\n if (session.message) {\n const welcomeMessage: ChatMessage = {\n id: `welcome-${Date.now()}`,\n text: session.message,\n sender: 'bot',\n timestamp: new Date(),\n richContent: session.richContent,\n };\n this.setState({\n messages: [welcomeMessage],\n });\n }\n } catch (error: any) {\n console.error('Error initializing Dialogflow session:', error);\n this.setState({ \n isLoading: false,\n error: error.message || 'Failed to initialize chat',\n });\n \n // Show fallback welcome message\n const fallbackMessage: ChatMessage = {\n id: `fallback-${Date.now()}`,\n text: this.config.fallbackWelcomeMessage || 'Hello! How can I help you today?',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [fallbackMessage],\n });\n }\n }\n }\n\n /**\n * Close chat\n */\n closeChat(): void {\n this.setState({ isOpen: false });\n }\n\n /**\n * Close welcome popup\n */\n closeWelcomePopup(): void {\n this.setState({ showWelcomePopup: false });\n }\n\n /**\n * Toggle chat\n */\n toggleChat(): void {\n const willBeOpen = !this.state.isOpen;\n this.setState({ isOpen: willBeOpen });\n if (willBeOpen && this.state.showWelcomePopup) {\n this.setState({ showWelcomePopup: false });\n }\n }\n\n /**\n * Set input value\n */\n setInputValue(value: string): void {\n this.setState({ inputValue: value });\n }\n\n /**\n * Clear error\n */\n clearError(): void {\n this.setState({ error: null });\n }\n\n /**\n * Send message\n */\n async sendMessage(text: string, skipUserMessage: boolean = false): Promise<void> {\n if (!text.trim() || this.state.isLoading) {\n return;\n }\n\n // Handle user info collection for handoff\n if (this.collectingUserInfo) {\n // Add user message first so it appears in chat\n const userMessage: ChatMessage = {\n id: `user-${Date.now()}`,\n text: text.trim(),\n sender: 'user',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, userMessage],\n inputValue: '',\n isLoading: false,\n error: null,\n });\n \n // Then handle the info collection\n await this.handleUserInfoCollection(text);\n return;\n }\n\n // Add user message unless skipped (e.g., when chip button already added it)\n if (!skipUserMessage) {\n const userMessage: ChatMessage = {\n id: `user-${Date.now()}`,\n text: text.trim(),\n sender: 'user',\n timestamp: new Date(),\n };\n\n this.setState({\n messages: [...this.state.messages, userMessage],\n inputValue: '',\n isLoading: true,\n error: null,\n });\n } else {\n this.setState({\n inputValue: '',\n isLoading: true,\n error: null,\n });\n }\n\n try {\n if (this.state.chatMode === 'human') {\n // Human support mode\n await this.sendHumanMessage(text);\n } else {\n // AI mode (Dialogflow)\n await this.sendAIMessage(text);\n }\n } catch (error: any) {\n console.error('Error sending message:', error);\n \n // chat_resolved is a normal terminal condition, not an error\n if (error instanceof ChatResolvedError || error?.name === 'ChatResolvedError' || error?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n \n // Add error message to chat\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: this.config.debug \n ? `Error: ${error.message || 'Failed to send message'}`\n : error.message?.includes('CORS') || error.message?.includes('Failed to fetch')\n ? 'Unable to connect to Dialogflow. Please check your configuration and network.'\n : 'Sorry, I\\'m having trouble processing your message. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n \n this.setState({\n messages: [...this.state.messages, errorMessage],\n error: error.message || 'Failed to send message',\n isLoading: false,\n });\n }\n }\n\n /**\n * Send message to Dialogflow\n */\n private async sendAIMessage(text: string): Promise<void> {\n if (!this.config.dfProjectId || !this.config.dfAgentId) {\n throw new Error('Dialogflow configuration is missing');\n }\n\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId!,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId!,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n\n // Create session if needed\n if (!this.state.sessionId) {\n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ sessionId: session.session_id });\n }\n\n // Send message (correct parameter order: message, sessionId, config)\n if (this.config.debug) {\n console.log('Sending message to Dialogflow:', {\n message: text,\n sessionId: this.state.sessionId,\n hasConfig: !!dialogflowConfig,\n });\n }\n \n const response = await sendDialogflowMessage(\n text,\n this.state.sessionId!,\n dialogflowConfig\n );\n\n if (this.config.debug) {\n console.log('Dialogflow response:', {\n response: response.response,\n hasRichContent: !!response.richContent,\n richContent: response.richContent,\n });\n }\n\n // Check for handoff\n if (response.handoff === true) {\n // Add bot response first\n const botMessage: ChatMessage = {\n id: `bot-${Date.now()}`,\n text: response.response || this.config.fallbackWelcomeMessage || 'No response',\n sender: 'bot',\n timestamp: new Date(),\n richContent: response.richContent,\n };\n this.setState({\n messages: [...this.state.messages, botMessage],\n isLoading: false,\n });\n \n // Start collecting user info for handoff\n this.startUserInfoCollection();\n return;\n }\n \n const botMessage: ChatMessage = {\n id: `bot-${Date.now()}`,\n text: response.response || this.config.fallbackWelcomeMessage || 'No response',\n sender: 'bot',\n timestamp: new Date(),\n richContent: response.richContent,\n };\n\n this.setState({\n messages: [...this.state.messages, botMessage],\n isLoading: false,\n });\n }\n\n /**\n * Send message to human support\n */\n private async sendHumanMessage(text: string): Promise<void> {\n if (!this.chatId || !this.supportSessionId) {\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: 'Chat session not initialized. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n isLoading: false,\n });\n return;\n }\n\n if (!this.chatService) {\n throw new Error('Chat service not initialized');\n }\n\n // Send typing_stop before sending message\n this.chatService.sendTypingIndicator('typing_stop');\n if (this.typingTimeout) {\n clearTimeout(this.typingTimeout);\n this.typingTimeout = null;\n }\n\n try {\n // Try WebSocket first, fallback to REST API\n const sentViaWs = this.chatService.sendMessageViaWebSocket(text.trim());\n \n if (!sentViaWs) {\n // Fallback to REST API\n await this.chatService.sendMessageToAgent(this.chatId, this.supportSessionId, text.trim());\n }\n \n this.setState({ isLoading: false });\n } catch (error: any) {\n // chat_resolved is a normal terminal condition, not an error\n if (error instanceof ChatResolvedError || error?.name === 'ChatResolvedError' || error?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n\n // Handle 401/404 - clear chat_id and reinitialize\n if (error.message?.includes('Chat not found') ||\n error.message?.includes('unauthorized') ||\n error.message?.includes('401') ||\n error.message?.includes('404')) {\n if (this.config.debug) {\n console.log('⚠️ Chat expired. Re-initializing...');\n }\n \n // Clear chat_id\n this.chatId = null;\n this.supportSessionId = null;\n const storage = safeLocalStorage();\n storage.removeItem('blockspark_chat_id');\n storage.removeItem('blockspark_session_id');\n \n // Try to reinitialize chat\n try {\n const newSession = await this.chatService.startSupportChat(\n this.state.sessionId || null,\n null,\n null,\n null\n );\n this.chatId = newSession.chat_id;\n this.supportSessionId = newSession.session_id;\n const storage1 = safeLocalStorage();\n storage1.setItem('blockspark_chat_id', this.chatId);\n storage1.setItem('blockspark_session_id', this.supportSessionId);\n \n // Retry sending message\n if (this.chatId && this.supportSessionId) {\n await this.chatService.sendMessageToAgent(\n this.chatId,\n this.supportSessionId,\n text.trim()\n );\n }\n this.setState({ isLoading: false });\n return;\n } catch (retryError: any) {\n if (retryError instanceof ChatResolvedError || retryError?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n throw retryError;\n }\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Switch to human mode\n */\n switchToHumanMode(): void {\n this.chatMode = 'human';\n this.setState({ chatMode: 'human' });\n safeLocalStorage().setItem('blockspark_chat_mode', 'HUMAN');\n }\n\n /**\n * Switch to AI mode\n */\n switchToBotMode(): void {\n this.chatMode = 'ai';\n this.setState({ chatMode: 'ai' });\n safeLocalStorage().setItem('blockspark_chat_mode', 'BOT');\n }\n\n /**\n * Initialize welcome popup\n */\n initializeWelcomePopup(): void {\n if (this.config.showWelcomePopup !== false) {\n const delay = this.config.welcomePopupDelay || 1500;\n setTimeout(() => {\n if (!this.state.isOpen) {\n this.setState({ showWelcomePopup: true });\n }\n }, delay);\n }\n }\n\n /**\n * Start user info collection for handoff\n */\n private startUserInfoCollection(): void {\n this.collectingUserInfo = true;\n this.userInfoStep = 'name';\n this.collectedUserName = '';\n this.collectedUserEmail = '';\n this.collectedUserMobile = '';\n \n // Add initial handoff message with better formatting\n const handoffMessage: ChatMessage = {\n id: `handoff-${Date.now()}`,\n text: '👤 You\\'re being connected to a live support agent. Please wait while we transfer your conversation...',\n sender: 'bot',\n timestamp: new Date(),\n };\n \n // Ask for name\n const namePrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'To connect you with a human agent, I\\'ll need some information.\\n\\nPlease provide your name:',\n sender: 'bot',\n timestamp: new Date(),\n };\n \n this.setState({\n messages: [...this.state.messages, handoffMessage, namePrompt],\n });\n }\n\n /**\n * Handle user info collection\n */\n private async handleUserInfoCollection(text: string): Promise<void> {\n if (this.userInfoStep === 'name') {\n // Save name and ask for email\n const name = text.trim();\n this.collectedUserName = name;\n this.userInfoStep = 'email';\n \n // Ask for email\n const emailPrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: '✅ Thank you! Now please provide your email address:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, emailPrompt],\n inputValue: '',\n });\n return;\n } else if (this.userInfoStep === 'email') {\n // Validate email format\n const email = text.trim();\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n \n if (!emailRegex.test(email)) {\n // Invalid email, ask again\n const invalidEmailMessage: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Please provide a valid email address:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, invalidEmailMessage],\n inputValue: '',\n });\n return;\n }\n \n // Save email and ask for mobile\n this.collectedUserEmail = email;\n this.userInfoStep = 'mobile';\n \n // Ask for mobile\n const mobilePrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: '✅ Thank you! Now please provide your mobile number:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, mobilePrompt],\n inputValue: '',\n });\n return;\n } else if (this.userInfoStep === 'mobile') {\n // Validate mobile format\n const mobile = text.trim();\n const mobileRegex = /^[\\+]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[0-9]{1,9}$/;\n \n if (!mobileRegex.test(mobile) || mobile.length < 10) {\n // Invalid mobile, ask again\n const invalidMobileMessage: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Please provide a valid mobile number (e.g., +1234567890):',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, invalidMobileMessage],\n inputValue: '',\n });\n return;\n }\n \n // Save mobile and proceed with handoff\n this.collectedUserMobile = mobile;\n \n // Reset collection state\n this.collectingUserInfo = false;\n this.userInfoStep = null;\n \n // Proceed with handoff using collected info\n await this.handleHandoff(this.collectedUserName, this.collectedUserEmail, mobile);\n this.setState({ inputValue: '' });\n }\n }\n\n /**\n * Handle handoff from Dialogflow to human support\n */\n async handleHandoff(customerName?: string, customerEmail?: string, customerMobile?: string): Promise<void> {\n if (!this.chatService) {\n throw new Error('Chat service not initialized');\n }\n\n try {\n this.isConnectingToAgent = true;\n \n // Get Dialogflow session ID if available\n const dialogflowSessionId = this.state.sessionId;\n \n // STEP 1: Ensure chat is initialized\n const session = await this.chatService.ensureChatInitialized(\n this.chatId,\n this.supportSessionId,\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!session || !session.chat_id) {\n throw new Error('Failed to initialize chat session');\n }\n \n const currentChatId = session.chat_id;\n const currentSupportSessionId = session.session_id;\n \n // Update state if chat was newly initialized\n if (currentChatId !== this.chatId) {\n this.chatId = currentChatId;\n this.supportSessionId = currentSupportSessionId;\n const storage = safeLocalStorage();\n storage.setItem('blockspark_chat_id', this.chatId);\n storage.setItem('blockspark_session_id', this.supportSessionId);\n if (this.config.debug) {\n console.log('✅ Chat initialized:', { chatId: currentChatId, sessionId: currentSupportSessionId });\n }\n }\n\n // STEP 2: Request handoff\n try {\n await this.chatService.requestHandoff(\n currentChatId,\n currentSupportSessionId,\n 'Customer requested human agent',\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (this.config.debug) {\n console.log('✅ Handoff requested successfully');\n }\n } catch (handoffError: any) {\n // Handle 401/404 or \"chat not found\" - clear chat_id and retry\n if (handoffError.message?.includes('Invalid chat_id') || \n handoffError.message?.includes('Chat not found') ||\n handoffError.message?.includes('unauthorized') ||\n handoffError.message?.includes('400') ||\n handoffError.message?.includes('401') ||\n handoffError.message?.includes('404') ||\n handoffError.message?.includes('expired')) {\n if (this.config.debug) {\n console.log('⚠️ Chat expired or not found. Re-initializing chat...');\n }\n \n // Clear old chat_id\n this.chatId = null;\n this.supportSessionId = null;\n const storage2 = safeLocalStorage();\n storage2.removeItem('blockspark_chat_id');\n storage2.removeItem('blockspark_session_id');\n \n // Create new chat session\n const newSession = await this.chatService.startSupportChat(\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!newSession || !newSession.chat_id) {\n throw new Error('Failed to re-initialize chat session');\n }\n \n this.chatId = newSession.chat_id;\n this.supportSessionId = newSession.session_id;\n const storage4 = safeLocalStorage();\n storage4.setItem('blockspark_chat_id', this.chatId);\n storage4.setItem('blockspark_session_id', this.supportSessionId);\n \n // Retry handoff with new chat_id\n await this.chatService.requestHandoff(\n this.chatId,\n this.supportSessionId,\n 'Customer requested human agent',\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (this.config.debug) {\n console.log('✅ Handoff requested successfully after retry');\n }\n } else {\n throw handoffError;\n }\n }\n\n // Switch to human mode\n this.switchToHumanMode();\n this.chatResolved = false;\n this.agentAccepted = false;\n\n // Add connecting message\n const connectingMessage: ChatMessage = {\n id: `connecting-${Date.now()}`,\n text: '🔄 Connecting you to a human agent...',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, connectingMessage],\n });\n\n // Connect WebSocket with handlers\n if (currentChatId && currentSupportSessionId) {\n this.chatService.connectWebSocket(\n currentChatId,\n currentSupportSessionId,\n (message: WebSocketMessage) => {\n this.handleWebSocketMessage(message);\n },\n (connected: boolean) => {\n this.wsConnected = connected;\n }\n );\n }\n \n this.isConnectingToAgent = false;\n } catch (error: any) {\n console.error('Error handling handoff:', error);\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: this.config.debug\n ? `Handoff error: ${error.message}`\n : 'Failed to connect to agent. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n this.isConnectingToAgent = false;\n }\n }\n\n /**\n * Handle WebSocket messages\n */\n private handleWebSocketMessage(message: WebSocketMessage): void {\n switch (message.type) {\n case 'message':\n if (message.content) {\n // Only display messages from agent\n if (message.sender_type === 'agent' || !message.sender_type) {\n const agentMessage: ChatMessage = {\n id: message.id || `agent-${Date.now()}`,\n text: message.content,\n sender: 'agent',\n timestamp: new Date(message.timestamp || Date.now()),\n };\n \n // Avoid duplicate messages\n const existingIds = new Set(this.state.messages.map(m => m.id));\n if (!existingIds.has(agentMessage.id)) {\n this.setState({\n messages: [...this.state.messages, agentMessage],\n });\n }\n \n // Hide typing indicator when message received\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n }\n }\n break;\n\n case 'typing_start':\n if (message.sender_type === 'agent') {\n this.agentTyping = true;\n // Auto-hide after 3 seconds if no message received\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n }\n this.agentTypingTimeout = setTimeout(() => {\n this.agentTyping = false;\n }, 3000);\n }\n break;\n\n case 'typing_stop':\n if (message.sender_type === 'agent') {\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n }\n break;\n\n case 'agent_changed':\n if (message.to_agent) {\n this.currentAgent = {\n id: message.to_agent_id,\n name: message.to_agent,\n };\n\n // Add system message to chat\n const systemMessage: ChatMessage = {\n id: `system-${Date.now()}`,\n text: message.from_agent\n ? `Chat has been transferred from ${message.from_agent} to ${message.to_agent}`\n : `Chat has been transferred to ${message.to_agent}`,\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, systemMessage],\n });\n }\n break;\n\n case 'agent_accepted':\n this.agentAccepted = true;\n this.isConnectingToAgent = false;\n const acceptedMessage: ChatMessage = {\n id: message.id || `agent-accepted-${Date.now()}`,\n text: 'You can chat now, the agent has accepted your request.',\n sender: 'bot',\n timestamp: message.timestamp ? new Date(message.timestamp) : new Date(),\n };\n const existingIds = new Set(this.state.messages.map(m => m.id));\n if (!existingIds.has(acceptedMessage.id)) {\n this.setState({\n messages: [...this.state.messages, acceptedMessage],\n });\n }\n if (message.to_agent) {\n this.currentAgent = {\n name: message.to_agent,\n id: message.to_agent_id,\n };\n }\n break;\n\n case 'chat_resolved':\n case 'chat_ended':\n this.enterResolvedState(message.chat_id || null);\n break;\n\n case 'chat_info':\n if (message.status === 'active') {\n this.isConnectingToAgent = false;\n this.agentAccepted = true;\n } else if (message.status === 'resolved' || message.status === 'ended') {\n this.enterResolvedState(message.chat_id || null);\n }\n if (message.agent_id) {\n this.currentAgent = {\n ...this.currentAgent,\n id: message.agent_id,\n };\n }\n break;\n\n case 'error':\n console.error('WebSocket error:', message.error);\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: message.error || 'An error occurred. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n break;\n }\n }\n\n /**\n * Enter resolved state\n */\n private enterResolvedState(resolvedChatId?: string | null): void {\n this.chatResolved = true;\n this.isConnectingToAgent = false;\n this.agentAccepted = false;\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n\n // Stop WS + prevent any reuse of the old chat_id\n if (this.chatService) {\n this.chatService.disconnectWebSocket();\n }\n this.chatId = null;\n this.supportSessionId = null;\n const storage = safeLocalStorage();\n storage.removeItem('blockspark_chat_id');\n storage.removeItem('blockspark_session_id');\n \n // Add thank you message before reset\n const thankYouMessage: ChatMessage = {\n id: `resolved-${Date.now()}`,\n text: 'Thank you for contacting us!',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, thankYouMessage],\n });\n \n // Automatically reset to BOT mode after showing thank you message\n setTimeout(async () => {\n this.switchToBotMode();\n this.chatResolved = false;\n this.setState({\n messages: [],\n sessionId: null, // Clear session ID to force recreation\n });\n this.collectingUserInfo = false;\n this.userInfoStep = null;\n this.collectedUserName = '';\n this.collectedUserEmail = '';\n this.collectedUserMobile = '';\n \n // Recreate Dialogflow session to start fresh\n if (this.config.dfProjectId && this.config.dfAgentId && this.state.isOpen) {\n try {\n this.setState({ isLoading: true });\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n \n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ \n sessionId: session.session_id,\n isLoading: false,\n });\n \n // Add welcome message from Dialogflow if available\n if (session.message) {\n const welcomeMessage: ChatMessage = {\n id: `welcome-${Date.now()}`,\n text: session.message,\n sender: 'bot',\n timestamp: new Date(),\n richContent: session.richContent,\n };\n this.setState({\n messages: [welcomeMessage],\n });\n }\n } catch (error: any) {\n console.error('Error recreating Dialogflow session after handoff:', error);\n this.setState({ \n isLoading: false,\n error: error.message || 'Failed to initialize chat',\n });\n \n // Show fallback welcome message\n const fallbackMessage: ChatMessage = {\n id: `fallback-${Date.now()}`,\n text: this.config.fallbackWelcomeMessage || 'Hello! How can I help you today?',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [fallbackMessage],\n });\n }\n }\n }, 2000);\n }\n\n /**\n * Load message history\n */\n async loadMessageHistory(preserveExisting: boolean = false): Promise<void> {\n if (!this.chatService || !this.chatId || !this.supportSessionId) {\n return;\n }\n\n try {\n if (this.chatId && this.supportSessionId) {\n const history = await this.chatService.loadMessageHistory(this.chatId, this.supportSessionId);\n \n const historyMessages: ChatMessage[] = history.map((msg: any) => ({\n id: msg.id || `history-${Date.now()}-${Math.random()}`,\n text: msg.content,\n sender: msg.sender_type === 'agent' ? 'agent' : 'user',\n timestamp: new Date(msg.timestamp),\n }));\n\n if (preserveExisting) {\n // Merge with existing messages, avoiding duplicates\n const existingIds = new Set(this.state.messages.map(m => m.id));\n const newMessages = historyMessages.filter(m => !existingIds.has(m.id));\n \n // Combine existing messages with new history messages\n // Sort by timestamp to maintain chronological order\n const combined = [...this.state.messages, ...newMessages].sort((a, b) => \n a.timestamp.getTime() - b.timestamp.getTime()\n );\n \n this.setState({\n messages: combined,\n });\n } else {\n // Replace all messages\n this.setState({\n messages: historyMessages,\n });\n }\n }\n } catch (error: any) {\n console.error('Error loading message history:', error);\n if (this.config.debug) {\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: `Failed to load chat history: ${error.message}`,\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n }\n }\n }\n\n /**\n * Get additional state for UI (not in WidgetState but needed by components)\n */\n getAdditionalState() {\n return {\n wsConnected: this.wsConnected,\n agentTyping: this.agentTyping,\n currentAgent: this.currentAgent,\n isConnectingToAgent: this.isConnectingToAgent,\n agentAccepted: this.agentAccepted,\n chatResolved: this.chatResolved,\n };\n }\n\n /**\n * Cleanup\n */\n destroy(): void {\n if (this.typingTimeout) {\n clearTimeout(this.typingTimeout);\n }\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n }\n if (this.chatService) {\n this.chatService.disconnectWebSocket();\n }\n this.listeners.clear();\n }\n}\n"],"names":["botMessage","existingIds"],"mappings":";;;AAkBO,MAAM,mBAAmB;AAAA,EA6B9B,YAAY,QAAsB;AA1BlC,SAAQ,gCAAmD,IAAA;AAC3D,SAAQ,WAA2B;AACnC,SAAQ,SAAwB;AAChC,SAAQ,mBAAkC;AAC1C,SAAQ,cAA2D;AAGnE,SAAQ,qBAA8B;AACtC,SAAQ,eAAmD;AAC3D,SAAQ,oBAA4B;AACpC,SAAQ,qBAA6B;AACrC,SAAQ,sBAA8B;AAGtC,SAAQ,cAAuB;AAC/B,SAAQ,cAAuB;AAC/B,SAAQ,eAA8C,EAAE,MAAM,QAAA;AAC9D,SAAQ,sBAA+B;AACvC,SAAQ,gBAAyB;AACjC,SAAQ,eAAwB;AAChC,SAAQ,gBAA+B;AAGvC,SAAQ,gBAAuC;AAC/C,SAAQ,qBAA4C;AAGlD,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,MACX,QAAQ;AAAA,MACR,kBAAkB;AAAA,MAClB,UAAU,CAAA;AAAA,MACV,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,OAAO;AAAA,MACP,WAAW;AAAA,MACX,UAAU;AAAA,IAAA;AAIZ,SAAK,cAAc,kBAAkB;AAAA,MACnC,SAAS,KAAK,OAAO,kBAAkB;AAAA,MACvC,OAAO,KAAK,OAAO,gBAAgB;AAAA,MACnC,OAAO,KAAK,OAAO,SAAS;AAAA,IAAA,CAC7B;AAGD,UAAM,UAAU,iBAAA;AAChB,UAAM,YAAY,QAAQ,QAAQ,sBAAsB;AACxD,QAAI,WAAW;AACb,WAAK,WAAW,cAAc,UAAU,UAAU;AAClD,WAAK,MAAM,WAAW,KAAK;AAAA,IAC7B;AAEA,SAAK,SAAS,QAAQ,QAAQ,oBAAoB;AAClD,SAAK,mBAAmB,QAAQ,QAAQ,uBAAuB;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,UAAoD;AAC5D,SAAK,UAAU,IAAI,QAAQ;AAC3B,WAAO,MAAM;AACX,WAAK,UAAU,OAAO,QAAQ;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAAwB;AACtB,WAAO,EAAE,GAAG,KAAK,MAAA;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKQ,SAAS,SAAqC;AACpD,SAAK,QAAQ,EAAE,GAAG,KAAK,OAAO,GAAG,QAAA;AACjC,SAAK,UAAU,QAAQ,CAAA,aAAY,SAAS,KAAK,SAAA,CAAU,CAAC;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,QAAqC;AAChD,SAAK,SAAS,EAAE,GAAG,KAAK,QAAQ,GAAG,OAAA;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAA0B;AAC9B,SAAK,SAAS,EAAE,QAAQ,KAAA,CAAM;AAC9B,QAAI,KAAK,MAAM,kBAAkB;AAC/B,WAAK,SAAS,EAAE,kBAAkB,MAAA,CAAO;AAAA,IAC3C;AAGA,QAAI,KAAK,MAAM,aAAa,QAAQ,CAAC,KAAK,MAAM,aAAa,KAAK,OAAO,eAAe,KAAK,OAAO,WAAW;AAC7G,UAAI;AACF,aAAK,SAAS,EAAE,WAAW,KAAA,CAAM;AACjC,cAAM,mBAAqC;AAAA,UACzC,aAAa,KAAK,OAAO;AAAA,UACzB,YAAY,KAAK,OAAO,cAAc;AAAA,UACtC,WAAW,KAAK,OAAO;AAAA,UACvB,mBAAmB,KAAK,OAAO;AAAA,UAC/B,aAAa,KAAK,OAAO;AAAA,UACzB,cAAc,KAAK,OAAO,gBAAgB;AAAA,QAAA;AAG5C,cAAM,UAAU,MAAM,wBAAwB,gBAAgB;AAC9D,aAAK,SAAS;AAAA,UACZ,WAAW,QAAQ;AAAA,UACnB,WAAW;AAAA,QAAA,CACZ;AAGD,YAAI,QAAQ,SAAS;AACnB,gBAAM,iBAA8B;AAAA,YAClC,IAAI,WAAW,KAAK,IAAA,CAAK;AAAA,YACzB,MAAM,QAAQ;AAAA,YACd,QAAQ;AAAA,YACR,+BAAe,KAAA;AAAA,YACf,aAAa,QAAQ;AAAA,UAAA;AAEvB,eAAK,SAAS;AAAA,YACZ,UAAU,CAAC,cAAc;AAAA,UAAA,CAC1B;AAAA,QACH;AAAA,MACF,SAAS,OAAY;AACnB,gBAAQ,MAAM,0CAA0C,KAAK;AAC7D,aAAK,SAAS;AAAA,UACZ,WAAW;AAAA,UACX,OAAO,MAAM,WAAW;AAAA,QAAA,CACzB;AAGD,cAAM,kBAA+B;AAAA,UACnC,IAAI,YAAY,KAAK,IAAA,CAAK;AAAA,UAC1B,MAAM,KAAK,OAAO,0BAA0B;AAAA,UAC5C,QAAQ;AAAA,UACR,+BAAe,KAAA;AAAA,QAAK;AAEtB,aAAK,SAAS;AAAA,UACZ,UAAU,CAAC,eAAe;AAAA,QAAA,CAC3B;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,YAAkB;AAChB,SAAK,SAAS,EAAE,QAAQ,MAAA,CAAO;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA0B;AACxB,SAAK,SAAS,EAAE,kBAAkB,MAAA,CAAO;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,UAAM,aAAa,CAAC,KAAK,MAAM;AAC/B,SAAK,SAAS,EAAE,QAAQ,WAAA,CAAY;AACpC,QAAI,cAAc,KAAK,MAAM,kBAAkB;AAC7C,WAAK,SAAS,EAAE,kBAAkB,MAAA,CAAO;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,OAAqB;AACjC,SAAK,SAAS,EAAE,YAAY,MAAA,CAAO;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,SAAK,SAAS,EAAE,OAAO,KAAA,CAAM;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,MAAc,kBAA2B,OAAsB;AAC/E,QAAI,CAAC,KAAK,KAAA,KAAU,KAAK,MAAM,WAAW;AACxC;AAAA,IACF;AAGA,QAAI,KAAK,oBAAoB;AAE3B,YAAM,cAA2B;AAAA,QAC/B,IAAI,QAAQ,KAAK,IAAA,CAAK;AAAA,QACtB,MAAM,KAAK,KAAA;AAAA,QACX,QAAQ;AAAA,QACR,+BAAe,KAAA;AAAA,MAAK;AAEtB,WAAK,SAAS;AAAA,QACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,WAAW;AAAA,QAC9C,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,OAAO;AAAA,MAAA,CACR;AAGD,YAAM,KAAK,yBAAyB,IAAI;AACxC;AAAA,IACF;AAGA,QAAI,CAAC,iBAAiB;AACpB,YAAM,cAA2B;AAAA,QAC/B,IAAI,QAAQ,KAAK,IAAA,CAAK;AAAA,QACtB,MAAM,KAAK,KAAA;AAAA,QACX,QAAQ;AAAA,QACR,+BAAe,KAAA;AAAA,MAAK;AAGtB,WAAK,SAAS;AAAA,QACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,WAAW;AAAA,QAC9C,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,OAAO;AAAA,MAAA,CACR;AAAA,IACH,OAAO;AACL,WAAK,SAAS;AAAA,QACZ,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,OAAO;AAAA,MAAA,CACR;AAAA,IACH;AAEA,QAAI;AACF,UAAI,KAAK,MAAM,aAAa,SAAS;AAEnC,cAAM,KAAK,iBAAiB,IAAI;AAAA,MAClC,OAAO;AAEL,cAAM,KAAK,cAAc,IAAI;AAAA,MAC/B;AAAA,IACF,SAAS,OAAY;AACnB,cAAQ,MAAM,0BAA0B,KAAK;AAG7C,UAAI,iBAAiB,qBAAqB,OAAO,SAAS,uBAAuB,OAAO,YAAY,iBAAiB;AACnH,aAAK,mBAAmB,KAAK,MAAM;AACnC;AAAA,MACF;AAGA,YAAM,eAA4B;AAAA,QAChC,IAAI,SAAS,KAAK,IAAA,CAAK;AAAA,QACvB,MAAM,KAAK,OAAO,QACd,UAAU,MAAM,WAAW,wBAAwB,KACnD,MAAM,SAAS,SAAS,MAAM,KAAK,MAAM,SAAS,SAAS,iBAAiB,IAC5E,kFACA;AAAA,QACJ,QAAQ;AAAA,QACR,+BAAe,KAAA;AAAA,MAAK;AAGtB,WAAK,SAAS;AAAA,QACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,YAAY;AAAA,QAC/C,OAAO,MAAM,WAAW;AAAA,QACxB,WAAW;AAAA,MAAA,CACZ;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,cAAc,MAA6B;AACvD,QAAI,CAAC,KAAK,OAAO,eAAe,CAAC,KAAK,OAAO,WAAW;AACtD,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AAEA,UAAM,mBAAqC;AAAA,MACzC,aAAa,KAAK,OAAO;AAAA,MACzB,YAAY,KAAK,OAAO,cAAc;AAAA,MACtC,WAAW,KAAK,OAAO;AAAA,MACvB,mBAAmB,KAAK,OAAO;AAAA,MAC/B,aAAa,KAAK,OAAO;AAAA,MACzB,cAAc,KAAK,OAAO,gBAAgB;AAAA,IAAA;AAI5C,QAAI,CAAC,KAAK,MAAM,WAAW;AACzB,YAAM,UAAU,MAAM,wBAAwB,gBAAgB;AAC9D,WAAK,SAAS,EAAE,WAAW,QAAQ,YAAY;AAAA,IACjD;AAGA,QAAI,KAAK,OAAO,OAAO;AACrB,cAAQ,IAAI,kCAAkC;AAAA,QAC5C,SAAS;AAAA,QACT,WAAW,KAAK,MAAM;AAAA,QACtB,WAAW,CAAC,CAAC;AAAA,MAAA,CACd;AAAA,IACH;AAEA,UAAM,WAAW,MAAM;AAAA,MACrB;AAAA,MACA,KAAK,MAAM;AAAA,MACX;AAAA,IAAA;AAGF,QAAI,KAAK,OAAO,OAAO;AACrB,cAAQ,IAAI,wBAAwB;AAAA,QAClC,UAAU,SAAS;AAAA,QACnB,gBAAgB,CAAC,CAAC,SAAS;AAAA,QAC3B,aAAa,SAAS;AAAA,MAAA,CACvB;AAAA,IACH;AAGA,QAAI,SAAS,YAAY,MAAM;AAE7B,YAAMA,cAA0B;AAAA,QAC9B,IAAI,OAAO,KAAK,IAAA,CAAK;AAAA,QACrB,MAAM,SAAS,YAAY,KAAK,OAAO,0BAA0B;AAAA,QACjE,QAAQ;AAAA,QACR,+BAAe,KAAA;AAAA,QACf,aAAa,SAAS;AAAA,MAAA;AAExB,WAAK,SAAS;AAAA,QACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAUA,WAAU;AAAA,QAC7C,WAAW;AAAA,MAAA,CACZ;AAGD,WAAK,wBAAA;AACL;AAAA,IACF;AAEA,UAAM,aAA0B;AAAA,MAC9B,IAAI,OAAO,KAAK,IAAA,CAAK;AAAA,MACrB,MAAM,SAAS,YAAY,KAAK,OAAO,0BAA0B;AAAA,MACjE,QAAQ;AAAA,MACR,+BAAe,KAAA;AAAA,MACf,aAAa,SAAS;AAAA,IAAA;AAGxB,SAAK,SAAS;AAAA,MACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,UAAU;AAAA,MAC7C,WAAW;AAAA,IAAA,CACZ;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBAAiB,MAA6B;AAC1D,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,kBAAkB;AAC1C,YAAM,eAA4B;AAAA,QAChC,IAAI,SAAS,KAAK,IAAA,CAAK;AAAA,QACvB,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,+BAAe,KAAA;AAAA,MAAK;AAEtB,WAAK,SAAS;AAAA,QACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,YAAY;AAAA,QAC/C,WAAW;AAAA,MAAA,CACZ;AACD;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAGA,SAAK,YAAY,oBAAoB,aAAa;AAClD,QAAI,KAAK,eAAe;AACtB,mBAAa,KAAK,aAAa;AAC/B,WAAK,gBAAgB;AAAA,IACvB;AAEA,QAAI;AAEF,YAAM,YAAY,KAAK,YAAY,wBAAwB,KAAK,MAAM;AAEtE,UAAI,CAAC,WAAW;AAEd,cAAM,KAAK,YAAY,mBAAmB,KAAK,QAAQ,KAAK,kBAAkB,KAAK,MAAM;AAAA,MAC3F;AAEA,WAAK,SAAS,EAAE,WAAW,MAAA,CAAO;AAAA,IACpC,SAAS,OAAY;AAEnB,UAAI,iBAAiB,qBAAqB,OAAO,SAAS,uBAAuB,OAAO,YAAY,iBAAiB;AACnH,aAAK,mBAAmB,KAAK,MAAM;AACnC;AAAA,MACF;AAGA,UAAI,MAAM,SAAS,SAAS,gBAAgB,KACxC,MAAM,SAAS,SAAS,cAAc,KACtC,MAAM,SAAS,SAAS,KAAK,KAC7B,MAAM,SAAS,SAAS,KAAK,GAAG;AAClC,YAAI,KAAK,OAAO,OAAO;AACrB,kBAAQ,IAAI,qCAAqC;AAAA,QACnD;AAGA,aAAK,SAAS;AACd,aAAK,mBAAmB;AACxB,cAAM,UAAU,iBAAA;AAChB,gBAAQ,WAAW,oBAAoB;AACvC,gBAAQ,WAAW,uBAAuB;AAG1C,YAAI;AACF,gBAAM,aAAa,MAAM,KAAK,YAAY;AAAA,YACxC,KAAK,MAAM,aAAa;AAAA,YACxB;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAEF,eAAK,SAAS,WAAW;AACzB,eAAK,mBAAmB,WAAW;AACnC,gBAAM,WAAW,iBAAA;AACjB,mBAAS,QAAQ,sBAAsB,KAAK,MAAM;AAClD,mBAAS,QAAQ,yBAAyB,KAAK,gBAAgB;AAG/D,cAAI,KAAK,UAAU,KAAK,kBAAkB;AACxC,kBAAM,KAAK,YAAY;AAAA,cACrB,KAAK;AAAA,cACL,KAAK;AAAA,cACL,KAAK,KAAA;AAAA,YAAK;AAAA,UAEd;AACA,eAAK,SAAS,EAAE,WAAW,MAAA,CAAO;AAClC;AAAA,QACF,SAAS,YAAiB;AACxB,cAAI,sBAAsB,qBAAqB,YAAY,YAAY,iBAAiB;AACtF,iBAAK,mBAAmB,KAAK,MAAM;AACnC;AAAA,UACF;AACA,gBAAM;AAAA,QACR;AAAA,MACF,OAAO;AACL,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA0B;AACxB,SAAK,WAAW;AAChB,SAAK,SAAS,EAAE,UAAU,QAAA,CAAS;AACnC,uBAAmB,QAAQ,wBAAwB,OAAO;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAwB;AACtB,SAAK,WAAW;AAChB,SAAK,SAAS,EAAE,UAAU,KAAA,CAAM;AAChC,uBAAmB,QAAQ,wBAAwB,KAAK;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKA,yBAA+B;AAC7B,QAAI,KAAK,OAAO,qBAAqB,OAAO;AAC1C,YAAM,QAAQ,KAAK,OAAO,qBAAqB;AAC/C,iBAAW,MAAM;AACf,YAAI,CAAC,KAAK,MAAM,QAAQ;AACtB,eAAK,SAAS,EAAE,kBAAkB,KAAA,CAAM;AAAA,QAC1C;AAAA,MACF,GAAG,KAAK;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,0BAAgC;AACtC,SAAK,qBAAqB;AAC1B,SAAK,eAAe;AACpB,SAAK,oBAAoB;AACzB,SAAK,qBAAqB;AAC1B,SAAK,sBAAsB;AAG3B,UAAM,iBAA8B;AAAA,MAClC,IAAI,WAAW,KAAK,IAAA,CAAK;AAAA,MACzB,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,+BAAe,KAAA;AAAA,IAAK;AAItB,UAAM,aAA0B;AAAA,MAC9B,IAAI,UAAU,KAAK,IAAA,CAAK;AAAA,MACxB,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,+BAAe,KAAA;AAAA,IAAK;AAGtB,SAAK,SAAS;AAAA,MACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,gBAAgB,UAAU;AAAA,IAAA,CAC9D;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,yBAAyB,MAA6B;AAClE,QAAI,KAAK,iBAAiB,QAAQ;AAEhC,YAAM,OAAO,KAAK,KAAA;AAClB,WAAK,oBAAoB;AACzB,WAAK,eAAe;AAGpB,YAAM,cAA2B;AAAA,QAC/B,IAAI,UAAU,KAAK,IAAA,CAAK;AAAA,QACxB,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,+BAAe,KAAA;AAAA,MAAK;AAEtB,WAAK,SAAS;AAAA,QACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,WAAW;AAAA,QAC9C,YAAY;AAAA,MAAA,CACb;AACD;AAAA,IACF,WAAW,KAAK,iBAAiB,SAAS;AAExC,YAAM,QAAQ,KAAK,KAAA;AACnB,YAAM,aAAa;AAEnB,UAAI,CAAC,WAAW,KAAK,KAAK,GAAG;AAE3B,cAAM,sBAAmC;AAAA,UACvC,IAAI,UAAU,KAAK,IAAA,CAAK;AAAA,UACxB,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,+BAAe,KAAA;AAAA,QAAK;AAEtB,aAAK,SAAS;AAAA,UACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,mBAAmB;AAAA,UACtD,YAAY;AAAA,QAAA,CACb;AACD;AAAA,MACF;AAGA,WAAK,qBAAqB;AAC1B,WAAK,eAAe;AAGpB,YAAM,eAA4B;AAAA,QAChC,IAAI,UAAU,KAAK,IAAA,CAAK;AAAA,QACxB,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,+BAAe,KAAA;AAAA,MAAK;AAEtB,WAAK,SAAS;AAAA,QACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,YAAY;AAAA,QAC/C,YAAY;AAAA,MAAA,CACb;AACD;AAAA,IACF,WAAW,KAAK,iBAAiB,UAAU;AAEzC,YAAM,SAAS,KAAK,KAAA;AACpB,YAAM,cAAc;AAEpB,UAAI,CAAC,YAAY,KAAK,MAAM,KAAK,OAAO,SAAS,IAAI;AAEnD,cAAM,uBAAoC;AAAA,UACxC,IAAI,UAAU,KAAK,IAAA,CAAK;AAAA,UACxB,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,+BAAe,KAAA;AAAA,QAAK;AAEtB,aAAK,SAAS;AAAA,UACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,oBAAoB;AAAA,UACvD,YAAY;AAAA,QAAA,CACb;AACD;AAAA,MACF;AAGA,WAAK,sBAAsB;AAG3B,WAAK,qBAAqB;AAC1B,WAAK,eAAe;AAGpB,YAAM,KAAK,cAAc,KAAK,mBAAmB,KAAK,oBAAoB,MAAM;AAChF,WAAK,SAAS,EAAE,YAAY,GAAA,CAAI;AAAA,IAClC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAc,cAAuB,eAAwB,gBAAwC;AACzG,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAEA,QAAI;AACF,WAAK,sBAAsB;AAG3B,YAAM,sBAAsB,KAAK,MAAM;AAGvC,YAAM,UAAU,MAAM,KAAK,YAAY;AAAA,QACrC,KAAK;AAAA,QACL,KAAK;AAAA,QACL,uBAAuB;AAAA,QACvB,gBAAgB;AAAA,QAChB,iBAAiB;AAAA,QACjB,kBAAkB;AAAA,MAAA;AAGpB,UAAI,CAAC,WAAW,CAAC,QAAQ,SAAS;AAChC,cAAM,IAAI,MAAM,mCAAmC;AAAA,MACrD;AAEA,YAAM,gBAAgB,QAAQ;AAC9B,YAAM,0BAA0B,QAAQ;AAGxC,UAAI,kBAAkB,KAAK,QAAQ;AACjC,aAAK,SAAS;AACd,aAAK,mBAAmB;AACxB,cAAM,UAAU,iBAAA;AAChB,gBAAQ,QAAQ,sBAAsB,KAAK,MAAM;AACjD,gBAAQ,QAAQ,yBAAyB,KAAK,gBAAgB;AAC9D,YAAI,KAAK,OAAO,OAAO;AACrB,kBAAQ,IAAI,uBAAuB,EAAE,QAAQ,eAAe,WAAW,yBAAyB;AAAA,QAClG;AAAA,MACF;AAGA,UAAI;AACF,cAAM,KAAK,YAAY;AAAA,UACrB;AAAA,UACA;AAAA,UACA;AAAA,UACA,uBAAuB;AAAA,UACvB,gBAAgB;AAAA,UAChB,iBAAiB;AAAA,UACjB,kBAAkB;AAAA,QAAA;AAGpB,YAAI,KAAK,OAAO,OAAO;AACrB,kBAAQ,IAAI,kCAAkC;AAAA,QAChD;AAAA,MACF,SAAS,cAAmB;AAE1B,YAAI,aAAa,SAAS,SAAS,iBAAiB,KAChD,aAAa,SAAS,SAAS,gBAAgB,KAC/C,aAAa,SAAS,SAAS,cAAc,KAC7C,aAAa,SAAS,SAAS,KAAK,KACpC,aAAa,SAAS,SAAS,KAAK,KACpC,aAAa,SAAS,SAAS,KAAK,KACpC,aAAa,SAAS,SAAS,SAAS,GAAG;AAC7C,cAAI,KAAK,OAAO,OAAO;AACrB,oBAAQ,IAAI,uDAAuD;AAAA,UACrE;AAGA,eAAK,SAAS;AACd,eAAK,mBAAmB;AACxB,gBAAM,WAAW,iBAAA;AACjB,mBAAS,WAAW,oBAAoB;AACxC,mBAAS,WAAW,uBAAuB;AAG3C,gBAAM,aAAa,MAAM,KAAK,YAAY;AAAA,YACxC,uBAAuB;AAAA,YACvB,gBAAgB;AAAA,YAChB,iBAAiB;AAAA,YACjB,kBAAkB;AAAA,UAAA;AAGpB,cAAI,CAAC,cAAc,CAAC,WAAW,SAAS;AACtC,kBAAM,IAAI,MAAM,sCAAsC;AAAA,UACxD;AAEA,eAAK,SAAS,WAAW;AACzB,eAAK,mBAAmB,WAAW;AACnC,gBAAM,WAAW,iBAAA;AACjB,mBAAS,QAAQ,sBAAsB,KAAK,MAAM;AAClD,mBAAS,QAAQ,yBAAyB,KAAK,gBAAgB;AAG/D,gBAAM,KAAK,YAAY;AAAA,YACrB,KAAK;AAAA,YACL,KAAK;AAAA,YACL;AAAA,YACA,uBAAuB;AAAA,YACvB,gBAAgB;AAAA,YAChB,iBAAiB;AAAA,YACjB,kBAAkB;AAAA,UAAA;AAGpB,cAAI,KAAK,OAAO,OAAO;AACrB,oBAAQ,IAAI,8CAA8C;AAAA,UAC5D;AAAA,QACF,OAAO;AACL,gBAAM;AAAA,QACR;AAAA,MACF;AAGA,WAAK,kBAAA;AACL,WAAK,eAAe;AACpB,WAAK,gBAAgB;AAGrB,YAAM,oBAAiC;AAAA,QACrC,IAAI,cAAc,KAAK,IAAA,CAAK;AAAA,QAC5B,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,+BAAe,KAAA;AAAA,MAAK;AAEtB,WAAK,SAAS;AAAA,QACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,iBAAiB;AAAA,MAAA,CACrD;AAGD,UAAI,iBAAiB,yBAAyB;AAC5C,aAAK,YAAY;AAAA,UACf;AAAA,UACA;AAAA,UACA,CAAC,YAA8B;AAC7B,iBAAK,uBAAuB,OAAO;AAAA,UACrC;AAAA,UACA,CAAC,cAAuB;AACtB,iBAAK,cAAc;AAAA,UACrB;AAAA,QAAA;AAAA,MAEJ;AAEA,WAAK,sBAAsB;AAAA,IAC7B,SAAS,OAAY;AACnB,cAAQ,MAAM,2BAA2B,KAAK;AAC9C,YAAM,eAA4B;AAAA,QAChC,IAAI,SAAS,KAAK,IAAA,CAAK;AAAA,QACvB,MAAM,KAAK,OAAO,QACd,kBAAkB,MAAM,OAAO,KAC/B;AAAA,QACJ,QAAQ;AAAA,QACR,+BAAe,KAAA;AAAA,MAAK;AAEtB,WAAK,SAAS;AAAA,QACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,YAAY;AAAA,MAAA,CAChD;AACD,WAAK,sBAAsB;AAAA,IAC7B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,uBAAuB,SAAiC;AAC9D,YAAQ,QAAQ,MAAA;AAAA,MACd,KAAK;AACH,YAAI,QAAQ,SAAS;AAEnB,cAAI,QAAQ,gBAAgB,WAAW,CAAC,QAAQ,aAAa;AAC3D,kBAAM,eAA4B;AAAA,cAChC,IAAI,QAAQ,MAAM,SAAS,KAAK,KAAK;AAAA,cACrC,MAAM,QAAQ;AAAA,cACd,QAAQ;AAAA,cACR,WAAW,IAAI,KAAK,QAAQ,aAAa,KAAK,KAAK;AAAA,YAAA;AAIrD,kBAAMC,eAAc,IAAI,IAAI,KAAK,MAAM,SAAS,IAAI,CAAA,MAAK,EAAE,EAAE,CAAC;AAC9D,gBAAI,CAACA,aAAY,IAAI,aAAa,EAAE,GAAG;AACrC,mBAAK,SAAS;AAAA,gBACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,YAAY;AAAA,cAAA,CAChD;AAAA,YACH;AAGA,iBAAK,cAAc;AACnB,gBAAI,KAAK,oBAAoB;AAC3B,2BAAa,KAAK,kBAAkB;AACpC,mBAAK,qBAAqB;AAAA,YAC5B;AAAA,UACF;AAAA,QACF;AACA;AAAA,MAEF,KAAK;AACH,YAAI,QAAQ,gBAAgB,SAAS;AACnC,eAAK,cAAc;AAEnB,cAAI,KAAK,oBAAoB;AAC3B,yBAAa,KAAK,kBAAkB;AAAA,UACtC;AACA,eAAK,qBAAqB,WAAW,MAAM;AACzC,iBAAK,cAAc;AAAA,UACrB,GAAG,GAAI;AAAA,QACT;AACA;AAAA,MAEF,KAAK;AACH,YAAI,QAAQ,gBAAgB,SAAS;AACnC,eAAK,cAAc;AACnB,cAAI,KAAK,oBAAoB;AAC3B,yBAAa,KAAK,kBAAkB;AACpC,iBAAK,qBAAqB;AAAA,UAC5B;AAAA,QACF;AACA;AAAA,MAEF,KAAK;AACH,YAAI,QAAQ,UAAU;AACpB,eAAK,eAAe;AAAA,YAClB,IAAI,QAAQ;AAAA,YACZ,MAAM,QAAQ;AAAA,UAAA;AAIhB,gBAAM,gBAA6B;AAAA,YACjC,IAAI,UAAU,KAAK,IAAA,CAAK;AAAA,YACxB,MAAM,QAAQ,aACV,kCAAkC,QAAQ,UAAU,OAAO,QAAQ,QAAQ,KAC3E,gCAAgC,QAAQ,QAAQ;AAAA,YACpD,QAAQ;AAAA,YACR,+BAAe,KAAA;AAAA,UAAK;AAEtB,eAAK,SAAS;AAAA,YACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,aAAa;AAAA,UAAA,CACjD;AAAA,QACH;AACA;AAAA,MAEF,KAAK;AACH,aAAK,gBAAgB;AACrB,aAAK,sBAAsB;AAC3B,cAAM,kBAA+B;AAAA,UACnC,IAAI,QAAQ,MAAM,kBAAkB,KAAK,KAAK;AAAA,UAC9C,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,WAAW,QAAQ,YAAY,IAAI,KAAK,QAAQ,SAAS,IAAI,oBAAI,KAAA;AAAA,QAAK;AAExE,cAAM,cAAc,IAAI,IAAI,KAAK,MAAM,SAAS,IAAI,CAAA,MAAK,EAAE,EAAE,CAAC;AAC9D,YAAI,CAAC,YAAY,IAAI,gBAAgB,EAAE,GAAG;AACxC,eAAK,SAAS;AAAA,YACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,eAAe;AAAA,UAAA,CACnD;AAAA,QACH;AACA,YAAI,QAAQ,UAAU;AACpB,eAAK,eAAe;AAAA,YAClB,MAAM,QAAQ;AAAA,YACd,IAAI,QAAQ;AAAA,UAAA;AAAA,QAEhB;AACA;AAAA,MAEF,KAAK;AAAA,MACL,KAAK;AACH,aAAK,mBAAmB,QAAQ,WAAW,IAAI;AAC/C;AAAA,MAEF,KAAK;AACH,YAAI,QAAQ,WAAW,UAAU;AAC/B,eAAK,sBAAsB;AAC3B,eAAK,gBAAgB;AAAA,QACvB,WAAW,QAAQ,WAAW,cAAc,QAAQ,WAAW,SAAS;AACtE,eAAK,mBAAmB,QAAQ,WAAW,IAAI;AAAA,QACjD;AACA,YAAI,QAAQ,UAAU;AACpB,eAAK,eAAe;AAAA,YAClB,GAAG,KAAK;AAAA,YACR,IAAI,QAAQ;AAAA,UAAA;AAAA,QAEhB;AACA;AAAA,MAEF,KAAK;AACH,gBAAQ,MAAM,oBAAoB,QAAQ,KAAK;AAC/C,cAAM,eAA4B;AAAA,UAChC,IAAI,SAAS,KAAK,IAAA,CAAK;AAAA,UACvB,MAAM,QAAQ,SAAS;AAAA,UACvB,QAAQ;AAAA,UACR,+BAAe,KAAA;AAAA,QAAK;AAEtB,aAAK,SAAS;AAAA,UACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,YAAY;AAAA,QAAA,CAChD;AACD;AAAA,IAAA;AAAA,EAEN;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAmB,gBAAsC;AAC/D,SAAK,eAAe;AACpB,SAAK,sBAAsB;AAC3B,SAAK,gBAAgB;AACrB,SAAK,cAAc;AACnB,QAAI,KAAK,oBAAoB;AAC3B,mBAAa,KAAK,kBAAkB;AACpC,WAAK,qBAAqB;AAAA,IAC5B;AAGA,QAAI,KAAK,aAAa;AACpB,WAAK,YAAY,oBAAA;AAAA,IACnB;AACA,SAAK,SAAS;AACd,SAAK,mBAAmB;AACxB,UAAM,UAAU,iBAAA;AAChB,YAAQ,WAAW,oBAAoB;AACvC,YAAQ,WAAW,uBAAuB;AAG1C,UAAM,kBAA+B;AAAA,MACnC,IAAI,YAAY,KAAK,IAAA,CAAK;AAAA,MAC1B,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,+BAAe,KAAA;AAAA,IAAK;AAEtB,SAAK,SAAS;AAAA,MACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,eAAe;AAAA,IAAA,CACnD;AAGD,eAAW,YAAY;AACrB,WAAK,gBAAA;AACL,WAAK,eAAe;AACpB,WAAK,SAAS;AAAA,QACZ,UAAU,CAAA;AAAA,QACV,WAAW;AAAA;AAAA,MAAA,CACZ;AACD,WAAK,qBAAqB;AAC1B,WAAK,eAAe;AACpB,WAAK,oBAAoB;AACzB,WAAK,qBAAqB;AAC1B,WAAK,sBAAsB;AAG3B,UAAI,KAAK,OAAO,eAAe,KAAK,OAAO,aAAa,KAAK,MAAM,QAAQ;AACzE,YAAI;AACF,eAAK,SAAS,EAAE,WAAW,KAAA,CAAM;AACjC,gBAAM,mBAAqC;AAAA,YACzC,aAAa,KAAK,OAAO;AAAA,YACzB,YAAY,KAAK,OAAO,cAAc;AAAA,YACtC,WAAW,KAAK,OAAO;AAAA,YACvB,mBAAmB,KAAK,OAAO;AAAA,YAC/B,aAAa,KAAK,OAAO;AAAA,YACzB,cAAc,KAAK,OAAO,gBAAgB;AAAA,UAAA;AAG5C,gBAAM,UAAU,MAAM,wBAAwB,gBAAgB;AAC9D,eAAK,SAAS;AAAA,YACZ,WAAW,QAAQ;AAAA,YACnB,WAAW;AAAA,UAAA,CACZ;AAGD,cAAI,QAAQ,SAAS;AACnB,kBAAM,iBAA8B;AAAA,cAClC,IAAI,WAAW,KAAK,IAAA,CAAK;AAAA,cACzB,MAAM,QAAQ;AAAA,cACd,QAAQ;AAAA,cACR,+BAAe,KAAA;AAAA,cACf,aAAa,QAAQ;AAAA,YAAA;AAEvB,iBAAK,SAAS;AAAA,cACZ,UAAU,CAAC,cAAc;AAAA,YAAA,CAC1B;AAAA,UACH;AAAA,QACF,SAAS,OAAY;AACnB,kBAAQ,MAAM,sDAAsD,KAAK;AACzE,eAAK,SAAS;AAAA,YACZ,WAAW;AAAA,YACX,OAAO,MAAM,WAAW;AAAA,UAAA,CACzB;AAGD,gBAAM,kBAA+B;AAAA,YACnC,IAAI,YAAY,KAAK,IAAA,CAAK;AAAA,YAC1B,MAAM,KAAK,OAAO,0BAA0B;AAAA,YAC5C,QAAQ;AAAA,YACR,+BAAe,KAAA;AAAA,UAAK;AAEtB,eAAK,SAAS;AAAA,YACZ,UAAU,CAAC,eAAe;AAAA,UAAA,CAC3B;AAAA,QACH;AAAA,MACF;AAAA,IACF,GAAG,GAAI;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBAAmB,mBAA4B,OAAsB;AACzE,QAAI,CAAC,KAAK,eAAe,CAAC,KAAK,UAAU,CAAC,KAAK,kBAAkB;AAC/D;AAAA,IACF;AAEA,QAAI;AACF,UAAI,KAAK,UAAU,KAAK,kBAAkB;AACxC,cAAM,UAAU,MAAM,KAAK,YAAY,mBAAmB,KAAK,QAAQ,KAAK,gBAAgB;AAE5F,cAAM,kBAAiC,QAAQ,IAAI,CAAC,SAAc;AAAA,UAChE,IAAI,IAAI,MAAM,WAAW,KAAK,KAAK,IAAI,KAAK,OAAA,CAAQ;AAAA,UACpD,MAAM,IAAI;AAAA,UACV,QAAQ,IAAI,gBAAgB,UAAU,UAAU;AAAA,UAChD,WAAW,IAAI,KAAK,IAAI,SAAS;AAAA,QAAA,EACjC;AAEF,YAAI,kBAAkB;AAEpB,gBAAM,cAAc,IAAI,IAAI,KAAK,MAAM,SAAS,IAAI,CAAA,MAAK,EAAE,EAAE,CAAC;AAC9D,gBAAM,cAAc,gBAAgB,OAAO,CAAA,MAAK,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC;AAItE,gBAAM,WAAW,CAAC,GAAG,KAAK,MAAM,UAAU,GAAG,WAAW,EAAE;AAAA,YAAK,CAAC,GAAG,MACjE,EAAE,UAAU,YAAY,EAAE,UAAU,QAAA;AAAA,UAAQ;AAG9C,eAAK,SAAS;AAAA,YACZ,UAAU;AAAA,UAAA,CACX;AAAA,QACH,OAAO;AAEL,eAAK,SAAS;AAAA,YACZ,UAAU;AAAA,UAAA,CACX;AAAA,QACH;AAAA,MACF;AAAA,IACF,SAAS,OAAY;AACnB,cAAQ,MAAM,kCAAkC,KAAK;AACrD,UAAI,KAAK,OAAO,OAAO;AACrB,cAAM,eAA4B;AAAA,UAChC,IAAI,SAAS,KAAK,IAAA,CAAK;AAAA,UACvB,MAAM,gCAAgC,MAAM,OAAO;AAAA,UACnD,QAAQ;AAAA,UACR,+BAAe,KAAA;AAAA,QAAK;AAEtB,aAAK,SAAS;AAAA,UACZ,UAAU,CAAC,GAAG,KAAK,MAAM,UAAU,YAAY;AAAA,QAAA,CAChD;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqB;AACnB,WAAO;AAAA,MACL,aAAa,KAAK;AAAA,MAClB,aAAa,KAAK;AAAA,MAClB,cAAc,KAAK;AAAA,MACnB,qBAAqB,KAAK;AAAA,MAC1B,eAAe,KAAK;AAAA,MACpB,cAAc,KAAK;AAAA,IAAA;AAAA,EAEvB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACd,QAAI,KAAK,eAAe;AACtB,mBAAa,KAAK,aAAa;AAAA,IACjC;AACA,QAAI,KAAK,oBAAoB;AAC3B,mBAAa,KAAK,kBAAkB;AAAA,IACtC;AACA,QAAI,KAAK,aAAa;AACpB,WAAK,YAAY,oBAAA;AAAA,IACnB;AACA,SAAK,UAAU,MAAA;AAAA,EACjB;AACF;"}
|