@cognitiondesk/widget 1.2.1 → 1.2.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.
@@ -1,4 +1,4 @@
1
- (function(l,f){typeof exports=="object"&&typeof module<"u"?f(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],f):(l=typeof globalThis<"u"?globalThis:l||self,f(l.CognitionDeskWidgetReact={},l.jsxRuntime,l.React))})(this,function(l,f,g){"use strict";const H="https://mounaji-backendv3.onrender.com",T=`
1
+ (function(h,m){typeof exports=="object"&&typeof module<"u"?m(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],m):(h=typeof globalThis<"u"?globalThis:h||self,m(h.CognitionDeskWidgetReact={},h.jsxRuntime,h.React))})(this,function(h,m,g){"use strict";const H="https://mounaji-backendv3.onrender.com",T=`
2
2
  :host {
3
3
  all: initial;
4
4
  font-family: system-ui, sans-serif;
@@ -244,7 +244,7 @@
244
244
  font-size: 16px;
245
245
  }
246
246
  }
247
- `,v={chat:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',close:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',send:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>'};function S(){return"cd_"+Math.random().toString(36).slice(2)+Date.now().toString(36)}let k=class{constructor(t={}){var e,a,s,r,n;if(!t.apiKey)throw new Error("[CognitionDesk] apiKey is required");this._cfg={apiKey:t.apiKey,widgetId:t.widgetId||null,assistantId:t.assistantId||null,backendUrl:t.backendUrl||H,primaryColor:t.primaryColor||"#2563eb",theme:t.theme||"light",botName:t.botName||"AI Assistant",botEmoji:t.botEmoji||"🤖",welcomeMessage:t.welcomeMessage||"Hello! How can I help you today?",placeholder:t.placeholder||"Type a message…",position:t.position||"bottom-right",streaming:t.streaming!==!1,rateLimiting:{enabled:((e=t.rateLimiting)==null?void 0:e.enabled)!==!1,maxMessagesPerSession:((a=t.rateLimiting)==null?void 0:a.maxMessagesPerSession)??0,maxMessagesPerMinute:((s=t.rateLimiting)==null?void 0:s.maxMessagesPerMinute)??0,limitReachedMessage:((r=t.rateLimiting)==null?void 0:r.limitReachedMessage)||"You've reached the message limit for this session.",rateLimitMessage:((n=t.rateLimiting)==null?void 0:n.rateLimitMessage)||"You're sending messages too quickly. Please wait a moment."}},this._sessionId=S(),this._messageCount=0,this._minuteCount=0,this._minuteStart=Date.now(),this._messages=[],this._open=!1,this._loading=!1,this._container=null,this._shadow=null,this._panel=null,this._messagesEl=null,this._textarea=null,this._sendBtn=null,this._viewportHandler=null}mount(t){const e=()=>{const a=t||document.body;this._container=document.createElement("div"),this._container.setAttribute("data-cognitiondesk",""),a.appendChild(this._container),this._shadow=this._container.attachShadow({mode:"open"});const s=document.createElement("style");s.textContent=T,this._shadow.appendChild(s),this._buildDOM(),this._applyTheme(),this._syncViewportMetrics(),this._bindViewportMetrics(),this._bindEvents(),this._cfg.welcomeMessage&&this._appendMessage("assistant",this._cfg.welcomeMessage,!1)};return this._cfg.widgetId?this._fetchWidgetConfig().then(()=>e()).catch(()=>e()):(e(),Promise.resolve(this))}async _fetchWidgetConfig(){var e;const t=`${this._cfg.backendUrl}/platforms/web-widget/public/${this._cfg.widgetId}`;try{const a=await fetch(t);if(!a.ok)return;const{config:s}=await a.json();if(!s)return;s.botName&&!this._userSet("botName")&&(this._cfg.botName=s.botName),s.welcomeMessage&&!this._userSet("welcomeMessage")&&(this._cfg.welcomeMessage=s.welcomeMessage),s.primaryColor&&!this._userSet("primaryColor")&&(this._cfg.primaryColor=s.primaryColor),s.placeholder&&!this._userSet("placeholder")&&(this._cfg.placeholder=s.placeholder),s.assistantId&&!this._cfg.assistantId&&(this._cfg.assistantId=s.assistantId),(e=s.avatar)!=null&&e.value&&!this._userSet("botEmoji")&&(this._cfg.botEmoji=s.avatar.value),s.rateLimiting&&(this._cfg.rateLimiting={...this._cfg.rateLimiting,...s.rateLimiting})}catch{}}_userSet(t){return!1}unmount(){this._unbindViewportMetrics(),this._container&&(this._container.remove(),this._container=null)}open(){var t,e;this._open=!0,this._syncViewportMetrics(),(t=this._panel)==null||t.classList.add("open"),(e=this._textarea)==null||e.focus()}close(){var t;this._open=!1,(t=this._panel)==null||t.classList.remove("open")}toggle(){this._open?this.close():this.open()}clearHistory(){this._messages=[],this._messagesEl&&(this._messagesEl.innerHTML=""),this._cfg.welcomeMessage&&this._appendMessage("assistant",this._cfg.welcomeMessage)}_buildDOM(){const t=document.createElement("div");t.className="cd-root";const e=document.createElement("button");e.className="cd-widget-btn",e.innerHTML=v.chat,e.setAttribute("aria-label","Open chat"),e.style.setProperty("--cd-primary",this._cfg.primaryColor),this._toggleBtn=e;const a=document.createElement("div");a.className="cd-panel",this._panel=a;const s=document.createElement("div");s.className="cd-header",s.innerHTML=`
247
+ `,y={chat:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',close:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',send:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>'};function P(){return"cd_"+Math.random().toString(36).slice(2)+Date.now().toString(36)}let M=class{constructor(t={}){var e,i,s,a,n;if(!t.apiKey)throw new Error("[CognitionDesk] apiKey is required");this._overrides=new Set(t.overrideSettings?Object.keys(t.overrideSettings):[]),this._cfg={apiKey:t.apiKey,widgetId:t.widgetId||null,assistantId:t.assistantId||null,backendUrl:t.backendUrl||H,primaryColor:t.primaryColor||"#2563eb",theme:t.theme||"light",botName:t.botName||"AI Assistant",botEmoji:t.botEmoji||"🤖",welcomeMessage:t.welcomeMessage||"Hello! How can I help you today?",placeholder:t.placeholder||"Type a message…",position:t.position||"bottom-right",streaming:t.streaming!==!1,rateLimiting:{enabled:((e=t.rateLimiting)==null?void 0:e.enabled)!==!1,maxMessagesPerSession:((i=t.rateLimiting)==null?void 0:i.maxMessagesPerSession)??0,maxMessagesPerMinute:((s=t.rateLimiting)==null?void 0:s.maxMessagesPerMinute)??0,limitReachedMessage:((a=t.rateLimiting)==null?void 0:a.limitReachedMessage)||"You've reached the message limit for this session.",rateLimitMessage:((n=t.rateLimiting)==null?void 0:n.rateLimitMessage)||"You're sending messages too quickly. Please wait a moment."},overrideSettings:t.overrideSettings||null},t.overrideSettings&&this._applyOverrides(t.overrideSettings),this._sessionId=P(),this._messageCount=0,this._minuteCount=0,this._minuteStart=Date.now(),this._messages=[],this._open=!1,this._loading=!1,this._container=null,this._shadow=null,this._panel=null,this._messagesEl=null,this._textarea=null,this._sendBtn=null,this._viewportHandler=null,this._refreshPending=!1}mount(t){const e=()=>{const i=t||document.body;this._container=document.createElement("div"),this._container.setAttribute("data-cognitiondesk",""),i.appendChild(this._container),this._shadow=this._container.attachShadow({mode:"open"});const s=document.createElement("style");s.textContent=T,this._shadow.appendChild(s),this._buildDOM(),this._applyConfig(),this._syncViewportMetrics(),this._bindViewportMetrics(),this._bindEvents(),this._cfg.welcomeMessage&&this._appendMessage("assistant",this._cfg.welcomeMessage,!1)};return this._cfg.widgetId?this._fetchWidgetConfig().then(()=>e()).catch(()=>e()):(e(),Promise.resolve(this))}updateSettings(t){if(!t||typeof t!="object")return;const e={...this._cfg.overrideSettings||{},...t};this._cfg.overrideSettings=e,this._overrides=new Set(Object.keys(e)),this._applyOverrides(e),this._applyConfig()}async refreshConfig(){this._cfg.widgetId&&(await this._fetchWidgetConfig(),this._applyConfig())}_userSet(t){return this._overrides.has(t)}async _fetchWidgetConfig(){var e;const t=`${this._cfg.backendUrl}/platforms/web-widget/public/${this._cfg.widgetId}`;try{const i=await fetch(t);if(!i.ok)return;const{config:s}=await i.json();if(!s)return;const a=(n,o)=>{o!=null&&!this._userSet(n)&&(this._cfg[n]=o)};a("botName",s.botName),a("welcomeMessage",s.welcomeMessage),a("primaryColor",s.primaryColor),a("secondaryColor",s.secondaryColor),a("placeholder",s.placeholder),a("theme",s.theme),a("position",s.position),a("style",s.style),a("size",s.size),s.assistantId&&!this._cfg.assistantId&&(this._cfg.assistantId=s.assistantId),(e=s.avatar)!=null&&e.value&&!this._userSet("botEmoji")&&(this._cfg.botEmoji=s.avatar.value),s.rateLimiting&&(this._cfg.rateLimiting={...this._cfg.rateLimiting,...s.rateLimiting}),this._cfg.overrideSettings&&this._applyOverrides(this._cfg.overrideSettings)}catch{}}_applyOverrides(t){for(const[e,i]of Object.entries(t))e==="rateLimiting"&&typeof i=="object"?this._cfg.rateLimiting={...this._cfg.rateLimiting,...i}:this._cfg[e]=i}_applyConfig(){var s,a,n,o,d,c,l;const t=this._cfg.theme==="dark"||this._cfg.theme==="auto"&&((s=window.matchMedia)==null?void 0:s.call(window,"(prefers-color-scheme: dark)").matches);(a=this._root)==null||a.classList.toggle("cd-dark",t),(n=this._root)==null||n.style.setProperty("--cd-primary",this._cfg.primaryColor),(o=this._panel)==null||o.style.setProperty("--cd-primary",this._cfg.primaryColor),(d=this._toggleBtn)==null||d.style.setProperty("--cd-primary",this._cfg.primaryColor);const e=(c=this._shadow)==null?void 0:c.querySelector(".cd-header-avatar");e&&(e.textContent=this._cfg.botEmoji);const i=(l=this._shadow)==null?void 0:l.querySelector(".cd-header-name");i&&(i.textContent=this._cfg.botName),this._textarea&&(this._textarea.placeholder=this._cfg.placeholder)}_silentRefresh(){!this._cfg.widgetId||this._refreshPending||(this._refreshPending=!0,this._fetchWidgetConfig().then(()=>this._applyConfig()).catch(()=>{}).finally(()=>{this._refreshPending=!1}))}unmount(){this._unbindViewportMetrics(),this._container&&(this._container.remove(),this._container=null)}open(){var t,e;this._open=!0,this._syncViewportMetrics(),(t=this._panel)==null||t.classList.add("open"),(e=this._textarea)==null||e.focus(),this._silentRefresh()}close(){var t;this._open=!1,(t=this._panel)==null||t.classList.remove("open")}toggle(){this._open?this.close():this.open()}clearHistory(){this._messages=[],this._messagesEl&&(this._messagesEl.innerHTML=""),this._cfg.welcomeMessage&&this._appendMessage("assistant",this._cfg.welcomeMessage)}_buildDOM(){const t=document.createElement("div");t.className="cd-root";const e=document.createElement("button");e.className="cd-widget-btn",e.innerHTML=y.chat,e.setAttribute("aria-label","Open chat"),e.style.setProperty("--cd-primary",this._cfg.primaryColor),this._toggleBtn=e;const i=document.createElement("div");i.className="cd-panel",this._panel=i;const s=document.createElement("div");s.className="cd-header",s.innerHTML=`
248
248
  <div class="cd-header-avatar">${this._cfg.botEmoji}</div>
249
249
  <div class="cd-header-info">
250
250
  <div class="cd-header-name">${this._escHtml(this._cfg.botName)}</div>
@@ -252,5 +252,5 @@
252
252
  <span class="cd-status-dot"></span> Online
253
253
  </div>
254
254
  </div>
255
- `;const r=document.createElement("button");r.className="cd-close-btn",r.innerHTML=v.close,r.setAttribute("aria-label","Close chat"),s.appendChild(r),this._closeBtn=r;const n=document.createElement("div");n.className="cd-messages",n.setAttribute("role","log"),n.setAttribute("aria-live","polite"),this._messagesEl=n;const d=document.createElement("div");d.className="cd-input-area";const o=document.createElement("textarea");o.className="cd-textarea",o.rows=1,o.placeholder=this._cfg.placeholder,this._textarea=o;const c=document.createElement("button");c.className="cd-send-btn",c.innerHTML=v.send,c.setAttribute("aria-label","Send"),this._sendBtn=c,d.appendChild(o),d.appendChild(c);const p=document.createElement("div");p.className="cd-powered",p.innerHTML='Powered by <a href="https://cognitiondesk.com" target="_blank" rel="noopener">CognitionDesk</a>',a.appendChild(s),a.appendChild(n),a.appendChild(d),a.appendChild(p),t.appendChild(e),t.appendChild(a),this._shadow.appendChild(t),this._root=t}_applyTheme(){var e,a,s;(this._cfg.theme==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":this._cfg.theme)==="dark"&&((e=this._root)==null||e.classList.add("cd-dark")),(a=this._root)==null||a.style.setProperty("--cd-primary",this._cfg.primaryColor),(s=this._panel)==null||s.style.setProperty("--cd-primary",this._cfg.primaryColor)}_bindEvents(){this._toggleBtn.addEventListener("click",()=>this.toggle()),this._closeBtn.addEventListener("click",()=>this.close()),this._sendBtn.addEventListener("click",()=>this._sendMessage()),this._textarea.addEventListener("keydown",t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),this._sendMessage())}),this._textarea.addEventListener("input",()=>{this._textarea.style.height="auto",this._textarea.style.height=Math.min(this._textarea.scrollHeight,120)+"px"}),this._textarea.addEventListener("focus",()=>{this._syncViewportMetrics()})}_bindViewportMetrics(){this._viewportHandler||(this._viewportHandler=()=>this._syncViewportMetrics(),window.addEventListener("resize",this._viewportHandler,{passive:!0}),window.addEventListener("orientationchange",this._viewportHandler),window.visualViewport&&(window.visualViewport.addEventListener("resize",this._viewportHandler),window.visualViewport.addEventListener("scroll",this._viewportHandler)))}_unbindViewportMetrics(){this._viewportHandler&&(window.removeEventListener("resize",this._viewportHandler),window.removeEventListener("orientationchange",this._viewportHandler),window.visualViewport&&(window.visualViewport.removeEventListener("resize",this._viewportHandler),window.visualViewport.removeEventListener("scroll",this._viewportHandler)),this._viewportHandler=null)}_syncViewportMetrics(){const t=this._root||this._container;if(!t)return;const e=window.visualViewport,a=e?e.height:window.innerHeight;t.style.setProperty("--cd-viewport-height",`${Math.round(a)}px`)}async _sendMessage(){var a;const t=this._textarea.value.trim();if(!t||this._loading)return;const e=this._cfg.rateLimiting;if(e!=null&&e.enabled){const s=Date.now();if(s-this._minuteStart>=6e4&&(this._minuteCount=0,this._minuteStart=s),e.maxMessagesPerSession>0&&this._messageCount>=e.maxMessagesPerSession){this._appendMessage("error",e.limitReachedMessage,!1),this._textarea.disabled=!0,this._sendBtn.disabled=!0;return}if(e.maxMessagesPerMinute>0&&this._minuteCount>=e.maxMessagesPerMinute){this._appendMessage("error",e.rateLimitMessage,!1);return}}this._textarea.value="",this._textarea.style.height="auto",this._loading=!0,this._sendBtn.disabled=!0,this._messages.push({role:"user",content:t}),this._appendMessage("user",t,!1),this._messageCount+=1,this._minuteCount+=1;try{if(this._cfg.streaming)await this._callApiStream();else{const s=this._showTyping(),r=await this._callApi();this._removeTyping(s),this._messages.push({role:"assistant",content:r}),this._appendMessage("assistant",r,!0)}}catch(s){if(s.status===429||(a=s.message)!=null&&a.includes("429")){const r=s.rateLimitMessage||(e==null?void 0:e.rateLimitMessage)||"You're sending messages too quickly. Please wait a moment.";this._appendMessage("error",r,!1)}else this._appendMessage("error","Sorry, something went wrong. Please try again.",!1);console.error("[CognitionDesk]",s)}finally{this._loading=!1,(e==null?void 0:e.maxMessagesPerSession)>0&&this._messageCount>=e.maxMessagesPerSession||(this._sendBtn.disabled=!1),this._textarea.focus()}}_buildRequestBody(){return{messages:this._messages,assistantId:this._cfg.assistantId||void 0,userContext:{sessionId:this._sessionId,assistantId:this._cfg.assistantId||void 0,widgetId:this._cfg.widgetId||void 0,platform:"cognitiondesk-widget"}}}async _callApiStream(){const t=`${this._cfg.backendUrl}/chat-apiKeyAuth/stream`,e=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this._cfg.apiKey},body:JSON.stringify({...this._buildRequestBody(),stream:!0})});if(!e.ok){const o=await e.json().catch(()=>({})),c=new Error(o.message||`HTTP ${e.status}`);throw c.status=e.status,c.rateLimitMessage=o.message,c}const a=document.createElement("div");a.className="cd-msg assistant",a.innerHTML='<div class="cd-typing"><span></span><span></span><span></span></div>',this._messagesEl.appendChild(a),this._scrollToBottom();const s=e.body.getReader(),r=new TextDecoder;let n="",d=!1;try{for(;;){const{done:o,value:c}=await s.read();if(o)break;const p=r.decode(c,{stream:!0});for(const u of p.split(`
256
- `)){if(!u.startsWith("data: "))continue;const _=u.slice(6).trim();if(_==="[DONE]")break;let m;try{m=JSON.parse(_)}catch{continue}m.type==="content"&&m.data&&(d||(a.innerHTML="",d=!0),n+=m.data,a.innerHTML=this._renderMarkdown(n),this._scrollToBottom())}}}finally{s.releaseLock()}d||(a.innerHTML=this._renderMarkdown("No response")),n&&this._messages.push({role:"assistant",content:n})}async _callApi(){var s,r,n;const t=`${this._cfg.backendUrl}/chat-apiKeyAuth/chat`,e=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this._cfg.apiKey},body:JSON.stringify(this._buildRequestBody())});if(!e.ok){const d=await e.json().catch(()=>({})),o=new Error(d.message||`HTTP ${e.status}`);throw o.status=e.status,o.rateLimitMessage=d.message,o}const a=await e.json();return a.response||a.message||a.content||((n=(r=(s=a.choices)==null?void 0:s[0])==null?void 0:r.message)==null?void 0:n.content)||"No response"}_appendMessage(t,e,a=!0){const s=document.createElement("div");s.className=`cd-msg ${t}`,a&&t!=="user"?s.innerHTML=this._renderMarkdown(e):s.textContent=e,this._messagesEl.appendChild(s),this._scrollToBottom()}_renderMarkdown(t){if(!t)return"";let e=this._escHtml(t);return e=e.replace(/```[\w]*\n?([\s\S]*?)```/g,(a,s)=>`<pre style="background:#0f172a;color:#e2e8f0;padding:10px;border-radius:6px;font-size:12px;overflow-x:auto;margin:6px 0;white-space:pre-wrap">${s.trim()}</pre>`),e=e.replace(/`([^`]+)`/g,'<code style="background:rgba(0,0,0,.08);padding:1px 5px;border-radius:4px;font-size:.9em">$1</code>'),e=e.replace(/\*\*([^*]+)\*\*/g,"<strong>$1</strong>"),e=e.replace(/__([^_]+)__/g,"<strong>$1</strong>"),e=e.replace(/\*([^*]+)\*/g,"<em>$1</em>"),e=e.replace(/_([^_]+)_/g,"<em>$1</em>"),e=e.replace(/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g,'<a href="$2" target="_blank" rel="noopener" style="color:var(--cd-primary,#2563eb)">$1</a>'),e=e.replace(/\n/g,"<br>"),e}_showTyping(){const t=document.createElement("div");return t.className="cd-msg assistant",t.innerHTML='<div class="cd-typing"><span></span><span></span><span></span></div>',this._messagesEl.appendChild(t),this._scrollToBottom(),t}_removeTyping(t){t==null||t.remove()}_scrollToBottom(){this._messagesEl&&(this._messagesEl.scrollTop=this._messagesEl.scrollHeight)}_escHtml(t){return String(t).replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}};const N=g.forwardRef(function(t,e){const{apiKey:a,widgetId:s,assistantId:r,theme:n="light",primaryColor:d="#2563eb",botName:o="AI Assistant",botEmoji:c="🤖",welcomeMessage:p="Hello! How can I help you today?",placeholder:u="Type a message…",defaultOpen:_=!1,streaming:m=!0,backendUrl:M,maxMessagesPerSession:P=0,maxMessagesPerMinute:j=0,limitReachedMessage:C,rateLimitMessage:E,onOpen:b,onClose:x}=t,h=g.useRef(null),L=g.useRef(null);return g.useImperativeHandle(e,()=>({open:()=>{var i;return(i=h.current)==null?void 0:i.open()},close:()=>{var i;return(i=h.current)==null?void 0:i.close()},toggle:()=>{var i;return(i=h.current)==null?void 0:i.toggle()},clearHistory:()=>{var i;return(i=h.current)==null?void 0:i.clearHistory()}}),[]),g.useEffect(()=>{if(!a){console.error("[CognitionDesk] apiKey prop is required");return}const i=new k({apiKey:a,widgetId:s,assistantId:r,theme:n,primaryColor:d,botName:o,botEmoji:c,welcomeMessage:p,placeholder:u,streaming:m,...M?{backendUrl:M}:{},rateLimiting:{enabled:!0,maxMessagesPerSession:P,maxMessagesPerMinute:j,...C?{limitReachedMessage:C}:{},...E?{rateLimitMessage:E}:{}}});if(b||x){const w=i.open.bind(i),B=i.close.bind(i);i.open=(...y)=>{w(...y),b==null||b()},i.close=(...y)=>{B(...y),x==null||x()}}return Promise.resolve(i.mount(L.current)).then(()=>{h.current=i,_&&i.open()}),()=>{i.unmount(),h.current=null}},[a,s,r]),g.useEffect(()=>{var w;const i=h.current;i&&(i._cfg.theme=n,i._cfg.primaryColor=d,(w=i._applyTheme)==null||w.call(i))},[n,d]),f.jsx("div",{ref:L,"data-cognitiondesk-root":""})});l.CognitionDeskWidget=N,l.CognitionDeskWidgetCore=k,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})});
255
+ `;const a=document.createElement("button");a.className="cd-close-btn",a.innerHTML=y.close,a.setAttribute("aria-label","Close chat"),s.appendChild(a),this._closeBtn=a;const n=document.createElement("div");n.className="cd-messages",n.setAttribute("role","log"),n.setAttribute("aria-live","polite"),this._messagesEl=n;const o=document.createElement("div");o.className="cd-input-area";const d=document.createElement("textarea");d.className="cd-textarea",d.rows=1,d.placeholder=this._cfg.placeholder,this._textarea=d;const c=document.createElement("button");c.className="cd-send-btn",c.innerHTML=y.send,c.setAttribute("aria-label","Send"),this._sendBtn=c,o.appendChild(d),o.appendChild(c);const l=document.createElement("div");l.className="cd-powered",l.innerHTML='Powered by <a href="https://cognitiondesk.com" target="_blank" rel="noopener">CognitionDesk</a>',i.appendChild(s),i.appendChild(n),i.appendChild(o),i.appendChild(l),t.appendChild(e),t.appendChild(i),this._shadow.appendChild(t),this._root=t}_applyTheme(){var e,i,s;(this._cfg.theme==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":this._cfg.theme)==="dark"&&((e=this._root)==null||e.classList.add("cd-dark")),(i=this._root)==null||i.style.setProperty("--cd-primary",this._cfg.primaryColor),(s=this._panel)==null||s.style.setProperty("--cd-primary",this._cfg.primaryColor)}_bindEvents(){this._toggleBtn.addEventListener("click",()=>this.toggle()),this._closeBtn.addEventListener("click",()=>this.close()),this._sendBtn.addEventListener("click",()=>this._sendMessage()),this._textarea.addEventListener("keydown",t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),this._sendMessage())}),this._textarea.addEventListener("input",()=>{this._textarea.style.height="auto",this._textarea.style.height=Math.min(this._textarea.scrollHeight,120)+"px"}),this._textarea.addEventListener("focus",()=>{this._syncViewportMetrics()})}_bindViewportMetrics(){this._viewportHandler||(this._viewportHandler=()=>this._syncViewportMetrics(),window.addEventListener("resize",this._viewportHandler,{passive:!0}),window.addEventListener("orientationchange",this._viewportHandler),window.visualViewport&&(window.visualViewport.addEventListener("resize",this._viewportHandler),window.visualViewport.addEventListener("scroll",this._viewportHandler)))}_unbindViewportMetrics(){this._viewportHandler&&(window.removeEventListener("resize",this._viewportHandler),window.removeEventListener("orientationchange",this._viewportHandler),window.visualViewport&&(window.visualViewport.removeEventListener("resize",this._viewportHandler),window.visualViewport.removeEventListener("scroll",this._viewportHandler)),this._viewportHandler=null)}_syncViewportMetrics(){const t=this._root||this._container;if(!t)return;const e=window.visualViewport,i=e?e.height:window.innerHeight;t.style.setProperty("--cd-viewport-height",`${Math.round(i)}px`)}async _sendMessage(){var i;const t=this._textarea.value.trim();if(!t||this._loading)return;const e=this._cfg.rateLimiting;if(e!=null&&e.enabled){const s=Date.now();if(s-this._minuteStart>=6e4&&(this._minuteCount=0,this._minuteStart=s),e.maxMessagesPerSession>0&&this._messageCount>=e.maxMessagesPerSession){this._appendMessage("error",e.limitReachedMessage,!1),this._textarea.disabled=!0,this._sendBtn.disabled=!0;return}if(e.maxMessagesPerMinute>0&&this._minuteCount>=e.maxMessagesPerMinute){this._appendMessage("error",e.rateLimitMessage,!1);return}}this._textarea.value="",this._textarea.style.height="auto",this._loading=!0,this._sendBtn.disabled=!0,this._messages.push({role:"user",content:t}),this._appendMessage("user",t,!1),this._messageCount+=1,this._minuteCount+=1;try{if(this._cfg.streaming)await this._callApiStream();else{const s=this._showTyping(),a=await this._callApi();this._removeTyping(s),this._messages.push({role:"assistant",content:a}),this._appendMessage("assistant",a,!0)}}catch(s){if(s.status===429||(i=s.message)!=null&&i.includes("429")){const a=s.rateLimitMessage||(e==null?void 0:e.rateLimitMessage)||"You're sending messages too quickly. Please wait a moment.";this._appendMessage("error",a,!1)}else this._appendMessage("error","Sorry, something went wrong. Please try again.",!1);console.error("[CognitionDesk]",s)}finally{this._loading=!1,(e==null?void 0:e.maxMessagesPerSession)>0&&this._messageCount>=e.maxMessagesPerSession||(this._sendBtn.disabled=!1),this._textarea.focus()}}_buildRequestBody(){return{messages:this._messages,assistantId:this._cfg.assistantId||void 0,userContext:{sessionId:this._sessionId,assistantId:this._cfg.assistantId||void 0,widgetId:this._cfg.widgetId||void 0,platform:"cognitiondesk-widget"}}}async _callApiStream(){const t=`${this._cfg.backendUrl}/chat-apiKeyAuth/stream`,e=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this._cfg.apiKey},body:JSON.stringify({...this._buildRequestBody(),stream:!0})});if(!e.ok){const d=await e.json().catch(()=>({})),c=new Error(d.message||`HTTP ${e.status}`);throw c.status=e.status,c.rateLimitMessage=d.message,c}const i=document.createElement("div");i.className="cd-msg assistant",i.innerHTML='<div class="cd-typing"><span></span><span></span><span></span></div>',this._messagesEl.appendChild(i),this._scrollToBottom();const s=e.body.getReader(),a=new TextDecoder;let n="",o=!1;try{for(;;){const{done:d,value:c}=await s.read();if(d)break;const l=a.decode(c,{stream:!0});for(const _ of l.split(`
256
+ `)){if(!_.startsWith("data: "))continue;const b=_.slice(6).trim();if(b==="[DONE]")break;let f;try{f=JSON.parse(b)}catch{continue}f.type==="content"&&f.data&&(o||(i.innerHTML="",o=!0),n+=f.data,i.innerHTML=this._renderMarkdown(n),this._scrollToBottom())}}}finally{s.releaseLock()}o||(i.innerHTML=this._renderMarkdown("No response")),n&&this._messages.push({role:"assistant",content:n})}async _callApi(){var s,a,n;const t=`${this._cfg.backendUrl}/chat-apiKeyAuth/chat`,e=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this._cfg.apiKey},body:JSON.stringify(this._buildRequestBody())});if(!e.ok){const o=await e.json().catch(()=>({})),d=new Error(o.message||`HTTP ${e.status}`);throw d.status=e.status,d.rateLimitMessage=o.message,d}const i=await e.json();return i.response||i.message||i.content||((n=(a=(s=i.choices)==null?void 0:s[0])==null?void 0:a.message)==null?void 0:n.content)||"No response"}_appendMessage(t,e,i=!0){const s=document.createElement("div");s.className=`cd-msg ${t}`,i&&t!=="user"?s.innerHTML=this._renderMarkdown(e):s.textContent=e,this._messagesEl.appendChild(s),this._scrollToBottom()}_renderMarkdown(t){if(!t)return"";let e=this._escHtml(t);return e=e.replace(/```[\w]*\n?([\s\S]*?)```/g,(i,s)=>`<pre style="background:#0f172a;color:#e2e8f0;padding:10px;border-radius:6px;font-size:12px;overflow-x:auto;margin:6px 0;white-space:pre-wrap">${s.trim()}</pre>`),e=e.replace(/`([^`]+)`/g,'<code style="background:rgba(0,0,0,.08);padding:1px 5px;border-radius:4px;font-size:.9em">$1</code>'),e=e.replace(/\*\*([^*]+)\*\*/g,"<strong>$1</strong>"),e=e.replace(/__([^_]+)__/g,"<strong>$1</strong>"),e=e.replace(/\*([^*]+)\*/g,"<em>$1</em>"),e=e.replace(/_([^_]+)_/g,"<em>$1</em>"),e=e.replace(/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g,'<a href="$2" target="_blank" rel="noopener" style="color:var(--cd-primary,#2563eb)">$1</a>'),e=e.replace(/\n/g,"<br>"),e}_showTyping(){const t=document.createElement("div");return t.className="cd-msg assistant",t.innerHTML='<div class="cd-typing"><span></span><span></span><span></span></div>',this._messagesEl.appendChild(t),this._scrollToBottom(),t}_removeTyping(t){t==null||t.remove()}_scrollToBottom(){this._messagesEl&&(this._messagesEl.scrollTop=this._messagesEl.scrollHeight)}_escHtml(t){return String(t).replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}};const j=g.forwardRef(function(t,e){const{apiKey:i,widgetId:s,assistantId:a,theme:n="light",primaryColor:o="#2563eb",botName:d="AI Assistant",botEmoji:c="🤖",welcomeMessage:l="Hello! How can I help you today?",placeholder:_="Type a message…",defaultOpen:b=!1,streaming:f=!0,backendUrl:C,maxMessagesPerSession:N=0,maxMessagesPerMinute:z=0,limitReachedMessage:E,rateLimitMessage:L,onOpen:v,onClose:x,overrideSettings:u}=t,p=g.useRef(null),S=g.useRef(null);return g.useImperativeHandle(e,()=>({open:()=>{var r;return(r=p.current)==null?void 0:r.open()},close:()=>{var r;return(r=p.current)==null?void 0:r.close()},toggle:()=>{var r;return(r=p.current)==null?void 0:r.toggle()},clearHistory:()=>{var r;return(r=p.current)==null?void 0:r.clearHistory()}}),[]),g.useEffect(()=>{if(!i){console.error("[CognitionDesk] apiKey prop is required");return}const r=new M({apiKey:i,widgetId:s,assistantId:a,theme:n,primaryColor:o,botName:d,botEmoji:c,welcomeMessage:l,placeholder:_,streaming:f,...C?{backendUrl:C}:{},...u?{overrideSettings:u}:{},rateLimiting:{enabled:!0,maxMessagesPerSession:N,maxMessagesPerMinute:z,...E?{limitReachedMessage:E}:{},...L?{rateLimitMessage:L}:{}}});if(v||x){const w=r.open.bind(r),B=r.close.bind(r);r.open=(...k)=>{w(...k),v==null||v()},r.close=(...k)=>{B(...k),x==null||x()}}return Promise.resolve(r.mount(S.current)).then(()=>{p.current=r,b&&r.open()}),()=>{r.unmount(),p.current=null}},[i,s,a]),g.useEffect(()=>{var w;const r=p.current;r&&(r._cfg.theme=n,r._cfg.primaryColor=o,(w=r._applyConfig)==null||w.call(r))},[n,o]),g.useEffect(()=>{const r=p.current;!r||!u||r.updateSettings(u)},[u]),m.jsx("div",{ref:S,"data-cognitiondesk-root":""})});h.CognitionDeskWidget=j,h.CognitionDeskWidgetCore=M,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})});
package/dist/widget.es.js CHANGED
@@ -252,53 +252,112 @@ const u = "https://mounaji-backendv3.onrender.com", _ = `
252
252
  function b() {
253
253
  return "cd_" + Math.random().toString(36).slice(2) + Date.now().toString(36);
254
254
  }
255
- class f {
255
+ class m {
256
+ /**
257
+ * @param {Object} config
258
+ * @param {string} config.apiKey - Required. Your CognitionDesk API key.
259
+ * @param {string} [config.widgetId] - Widget ID from the dashboard. Enables remote config.
260
+ * @param {string} [config.assistantId] - Assistant ID (overrides server value if set).
261
+ * @param {string} [config.backendUrl] - Custom backend URL.
262
+ * @param {string} [config.theme] - 'light' | 'dark' | 'auto'
263
+ * @param {string} [config.primaryColor] - Hex color for buttons / header.
264
+ * @param {string} [config.botName] - Display name shown in the header.
265
+ * @param {string} [config.botEmoji] - Emoji shown as avatar.
266
+ * @param {string} [config.welcomeMessage] - First message shown to the user.
267
+ * @param {string} [config.placeholder] - Textarea placeholder text.
268
+ * @param {string} [config.position] - 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
269
+ * @param {boolean} [config.streaming] - Enable streaming responses (default: true).
270
+ * @param {Object} [config.overrideSettings]
271
+ * Explicit code-level overrides. Any key listed here takes precedence over
272
+ * the server-side dashboard config. Use this when you want to manage
273
+ * specific settings from code rather than the CognitionDesk dashboard.
274
+ *
275
+ * Example — let the dashboard control everything except color:
276
+ * overrideSettings: { primaryColor: '#e11d48' }
277
+ *
278
+ * Example — full code control (dashboard settings ignored):
279
+ * overrideSettings: {
280
+ * primaryColor: '#e11d48', botName: 'Aria', welcomeMessage: 'Hi!'
281
+ * }
282
+ *
283
+ * When omitted (default), ALL settings come from the dashboard.
284
+ */
256
285
  constructor(e = {}) {
257
286
  var t, a, s, i, r;
258
287
  if (!e.apiKey) throw new Error("[CognitionDesk] apiKey is required");
259
- this._cfg = {
288
+ this._overrides = new Set(
289
+ e.overrideSettings ? Object.keys(e.overrideSettings) : []
290
+ ), this._cfg = {
260
291
  apiKey: e.apiKey,
261
292
  widgetId: e.widgetId || null,
262
293
  assistantId: e.assistantId || null,
263
294
  backendUrl: e.backendUrl || u,
264
295
  primaryColor: e.primaryColor || "#2563eb",
265
296
  theme: e.theme || "light",
266
- // 'light' | 'dark' | 'auto'
267
297
  botName: e.botName || "AI Assistant",
268
298
  botEmoji: e.botEmoji || "🤖",
269
299
  welcomeMessage: e.welcomeMessage || "Hello! How can I help you today?",
270
300
  placeholder: e.placeholder || "Type a message…",
271
301
  position: e.position || "bottom-right",
272
302
  streaming: e.streaming !== !1,
273
- // default: true
274
- // Rate limiting — can be overridden by inline config or merged from server config
275
303
  rateLimiting: {
276
304
  enabled: ((t = e.rateLimiting) == null ? void 0 : t.enabled) !== !1,
277
305
  maxMessagesPerSession: ((a = e.rateLimiting) == null ? void 0 : a.maxMessagesPerSession) ?? 0,
278
306
  maxMessagesPerMinute: ((s = e.rateLimiting) == null ? void 0 : s.maxMessagesPerMinute) ?? 0,
279
307
  limitReachedMessage: ((i = e.rateLimiting) == null ? void 0 : i.limitReachedMessage) || "You've reached the message limit for this session.",
280
308
  rateLimitMessage: ((r = e.rateLimiting) == null ? void 0 : r.rateLimitMessage) || "You're sending messages too quickly. Please wait a moment."
281
- }
282
- }, this._sessionId = b(), this._messageCount = 0, this._minuteCount = 0, this._minuteStart = Date.now(), this._messages = [], this._open = !1, this._loading = !1, this._container = null, this._shadow = null, this._panel = null, this._messagesEl = null, this._textarea = null, this._sendBtn = null, this._viewportHandler = null;
309
+ },
310
+ // Store overrides for re-application after each config refresh
311
+ overrideSettings: e.overrideSettings || null
312
+ }, e.overrideSettings && this._applyOverrides(e.overrideSettings), this._sessionId = b(), this._messageCount = 0, this._minuteCount = 0, this._minuteStart = Date.now(), this._messages = [], this._open = !1, this._loading = !1, this._container = null, this._shadow = null, this._panel = null, this._messagesEl = null, this._textarea = null, this._sendBtn = null, this._viewportHandler = null, this._refreshPending = !1;
283
313
  }
284
314
  // ── Public API ──────────────────────────────────────────────────────────────
285
315
  /**
286
316
  * Mount the widget.
287
- * If `widgetId` was provided, fetches the server-side config first (async).
288
- * Returns a Promise so callers can await full initialisation.
317
+ * If `widgetId` is set, fetches server config first (async).
318
+ * Returns a Promise so callers can `await widget.mount()`.
289
319
  */
290
320
  mount(e) {
291
321
  const t = () => {
292
322
  const a = e || document.body;
293
323
  this._container = document.createElement("div"), this._container.setAttribute("data-cognitiondesk", ""), a.appendChild(this._container), this._shadow = this._container.attachShadow({ mode: "open" });
294
324
  const s = document.createElement("style");
295
- s.textContent = _, this._shadow.appendChild(s), this._buildDOM(), this._applyTheme(), this._syncViewportMetrics(), this._bindViewportMetrics(), this._bindEvents(), this._cfg.welcomeMessage && this._appendMessage("assistant", this._cfg.welcomeMessage, !1);
325
+ s.textContent = _, this._shadow.appendChild(s), this._buildDOM(), this._applyConfig(), this._syncViewportMetrics(), this._bindViewportMetrics(), this._bindEvents(), this._cfg.welcomeMessage && this._appendMessage("assistant", this._cfg.welcomeMessage, !1);
296
326
  };
297
327
  return this._cfg.widgetId ? this._fetchWidgetConfig().then(() => t()).catch(() => t()) : (t(), Promise.resolve(this));
298
328
  }
329
+ /**
330
+ * Programmatically update settings at runtime.
331
+ * Merges `newSettings` into `overrideSettings` and re-applies to the live DOM.
332
+ * Use this to change colors, bot name, etc. without remounting.
333
+ *
334
+ * widget.updateSettings({ primaryColor: '#dc2626', botName: 'Support Bot' });
335
+ */
336
+ updateSettings(e) {
337
+ if (!e || typeof e != "object") return;
338
+ const t = { ...this._cfg.overrideSettings || {}, ...e };
339
+ this._cfg.overrideSettings = t, this._overrides = new Set(Object.keys(t)), this._applyOverrides(t), this._applyConfig();
340
+ }
341
+ /**
342
+ * Fetch fresh config from the dashboard right now and apply it.
343
+ * Useful after the user changes settings in the CognitionDesk dashboard
344
+ * and wants them reflected immediately without reloading the page.
345
+ */
346
+ async refreshConfig() {
347
+ this._cfg.widgetId && (await this._fetchWidgetConfig(), this._applyConfig());
348
+ }
349
+ // ── Config internals ────────────────────────────────────────────────────────
350
+ /**
351
+ * Returns true if `key` is explicitly controlled by `overrideSettings`.
352
+ * Those keys are immune to server config overwrites.
353
+ */
354
+ _userSet(e) {
355
+ return this._overrides.has(e);
356
+ }
299
357
  /**
300
358
  * Fetch public widget config from the platform and merge into this._cfg.
301
- * Only fields not already overridden by the constructor are applied.
359
+ * Server values apply to any key NOT present in `overrideSettings`.
360
+ * After merging, overrides are re-applied so they always win.
302
361
  */
303
362
  async _fetchWidgetConfig() {
304
363
  var t;
@@ -308,20 +367,51 @@ class f {
308
367
  if (!a.ok) return;
309
368
  const { config: s } = await a.json();
310
369
  if (!s) return;
311
- s.botName && !this._userSet("botName") && (this._cfg.botName = s.botName), s.welcomeMessage && !this._userSet("welcomeMessage") && (this._cfg.welcomeMessage = s.welcomeMessage), s.primaryColor && !this._userSet("primaryColor") && (this._cfg.primaryColor = s.primaryColor), s.placeholder && !this._userSet("placeholder") && (this._cfg.placeholder = s.placeholder), s.assistantId && !this._cfg.assistantId && (this._cfg.assistantId = s.assistantId), (t = s.avatar) != null && t.value && !this._userSet("botEmoji") && (this._cfg.botEmoji = s.avatar.value), s.rateLimiting && (this._cfg.rateLimiting = { ...this._cfg.rateLimiting, ...s.rateLimiting });
370
+ const i = (r, n) => {
371
+ n != null && !this._userSet(r) && (this._cfg[r] = n);
372
+ };
373
+ i("botName", s.botName), i("welcomeMessage", s.welcomeMessage), i("primaryColor", s.primaryColor), i("secondaryColor", s.secondaryColor), i("placeholder", s.placeholder), i("theme", s.theme), i("position", s.position), i("style", s.style), i("size", s.size), s.assistantId && !this._cfg.assistantId && (this._cfg.assistantId = s.assistantId), (t = s.avatar) != null && t.value && !this._userSet("botEmoji") && (this._cfg.botEmoji = s.avatar.value), s.rateLimiting && (this._cfg.rateLimiting = { ...this._cfg.rateLimiting, ...s.rateLimiting }), this._cfg.overrideSettings && this._applyOverrides(this._cfg.overrideSettings);
312
374
  } catch {
313
375
  }
314
376
  }
315
- // eslint-disable-next-line no-unused-vars
316
- _userSet(e) {
317
- return !1;
377
+ /**
378
+ * Write override values into this._cfg (flat fields only; rateLimiting is merged).
379
+ */
380
+ _applyOverrides(e) {
381
+ for (const [t, a] of Object.entries(e))
382
+ t === "rateLimiting" && typeof a == "object" ? this._cfg.rateLimiting = { ...this._cfg.rateLimiting, ...a } : this._cfg[t] = a;
383
+ }
384
+ /**
385
+ * Update live DOM elements to reflect the current this._cfg.
386
+ * Safe to call before or after mounting.
387
+ */
388
+ _applyConfig() {
389
+ var s, i, r, n, o, d, c;
390
+ const e = this._cfg.theme === "dark" || this._cfg.theme === "auto" && ((s = window.matchMedia) == null ? void 0 : s.call(window, "(prefers-color-scheme: dark)").matches);
391
+ (i = this._root) == null || i.classList.toggle("cd-dark", e), (r = this._root) == null || r.style.setProperty("--cd-primary", this._cfg.primaryColor), (n = this._panel) == null || n.style.setProperty("--cd-primary", this._cfg.primaryColor), (o = this._toggleBtn) == null || o.style.setProperty("--cd-primary", this._cfg.primaryColor);
392
+ const t = (d = this._shadow) == null ? void 0 : d.querySelector(".cd-header-avatar");
393
+ t && (t.textContent = this._cfg.botEmoji);
394
+ const a = (c = this._shadow) == null ? void 0 : c.querySelector(".cd-header-name");
395
+ a && (a.textContent = this._cfg.botName), this._textarea && (this._textarea.placeholder = this._cfg.placeholder);
396
+ }
397
+ /**
398
+ * Silently refresh config from server in the background.
399
+ * Called each time the panel opens so dashboard changes
400
+ * are reflected without reloading the page.
401
+ * Uses a debounce flag to avoid concurrent fetches.
402
+ */
403
+ _silentRefresh() {
404
+ !this._cfg.widgetId || this._refreshPending || (this._refreshPending = !0, this._fetchWidgetConfig().then(() => this._applyConfig()).catch(() => {
405
+ }).finally(() => {
406
+ this._refreshPending = !1;
407
+ }));
318
408
  }
319
409
  unmount() {
320
410
  this._unbindViewportMetrics(), this._container && (this._container.remove(), this._container = null);
321
411
  }
322
412
  open() {
323
413
  var e, t;
324
- this._open = !0, this._syncViewportMetrics(), (e = this._panel) == null || e.classList.add("open"), (t = this._textarea) == null || t.focus();
414
+ this._open = !0, this._syncViewportMetrics(), (e = this._panel) == null || e.classList.add("open"), (t = this._textarea) == null || t.focus(), this._silentRefresh();
325
415
  }
326
416
  close() {
327
417
  var e;
@@ -355,14 +445,14 @@ class f {
355
445
  i.className = "cd-close-btn", i.innerHTML = p.close, i.setAttribute("aria-label", "Close chat"), s.appendChild(i), this._closeBtn = i;
356
446
  const r = document.createElement("div");
357
447
  r.className = "cd-messages", r.setAttribute("role", "log"), r.setAttribute("aria-live", "polite"), this._messagesEl = r;
358
- const o = document.createElement("div");
359
- o.className = "cd-input-area";
360
- const n = document.createElement("textarea");
361
- n.className = "cd-textarea", n.rows = 1, n.placeholder = this._cfg.placeholder, this._textarea = n;
448
+ const n = document.createElement("div");
449
+ n.className = "cd-input-area";
450
+ const o = document.createElement("textarea");
451
+ o.className = "cd-textarea", o.rows = 1, o.placeholder = this._cfg.placeholder, this._textarea = o;
362
452
  const d = document.createElement("button");
363
- d.className = "cd-send-btn", d.innerHTML = p.send, d.setAttribute("aria-label", "Send"), this._sendBtn = d, o.appendChild(n), o.appendChild(d);
364
- const l = document.createElement("div");
365
- l.className = "cd-powered", l.innerHTML = 'Powered by <a href="https://cognitiondesk.com" target="_blank" rel="noopener">CognitionDesk</a>', a.appendChild(s), a.appendChild(r), a.appendChild(o), a.appendChild(l), e.appendChild(t), e.appendChild(a), this._shadow.appendChild(e), this._root = e;
453
+ d.className = "cd-send-btn", d.innerHTML = p.send, d.setAttribute("aria-label", "Send"), this._sendBtn = d, n.appendChild(o), n.appendChild(d);
454
+ const c = document.createElement("div");
455
+ c.className = "cd-powered", c.innerHTML = 'Powered by <a href="https://cognitiondesk.com" target="_blank" rel="noopener">CognitionDesk</a>', a.appendChild(s), a.appendChild(r), a.appendChild(n), a.appendChild(c), e.appendChild(t), e.appendChild(a), this._shadow.appendChild(e), this._root = e;
366
456
  }
367
457
  _applyTheme() {
368
458
  var t, a, s;
@@ -446,36 +536,36 @@ class f {
446
536
  body: JSON.stringify({ ...this._buildRequestBody(), stream: !0 })
447
537
  });
448
538
  if (!t.ok) {
449
- const n = await t.json().catch(() => ({})), d = new Error(n.message || `HTTP ${t.status}`);
450
- throw d.status = t.status, d.rateLimitMessage = n.message, d;
539
+ const o = await t.json().catch(() => ({})), d = new Error(o.message || `HTTP ${t.status}`);
540
+ throw d.status = t.status, d.rateLimitMessage = o.message, d;
451
541
  }
452
542
  const a = document.createElement("div");
453
543
  a.className = "cd-msg assistant", a.innerHTML = '<div class="cd-typing"><span></span><span></span><span></span></div>', this._messagesEl.appendChild(a), this._scrollToBottom();
454
544
  const s = t.body.getReader(), i = new TextDecoder();
455
- let r = "", o = !1;
545
+ let r = "", n = !1;
456
546
  try {
457
547
  for (; ; ) {
458
- const { done: n, value: d } = await s.read();
459
- if (n) break;
460
- const l = i.decode(d, { stream: !0 });
461
- for (const g of l.split(`
548
+ const { done: o, value: d } = await s.read();
549
+ if (o) break;
550
+ const c = i.decode(d, { stream: !0 });
551
+ for (const g of c.split(`
462
552
  `)) {
463
553
  if (!g.startsWith("data: ")) continue;
464
- const m = g.slice(6).trim();
465
- if (m === "[DONE]") break;
554
+ const f = g.slice(6).trim();
555
+ if (f === "[DONE]") break;
466
556
  let h;
467
557
  try {
468
- h = JSON.parse(m);
558
+ h = JSON.parse(f);
469
559
  } catch {
470
560
  continue;
471
561
  }
472
- h.type === "content" && h.data && (o || (a.innerHTML = "", o = !0), r += h.data, a.innerHTML = this._renderMarkdown(r), this._scrollToBottom());
562
+ h.type === "content" && h.data && (n || (a.innerHTML = "", n = !0), r += h.data, a.innerHTML = this._renderMarkdown(r), this._scrollToBottom());
473
563
  }
474
564
  }
475
565
  } finally {
476
566
  s.releaseLock();
477
567
  }
478
- o || (a.innerHTML = this._renderMarkdown("No response")), r && this._messages.push({ role: "assistant", content: r });
568
+ n || (a.innerHTML = this._renderMarkdown("No response")), r && this._messages.push({ role: "assistant", content: r });
479
569
  }
480
570
  /** Non-streaming fallback path */
481
571
  async _callApi() {
@@ -486,8 +576,8 @@ class f {
486
576
  body: JSON.stringify(this._buildRequestBody())
487
577
  });
488
578
  if (!t.ok) {
489
- const o = await t.json().catch(() => ({})), n = new Error(o.message || `HTTP ${t.status}`);
490
- throw n.status = t.status, n.rateLimitMessage = o.message, n;
579
+ const n = await t.json().catch(() => ({})), o = new Error(n.message || `HTTP ${t.status}`);
580
+ throw o.status = t.status, o.rateLimitMessage = n.message, o;
491
581
  }
492
582
  const a = await t.json();
493
583
  return a.response || a.message || a.content || ((r = (i = (s = a.choices) == null ? void 0 : s[0]) == null ? void 0 : i.message) == null ? void 0 : r.content) || "No response";
@@ -523,16 +613,16 @@ class f {
523
613
  return String(e).replace(/[&<>"']/g, (t) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[t]);
524
614
  }
525
615
  }
526
- function x(c) {
527
- const e = new f(c);
616
+ function v(l) {
617
+ const e = new m(l);
528
618
  return e.mount(), e;
529
619
  }
530
620
  if (typeof document < "u") {
531
- const c = () => {
621
+ const l = () => {
532
622
  document.querySelectorAll("script[data-api-key]").forEach((e) => {
533
623
  const t = e.getAttribute("data-api-key");
534
624
  if (!t) return;
535
- const a = e.getAttribute("data-widget-id") || void 0, s = e.getAttribute("data-streaming"), i = new f({
625
+ const a = e.getAttribute("data-widget-id") || void 0, s = e.getAttribute("data-streaming"), i = new m({
536
626
  apiKey: t,
537
627
  widgetId: a,
538
628
  assistantId: e.getAttribute("data-assistant-id") || void 0,
@@ -548,10 +638,10 @@ if (typeof document < "u") {
548
638
  Promise.resolve(i.mount());
549
639
  });
550
640
  };
551
- document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", c) : c();
641
+ document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", l) : l();
552
642
  }
553
643
  export {
554
- f as CognitionDeskWidget,
555
- f as default,
556
- x as init
644
+ m as CognitionDeskWidget,
645
+ m as default,
646
+ v as init
557
647
  };
@@ -1,4 +1,4 @@
1
- (function(c,l){typeof exports=="object"&&typeof module<"u"?l(exports):typeof define=="function"&&define.amd?define(["exports"],l):(c=typeof globalThis<"u"?globalThis:c||self,l(c.CognitionDeskWidget={}))})(this,function(c){"use strict";const l="https://mounaji-backendv3.onrender.com",b=`
1
+ (function(c,h){typeof exports=="object"&&typeof module<"u"?h(exports):typeof define=="function"&&define.amd?define(["exports"],h):(c=typeof globalThis<"u"?globalThis:c||self,h(c.CognitionDeskWidget={}))})(this,function(c){"use strict";const h="https://mounaji-backendv3.onrender.com",b=`
2
2
  :host {
3
3
  all: initial;
4
4
  font-family: system-ui, sans-serif;
@@ -244,7 +244,7 @@
244
244
  font-size: 16px;
245
245
  }
246
246
  }
247
- `,f={chat:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',close:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',send:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>'};function w(){return"cd_"+Math.random().toString(36).slice(2)+Date.now().toString(36)}class g{constructor(e={}){var t,a,s,i,n;if(!e.apiKey)throw new Error("[CognitionDesk] apiKey is required");this._cfg={apiKey:e.apiKey,widgetId:e.widgetId||null,assistantId:e.assistantId||null,backendUrl:e.backendUrl||l,primaryColor:e.primaryColor||"#2563eb",theme:e.theme||"light",botName:e.botName||"AI Assistant",botEmoji:e.botEmoji||"🤖",welcomeMessage:e.welcomeMessage||"Hello! How can I help you today?",placeholder:e.placeholder||"Type a message…",position:e.position||"bottom-right",streaming:e.streaming!==!1,rateLimiting:{enabled:((t=e.rateLimiting)==null?void 0:t.enabled)!==!1,maxMessagesPerSession:((a=e.rateLimiting)==null?void 0:a.maxMessagesPerSession)??0,maxMessagesPerMinute:((s=e.rateLimiting)==null?void 0:s.maxMessagesPerMinute)??0,limitReachedMessage:((i=e.rateLimiting)==null?void 0:i.limitReachedMessage)||"You've reached the message limit for this session.",rateLimitMessage:((n=e.rateLimiting)==null?void 0:n.rateLimitMessage)||"You're sending messages too quickly. Please wait a moment."}},this._sessionId=w(),this._messageCount=0,this._minuteCount=0,this._minuteStart=Date.now(),this._messages=[],this._open=!1,this._loading=!1,this._container=null,this._shadow=null,this._panel=null,this._messagesEl=null,this._textarea=null,this._sendBtn=null,this._viewportHandler=null}mount(e){const t=()=>{const a=e||document.body;this._container=document.createElement("div"),this._container.setAttribute("data-cognitiondesk",""),a.appendChild(this._container),this._shadow=this._container.attachShadow({mode:"open"});const s=document.createElement("style");s.textContent=b,this._shadow.appendChild(s),this._buildDOM(),this._applyTheme(),this._syncViewportMetrics(),this._bindViewportMetrics(),this._bindEvents(),this._cfg.welcomeMessage&&this._appendMessage("assistant",this._cfg.welcomeMessage,!1)};return this._cfg.widgetId?this._fetchWidgetConfig().then(()=>t()).catch(()=>t()):(t(),Promise.resolve(this))}async _fetchWidgetConfig(){var t;const e=`${this._cfg.backendUrl}/platforms/web-widget/public/${this._cfg.widgetId}`;try{const a=await fetch(e);if(!a.ok)return;const{config:s}=await a.json();if(!s)return;s.botName&&!this._userSet("botName")&&(this._cfg.botName=s.botName),s.welcomeMessage&&!this._userSet("welcomeMessage")&&(this._cfg.welcomeMessage=s.welcomeMessage),s.primaryColor&&!this._userSet("primaryColor")&&(this._cfg.primaryColor=s.primaryColor),s.placeholder&&!this._userSet("placeholder")&&(this._cfg.placeholder=s.placeholder),s.assistantId&&!this._cfg.assistantId&&(this._cfg.assistantId=s.assistantId),(t=s.avatar)!=null&&t.value&&!this._userSet("botEmoji")&&(this._cfg.botEmoji=s.avatar.value),s.rateLimiting&&(this._cfg.rateLimiting={...this._cfg.rateLimiting,...s.rateLimiting})}catch{}}_userSet(e){return!1}unmount(){this._unbindViewportMetrics(),this._container&&(this._container.remove(),this._container=null)}open(){var e,t;this._open=!0,this._syncViewportMetrics(),(e=this._panel)==null||e.classList.add("open"),(t=this._textarea)==null||t.focus()}close(){var e;this._open=!1,(e=this._panel)==null||e.classList.remove("open")}toggle(){this._open?this.close():this.open()}clearHistory(){this._messages=[],this._messagesEl&&(this._messagesEl.innerHTML=""),this._cfg.welcomeMessage&&this._appendMessage("assistant",this._cfg.welcomeMessage)}_buildDOM(){const e=document.createElement("div");e.className="cd-root";const t=document.createElement("button");t.className="cd-widget-btn",t.innerHTML=f.chat,t.setAttribute("aria-label","Open chat"),t.style.setProperty("--cd-primary",this._cfg.primaryColor),this._toggleBtn=t;const a=document.createElement("div");a.className="cd-panel",this._panel=a;const s=document.createElement("div");s.className="cd-header",s.innerHTML=`
247
+ `,m={chat:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',close:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',send:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>'};function v(){return"cd_"+Math.random().toString(36).slice(2)+Date.now().toString(36)}class g{constructor(e={}){var t,i,s,a,r;if(!e.apiKey)throw new Error("[CognitionDesk] apiKey is required");this._overrides=new Set(e.overrideSettings?Object.keys(e.overrideSettings):[]),this._cfg={apiKey:e.apiKey,widgetId:e.widgetId||null,assistantId:e.assistantId||null,backendUrl:e.backendUrl||h,primaryColor:e.primaryColor||"#2563eb",theme:e.theme||"light",botName:e.botName||"AI Assistant",botEmoji:e.botEmoji||"🤖",welcomeMessage:e.welcomeMessage||"Hello! How can I help you today?",placeholder:e.placeholder||"Type a message…",position:e.position||"bottom-right",streaming:e.streaming!==!1,rateLimiting:{enabled:((t=e.rateLimiting)==null?void 0:t.enabled)!==!1,maxMessagesPerSession:((i=e.rateLimiting)==null?void 0:i.maxMessagesPerSession)??0,maxMessagesPerMinute:((s=e.rateLimiting)==null?void 0:s.maxMessagesPerMinute)??0,limitReachedMessage:((a=e.rateLimiting)==null?void 0:a.limitReachedMessage)||"You've reached the message limit for this session.",rateLimitMessage:((r=e.rateLimiting)==null?void 0:r.rateLimitMessage)||"You're sending messages too quickly. Please wait a moment."},overrideSettings:e.overrideSettings||null},e.overrideSettings&&this._applyOverrides(e.overrideSettings),this._sessionId=v(),this._messageCount=0,this._minuteCount=0,this._minuteStart=Date.now(),this._messages=[],this._open=!1,this._loading=!1,this._container=null,this._shadow=null,this._panel=null,this._messagesEl=null,this._textarea=null,this._sendBtn=null,this._viewportHandler=null,this._refreshPending=!1}mount(e){const t=()=>{const i=e||document.body;this._container=document.createElement("div"),this._container.setAttribute("data-cognitiondesk",""),i.appendChild(this._container),this._shadow=this._container.attachShadow({mode:"open"});const s=document.createElement("style");s.textContent=b,this._shadow.appendChild(s),this._buildDOM(),this._applyConfig(),this._syncViewportMetrics(),this._bindViewportMetrics(),this._bindEvents(),this._cfg.welcomeMessage&&this._appendMessage("assistant",this._cfg.welcomeMessage,!1)};return this._cfg.widgetId?this._fetchWidgetConfig().then(()=>t()).catch(()=>t()):(t(),Promise.resolve(this))}updateSettings(e){if(!e||typeof e!="object")return;const t={...this._cfg.overrideSettings||{},...e};this._cfg.overrideSettings=t,this._overrides=new Set(Object.keys(t)),this._applyOverrides(t),this._applyConfig()}async refreshConfig(){this._cfg.widgetId&&(await this._fetchWidgetConfig(),this._applyConfig())}_userSet(e){return this._overrides.has(e)}async _fetchWidgetConfig(){var t;const e=`${this._cfg.backendUrl}/platforms/web-widget/public/${this._cfg.widgetId}`;try{const i=await fetch(e);if(!i.ok)return;const{config:s}=await i.json();if(!s)return;const a=(r,n)=>{n!=null&&!this._userSet(r)&&(this._cfg[r]=n)};a("botName",s.botName),a("welcomeMessage",s.welcomeMessage),a("primaryColor",s.primaryColor),a("secondaryColor",s.secondaryColor),a("placeholder",s.placeholder),a("theme",s.theme),a("position",s.position),a("style",s.style),a("size",s.size),s.assistantId&&!this._cfg.assistantId&&(this._cfg.assistantId=s.assistantId),(t=s.avatar)!=null&&t.value&&!this._userSet("botEmoji")&&(this._cfg.botEmoji=s.avatar.value),s.rateLimiting&&(this._cfg.rateLimiting={...this._cfg.rateLimiting,...s.rateLimiting}),this._cfg.overrideSettings&&this._applyOverrides(this._cfg.overrideSettings)}catch{}}_applyOverrides(e){for(const[t,i]of Object.entries(e))t==="rateLimiting"&&typeof i=="object"?this._cfg.rateLimiting={...this._cfg.rateLimiting,...i}:this._cfg[t]=i}_applyConfig(){var s,a,r,n,o,d,l;const e=this._cfg.theme==="dark"||this._cfg.theme==="auto"&&((s=window.matchMedia)==null?void 0:s.call(window,"(prefers-color-scheme: dark)").matches);(a=this._root)==null||a.classList.toggle("cd-dark",e),(r=this._root)==null||r.style.setProperty("--cd-primary",this._cfg.primaryColor),(n=this._panel)==null||n.style.setProperty("--cd-primary",this._cfg.primaryColor),(o=this._toggleBtn)==null||o.style.setProperty("--cd-primary",this._cfg.primaryColor);const t=(d=this._shadow)==null?void 0:d.querySelector(".cd-header-avatar");t&&(t.textContent=this._cfg.botEmoji);const i=(l=this._shadow)==null?void 0:l.querySelector(".cd-header-name");i&&(i.textContent=this._cfg.botName),this._textarea&&(this._textarea.placeholder=this._cfg.placeholder)}_silentRefresh(){!this._cfg.widgetId||this._refreshPending||(this._refreshPending=!0,this._fetchWidgetConfig().then(()=>this._applyConfig()).catch(()=>{}).finally(()=>{this._refreshPending=!1}))}unmount(){this._unbindViewportMetrics(),this._container&&(this._container.remove(),this._container=null)}open(){var e,t;this._open=!0,this._syncViewportMetrics(),(e=this._panel)==null||e.classList.add("open"),(t=this._textarea)==null||t.focus(),this._silentRefresh()}close(){var e;this._open=!1,(e=this._panel)==null||e.classList.remove("open")}toggle(){this._open?this.close():this.open()}clearHistory(){this._messages=[],this._messagesEl&&(this._messagesEl.innerHTML=""),this._cfg.welcomeMessage&&this._appendMessage("assistant",this._cfg.welcomeMessage)}_buildDOM(){const e=document.createElement("div");e.className="cd-root";const t=document.createElement("button");t.className="cd-widget-btn",t.innerHTML=m.chat,t.setAttribute("aria-label","Open chat"),t.style.setProperty("--cd-primary",this._cfg.primaryColor),this._toggleBtn=t;const i=document.createElement("div");i.className="cd-panel",this._panel=i;const s=document.createElement("div");s.className="cd-header",s.innerHTML=`
248
248
  <div class="cd-header-avatar">${this._cfg.botEmoji}</div>
249
249
  <div class="cd-header-info">
250
250
  <div class="cd-header-name">${this._escHtml(this._cfg.botName)}</div>
@@ -252,5 +252,5 @@
252
252
  <span class="cd-status-dot"></span> Online
253
253
  </div>
254
254
  </div>
255
- `;const i=document.createElement("button");i.className="cd-close-btn",i.innerHTML=f.close,i.setAttribute("aria-label","Close chat"),s.appendChild(i),this._closeBtn=i;const n=document.createElement("div");n.className="cd-messages",n.setAttribute("role","log"),n.setAttribute("aria-live","polite"),this._messagesEl=n;const o=document.createElement("div");o.className="cd-input-area";const r=document.createElement("textarea");r.className="cd-textarea",r.rows=1,r.placeholder=this._cfg.placeholder,this._textarea=r;const d=document.createElement("button");d.className="cd-send-btn",d.innerHTML=f.send,d.setAttribute("aria-label","Send"),this._sendBtn=d,o.appendChild(r),o.appendChild(d);const p=document.createElement("div");p.className="cd-powered",p.innerHTML='Powered by <a href="https://cognitiondesk.com" target="_blank" rel="noopener">CognitionDesk</a>',a.appendChild(s),a.appendChild(n),a.appendChild(o),a.appendChild(p),e.appendChild(t),e.appendChild(a),this._shadow.appendChild(e),this._root=e}_applyTheme(){var t,a,s;(this._cfg.theme==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":this._cfg.theme)==="dark"&&((t=this._root)==null||t.classList.add("cd-dark")),(a=this._root)==null||a.style.setProperty("--cd-primary",this._cfg.primaryColor),(s=this._panel)==null||s.style.setProperty("--cd-primary",this._cfg.primaryColor)}_bindEvents(){this._toggleBtn.addEventListener("click",()=>this.toggle()),this._closeBtn.addEventListener("click",()=>this.close()),this._sendBtn.addEventListener("click",()=>this._sendMessage()),this._textarea.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),this._sendMessage())}),this._textarea.addEventListener("input",()=>{this._textarea.style.height="auto",this._textarea.style.height=Math.min(this._textarea.scrollHeight,120)+"px"}),this._textarea.addEventListener("focus",()=>{this._syncViewportMetrics()})}_bindViewportMetrics(){this._viewportHandler||(this._viewportHandler=()=>this._syncViewportMetrics(),window.addEventListener("resize",this._viewportHandler,{passive:!0}),window.addEventListener("orientationchange",this._viewportHandler),window.visualViewport&&(window.visualViewport.addEventListener("resize",this._viewportHandler),window.visualViewport.addEventListener("scroll",this._viewportHandler)))}_unbindViewportMetrics(){this._viewportHandler&&(window.removeEventListener("resize",this._viewportHandler),window.removeEventListener("orientationchange",this._viewportHandler),window.visualViewport&&(window.visualViewport.removeEventListener("resize",this._viewportHandler),window.visualViewport.removeEventListener("scroll",this._viewportHandler)),this._viewportHandler=null)}_syncViewportMetrics(){const e=this._root||this._container;if(!e)return;const t=window.visualViewport,a=t?t.height:window.innerHeight;e.style.setProperty("--cd-viewport-height",`${Math.round(a)}px`)}async _sendMessage(){var a;const e=this._textarea.value.trim();if(!e||this._loading)return;const t=this._cfg.rateLimiting;if(t!=null&&t.enabled){const s=Date.now();if(s-this._minuteStart>=6e4&&(this._minuteCount=0,this._minuteStart=s),t.maxMessagesPerSession>0&&this._messageCount>=t.maxMessagesPerSession){this._appendMessage("error",t.limitReachedMessage,!1),this._textarea.disabled=!0,this._sendBtn.disabled=!0;return}if(t.maxMessagesPerMinute>0&&this._minuteCount>=t.maxMessagesPerMinute){this._appendMessage("error",t.rateLimitMessage,!1);return}}this._textarea.value="",this._textarea.style.height="auto",this._loading=!0,this._sendBtn.disabled=!0,this._messages.push({role:"user",content:e}),this._appendMessage("user",e,!1),this._messageCount+=1,this._minuteCount+=1;try{if(this._cfg.streaming)await this._callApiStream();else{const s=this._showTyping(),i=await this._callApi();this._removeTyping(s),this._messages.push({role:"assistant",content:i}),this._appendMessage("assistant",i,!0)}}catch(s){if(s.status===429||(a=s.message)!=null&&a.includes("429")){const i=s.rateLimitMessage||(t==null?void 0:t.rateLimitMessage)||"You're sending messages too quickly. Please wait a moment.";this._appendMessage("error",i,!1)}else this._appendMessage("error","Sorry, something went wrong. Please try again.",!1);console.error("[CognitionDesk]",s)}finally{this._loading=!1,(t==null?void 0:t.maxMessagesPerSession)>0&&this._messageCount>=t.maxMessagesPerSession||(this._sendBtn.disabled=!1),this._textarea.focus()}}_buildRequestBody(){return{messages:this._messages,assistantId:this._cfg.assistantId||void 0,userContext:{sessionId:this._sessionId,assistantId:this._cfg.assistantId||void 0,widgetId:this._cfg.widgetId||void 0,platform:"cognitiondesk-widget"}}}async _callApiStream(){const e=`${this._cfg.backendUrl}/chat-apiKeyAuth/stream`,t=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this._cfg.apiKey},body:JSON.stringify({...this._buildRequestBody(),stream:!0})});if(!t.ok){const r=await t.json().catch(()=>({})),d=new Error(r.message||`HTTP ${t.status}`);throw d.status=t.status,d.rateLimitMessage=r.message,d}const a=document.createElement("div");a.className="cd-msg assistant",a.innerHTML='<div class="cd-typing"><span></span><span></span><span></span></div>',this._messagesEl.appendChild(a),this._scrollToBottom();const s=t.body.getReader(),i=new TextDecoder;let n="",o=!1;try{for(;;){const{done:r,value:d}=await s.read();if(r)break;const p=i.decode(d,{stream:!0});for(const u of p.split(`
256
- `)){if(!u.startsWith("data: "))continue;const _=u.slice(6).trim();if(_==="[DONE]")break;let m;try{m=JSON.parse(_)}catch{continue}m.type==="content"&&m.data&&(o||(a.innerHTML="",o=!0),n+=m.data,a.innerHTML=this._renderMarkdown(n),this._scrollToBottom())}}}finally{s.releaseLock()}o||(a.innerHTML=this._renderMarkdown("No response")),n&&this._messages.push({role:"assistant",content:n})}async _callApi(){var s,i,n;const e=`${this._cfg.backendUrl}/chat-apiKeyAuth/chat`,t=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this._cfg.apiKey},body:JSON.stringify(this._buildRequestBody())});if(!t.ok){const o=await t.json().catch(()=>({})),r=new Error(o.message||`HTTP ${t.status}`);throw r.status=t.status,r.rateLimitMessage=o.message,r}const a=await t.json();return a.response||a.message||a.content||((n=(i=(s=a.choices)==null?void 0:s[0])==null?void 0:i.message)==null?void 0:n.content)||"No response"}_appendMessage(e,t,a=!0){const s=document.createElement("div");s.className=`cd-msg ${e}`,a&&e!=="user"?s.innerHTML=this._renderMarkdown(t):s.textContent=t,this._messagesEl.appendChild(s),this._scrollToBottom()}_renderMarkdown(e){if(!e)return"";let t=this._escHtml(e);return t=t.replace(/```[\w]*\n?([\s\S]*?)```/g,(a,s)=>`<pre style="background:#0f172a;color:#e2e8f0;padding:10px;border-radius:6px;font-size:12px;overflow-x:auto;margin:6px 0;white-space:pre-wrap">${s.trim()}</pre>`),t=t.replace(/`([^`]+)`/g,'<code style="background:rgba(0,0,0,.08);padding:1px 5px;border-radius:4px;font-size:.9em">$1</code>'),t=t.replace(/\*\*([^*]+)\*\*/g,"<strong>$1</strong>"),t=t.replace(/__([^_]+)__/g,"<strong>$1</strong>"),t=t.replace(/\*([^*]+)\*/g,"<em>$1</em>"),t=t.replace(/_([^_]+)_/g,"<em>$1</em>"),t=t.replace(/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g,'<a href="$2" target="_blank" rel="noopener" style="color:var(--cd-primary,#2563eb)">$1</a>'),t=t.replace(/\n/g,"<br>"),t}_showTyping(){const e=document.createElement("div");return e.className="cd-msg assistant",e.innerHTML='<div class="cd-typing"><span></span><span></span><span></span></div>',this._messagesEl.appendChild(e),this._scrollToBottom(),e}_removeTyping(e){e==null||e.remove()}_scrollToBottom(){this._messagesEl&&(this._messagesEl.scrollTop=this._messagesEl.scrollHeight)}_escHtml(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}}function x(h){const e=new g(h);return e.mount(),e}if(typeof document<"u"){const h=()=>{document.querySelectorAll("script[data-api-key]").forEach(e=>{const t=e.getAttribute("data-api-key");if(!t)return;const a=e.getAttribute("data-widget-id")||void 0,s=e.getAttribute("data-streaming"),i=new g({apiKey:t,widgetId:a,assistantId:e.getAttribute("data-assistant-id")||void 0,theme:e.getAttribute("data-theme")||"light",primaryColor:e.getAttribute("data-primary-color")||"#2563eb",botName:e.getAttribute("data-bot-name")||"AI Assistant",botEmoji:e.getAttribute("data-bot-emoji")||void 0,welcomeMessage:e.getAttribute("data-welcome-message")||void 0,placeholder:e.getAttribute("data-placeholder")||void 0,backendUrl:e.getAttribute("data-backend-url")||void 0,streaming:s===null?!0:s!=="false"});Promise.resolve(i.mount())})};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",h):h()}c.CognitionDeskWidget=g,c.default=g,c.init=x,Object.defineProperties(c,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
255
+ `;const a=document.createElement("button");a.className="cd-close-btn",a.innerHTML=m.close,a.setAttribute("aria-label","Close chat"),s.appendChild(a),this._closeBtn=a;const r=document.createElement("div");r.className="cd-messages",r.setAttribute("role","log"),r.setAttribute("aria-live","polite"),this._messagesEl=r;const n=document.createElement("div");n.className="cd-input-area";const o=document.createElement("textarea");o.className="cd-textarea",o.rows=1,o.placeholder=this._cfg.placeholder,this._textarea=o;const d=document.createElement("button");d.className="cd-send-btn",d.innerHTML=m.send,d.setAttribute("aria-label","Send"),this._sendBtn=d,n.appendChild(o),n.appendChild(d);const l=document.createElement("div");l.className="cd-powered",l.innerHTML='Powered by <a href="https://cognitiondesk.com" target="_blank" rel="noopener">CognitionDesk</a>',i.appendChild(s),i.appendChild(r),i.appendChild(n),i.appendChild(l),e.appendChild(t),e.appendChild(i),this._shadow.appendChild(e),this._root=e}_applyTheme(){var t,i,s;(this._cfg.theme==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":this._cfg.theme)==="dark"&&((t=this._root)==null||t.classList.add("cd-dark")),(i=this._root)==null||i.style.setProperty("--cd-primary",this._cfg.primaryColor),(s=this._panel)==null||s.style.setProperty("--cd-primary",this._cfg.primaryColor)}_bindEvents(){this._toggleBtn.addEventListener("click",()=>this.toggle()),this._closeBtn.addEventListener("click",()=>this.close()),this._sendBtn.addEventListener("click",()=>this._sendMessage()),this._textarea.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),this._sendMessage())}),this._textarea.addEventListener("input",()=>{this._textarea.style.height="auto",this._textarea.style.height=Math.min(this._textarea.scrollHeight,120)+"px"}),this._textarea.addEventListener("focus",()=>{this._syncViewportMetrics()})}_bindViewportMetrics(){this._viewportHandler||(this._viewportHandler=()=>this._syncViewportMetrics(),window.addEventListener("resize",this._viewportHandler,{passive:!0}),window.addEventListener("orientationchange",this._viewportHandler),window.visualViewport&&(window.visualViewport.addEventListener("resize",this._viewportHandler),window.visualViewport.addEventListener("scroll",this._viewportHandler)))}_unbindViewportMetrics(){this._viewportHandler&&(window.removeEventListener("resize",this._viewportHandler),window.removeEventListener("orientationchange",this._viewportHandler),window.visualViewport&&(window.visualViewport.removeEventListener("resize",this._viewportHandler),window.visualViewport.removeEventListener("scroll",this._viewportHandler)),this._viewportHandler=null)}_syncViewportMetrics(){const e=this._root||this._container;if(!e)return;const t=window.visualViewport,i=t?t.height:window.innerHeight;e.style.setProperty("--cd-viewport-height",`${Math.round(i)}px`)}async _sendMessage(){var i;const e=this._textarea.value.trim();if(!e||this._loading)return;const t=this._cfg.rateLimiting;if(t!=null&&t.enabled){const s=Date.now();if(s-this._minuteStart>=6e4&&(this._minuteCount=0,this._minuteStart=s),t.maxMessagesPerSession>0&&this._messageCount>=t.maxMessagesPerSession){this._appendMessage("error",t.limitReachedMessage,!1),this._textarea.disabled=!0,this._sendBtn.disabled=!0;return}if(t.maxMessagesPerMinute>0&&this._minuteCount>=t.maxMessagesPerMinute){this._appendMessage("error",t.rateLimitMessage,!1);return}}this._textarea.value="",this._textarea.style.height="auto",this._loading=!0,this._sendBtn.disabled=!0,this._messages.push({role:"user",content:e}),this._appendMessage("user",e,!1),this._messageCount+=1,this._minuteCount+=1;try{if(this._cfg.streaming)await this._callApiStream();else{const s=this._showTyping(),a=await this._callApi();this._removeTyping(s),this._messages.push({role:"assistant",content:a}),this._appendMessage("assistant",a,!0)}}catch(s){if(s.status===429||(i=s.message)!=null&&i.includes("429")){const a=s.rateLimitMessage||(t==null?void 0:t.rateLimitMessage)||"You're sending messages too quickly. Please wait a moment.";this._appendMessage("error",a,!1)}else this._appendMessage("error","Sorry, something went wrong. Please try again.",!1);console.error("[CognitionDesk]",s)}finally{this._loading=!1,(t==null?void 0:t.maxMessagesPerSession)>0&&this._messageCount>=t.maxMessagesPerSession||(this._sendBtn.disabled=!1),this._textarea.focus()}}_buildRequestBody(){return{messages:this._messages,assistantId:this._cfg.assistantId||void 0,userContext:{sessionId:this._sessionId,assistantId:this._cfg.assistantId||void 0,widgetId:this._cfg.widgetId||void 0,platform:"cognitiondesk-widget"}}}async _callApiStream(){const e=`${this._cfg.backendUrl}/chat-apiKeyAuth/stream`,t=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this._cfg.apiKey},body:JSON.stringify({...this._buildRequestBody(),stream:!0})});if(!t.ok){const o=await t.json().catch(()=>({})),d=new Error(o.message||`HTTP ${t.status}`);throw d.status=t.status,d.rateLimitMessage=o.message,d}const i=document.createElement("div");i.className="cd-msg assistant",i.innerHTML='<div class="cd-typing"><span></span><span></span><span></span></div>',this._messagesEl.appendChild(i),this._scrollToBottom();const s=t.body.getReader(),a=new TextDecoder;let r="",n=!1;try{for(;;){const{done:o,value:d}=await s.read();if(o)break;const l=a.decode(d,{stream:!0});for(const u of l.split(`
256
+ `)){if(!u.startsWith("data: "))continue;const _=u.slice(6).trim();if(_==="[DONE]")break;let f;try{f=JSON.parse(_)}catch{continue}f.type==="content"&&f.data&&(n||(i.innerHTML="",n=!0),r+=f.data,i.innerHTML=this._renderMarkdown(r),this._scrollToBottom())}}}finally{s.releaseLock()}n||(i.innerHTML=this._renderMarkdown("No response")),r&&this._messages.push({role:"assistant",content:r})}async _callApi(){var s,a,r;const e=`${this._cfg.backendUrl}/chat-apiKeyAuth/chat`,t=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this._cfg.apiKey},body:JSON.stringify(this._buildRequestBody())});if(!t.ok){const n=await t.json().catch(()=>({})),o=new Error(n.message||`HTTP ${t.status}`);throw o.status=t.status,o.rateLimitMessage=n.message,o}const i=await t.json();return i.response||i.message||i.content||((r=(a=(s=i.choices)==null?void 0:s[0])==null?void 0:a.message)==null?void 0:r.content)||"No response"}_appendMessage(e,t,i=!0){const s=document.createElement("div");s.className=`cd-msg ${e}`,i&&e!=="user"?s.innerHTML=this._renderMarkdown(t):s.textContent=t,this._messagesEl.appendChild(s),this._scrollToBottom()}_renderMarkdown(e){if(!e)return"";let t=this._escHtml(e);return t=t.replace(/```[\w]*\n?([\s\S]*?)```/g,(i,s)=>`<pre style="background:#0f172a;color:#e2e8f0;padding:10px;border-radius:6px;font-size:12px;overflow-x:auto;margin:6px 0;white-space:pre-wrap">${s.trim()}</pre>`),t=t.replace(/`([^`]+)`/g,'<code style="background:rgba(0,0,0,.08);padding:1px 5px;border-radius:4px;font-size:.9em">$1</code>'),t=t.replace(/\*\*([^*]+)\*\*/g,"<strong>$1</strong>"),t=t.replace(/__([^_]+)__/g,"<strong>$1</strong>"),t=t.replace(/\*([^*]+)\*/g,"<em>$1</em>"),t=t.replace(/_([^_]+)_/g,"<em>$1</em>"),t=t.replace(/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g,'<a href="$2" target="_blank" rel="noopener" style="color:var(--cd-primary,#2563eb)">$1</a>'),t=t.replace(/\n/g,"<br>"),t}_showTyping(){const e=document.createElement("div");return e.className="cd-msg assistant",e.innerHTML='<div class="cd-typing"><span></span><span></span><span></span></div>',this._messagesEl.appendChild(e),this._scrollToBottom(),e}_removeTyping(e){e==null||e.remove()}_scrollToBottom(){this._messagesEl&&(this._messagesEl.scrollTop=this._messagesEl.scrollHeight)}_escHtml(e){return String(e).replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}}function w(p){const e=new g(p);return e.mount(),e}if(typeof document<"u"){const p=()=>{document.querySelectorAll("script[data-api-key]").forEach(e=>{const t=e.getAttribute("data-api-key");if(!t)return;const i=e.getAttribute("data-widget-id")||void 0,s=e.getAttribute("data-streaming"),a=new g({apiKey:t,widgetId:i,assistantId:e.getAttribute("data-assistant-id")||void 0,theme:e.getAttribute("data-theme")||"light",primaryColor:e.getAttribute("data-primary-color")||"#2563eb",botName:e.getAttribute("data-bot-name")||"AI Assistant",botEmoji:e.getAttribute("data-bot-emoji")||void 0,welcomeMessage:e.getAttribute("data-welcome-message")||void 0,placeholder:e.getAttribute("data-placeholder")||void 0,backendUrl:e.getAttribute("data-backend-url")||void 0,streaming:s===null?!0:s!=="false"});Promise.resolve(a.mount())})};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",p):p()}c.CognitionDeskWidget=g,c.default=g,c.init=w,Object.defineProperties(c,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cognitiondesk/widget",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Embed a CognitionDesk AI chat widget into any website. Authenticate with an API key from your CognitionDesk dashboard.",
5
5
  "keywords": ["chat", "widget", "ai", "cognitiondesk", "chatbot", "react", "streaming", "mounaji"],
6
6
  "license": "MIT",
package/src/react.jsx CHANGED
@@ -23,6 +23,16 @@
23
23
  * onOpen={() => console.log('chat opened')}
24
24
  * onClose={() => console.log('chat closed')}
25
25
  * />
26
+ *
27
+ * // Mixed: load base config from platform, override specific fields in code
28
+ * <CognitionDeskWidget
29
+ * apiKey="YOUR_API_KEY"
30
+ * widgetId="widget_xxx"
31
+ * overrideSettings={{ primaryColor: '#7c3aed', botName: 'Aria' }}
32
+ * />
33
+ * // Fields listed in overrideSettings are controlled by code and will NOT be
34
+ * // overwritten by dashboard changes. All other fields continue to sync from
35
+ * // the platform on every panel open.
26
36
  */
27
37
 
28
38
  import { useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
@@ -49,6 +59,10 @@ export const CognitionDeskWidget = forwardRef(function CognitionDeskWidget(props
49
59
  rateLimitMessage,
50
60
  onOpen,
51
61
  onClose,
62
+ // Fields listed here are owned by code and won't be overwritten by
63
+ // dashboard config refreshes. Pass an object whose keys match widget
64
+ // config fields, e.g. { primaryColor: '#7c3aed', botName: 'Aria' }.
65
+ overrideSettings,
52
66
  } = props;
53
67
 
54
68
  const widgetRef = useRef(null);
@@ -79,7 +93,8 @@ export const CognitionDeskWidget = forwardRef(function CognitionDeskWidget(props
79
93
  welcomeMessage,
80
94
  placeholder,
81
95
  streaming,
82
- ...(backendUrl ? { backendUrl } : {}),
96
+ ...(backendUrl ? { backendUrl } : {}),
97
+ ...(overrideSettings ? { overrideSettings } : {}),
83
98
  rateLimiting: {
84
99
  enabled: true,
85
100
  maxMessagesPerSession,
@@ -116,9 +131,17 @@ export const CognitionDeskWidget = forwardRef(function CognitionDeskWidget(props
116
131
  if (!w) return;
117
132
  w._cfg.theme = theme;
118
133
  w._cfg.primaryColor = primaryColor;
119
- w._applyTheme?.();
134
+ w._applyConfig?.();
120
135
  }, [theme, primaryColor]);
121
136
 
137
+ // Sync overrideSettings changes at runtime — updates which fields are
138
+ // code-controlled and immediately re-applies the overridden values.
139
+ useEffect(() => {
140
+ const w = widgetRef.current;
141
+ if (!w || !overrideSettings) return;
142
+ w.updateSettings(overrideSettings);
143
+ }, [overrideSettings]);
144
+
122
145
  return <div ref={mountRef} data-cognitiondesk-root="" />;
123
146
  });
124
147