@usesophi/sophi-web-sdk 0.1.0 → 1.0.1

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/index.cjs CHANGED
@@ -1,3 +1,3 @@
1
- 'use strict';var f={ADD_TO_CART:"add_to_cart",READY:"ready",ERROR:"error",SEND_TO_CHECKOUT:"send_to_checkout"},o={USER_DATA:"user_data",CONFIG:"config",UPDATE_USER_CART:"update_user_cart",DESTROY:"destroy",SESSION_DATA:"session_data",CLIENT_ID_UPDATED:"client_id_updated",LAYOUT_CONFIG:"layout_config",TOGGLE_HISTORY:"toggle_history"};var s=class s{constructor(e,t){this.namespace=s.sanitizeNamespace(e),this.maxAgeSeconds=t?.maxAgeSeconds??s.DEFAULT_MAX_AGE_SECONDS,this.keys={...s.DEFAULT_KEYS,...t?.keys??{}};}static buildNamespace(e,t){return s.sanitizeNamespace(`sophi-widget-${e}-${t}`)}static canUseCookies(){return typeof document<"u"&&typeof document.cookie=="string"}set(e,t){s.canUseCookies()&&(document.cookie=`${this.formatName(e)}=${encodeURIComponent(t)}; path=/; max-age=${this.maxAgeSeconds}; samesite=lax`);}get(e){return s.canUseCookies()?s.readRawCookie(this.formatName(e)):null}delete(e){s.canUseCookies()&&(document.cookie=`${this.formatName(e)}=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; samesite=lax`);}clearAll(){Object.keys(this.keys).forEach(e=>{this.delete(e);});}formatName(e){return `${this.namespace}-${this.keys[e]}`}static readRawCookie(e){let t=document.cookie.split(";").map(i=>i.trim());for(let i of t){if(!i)continue;let[r,...n]=i.split("=");if(r===e)return decodeURIComponent(n.join("="))}return null}static sanitizeNamespace(e){let t=e.replace(/[^a-zA-Z0-9_-]/g,"");return t.length?t:"sophi-widget"}};s.DEFAULT_MAX_AGE_SECONDS=3600*24*30,s.DEFAULT_KEYS={clientId:"client-id",externalUserId:"external-user-id",sessionData:"session-data",metadataHash:"metadata-hash"};var d=s;var c=class{constructor(e,t,i){this.clientId=null;this.userId=void 0;this.storedUserId=null;this.baseUrl=e,this.apiKey=t,this.userId=i,this.cookieManager=new d(d.buildNamespace(e,t)),this.restoreSessionFromCookies();}async createSession(e){let t=`${this.baseUrl}/api/v1/auth/client/session`;try{let i={"Content-Type":"application/json",Accept:"application/json","x-api-key":this.apiKey};if(this.clientId){i["x-sophi-client-id"]=this.clientId;let g=this.storedUserId||null,l=this.userId||null;g!==l&&l&&(await this.mergeUser({userId:l}),this.storedUserId=l);}let r=await fetch(t,{method:"POST",headers:i,body:JSON.stringify({externalUserId:this.userId,metadata:e.metadata})});if(!r.ok){let g=await r.text();throw new Error(`Failed to create session: ${r.status} ${r.statusText}. ${g}`)}let n=await r.json();if(!n.success)throw new Error(`Session creation failed: ${n.message||"Unknown error"}`);if(!n.data)throw new Error("Session data is missing from response");return this.persistClientInfo(n.data.clientId,this.userId),n.data}catch(i){throw i instanceof Error?i:new Error(`Unexpected error during session creation: ${String(i)}`)}}validateSessionData(e){return !!(e.accessToken&&e.sessionId&&e.clientId&&e.companyCode&&e.expiresAt)}async mergeUser(e){let t=`${this.baseUrl}/api/v1/auth/client/info`;try{if(!this.clientId)throw new Error("Client ID is not set. Please create a session first.");let i=await fetch(t,{method:"PATCH",headers:{"Content-Type":"application/json",Accept:"application/json","x-api-key":this.apiKey,"x-sophi-client-id":this.clientId},body:JSON.stringify({externalUserId:e.userId})});if(!i.ok){let n=await i.text();throw new Error(`Failed to merge user: ${i.status} ${i.statusText}. ${n}`)}let r=await i.json();if(!r.success)throw new Error(`User merge failed: ${r.message||"Unknown error"}`);if(!r.data)throw new Error("Merge data is missing from response");return r.data}catch(i){throw i instanceof Error?i:new Error(`Unexpected error during user merge: ${String(i)}`)}}persistClientInfo(e,t){this.clientId=e,this.userId=t,this.storedUserId=t||null,d.canUseCookies()&&(this.cookieManager.set("clientId",e),this.cookieManager.set("externalUserId",t||""));}restoreSessionFromCookies(){if(!d.canUseCookies())return;let e=this.cookieManager.get("externalUserId"),t=this.cookieManager.get("clientId");if(this.storedUserId=e||null,!t)return;let i=e||null,r=this.userId||null;if(i===r){this.clientId=t,!this.userId&&e&&(this.userId=e);return}if(i&&!r){this.clearStoredClientInfo();return}if(i&&r&&i!==r){this.clearStoredClientInfo();return}if(!i&&r){this.clientId=t;return}}clearStoredClientInfo(){this.clientId=null,this.storedUserId=null,d.canUseCookies()&&this.cookieManager.clearAll();}};var m={WIDTH:"100%",HEIGHT:"600px"},p={test:"http://10.0.2.127:80",production:"https://api.usesophi.com"},I={CREATE_SESSION:"/api/v1/auth/client/session"},a={MISSING_API_KEY:"API key is required and must be a string",MISSING_CLIENT_ID:"Client ID is required and must be a string",MISSING_USER_ID:"User ID is required and must be a string",MISSING_CONTAINER:"Container is required",MISSING_IFRAME_URL:"Iframe URL is required and must be a string",INVALID_IFRAME_URL:"Invalid iframe URL",INVALID_ENVIRONMENT:"Invalid environment. Must be 'dev', 'test', 'staging', or 'production'",CONTAINER_NOT_FOUND:"Container element not found",NOT_INITIALIZED:"Widget not initialized. Call init() first.",ALREADY_INITIALIZED:"Sophi Widget is already initialized. Call destroy() first to reinitialize.",SESSION_CREATION_FAILED:"Failed to create authentication session",INVALID_SESSION_DATA:"Invalid session data received from API",YOU_NEED_TO_INIT_THE_WIDGET_FIRST:"You need to initialize the widget first. Call init() before calling this method."};var h=class{constructor(){this.config=null;this.iframe=null;this.container=null;this.eventListeners=new Map;this.messageHandler=null;this.isInitialized=false;this.iframeOrigin=null;this.sessionData=null;this.apiService=null;this.apiBaseUrl=null;}async init(e){if(this.isInitialized){console.warn(a.ALREADY_INITIALIZED);return}try{this.validateConfig(e),this.config=this.formatConfig(e),this.apiBaseUrl=p[e.environment||"production"],this.apiService=new c(this.apiBaseUrl,e.apiKey,e.userId),await this.createAuthSession(),this.isInitialized=!0;try{let t=new URL(this.getIframeUrl());this.iframeOrigin=t.origin;}catch{let i=new Error(`${a.INVALID_IFRAME_URL}: ${this.getIframeUrl()}`);throw this.emitError(i),i}if(this.container=this.resolveContainer(e.container),!this.container){let t=new Error(a.CONTAINER_NOT_FOUND);throw this.emitError(t),t}this.createIframe(),this.setupMessageListener(),this.iframe?.addEventListener("load",()=>{setTimeout(()=>{this.sendSessionData(),this.config?.layout&&this.sendLayoutConfig();},100);}),e.onReady&&e.onReady();}catch(t){this.isInitialized=false,this.config=null,this.apiService=null,this.sessionData=null;let i=t instanceof Error?t:new Error(String(t));throw this.emitError(i),i}}sendUserData(e){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let t={type:o.USER_DATA,data:e};this.postMessage(t);}sendToggleHistory(){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let e={type:o.TOGGLE_HISTORY};this.postMessage(e);}updateUserCart(e){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let t={type:o.UPDATE_USER_CART,data:e};this.postMessage(t);}onDestroy(){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let e={type:o.DESTROY};this.postMessage(e);}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t);}off(e,t){let i=this.eventListeners.get(e);i&&i.delete(t);}show(){this.iframe&&(this.iframe.style.display="block");}hide(){this.iframe&&(this.iframe.style.display="none");}async destroy(){this.onDestroy(),await new Promise(e=>setTimeout(e,300)),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.iframe&&this.iframe.parentNode&&(this.iframe.parentNode.removeChild(this.iframe),this.iframe=null),this.eventListeners.clear(),this.config=null,this.container=null,this.isInitialized=false,this.iframeOrigin=null,this.sessionData=null,this.apiService=null;}isReady(){return this.isInitialized&&this.iframe!==null}validateConfig(e){if(!e.apiKey||typeof e.apiKey!="string")throw new Error(a.MISSING_API_KEY);if(e.userId&&typeof e.userId!="string")throw new Error(a.MISSING_USER_ID);if(!e.container)throw new Error(a.MISSING_CONTAINER)}formatConfig(e){return {...e,userId:e.userId||void 0}}async createAuthSession(){if(!this.config||!this.apiService)throw new Error(a.NOT_INITIALIZED);try{if(this.sessionData=await this.apiService.createSession({externalUserId:this.config.userId,metadata:this.config.metadata}),!this.apiService.validateSessionData(this.sessionData))throw new Error(a.INVALID_SESSION_DATA)}catch(e){throw e instanceof Error?e:new Error(a.SESSION_CREATION_FAILED)}}sendSessionData(){if(!this.sessionData){console.warn("Session data not available");return}let e={type:o.SESSION_DATA,data:{...this.sessionData,userName:this.config?.userName}};this.postMessage(e);}sendLayoutConfig(){if(!this.config?.layout)return;let e={type:o.LAYOUT_CONFIG,data:this.config.layout};this.postMessage(e);}resolveContainer(e){return typeof e=="string"?document.querySelector(e):e}createIframe(){if(!this.container||!this.config)return;let e=document.createElement("iframe");e.src=this.buildIframeUrl(),e.style.width=this.config.width||"100%",e.style.height=this.config.height||"600px",e.style.border="none",e.title="Sophi AI Widget",e.allow="microphone; camera",this.container.appendChild(e),this.iframe=e;}buildIframeUrl(){return this.config?new URL(this.getIframeUrl()).toString():""}getIframeUrl(){return this.config?this.config.environment==="production"?"https://app.usesophi.com":"http://localhost:5173":""}setupMessageListener(){this.messageHandler=e=>{if(this.iframeOrigin&&e.origin!==this.iframeOrigin){console.warn(`Received message from untrusted origin: ${e.origin}`);return}try{let t=typeof e.data=="string"?JSON.parse(e.data):e.data;this.handleIncomingMessage(t);}catch(t){console.error("Error processing message from iframe:",t);}},window.addEventListener("message",this.messageHandler);}handleIncomingMessage(e){switch(e.type){case "add_to_cart":this.isValidAddToCartMessage(e.data)?this.emit("add_to_cart",e.data):(console.error("Invalid add_to_cart message structure:",e.data),this.emitError(new Error("Invalid add_to_cart message format")));break;case "send_to_checkout":this.emit("send_to_checkout",void 0);break;case "ready":this.emit("ready",void 0);break;case "error":let t=e.data instanceof Error?e.data:new Error(String(e.data));this.emitError(t);break;default:console.warn("Unknown message type:",e);}}isValidAddToCartMessage(e){if(!e||typeof e!="object")return false;let t=e;return Array.isArray(t.products)?t.products.every(i=>{if(!i||typeof i!="object")return false;let r=i;return !(typeof r.productId!="string"||r.variantId!==void 0&&typeof r.variantId!="string")}):false}postMessage(e){if(!this.iframe||!this.iframe.contentWindow||!this.iframeOrigin){console.warn("Cannot send message: iframe not ready");return}try{this.iframe.contentWindow.postMessage(e,this.iframeOrigin);}catch(t){console.error("Error sending message to iframe:",t),this.emitError(t instanceof Error?t:new Error(String(t)));}}emit(e,t){let i=this.eventListeners.get(e);i&&i.forEach(r=>{try{r(t);}catch(n){console.error(`Error in ${e} event handler:`,n);}});}emitError(e){this.emit("error",e),this.config?.onError&&this.config.onError(e);}};
1
+ 'use strict';var f={ADD_TO_CART:"add_to_cart",READY:"ready",ERROR:"error",SEND_TO_CHECKOUT:"send_to_checkout"},o={USER_DATA:"user_data",CONFIG:"config",UPDATE_USER_CART:"update_user_cart",DESTROY:"destroy",SESSION_DATA:"session_data",CLIENT_ID_UPDATED:"client_id_updated",LAYOUT_CONFIG:"layout_config",TOGGLE_HISTORY:"toggle_history"};var s=class s{constructor(e,t){this.namespace=s.sanitizeNamespace(e),this.maxAgeSeconds=t?.maxAgeSeconds??s.DEFAULT_MAX_AGE_SECONDS,this.keys={...s.DEFAULT_KEYS,...t?.keys??{}};}static buildNamespace(e,t){return s.sanitizeNamespace(`sophi-widget-${e}-${t}`)}static canUseCookies(){return typeof document<"u"&&typeof document.cookie=="string"}set(e,t){s.canUseCookies()&&(document.cookie=`${this.formatName(e)}=${encodeURIComponent(t)}; path=/; max-age=${this.maxAgeSeconds}; samesite=lax`);}get(e){return s.canUseCookies()?s.readRawCookie(this.formatName(e)):null}delete(e){s.canUseCookies()&&(document.cookie=`${this.formatName(e)}=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; samesite=lax`);}clearAll(){Object.keys(this.keys).forEach(e=>{this.delete(e);});}formatName(e){return `${this.namespace}-${this.keys[e]}`}static readRawCookie(e){let t=document.cookie.split(";").map(i=>i.trim());for(let i of t){if(!i)continue;let[r,...n]=i.split("=");if(r===e)return decodeURIComponent(n.join("="))}return null}static sanitizeNamespace(e){let t=e.replace(/[^a-zA-Z0-9_-]/g,"");return t.length?t:"sophi-widget"}};s.DEFAULT_MAX_AGE_SECONDS=3600*24*30,s.DEFAULT_KEYS={clientId:"client-id",externalUserId:"external-user-id",sessionData:"session-data",metadataHash:"metadata-hash"};var d=s;var c=class{constructor(e,t,i){this.clientId=null;this.userId=void 0;this.storedUserId=null;this.baseUrl=e,this.apiKey=t,this.userId=i,this.cookieManager=new d(d.buildNamespace(e,t)),this.restoreSessionFromCookies();}async createSession(e){let t=`${this.baseUrl}/api/v1/auth/client/session`;try{let i={"Content-Type":"application/json",Accept:"application/json","x-api-key":this.apiKey};if(this.clientId){i["x-sophi-client-id"]=this.clientId;let g=this.storedUserId||null,l=this.userId||null;g!==l&&l&&(await this.mergeUser({userId:l}),this.storedUserId=l);}let r=await fetch(t,{method:"POST",headers:i,body:JSON.stringify({externalUserId:this.userId,metadata:e.metadata})});if(!r.ok){let g=await r.text();throw new Error(`Failed to create session: ${r.status} ${r.statusText}. ${g}`)}let n=await r.json();if(!n.success)throw new Error(`Session creation failed: ${n.message||"Unknown error"}`);if(!n.data)throw new Error("Session data is missing from response");return this.persistClientInfo(n.data.clientId,this.userId),n.data}catch(i){throw i instanceof Error?i:new Error(`Unexpected error during session creation: ${String(i)}`)}}validateSessionData(e){return !!(e.accessToken&&e.sessionId&&e.clientId&&e.companyCode&&e.expiresAt)}async mergeUser(e){let t=`${this.baseUrl}/api/v1/auth/client/info`;try{if(!this.clientId)throw new Error("Client ID is not set. Please create a session first.");let i=await fetch(t,{method:"PATCH",headers:{"Content-Type":"application/json",Accept:"application/json","x-api-key":this.apiKey,"x-sophi-client-id":this.clientId},body:JSON.stringify({externalUserId:e.userId})});if(!i.ok){let n=await i.text();throw new Error(`Failed to merge user: ${i.status} ${i.statusText}. ${n}`)}let r=await i.json();if(!r.success)throw new Error(`User merge failed: ${r.message||"Unknown error"}`);if(!r.data)throw new Error("Merge data is missing from response");return r.data}catch(i){throw i instanceof Error?i:new Error(`Unexpected error during user merge: ${String(i)}`)}}persistClientInfo(e,t){this.clientId=e,this.userId=t,this.storedUserId=t||null,d.canUseCookies()&&(this.cookieManager.set("clientId",e),this.cookieManager.set("externalUserId",t||""));}restoreSessionFromCookies(){if(!d.canUseCookies())return;let e=this.cookieManager.get("externalUserId"),t=this.cookieManager.get("clientId");if(this.storedUserId=e||null,!t)return;let i=e||null,r=this.userId||null;if(i===r){this.clientId=t,!this.userId&&e&&(this.userId=e);return}if(i&&!r){this.clearStoredClientInfo();return}if(i&&r&&i!==r){this.clearStoredClientInfo();return}if(!i&&r){this.clientId=t;return}}clearStoredClientInfo(){this.clientId=null,this.storedUserId=null,d.canUseCookies()&&this.cookieManager.clearAll();}};var m={WIDTH:"100%",HEIGHT:"600px"},p={test:"http://10.0.2.127:80",production:"https://api.usesophi.com"},I={CREATE_SESSION:"/api/v1/auth/client/session"},a={MISSING_API_KEY:"API key is required and must be a string",MISSING_CLIENT_ID:"Client ID is required and must be a string",MISSING_USER_ID:"User ID is required and must be a string",MISSING_CONTAINER:"Container is required",MISSING_IFRAME_URL:"Iframe URL is required and must be a string",INVALID_IFRAME_URL:"Invalid iframe URL",INVALID_ENVIRONMENT:"Invalid environment. Must be 'dev', 'test', 'staging', or 'production'",CONTAINER_NOT_FOUND:"Container element not found",NOT_INITIALIZED:"Widget not initialized. Call init() first.",ALREADY_INITIALIZED:"Sophi Widget is already initialized. Call destroy() first to reinitialize.",SESSION_CREATION_FAILED:"Failed to create authentication session",INVALID_SESSION_DATA:"Invalid session data received from API",YOU_NEED_TO_INIT_THE_WIDGET_FIRST:"You need to initialize the widget first. Call init() before calling this method."};var h=class{constructor(){this.config=null;this.iframe=null;this.container=null;this.eventListeners=new Map;this.messageHandler=null;this.isInitialized=false;this.iframeOrigin=null;this.sessionData=null;this.apiService=null;this.apiBaseUrl=null;}async init(e){if(this.isInitialized){console.warn(a.ALREADY_INITIALIZED);return}try{this.validateConfig(e),this.config=this.formatConfig(e),this.apiBaseUrl=p[e.environment||"production"],this.apiService=new c(this.apiBaseUrl,e.apiKey,e.userId),await this.createAuthSession(),this.isInitialized=!0;try{let t=new URL(this.getIframeUrl());this.iframeOrigin=t.origin;}catch{let i=new Error(`${a.INVALID_IFRAME_URL}: ${this.getIframeUrl()}`);throw this.emitError(i),i}if(this.container=this.resolveContainer(e.container),!this.container){let t=new Error(a.CONTAINER_NOT_FOUND);throw this.emitError(t),t}this.createIframe(),this.setupMessageListener(),this.iframe?.addEventListener("load",()=>{setTimeout(()=>{this.sendSessionData(),this.config?.layout&&this.sendLayoutConfig();},100);}),e.onReady&&e.onReady();}catch(t){this.isInitialized=false,this.config=null,this.apiService=null,this.sessionData=null;let i=t instanceof Error?t:new Error(String(t));throw this.emitError(i),i}}sendUserData(e){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let t={type:o.USER_DATA,data:e};this.postMessage(t);}sendToggleHistory(){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let e={type:o.TOGGLE_HISTORY};this.postMessage(e);}updateUserCart(e){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let t={type:o.UPDATE_USER_CART,data:e};this.postMessage(t);}onDestroy(){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let e={type:o.DESTROY};this.postMessage(e);}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t);}off(e,t){let i=this.eventListeners.get(e);i&&i.delete(t);}show(){this.iframe&&(this.iframe.style.display="block");}hide(){this.iframe&&(this.iframe.style.display="none");}async destroy(){this.onDestroy(),await new Promise(e=>setTimeout(e,300)),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.iframe&&this.iframe.parentNode&&(this.iframe.parentNode.removeChild(this.iframe),this.iframe=null),this.eventListeners.clear(),this.config=null,this.container=null,this.isInitialized=false,this.iframeOrigin=null,this.sessionData=null,this.apiService=null;}isReady(){return this.isInitialized&&this.iframe!==null}validateConfig(e){if(!e.apiKey||typeof e.apiKey!="string")throw new Error(a.MISSING_API_KEY);if(e.userId&&typeof e.userId!="string")throw new Error(a.MISSING_USER_ID);if(!e.container)throw new Error(a.MISSING_CONTAINER)}formatConfig(e){return {...e,userId:e.userId||void 0}}async createAuthSession(){if(!this.config||!this.apiService)throw new Error(a.NOT_INITIALIZED);try{if(this.sessionData=await this.apiService.createSession({externalUserId:this.config.userId,metadata:this.config.metadata}),!this.apiService.validateSessionData(this.sessionData))throw new Error(a.INVALID_SESSION_DATA)}catch(e){throw e instanceof Error?e:new Error(a.SESSION_CREATION_FAILED)}}sendSessionData(){if(!this.sessionData){console.warn("Session data not available");return}let e={type:o.SESSION_DATA,data:{...this.sessionData,userName:this.config?.userName}};this.postMessage(e);}sendLayoutConfig(){if(!this.config?.layout)return;let e={type:o.LAYOUT_CONFIG,data:this.config.layout};this.postMessage(e);}resolveContainer(e){return typeof e=="string"?document.querySelector(e):e}createIframe(){if(!this.container||!this.config)return;let e=document.createElement("iframe");e.src=this.buildIframeUrl(),e.style.width=this.config.width||"100%",e.style.height=this.config.height||"600px",e.style.border="none",e.title="Sophi AI Widget",e.allow="microphone; camera; clipboard-write",this.container.appendChild(e),this.iframe=e;}buildIframeUrl(){return this.config?new URL(this.getIframeUrl()).toString():""}getIframeUrl(){return this.config?this.config.environment==="production"?"https://app.usesophi.com":"http://localhost:5173":""}setupMessageListener(){this.messageHandler=e=>{if(this.iframeOrigin&&e.origin!==this.iframeOrigin){console.warn(`Received message from untrusted origin: ${e.origin}`);return}try{let t=typeof e.data=="string"?JSON.parse(e.data):e.data;this.handleIncomingMessage(t);}catch(t){console.error("Error processing message from iframe:",t);}},window.addEventListener("message",this.messageHandler);}handleIncomingMessage(e){switch(e.type){case "add_to_cart":this.isValidAddToCartMessage(e.data)?this.emit("add_to_cart",e.data):(console.error("Invalid add_to_cart message structure:",e.data),this.emitError(new Error("Invalid add_to_cart message format")));break;case "send_to_checkout":this.emit("send_to_checkout",void 0);break;case "ready":this.emit("ready",void 0);break;case "error":let t=e.data instanceof Error?e.data:new Error(String(e.data));this.emitError(t);break;default:console.warn("Unknown message type:",e);}}isValidAddToCartMessage(e){if(!e||typeof e!="object")return false;let t=e;return Array.isArray(t.products)?t.products.every(i=>{if(!i||typeof i!="object")return false;let r=i;return !(typeof r.productId!="string"||r.variantId!==void 0&&typeof r.variantId!="string")}):false}postMessage(e){if(!this.iframe||!this.iframe.contentWindow||!this.iframeOrigin){console.warn("Cannot send message: iframe not ready");return}try{this.iframe.contentWindow.postMessage(e,this.iframeOrigin);}catch(t){console.error("Error sending message to iframe:",t),this.emitError(t instanceof Error?t:new Error(String(t)));}}emit(e,t){let i=this.eventListeners.get(e);i&&i.forEach(r=>{try{r(t);}catch(n){console.error(`Error in ${e} event handler:`,n);}});}emitError(e){this.emit("error",e),this.config?.onError&&this.config.onError(e);}};
2
2
  exports.API_BASE_URLS=p;exports.API_ENDPOINTS=I;exports.ApiService=c;exports.DEFAULT_CONFIG=m;exports.ERROR_MESSAGES=a;exports.IncomingMessageTypes=f;exports.OutgoingMessageTypes=o;exports.SophiWidget=h;//# sourceMappingURL=index.cjs.map
3
3
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/services/cookie.utils.ts","../src/services/api.service.ts","../src/constants/config.ts","../src/SophiWidget.ts"],"names":["IncomingMessageTypes","OutgoingMessageTypes","_CookieManager","namespace","options","baseUrl","apiKey","key","value","name","cookies","cookie","cookieName","cookieValueParts","sanitized","CookieManager","ApiService","userId","request","url","headers","normalizedStored","normalizedCurrent","response","errorText","data","error","sessionData","clientId","storedUserId","storedClientId","normalizedStoredUserId","normalizedCurrentUserId","DEFAULT_CONFIG","API_BASE_URLS","API_ENDPOINTS","ERROR_MESSAGES","SophiWidget","config","err","message","cart","event","handler","handlers","resolve","container","iframe","product","prod"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Layout options sent to the iframe on init so the child app can adjust its layout.\n */\nexport interface LayoutConfig {\n /**\n * When true, show the header; when false, hide it.\n * Omitted/undefined means use the child app's default.\n */\n header?: boolean;\n}\n\n/**\n * Configuration for initializing the Sophi Widget\n */\nexport interface SophiConfig {\n /**\n * API key for authentication with Sophi services (x-api-key header)\n * This comes from the parent application\n */\n apiKey: string;\n\n /**\n * External user ID for authentication (x-sophi-external-user-id header)\n * This comes from the parent application\n */\n userId?: string;\n\n /**\n * User name for the user\n */\n userName?: string;\n\n /**\n * Container element selector (e.g., '#widget') or HTMLElement where the widget will be mounted\n */\n container: string | HTMLElement;\n\n /**\n * Optional metadata to send with the session request\n */\n metadata?: Record<string, unknown>;\n\n /**\n * Width of the widget iframe\n * @default '100%'\n */\n width?: string;\n\n /**\n * Height of the widget iframe\n * @default '600px'\n */\n height?: string;\n\n /**\n * Callback fired when the widget is ready\n */\n onReady?: () => void;\n\n /**\n * Callback fired when an error occurs\n */\n onError?: (error: Error) => void;\n\n /**\n * Environment to use for the API\n */\n environment?: \"test\" | \"production\";\n\n /**\n * Layout options sent to the iframe on init. The child app receives these via a\n * postMessage and can show/hide header (and future layout options) accordingly.\n */\n layout?: LayoutConfig;\n}\n\n/**\n * Product information for add to cart events\n */\nexport interface Product {\n /**\n * Unique product identifier\n */\n productId: string;\n\n /**\n * Optional variant identifier\n */\n variantId?: string;\n}\n\n/**\n * Add to cart event data\n */\nexport interface AddToCartEvent {\n /**\n * List of products to add to cart\n */\n products: Product[];\n}\n\n/**\n * User data that can be sent to the widget\n */\nexport interface UserData {\n /**\n * User ID\n */\n userId?: string;\n\n /**\n * User email\n */\n email?: string;\n\n /**\n * User name\n */\n name?: string;\n\n /**\n * Additional custom data\n */\n [key: string]: unknown;\n}\n\nexport interface IUserCartItem {\n productId: string;\n variantId: string;\n quantity?: number;\n}\n\nexport interface IUserCart {\n cardId: string;\n items: IUserCartItem[];\n}\n\n/**\n * Message types that can be received from the iframe\n */\nexport type IncomingMessageType = \"add_to_cart\" | \"send_to_checkout\" | \"ready\" | \"error\";\n\n/**\n * Incoming message type constants for easy access\n * @example\n * widget.on(IncomingMessageTypes.ADD_TO_CART, (data) => {...})\n */\nexport const IncomingMessageTypes = {\n ADD_TO_CART: \"add_to_cart\",\n READY: \"ready\",\n ERROR: \"error\",\n SEND_TO_CHECKOUT: \"send_to_checkout\",\n} as const;\n\n/**\n * Message types that can be sent to the iframe\n */\nexport type OutgoingMessageType = \"user_data\" | \"config\" | \"update_user_cart\" | \"destroy\" | \"session_data\" | \"client_id_updated\" | \"layout_config\" | \"toggle_history\";\n\n/**\n * Outgoing message type constants for easy access\n * @example\n * widget.sendMessage({ type: OutgoingMessageTypes.USER_DATA, data: {...} })\n */\nexport const OutgoingMessageTypes = {\n USER_DATA: \"user_data\",\n CONFIG: \"config\",\n UPDATE_USER_CART: \"update_user_cart\",\n DESTROY: \"destroy\",\n SESSION_DATA: \"session_data\",\n CLIENT_ID_UPDATED: \"client_id_updated\",\n LAYOUT_CONFIG: \"layout_config\",\n TOGGLE_HISTORY: \"toggle_history\",\n} as const;\n\n/**\n * Incoming message structure from iframe\n */\nexport interface IncomingMessage {\n type: IncomingMessageType;\n data?: unknown;\n}\n\n/**\n * Outgoing message structure to iframe\n */\nexport interface OutgoingMessage {\n type: OutgoingMessageType;\n data?: unknown;\n}\n\n/**\n * Event map for type-safe event handling\n */\nexport interface SophiEventMap {\n /**\n * Fired when products should be added to cart\n */\n add_to_cart: AddToCartEvent;\n\n /**\n * Fired when the widget is ready\n */\n ready: void;\n\n /**\n * Fired when an error occurs\n */\n error: Error;\n\n /**\n * Fired when the user should be sent to checkout\n */\n send_to_checkout: void;\n}\n\n/**\n * Event handler type\n */\nexport type EventHandler<T> = (data: T) => void;\n\n/**\n * Event name type\n */\nexport type EventName = keyof SophiEventMap;\n\n/**\n * Authentication session request payload\n */\nexport interface AuthSessionRequest {\n /**\n * External user ID from the parent application\n */\n externalUserId?: string;\n\n /**\n * Optional metadata to include with the session\n */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Session data returned from the authentication API\n */\nexport interface SessionData {\n /**\n * JWT access token for authenticating requests\n */\n accessToken: string;\n\n /**\n * Unique session identifier\n */\n sessionId: string;\n\n /**\n * Client ID\n */\n clientId: string;\n\n /**\n * Company code\n */\n companyCode: string;\n\n /**\n * Session expiration timestamp\n */\n expiresAt: string;\n\n /**\n * userName of the user\n */\n userName: string;\n}\n\n/**\n * Authentication session API response\n */\nexport interface AuthSessionResponse {\n /**\n * Whether the request was successful\n */\n success: boolean;\n\n /**\n * Response message\n */\n message: string;\n\n /**\n * Session data\n */\n data?: SessionData;\n}\n\n/**\n * Merge user request payload\n */\nexport interface MergeUserRequest {\n /**\n * The logged-in user ID to merge to\n */\n userId: string;\n}\n\n/**\n * Merge user data returned from the API\n */\nexport interface MergeUserData {\n /**\n * The resulting client ID after merge\n */\n clientId: string;\n\n /**\n * The external user ID\n */\n externalUserId: string;\n}\n\n/**\n * Merge user API response\n */\nexport interface MergeUserResponse {\n /**\n * Whether the request was successful\n */\n success: boolean;\n\n /**\n * Response message\n */\n message: string;\n\n /**\n * Merge result data\n */\n data?: MergeUserData;\n}\n","export type CookieKey = \"clientId\" | \"externalUserId\" | \"sessionData\" | \"metadataHash\";\n\nexport interface CookieManagerOptions {\n readonly maxAgeSeconds?: number;\n readonly keys?: Partial<Record<CookieKey, string>>;\n}\n\nexport class CookieManager {\n static readonly DEFAULT_MAX_AGE_SECONDS = 60 * 60 * 24 * 30; // 30 days\n static readonly DEFAULT_KEYS: Record<CookieKey, string> = {\n clientId: \"client-id\",\n externalUserId: \"external-user-id\",\n sessionData: \"session-data\",\n metadataHash: \"metadata-hash\",\n };\n\n constructor(namespace: string, options?: CookieManagerOptions) {\n this.namespace = CookieManager.sanitizeNamespace(namespace);\n this.maxAgeSeconds = options?.maxAgeSeconds ?? CookieManager.DEFAULT_MAX_AGE_SECONDS;\n this.keys = { ...CookieManager.DEFAULT_KEYS, ...(options?.keys ?? {}) };\n }\n\n private readonly namespace: string;\n private readonly maxAgeSeconds: number;\n private readonly keys: Record<CookieKey, string>;\n\n static buildNamespace(baseUrl: string, apiKey: string): string {\n return CookieManager.sanitizeNamespace(`sophi-widget-${baseUrl}-${apiKey}`);\n }\n\n static canUseCookies(): boolean {\n return typeof document !== \"undefined\" && typeof document.cookie === \"string\";\n }\n\n set(key: CookieKey, value: string): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n document.cookie = `${this.formatName(key)}=${encodeURIComponent(value)}; path=/; max-age=${this.maxAgeSeconds}; samesite=lax`;\n }\n\n get(key: CookieKey): string | null {\n if (!CookieManager.canUseCookies()) {\n return null;\n }\n\n return CookieManager.readRawCookie(this.formatName(key));\n }\n\n delete(key: CookieKey): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n document.cookie = `${this.formatName(key)}=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; samesite=lax`;\n }\n\n clearAll(): void {\n Object.keys(this.keys).forEach((key) => {\n this.delete(key as CookieKey);\n });\n }\n\n private formatName(key: CookieKey): string {\n return `${this.namespace}-${this.keys[key]}`;\n }\n\n private static readRawCookie(name: string): string | null {\n const cookies = document.cookie.split(\";\").map((cookie) => cookie.trim());\n for (const cookie of cookies) {\n if (!cookie) {\n continue;\n }\n const [cookieName, ...cookieValueParts] = cookie.split(\"=\");\n if (cookieName === name) {\n return decodeURIComponent(cookieValueParts.join(\"=\"));\n }\n }\n return null;\n }\n\n private static sanitizeNamespace(value: string): string {\n const sanitized = value.replace(/[^a-zA-Z0-9_-]/g, \"\");\n return sanitized.length ? sanitized : \"sophi-widget\";\n }\n}\n","import type { AuthSessionRequest, AuthSessionResponse, SessionData, MergeUserRequest, MergeUserResponse, MergeUserData } from \"../types\";\nimport { CookieManager } from \"./cookie.utils\";\n\n/**\n * API Service for Sophi authentication and session management\n */\nexport class ApiService {\n private baseUrl: string;\n private apiKey: string;\n private clientId: string | null = null;\n private userId: string | undefined = undefined;\n private storedUserId: string | null = null; // Track the userId from cookies for merge detection\n private cookieManager: CookieManager;\n\n constructor(baseUrl: string, apiKey: string, userId?: string) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.userId = userId;\n this.cookieManager = new CookieManager(CookieManager.buildNamespace(baseUrl, apiKey));\n this.restoreSessionFromCookies();\n }\n\n /**\n * Create a client session by calling the authentication endpoint\n * @param request - Session request with optional externalUserId and metadata\n * @returns Session data including accessToken, sessionId, etc.\n */\n async createSession(request: AuthSessionRequest): Promise<SessionData> {\n const url = `${this.baseUrl}/api/v1/auth/client/session`;\n\n try {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"x-api-key\": this.apiKey,\n };\n if (this.clientId) {\n headers[\"x-sophi-client-id\"] = this.clientId;\n // Check if we need to merge: user changed from stored (could be empty) to current\n const normalizedStored = this.storedUserId || null;\n const normalizedCurrent = this.userId || null;\n if (normalizedStored !== normalizedCurrent && normalizedCurrent) {\n await this.mergeUser({ userId: normalizedCurrent });\n // Update storedUserId after successful merge\n this.storedUserId = normalizedCurrent;\n }\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n externalUserId: this.userId,\n metadata: request.metadata,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to create session: ${response.status} ${response.statusText}. ${errorText}`);\n }\n\n const data: AuthSessionResponse = await response.json();\n\n if (!data.success) {\n throw new Error(`Session creation failed: ${data.message || \"Unknown error\"}`);\n }\n\n if (!data.data) {\n throw new Error(\"Session data is missing from response\");\n }\n this.persistClientInfo(data.data.clientId, this.userId);\n return data.data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error during session creation: ${String(error)}`);\n }\n }\n\n /**\n * Validate session data\n */\n validateSessionData(sessionData: SessionData): boolean {\n return !!(sessionData.accessToken && sessionData.sessionId && sessionData.clientId && sessionData.companyCode && sessionData.expiresAt);\n }\n\n /**\n * Merge guest user with logged-in user\n * @param request - Merge request with guestId and userId\n * @returns Merge result data including the resulting clientId\n */\n async mergeUser(request: MergeUserRequest): Promise<MergeUserData> {\n const url = `${this.baseUrl}/api/v1/auth/client/info`;\n\n try {\n if (!this.clientId) {\n throw new Error(\"Client ID is not set. Please create a session first.\");\n }\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"x-api-key\": this.apiKey,\n \"x-sophi-client-id\": this.clientId,\n },\n body: JSON.stringify({\n externalUserId: request.userId,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to merge user: ${response.status} ${response.statusText}. ${errorText}`);\n }\n\n const data: MergeUserResponse = await response.json();\n\n if (!data.success) {\n throw new Error(`User merge failed: ${data.message || \"Unknown error\"}`);\n }\n\n if (!data.data) {\n throw new Error(\"Merge data is missing from response\");\n }\n\n return data.data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error during user merge: ${String(error)}`);\n }\n }\n\n private persistClientInfo(clientId: string, userId?: string): void {\n this.clientId = clientId;\n this.userId = userId;\n this.storedUserId = userId || null; // Update stored userId to match current state\n\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n this.cookieManager.set(\"clientId\", clientId);\n // Always save externalUserId (even if empty) to track the session state\n this.cookieManager.set(\"externalUserId\", userId || \"\");\n }\n\n private restoreSessionFromCookies(): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n const storedUserId = this.cookieManager.get(\"externalUserId\");\n const storedClientId = this.cookieManager.get(\"clientId\");\n\n // Store the userId from cookies for merge detection later\n this.storedUserId = storedUserId || null;\n\n // If no clientId in cookies, nothing to restore\n if (!storedClientId) {\n return;\n }\n\n // Normalize empty values (undefined, null, empty string) to null for comparison\n const normalizedStoredUserId = storedUserId || null;\n const normalizedCurrentUserId = this.userId || null;\n\n // If userIds match, restore both clientId and userId\n if (normalizedStoredUserId === normalizedCurrentUserId) {\n this.clientId = storedClientId;\n if (!this.userId && storedUserId) {\n this.userId = storedUserId;\n }\n return;\n }\n\n // UserIds don't match - determine if we should clear or keep clientId\n \n // Case 1: Logout (filled -> empty) - clear session\n if (normalizedStoredUserId && !normalizedCurrentUserId) {\n this.clearStoredClientInfo();\n return;\n }\n\n // Case 2: Different logged-in users (filled -> different filled) - clear session for new user\n if (normalizedStoredUserId && normalizedCurrentUserId && normalizedStoredUserId !== normalizedCurrentUserId) {\n this.clearStoredClientInfo();\n return;\n }\n\n // Case 3: Guest -> Logged-in user (empty -> filled) - keep clientId for merge\n if (!normalizedStoredUserId && normalizedCurrentUserId) {\n this.clientId = storedClientId;\n return;\n }\n }\n\n private clearStoredClientInfo(): void {\n this.clientId = null;\n this.storedUserId = null;\n\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n this.cookieManager.clearAll();\n }\n}\n","/**\n * Default configuration constants for Sophi Widget\n */\nexport const DEFAULT_CONFIG = {\n /**\n * Default width of the widget iframe\n */\n WIDTH: \"100%\",\n\n /**\n * Default height of the widget iframe\n */\n HEIGHT: \"600px\",\n} as const;\n\n/**\n * API base URLs for different environments\n *\n * Note: These URLs will be visible in the client-side bundle.\n * This is normal and safe - the real security is in your API key validation.\n *\n * To use different URLs, modify these values before building the SDK.\n *\n * Production API URL - update before building for production\n */\nexport const API_BASE_URLS = {\n test: \"http://10.0.2.127:80\",\n production: \"https://api.usesophi.com\",\n} as const;\n\n/**\n * API endpoints configuration\n */\nexport const API_ENDPOINTS = {\n /**\n * Session creation endpoint path\n */\n CREATE_SESSION: \"/api/v1/auth/client/session\",\n} as const;\n\n/**\n * Error messages\n */\nexport const ERROR_MESSAGES = {\n MISSING_API_KEY: \"API key is required and must be a string\",\n MISSING_CLIENT_ID: \"Client ID is required and must be a string\",\n MISSING_USER_ID: \"User ID is required and must be a string\",\n MISSING_CONTAINER: \"Container is required\",\n MISSING_IFRAME_URL: \"Iframe URL is required and must be a string\",\n INVALID_IFRAME_URL: \"Invalid iframe URL\",\n INVALID_ENVIRONMENT: \"Invalid environment. Must be 'dev', 'test', 'staging', or 'production'\",\n CONTAINER_NOT_FOUND: \"Container element not found\",\n NOT_INITIALIZED: \"Widget not initialized. Call init() first.\",\n ALREADY_INITIALIZED: \"Sophi Widget is already initialized. Call destroy() first to reinitialize.\",\n SESSION_CREATION_FAILED: \"Failed to create authentication session\",\n INVALID_SESSION_DATA: \"Invalid session data received from API\",\n YOU_NEED_TO_INIT_THE_WIDGET_FIRST: \"You need to initialize the widget first. Call init() before calling this method.\",\n} as const;\n","import { type SophiConfig, type UserData, type EventHandler, type EventName, type SophiEventMap, type IncomingMessage, type OutgoingMessage, type AddToCartEvent, type IUserCart, type SessionData, type MergeUserRequest, type MergeUserData, OutgoingMessageTypes } from \"./types\";\nimport { ApiService } from \"./services/api.service\";\nimport { DEFAULT_CONFIG, ERROR_MESSAGES, API_BASE_URLS } from \"./constants/config\";\n\n/**\n * Main Sophi Widget SDK class\n * Provides a framework-agnostic way to embed and interact with the Sophi AI widget\n */\nexport class SophiWidget {\n private config: SophiConfig | null = null;\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLElement | null = null;\n private eventListeners: Map<EventName, Set<EventHandler<any>>> = new Map();\n private messageHandler: ((event: MessageEvent) => void) | null = null;\n private isInitialized = false;\n private iframeOrigin: string | null = null;\n private sessionData: SessionData | null = null;\n private apiService: ApiService | null = null;\n private apiBaseUrl: string | null = null;\n\n /**\n * Initialize the widget with configuration\n * @param config - Widget configuration\n */\n public async init(config: SophiConfig): Promise<void> {\n if (this.isInitialized) {\n console.warn(ERROR_MESSAGES.ALREADY_INITIALIZED);\n return;\n }\n\n try {\n // Validate configuration\n this.validateConfig(config);\n\n this.config = this.formatConfig(config);\n\n // Determine API URL based on environment\n this.apiBaseUrl = API_BASE_URLS[config.environment || \"production\"];\n\n // Initialize API service\n this.apiService = new ApiService(this.apiBaseUrl, config.apiKey, config.userId);\n\n // Create authentication session\n await this.createAuthSession();\n\n this.isInitialized = true;\n\n // Extract origin from iframe URL for security\n try {\n const url = new URL(this.getIframeUrl());\n this.iframeOrigin = url.origin;\n } catch (error) {\n const err = new Error(`${ERROR_MESSAGES.INVALID_IFRAME_URL}: ${this.getIframeUrl()}`);\n this.emitError(err);\n throw err;\n }\n\n // Resolve container element\n this.container = this.resolveContainer(config.container);\n\n if (!this.container) {\n const err = new Error(ERROR_MESSAGES.CONTAINER_NOT_FOUND);\n this.emitError(err);\n throw err;\n }\n\n // Create and mount iframe\n this.createIframe();\n\n // Setup postMessage listener\n this.setupMessageListener();\n\n // Send session data to iframe after it's loaded\n this.iframe?.addEventListener(\"load\", () => {\n // Small delay to ensure iframe is fully ready\n setTimeout(() => {\n this.sendSessionData();\n if (this.config?.layout) {\n this.sendLayoutConfig();\n }\n }, 100);\n });\n\n // Call onReady callback if provided\n if (config.onReady) {\n config.onReady();\n }\n } catch (error) {\n // Reset state on error\n this.isInitialized = false;\n this.config = null;\n this.apiService = null;\n this.sessionData = null;\n\n const err = error instanceof Error ? error : new Error(String(error));\n this.emitError(err);\n throw err;\n }\n }\n\n /**\n * Send user data to the widget\n * @param data - User data object\n */\n public sendUserData(data: UserData): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.USER_DATA,\n data,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Toggle chat history visibility in the iframe child app.\n */\n public sendToggleHistory(): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.TOGGLE_HISTORY,\n };\n\n this.postMessage(message);\n }\n\n public updateUserCart(cart: IUserCart): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.UPDATE_USER_CART,\n data: cart,\n };\n\n this.postMessage(message);\n }\n\n private onDestroy(): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.DESTROY,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Register an event listener\n * @param event - Event name\n * @param handler - Event handler function\n */\n public on<K extends EventName>(event: K, handler: EventHandler<SophiEventMap[K]>): void {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n /**\n * Unregister an event listener\n * @param event - Event name\n * @param handler - Event handler function to remove\n */\n public off<K extends EventName>(event: K, handler: EventHandler<SophiEventMap[K]>): void {\n const handlers = this.eventListeners.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n }\n\n /**\n * Show the widget\n */\n public show(): void {\n if (this.iframe) {\n this.iframe.style.display = \"block\";\n }\n }\n\n /**\n * Hide the widget\n */\n public hide(): void {\n if (this.iframe) {\n this.iframe.style.display = \"none\";\n }\n }\n\n /**\n * Destroy the widget and cleanup resources\n * Waits 300ms after sending destroy message to give iframe time to cleanup\n */\n public async destroy(): Promise<void> {\n this.onDestroy();\n\n // Wait 300ms to give iframe time to process the destroy event and cleanup\n await new Promise((resolve) => setTimeout(resolve, 300));\n\n // Remove message listener\n if (this.messageHandler) {\n window.removeEventListener(\"message\", this.messageHandler);\n this.messageHandler = null;\n }\n\n // Remove iframe\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n this.iframe = null;\n }\n\n // Clear event listeners\n this.eventListeners.clear();\n\n // Reset state\n this.config = null;\n this.container = null;\n this.isInitialized = false;\n this.iframeOrigin = null;\n this.sessionData = null;\n this.apiService = null;\n }\n\n /**\n * Check if widget is initialized\n */\n public isReady(): boolean {\n return this.isInitialized && this.iframe !== null;\n }\n\n /**\n * Validate configuration\n */\n private validateConfig(config: SophiConfig): void {\n if (!config.apiKey || typeof config.apiKey !== \"string\") {\n throw new Error(ERROR_MESSAGES.MISSING_API_KEY);\n }\n\n if (config.userId && typeof config.userId !== \"string\") {\n throw new Error(ERROR_MESSAGES.MISSING_USER_ID);\n }\n\n if (!config.container) {\n throw new Error(ERROR_MESSAGES.MISSING_CONTAINER);\n }\n }\n\n /**\n * Format configuration\n */\n private formatConfig(config: SophiConfig): SophiConfig {\n return {\n ...config,\n userId: config.userId || undefined,\n };\n }\n\n /**\n * Create authentication session with the API\n */\n private async createAuthSession(): Promise<void> {\n if (!this.config || !this.apiService) {\n throw new Error(ERROR_MESSAGES.NOT_INITIALIZED);\n }\n\n try {\n this.sessionData = await this.apiService.createSession({\n externalUserId: this.config.userId,\n metadata: this.config.metadata,\n });\n\n // Validate session data\n if (!this.apiService.validateSessionData(this.sessionData)) {\n throw new Error(ERROR_MESSAGES.INVALID_SESSION_DATA);\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(ERROR_MESSAGES.SESSION_CREATION_FAILED);\n throw err;\n }\n }\n\n /**\n * Send session data to iframe\n */\n private sendSessionData(): void {\n if (!this.sessionData) {\n console.warn(\"Session data not available\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.SESSION_DATA,\n data: { ...this.sessionData, userName: this.config?.userName },\n };\n\n this.postMessage(message);\n }\n\n /**\n * Send layout config to iframe so the child app can apply layout options (e.g. show/hide header).\n */\n private sendLayoutConfig(): void {\n if (!this.config?.layout) {\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.LAYOUT_CONFIG,\n data: this.config.layout,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Resolve container element from selector or element\n */\n private resolveContainer(container: string | HTMLElement): HTMLElement | null {\n if (typeof container === \"string\") {\n return document.querySelector(container);\n }\n return container;\n }\n\n /**\n * Create and mount the iframe\n */\n private createIframe(): void {\n if (!this.container || !this.config) {\n return;\n }\n\n const iframe = document.createElement(\"iframe\");\n\n // Set iframe attributes\n iframe.src = this.buildIframeUrl();\n iframe.style.width = this.config.width || \"100%\";\n iframe.style.height = this.config.height || \"600px\";\n iframe.style.border = \"none\";\n iframe.title = \"Sophi AI Widget\";\n iframe.allow = \"microphone; camera\";\n\n // Append to container\n this.container.appendChild(iframe);\n this.iframe = iframe;\n }\n\n /**\n * Build iframe URL with query parameters\n */\n private buildIframeUrl(): string {\n if (!this.config) {\n return \"\";\n }\n const url = new URL(this.getIframeUrl());\n\n return url.toString();\n }\n\n private getIframeUrl(): string {\n if (!this.config) {\n return \"\";\n }\n if (this.config.environment === \"production\") {\n return \"https://app.usesophi.com\";\n }\n return \"http://localhost:5173\";\n }\n\n /**\n * Setup postMessage listener for iframe communication\n */\n private setupMessageListener(): void {\n this.messageHandler = (event: MessageEvent) => {\n // Validate origin for security\n if (this.iframeOrigin && event.origin !== this.iframeOrigin) {\n console.warn(`Received message from untrusted origin: ${event.origin}`);\n return;\n }\n\n try {\n // Parse message\n const message: IncomingMessage = typeof event.data === \"string\" ? JSON.parse(event.data) : event.data;\n\n // Handle different message types\n this.handleIncomingMessage(message);\n } catch (error) {\n console.error(\"Error processing message from iframe:\", error);\n }\n };\n\n window.addEventListener(\"message\", this.messageHandler);\n }\n\n /**\n * Handle incoming messages from iframe\n */\n private handleIncomingMessage(message: IncomingMessage): void {\n switch (message.type) {\n case \"add_to_cart\":\n if (this.isValidAddToCartMessage(message.data)) {\n this.emit(\"add_to_cart\", message.data);\n } else {\n console.error(\"Invalid add_to_cart message structure:\", message.data);\n this.emitError(new Error(\"Invalid add_to_cart message format\"));\n }\n break;\n\n case \"send_to_checkout\":\n this.emit(\"send_to_checkout\", undefined);\n break;\n case \"ready\":\n this.emit(\"ready\", undefined);\n break;\n\n case \"error\":\n const error = message.data instanceof Error ? message.data : new Error(String(message.data));\n this.emitError(error);\n break;\n\n default:\n console.warn(\"Unknown message type:\", message);\n }\n }\n\n /**\n * Validate add_to_cart message structure\n */\n private isValidAddToCartMessage(data: unknown): data is AddToCartEvent {\n if (!data || typeof data !== \"object\") {\n return false;\n }\n\n const event = data as Record<string, unknown>;\n\n // Check products array exists and is an array\n if (!Array.isArray(event.products)) {\n return false;\n }\n\n // Validate each product in the array\n return event.products.every((product) => {\n if (!product || typeof product !== \"object\") {\n return false;\n }\n const prod = product as Record<string, unknown>;\n\n // productId is required and must be a string\n if (typeof prod.productId !== \"string\") {\n return false;\n }\n\n // variantId is optional, but if present must be a string\n if (prod.variantId !== undefined && typeof prod.variantId !== \"string\") {\n return false;\n }\n\n return true;\n });\n }\n\n /**\n * Post message to iframe\n */\n private postMessage(message: OutgoingMessage): void {\n if (!this.iframe || !this.iframe.contentWindow || !this.iframeOrigin) {\n console.warn(\"Cannot send message: iframe not ready\");\n return;\n }\n\n try {\n this.iframe.contentWindow.postMessage(message, this.iframeOrigin);\n } catch (error) {\n console.error(\"Error sending message to iframe:\", error);\n this.emitError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Emit event to registered listeners\n */\n private emit<K extends EventName>(event: K, data: SophiEventMap[K]): void {\n const handlers = this.eventListeners.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(data);\n } catch (error) {\n console.error(`Error in ${event} event handler:`, error);\n }\n });\n }\n }\n\n /**\n * Emit error event\n */\n private emitError(error: Error): void {\n this.emit(\"error\", error);\n\n // Also call onError callback if provided\n if (this.config?.onError) {\n this.config.onError(error);\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/services/cookie.utils.ts","../src/services/api.service.ts","../src/constants/config.ts","../src/SophiWidget.ts"],"names":["IncomingMessageTypes","OutgoingMessageTypes","_CookieManager","namespace","options","baseUrl","apiKey","key","value","name","cookies","cookie","cookieName","cookieValueParts","sanitized","CookieManager","ApiService","userId","request","url","headers","normalizedStored","normalizedCurrent","response","errorText","data","error","sessionData","clientId","storedUserId","storedClientId","normalizedStoredUserId","normalizedCurrentUserId","DEFAULT_CONFIG","API_BASE_URLS","API_ENDPOINTS","ERROR_MESSAGES","SophiWidget","config","err","message","cart","event","handler","handlers","resolve","container","iframe","product","prod"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Layout options sent to the iframe on init so the child app can adjust its layout.\n */\nexport interface LayoutConfig {\n /**\n * When true, show the header; when false, hide it.\n * Omitted/undefined means use the child app's default.\n */\n header?: boolean;\n}\n\n/**\n * Configuration for initializing the Sophi Widget\n */\nexport interface SophiConfig {\n /**\n * API key for authentication with Sophi services (x-api-key header)\n * This comes from the parent application\n */\n apiKey: string;\n\n /**\n * External user ID for authentication (x-sophi-external-user-id header)\n * This comes from the parent application\n */\n userId?: string;\n\n /**\n * User name for the user\n */\n userName?: string;\n\n /**\n * Container element selector (e.g., '#widget') or HTMLElement where the widget will be mounted\n */\n container: string | HTMLElement;\n\n /**\n * Optional metadata to send with the session request\n */\n metadata?: Record<string, unknown>;\n\n /**\n * Width of the widget iframe\n * @default '100%'\n */\n width?: string;\n\n /**\n * Height of the widget iframe\n * @default '600px'\n */\n height?: string;\n\n /**\n * Callback fired when the widget is ready\n */\n onReady?: () => void;\n\n /**\n * Callback fired when an error occurs\n */\n onError?: (error: Error) => void;\n\n /**\n * Environment to use for the API\n */\n environment?: \"test\" | \"production\";\n\n /**\n * Layout options sent to the iframe on init. The child app receives these via a\n * postMessage and can show/hide header (and future layout options) accordingly.\n */\n layout?: LayoutConfig;\n}\n\n/**\n * Product information for add to cart events\n */\nexport interface Product {\n /**\n * Unique product identifier\n */\n productId: string;\n\n /**\n * Optional variant identifier\n */\n variantId?: string;\n}\n\n/**\n * Add to cart event data\n */\nexport interface AddToCartEvent {\n /**\n * List of products to add to cart\n */\n products: Product[];\n}\n\n/**\n * User data that can be sent to the widget\n */\nexport interface UserData {\n /**\n * User ID\n */\n userId?: string;\n\n /**\n * User email\n */\n email?: string;\n\n /**\n * User name\n */\n name?: string;\n\n /**\n * Additional custom data\n */\n [key: string]: unknown;\n}\n\nexport interface IUserCartItem {\n productId: string;\n variantId: string;\n quantity?: number;\n}\n\nexport interface IUserCart {\n cardId: string;\n items: IUserCartItem[];\n}\n\n/**\n * Message types that can be received from the iframe\n */\nexport type IncomingMessageType = \"add_to_cart\" | \"send_to_checkout\" | \"ready\" | \"error\";\n\n/**\n * Incoming message type constants for easy access\n * @example\n * widget.on(IncomingMessageTypes.ADD_TO_CART, (data) => {...})\n */\nexport const IncomingMessageTypes = {\n ADD_TO_CART: \"add_to_cart\",\n READY: \"ready\",\n ERROR: \"error\",\n SEND_TO_CHECKOUT: \"send_to_checkout\",\n} as const;\n\n/**\n * Message types that can be sent to the iframe\n */\nexport type OutgoingMessageType = \"user_data\" | \"config\" | \"update_user_cart\" | \"destroy\" | \"session_data\" | \"client_id_updated\" | \"layout_config\" | \"toggle_history\";\n\n/**\n * Outgoing message type constants for easy access\n * @example\n * widget.sendMessage({ type: OutgoingMessageTypes.USER_DATA, data: {...} })\n */\nexport const OutgoingMessageTypes = {\n USER_DATA: \"user_data\",\n CONFIG: \"config\",\n UPDATE_USER_CART: \"update_user_cart\",\n DESTROY: \"destroy\",\n SESSION_DATA: \"session_data\",\n CLIENT_ID_UPDATED: \"client_id_updated\",\n LAYOUT_CONFIG: \"layout_config\",\n TOGGLE_HISTORY: \"toggle_history\",\n} as const;\n\n/**\n * Incoming message structure from iframe\n */\nexport interface IncomingMessage {\n type: IncomingMessageType;\n data?: unknown;\n}\n\n/**\n * Outgoing message structure to iframe\n */\nexport interface OutgoingMessage {\n type: OutgoingMessageType;\n data?: unknown;\n}\n\n/**\n * Event map for type-safe event handling\n */\nexport interface SophiEventMap {\n /**\n * Fired when products should be added to cart\n */\n add_to_cart: AddToCartEvent;\n\n /**\n * Fired when the widget is ready\n */\n ready: void;\n\n /**\n * Fired when an error occurs\n */\n error: Error;\n\n /**\n * Fired when the user should be sent to checkout\n */\n send_to_checkout: void;\n}\n\n/**\n * Event handler type\n */\nexport type EventHandler<T> = (data: T) => void;\n\n/**\n * Event name type\n */\nexport type EventName = keyof SophiEventMap;\n\n/**\n * Authentication session request payload\n */\nexport interface AuthSessionRequest {\n /**\n * External user ID from the parent application\n */\n externalUserId?: string;\n\n /**\n * Optional metadata to include with the session\n */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Session data returned from the authentication API\n */\nexport interface SessionData {\n /**\n * JWT access token for authenticating requests\n */\n accessToken: string;\n\n /**\n * Unique session identifier\n */\n sessionId: string;\n\n /**\n * Client ID\n */\n clientId: string;\n\n /**\n * Company code\n */\n companyCode: string;\n\n /**\n * Session expiration timestamp\n */\n expiresAt: string;\n\n /**\n * userName of the user\n */\n userName: string;\n}\n\n/**\n * Authentication session API response\n */\nexport interface AuthSessionResponse {\n /**\n * Whether the request was successful\n */\n success: boolean;\n\n /**\n * Response message\n */\n message: string;\n\n /**\n * Session data\n */\n data?: SessionData;\n}\n\n/**\n * Merge user request payload\n */\nexport interface MergeUserRequest {\n /**\n * The logged-in user ID to merge to\n */\n userId: string;\n}\n\n/**\n * Merge user data returned from the API\n */\nexport interface MergeUserData {\n /**\n * The resulting client ID after merge\n */\n clientId: string;\n\n /**\n * The external user ID\n */\n externalUserId: string;\n}\n\n/**\n * Merge user API response\n */\nexport interface MergeUserResponse {\n /**\n * Whether the request was successful\n */\n success: boolean;\n\n /**\n * Response message\n */\n message: string;\n\n /**\n * Merge result data\n */\n data?: MergeUserData;\n}\n","export type CookieKey = \"clientId\" | \"externalUserId\" | \"sessionData\" | \"metadataHash\";\n\nexport interface CookieManagerOptions {\n readonly maxAgeSeconds?: number;\n readonly keys?: Partial<Record<CookieKey, string>>;\n}\n\nexport class CookieManager {\n static readonly DEFAULT_MAX_AGE_SECONDS = 60 * 60 * 24 * 30; // 30 days\n static readonly DEFAULT_KEYS: Record<CookieKey, string> = {\n clientId: \"client-id\",\n externalUserId: \"external-user-id\",\n sessionData: \"session-data\",\n metadataHash: \"metadata-hash\",\n };\n\n constructor(namespace: string, options?: CookieManagerOptions) {\n this.namespace = CookieManager.sanitizeNamespace(namespace);\n this.maxAgeSeconds = options?.maxAgeSeconds ?? CookieManager.DEFAULT_MAX_AGE_SECONDS;\n this.keys = { ...CookieManager.DEFAULT_KEYS, ...(options?.keys ?? {}) };\n }\n\n private readonly namespace: string;\n private readonly maxAgeSeconds: number;\n private readonly keys: Record<CookieKey, string>;\n\n static buildNamespace(baseUrl: string, apiKey: string): string {\n return CookieManager.sanitizeNamespace(`sophi-widget-${baseUrl}-${apiKey}`);\n }\n\n static canUseCookies(): boolean {\n return typeof document !== \"undefined\" && typeof document.cookie === \"string\";\n }\n\n set(key: CookieKey, value: string): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n document.cookie = `${this.formatName(key)}=${encodeURIComponent(value)}; path=/; max-age=${this.maxAgeSeconds}; samesite=lax`;\n }\n\n get(key: CookieKey): string | null {\n if (!CookieManager.canUseCookies()) {\n return null;\n }\n\n return CookieManager.readRawCookie(this.formatName(key));\n }\n\n delete(key: CookieKey): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n document.cookie = `${this.formatName(key)}=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; samesite=lax`;\n }\n\n clearAll(): void {\n Object.keys(this.keys).forEach((key) => {\n this.delete(key as CookieKey);\n });\n }\n\n private formatName(key: CookieKey): string {\n return `${this.namespace}-${this.keys[key]}`;\n }\n\n private static readRawCookie(name: string): string | null {\n const cookies = document.cookie.split(\";\").map((cookie) => cookie.trim());\n for (const cookie of cookies) {\n if (!cookie) {\n continue;\n }\n const [cookieName, ...cookieValueParts] = cookie.split(\"=\");\n if (cookieName === name) {\n return decodeURIComponent(cookieValueParts.join(\"=\"));\n }\n }\n return null;\n }\n\n private static sanitizeNamespace(value: string): string {\n const sanitized = value.replace(/[^a-zA-Z0-9_-]/g, \"\");\n return sanitized.length ? sanitized : \"sophi-widget\";\n }\n}\n","import type { AuthSessionRequest, AuthSessionResponse, SessionData, MergeUserRequest, MergeUserResponse, MergeUserData } from \"../types\";\nimport { CookieManager } from \"./cookie.utils\";\n\n/**\n * API Service for Sophi authentication and session management\n */\nexport class ApiService {\n private baseUrl: string;\n private apiKey: string;\n private clientId: string | null = null;\n private userId: string | undefined = undefined;\n private storedUserId: string | null = null; // Track the userId from cookies for merge detection\n private cookieManager: CookieManager;\n\n constructor(baseUrl: string, apiKey: string, userId?: string) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.userId = userId;\n this.cookieManager = new CookieManager(CookieManager.buildNamespace(baseUrl, apiKey));\n this.restoreSessionFromCookies();\n }\n\n /**\n * Create a client session by calling the authentication endpoint\n * @param request - Session request with optional externalUserId and metadata\n * @returns Session data including accessToken, sessionId, etc.\n */\n async createSession(request: AuthSessionRequest): Promise<SessionData> {\n const url = `${this.baseUrl}/api/v1/auth/client/session`;\n\n try {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"x-api-key\": this.apiKey,\n };\n if (this.clientId) {\n headers[\"x-sophi-client-id\"] = this.clientId;\n // Check if we need to merge: user changed from stored (could be empty) to current\n const normalizedStored = this.storedUserId || null;\n const normalizedCurrent = this.userId || null;\n if (normalizedStored !== normalizedCurrent && normalizedCurrent) {\n await this.mergeUser({ userId: normalizedCurrent });\n // Update storedUserId after successful merge\n this.storedUserId = normalizedCurrent;\n }\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n externalUserId: this.userId,\n metadata: request.metadata,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to create session: ${response.status} ${response.statusText}. ${errorText}`);\n }\n\n const data: AuthSessionResponse = await response.json();\n\n if (!data.success) {\n throw new Error(`Session creation failed: ${data.message || \"Unknown error\"}`);\n }\n\n if (!data.data) {\n throw new Error(\"Session data is missing from response\");\n }\n this.persistClientInfo(data.data.clientId, this.userId);\n return data.data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error during session creation: ${String(error)}`);\n }\n }\n\n /**\n * Validate session data\n */\n validateSessionData(sessionData: SessionData): boolean {\n return !!(sessionData.accessToken && sessionData.sessionId && sessionData.clientId && sessionData.companyCode && sessionData.expiresAt);\n }\n\n /**\n * Merge guest user with logged-in user\n * @param request - Merge request with guestId and userId\n * @returns Merge result data including the resulting clientId\n */\n async mergeUser(request: MergeUserRequest): Promise<MergeUserData> {\n const url = `${this.baseUrl}/api/v1/auth/client/info`;\n\n try {\n if (!this.clientId) {\n throw new Error(\"Client ID is not set. Please create a session first.\");\n }\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"x-api-key\": this.apiKey,\n \"x-sophi-client-id\": this.clientId,\n },\n body: JSON.stringify({\n externalUserId: request.userId,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to merge user: ${response.status} ${response.statusText}. ${errorText}`);\n }\n\n const data: MergeUserResponse = await response.json();\n\n if (!data.success) {\n throw new Error(`User merge failed: ${data.message || \"Unknown error\"}`);\n }\n\n if (!data.data) {\n throw new Error(\"Merge data is missing from response\");\n }\n\n return data.data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error during user merge: ${String(error)}`);\n }\n }\n\n private persistClientInfo(clientId: string, userId?: string): void {\n this.clientId = clientId;\n this.userId = userId;\n this.storedUserId = userId || null; // Update stored userId to match current state\n\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n this.cookieManager.set(\"clientId\", clientId);\n // Always save externalUserId (even if empty) to track the session state\n this.cookieManager.set(\"externalUserId\", userId || \"\");\n }\n\n private restoreSessionFromCookies(): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n const storedUserId = this.cookieManager.get(\"externalUserId\");\n const storedClientId = this.cookieManager.get(\"clientId\");\n\n // Store the userId from cookies for merge detection later\n this.storedUserId = storedUserId || null;\n\n // If no clientId in cookies, nothing to restore\n if (!storedClientId) {\n return;\n }\n\n // Normalize empty values (undefined, null, empty string) to null for comparison\n const normalizedStoredUserId = storedUserId || null;\n const normalizedCurrentUserId = this.userId || null;\n\n // If userIds match, restore both clientId and userId\n if (normalizedStoredUserId === normalizedCurrentUserId) {\n this.clientId = storedClientId;\n if (!this.userId && storedUserId) {\n this.userId = storedUserId;\n }\n return;\n }\n\n // UserIds don't match - determine if we should clear or keep clientId\n \n // Case 1: Logout (filled -> empty) - clear session\n if (normalizedStoredUserId && !normalizedCurrentUserId) {\n this.clearStoredClientInfo();\n return;\n }\n\n // Case 2: Different logged-in users (filled -> different filled) - clear session for new user\n if (normalizedStoredUserId && normalizedCurrentUserId && normalizedStoredUserId !== normalizedCurrentUserId) {\n this.clearStoredClientInfo();\n return;\n }\n\n // Case 3: Guest -> Logged-in user (empty -> filled) - keep clientId for merge\n if (!normalizedStoredUserId && normalizedCurrentUserId) {\n this.clientId = storedClientId;\n return;\n }\n }\n\n private clearStoredClientInfo(): void {\n this.clientId = null;\n this.storedUserId = null;\n\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n this.cookieManager.clearAll();\n }\n}\n","/**\n * Default configuration constants for Sophi Widget\n */\nexport const DEFAULT_CONFIG = {\n /**\n * Default width of the widget iframe\n */\n WIDTH: \"100%\",\n\n /**\n * Default height of the widget iframe\n */\n HEIGHT: \"600px\",\n} as const;\n\n/**\n * API base URLs for different environments\n *\n * Note: These URLs will be visible in the client-side bundle.\n * This is normal and safe - the real security is in your API key validation.\n *\n * To use different URLs, modify these values before building the SDK.\n *\n * Production API URL - update before building for production\n */\nexport const API_BASE_URLS = {\n test: \"http://10.0.2.127:80\",\n production: \"https://api.usesophi.com\",\n} as const;\n\n/**\n * API endpoints configuration\n */\nexport const API_ENDPOINTS = {\n /**\n * Session creation endpoint path\n */\n CREATE_SESSION: \"/api/v1/auth/client/session\",\n} as const;\n\n/**\n * Error messages\n */\nexport const ERROR_MESSAGES = {\n MISSING_API_KEY: \"API key is required and must be a string\",\n MISSING_CLIENT_ID: \"Client ID is required and must be a string\",\n MISSING_USER_ID: \"User ID is required and must be a string\",\n MISSING_CONTAINER: \"Container is required\",\n MISSING_IFRAME_URL: \"Iframe URL is required and must be a string\",\n INVALID_IFRAME_URL: \"Invalid iframe URL\",\n INVALID_ENVIRONMENT: \"Invalid environment. Must be 'dev', 'test', 'staging', or 'production'\",\n CONTAINER_NOT_FOUND: \"Container element not found\",\n NOT_INITIALIZED: \"Widget not initialized. Call init() first.\",\n ALREADY_INITIALIZED: \"Sophi Widget is already initialized. Call destroy() first to reinitialize.\",\n SESSION_CREATION_FAILED: \"Failed to create authentication session\",\n INVALID_SESSION_DATA: \"Invalid session data received from API\",\n YOU_NEED_TO_INIT_THE_WIDGET_FIRST: \"You need to initialize the widget first. Call init() before calling this method.\",\n} as const;\n","import { type SophiConfig, type UserData, type EventHandler, type EventName, type SophiEventMap, type IncomingMessage, type OutgoingMessage, type AddToCartEvent, type IUserCart, type SessionData, type MergeUserRequest, type MergeUserData, OutgoingMessageTypes } from \"./types\";\nimport { ApiService } from \"./services/api.service\";\nimport { DEFAULT_CONFIG, ERROR_MESSAGES, API_BASE_URLS } from \"./constants/config\";\n\n/**\n * Main Sophi Widget SDK class\n * Provides a framework-agnostic way to embed and interact with the Sophi AI widget\n */\nexport class SophiWidget {\n private config: SophiConfig | null = null;\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLElement | null = null;\n private eventListeners: Map<EventName, Set<EventHandler<any>>> = new Map();\n private messageHandler: ((event: MessageEvent) => void) | null = null;\n private isInitialized = false;\n private iframeOrigin: string | null = null;\n private sessionData: SessionData | null = null;\n private apiService: ApiService | null = null;\n private apiBaseUrl: string | null = null;\n\n /**\n * Initialize the widget with configuration\n * @param config - Widget configuration\n */\n public async init(config: SophiConfig): Promise<void> {\n if (this.isInitialized) {\n console.warn(ERROR_MESSAGES.ALREADY_INITIALIZED);\n return;\n }\n\n try {\n // Validate configuration\n this.validateConfig(config);\n\n this.config = this.formatConfig(config);\n\n // Determine API URL based on environment\n this.apiBaseUrl = API_BASE_URLS[config.environment || \"production\"];\n\n // Initialize API service\n this.apiService = new ApiService(this.apiBaseUrl, config.apiKey, config.userId);\n\n // Create authentication session\n await this.createAuthSession();\n\n this.isInitialized = true;\n\n // Extract origin from iframe URL for security\n try {\n const url = new URL(this.getIframeUrl());\n this.iframeOrigin = url.origin;\n } catch (error) {\n const err = new Error(`${ERROR_MESSAGES.INVALID_IFRAME_URL}: ${this.getIframeUrl()}`);\n this.emitError(err);\n throw err;\n }\n\n // Resolve container element\n this.container = this.resolveContainer(config.container);\n\n if (!this.container) {\n const err = new Error(ERROR_MESSAGES.CONTAINER_NOT_FOUND);\n this.emitError(err);\n throw err;\n }\n\n // Create and mount iframe\n this.createIframe();\n\n // Setup postMessage listener\n this.setupMessageListener();\n\n // Send session data to iframe after it's loaded\n this.iframe?.addEventListener(\"load\", () => {\n // Small delay to ensure iframe is fully ready\n setTimeout(() => {\n this.sendSessionData();\n if (this.config?.layout) {\n this.sendLayoutConfig();\n }\n }, 100);\n });\n\n // Call onReady callback if provided\n if (config.onReady) {\n config.onReady();\n }\n } catch (error) {\n // Reset state on error\n this.isInitialized = false;\n this.config = null;\n this.apiService = null;\n this.sessionData = null;\n\n const err = error instanceof Error ? error : new Error(String(error));\n this.emitError(err);\n throw err;\n }\n }\n\n /**\n * Send user data to the widget\n * @param data - User data object\n */\n public sendUserData(data: UserData): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.USER_DATA,\n data,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Toggle chat history visibility in the iframe child app.\n */\n public sendToggleHistory(): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.TOGGLE_HISTORY,\n };\n\n this.postMessage(message);\n }\n\n public updateUserCart(cart: IUserCart): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.UPDATE_USER_CART,\n data: cart,\n };\n\n this.postMessage(message);\n }\n\n private onDestroy(): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.DESTROY,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Register an event listener\n * @param event - Event name\n * @param handler - Event handler function\n */\n public on<K extends EventName>(event: K, handler: EventHandler<SophiEventMap[K]>): void {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n /**\n * Unregister an event listener\n * @param event - Event name\n * @param handler - Event handler function to remove\n */\n public off<K extends EventName>(event: K, handler: EventHandler<SophiEventMap[K]>): void {\n const handlers = this.eventListeners.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n }\n\n /**\n * Show the widget\n */\n public show(): void {\n if (this.iframe) {\n this.iframe.style.display = \"block\";\n }\n }\n\n /**\n * Hide the widget\n */\n public hide(): void {\n if (this.iframe) {\n this.iframe.style.display = \"none\";\n }\n }\n\n /**\n * Destroy the widget and cleanup resources\n * Waits 300ms after sending destroy message to give iframe time to cleanup\n */\n public async destroy(): Promise<void> {\n this.onDestroy();\n\n // Wait 300ms to give iframe time to process the destroy event and cleanup\n await new Promise((resolve) => setTimeout(resolve, 300));\n\n // Remove message listener\n if (this.messageHandler) {\n window.removeEventListener(\"message\", this.messageHandler);\n this.messageHandler = null;\n }\n\n // Remove iframe\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n this.iframe = null;\n }\n\n // Clear event listeners\n this.eventListeners.clear();\n\n // Reset state\n this.config = null;\n this.container = null;\n this.isInitialized = false;\n this.iframeOrigin = null;\n this.sessionData = null;\n this.apiService = null;\n }\n\n /**\n * Check if widget is initialized\n */\n public isReady(): boolean {\n return this.isInitialized && this.iframe !== null;\n }\n\n /**\n * Validate configuration\n */\n private validateConfig(config: SophiConfig): void {\n if (!config.apiKey || typeof config.apiKey !== \"string\") {\n throw new Error(ERROR_MESSAGES.MISSING_API_KEY);\n }\n\n if (config.userId && typeof config.userId !== \"string\") {\n throw new Error(ERROR_MESSAGES.MISSING_USER_ID);\n }\n\n if (!config.container) {\n throw new Error(ERROR_MESSAGES.MISSING_CONTAINER);\n }\n }\n\n /**\n * Format configuration\n */\n private formatConfig(config: SophiConfig): SophiConfig {\n return {\n ...config,\n userId: config.userId || undefined,\n };\n }\n\n /**\n * Create authentication session with the API\n */\n private async createAuthSession(): Promise<void> {\n if (!this.config || !this.apiService) {\n throw new Error(ERROR_MESSAGES.NOT_INITIALIZED);\n }\n\n try {\n this.sessionData = await this.apiService.createSession({\n externalUserId: this.config.userId,\n metadata: this.config.metadata,\n });\n\n // Validate session data\n if (!this.apiService.validateSessionData(this.sessionData)) {\n throw new Error(ERROR_MESSAGES.INVALID_SESSION_DATA);\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(ERROR_MESSAGES.SESSION_CREATION_FAILED);\n throw err;\n }\n }\n\n /**\n * Send session data to iframe\n */\n private sendSessionData(): void {\n if (!this.sessionData) {\n console.warn(\"Session data not available\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.SESSION_DATA,\n data: { ...this.sessionData, userName: this.config?.userName },\n };\n\n this.postMessage(message);\n }\n\n /**\n * Send layout config to iframe so the child app can apply layout options (e.g. show/hide header).\n */\n private sendLayoutConfig(): void {\n if (!this.config?.layout) {\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.LAYOUT_CONFIG,\n data: this.config.layout,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Resolve container element from selector or element\n */\n private resolveContainer(container: string | HTMLElement): HTMLElement | null {\n if (typeof container === \"string\") {\n return document.querySelector(container);\n }\n return container;\n }\n\n /**\n * Create and mount the iframe\n */\n private createIframe(): void {\n if (!this.container || !this.config) {\n return;\n }\n\n const iframe = document.createElement(\"iframe\");\n\n // Set iframe attributes\n iframe.src = this.buildIframeUrl();\n iframe.style.width = this.config.width || \"100%\";\n iframe.style.height = this.config.height || \"600px\";\n iframe.style.border = \"none\";\n iframe.title = \"Sophi AI Widget\";\n iframe.allow = \"microphone; camera; clipboard-write\";\n\n // Append to container\n this.container.appendChild(iframe);\n this.iframe = iframe;\n }\n\n /**\n * Build iframe URL with query parameters\n */\n private buildIframeUrl(): string {\n if (!this.config) {\n return \"\";\n }\n const url = new URL(this.getIframeUrl());\n\n return url.toString();\n }\n\n private getIframeUrl(): string {\n if (!this.config) {\n return \"\";\n }\n if (this.config.environment === \"production\") {\n return \"https://app.usesophi.com\";\n }\n return \"http://localhost:5173\";\n }\n\n /**\n * Setup postMessage listener for iframe communication\n */\n private setupMessageListener(): void {\n this.messageHandler = (event: MessageEvent) => {\n // Validate origin for security\n if (this.iframeOrigin && event.origin !== this.iframeOrigin) {\n console.warn(`Received message from untrusted origin: ${event.origin}`);\n return;\n }\n\n try {\n // Parse message\n const message: IncomingMessage = typeof event.data === \"string\" ? JSON.parse(event.data) : event.data;\n\n // Handle different message types\n this.handleIncomingMessage(message);\n } catch (error) {\n console.error(\"Error processing message from iframe:\", error);\n }\n };\n\n window.addEventListener(\"message\", this.messageHandler);\n }\n\n /**\n * Handle incoming messages from iframe\n */\n private handleIncomingMessage(message: IncomingMessage): void {\n switch (message.type) {\n case \"add_to_cart\":\n if (this.isValidAddToCartMessage(message.data)) {\n this.emit(\"add_to_cart\", message.data);\n } else {\n console.error(\"Invalid add_to_cart message structure:\", message.data);\n this.emitError(new Error(\"Invalid add_to_cart message format\"));\n }\n break;\n\n case \"send_to_checkout\":\n this.emit(\"send_to_checkout\", undefined);\n break;\n case \"ready\":\n this.emit(\"ready\", undefined);\n break;\n\n case \"error\":\n const error = message.data instanceof Error ? message.data : new Error(String(message.data));\n this.emitError(error);\n break;\n\n default:\n console.warn(\"Unknown message type:\", message);\n }\n }\n\n /**\n * Validate add_to_cart message structure\n */\n private isValidAddToCartMessage(data: unknown): data is AddToCartEvent {\n if (!data || typeof data !== \"object\") {\n return false;\n }\n\n const event = data as Record<string, unknown>;\n\n // Check products array exists and is an array\n if (!Array.isArray(event.products)) {\n return false;\n }\n\n // Validate each product in the array\n return event.products.every((product) => {\n if (!product || typeof product !== \"object\") {\n return false;\n }\n const prod = product as Record<string, unknown>;\n\n // productId is required and must be a string\n if (typeof prod.productId !== \"string\") {\n return false;\n }\n\n // variantId is optional, but if present must be a string\n if (prod.variantId !== undefined && typeof prod.variantId !== \"string\") {\n return false;\n }\n\n return true;\n });\n }\n\n /**\n * Post message to iframe\n */\n private postMessage(message: OutgoingMessage): void {\n if (!this.iframe || !this.iframe.contentWindow || !this.iframeOrigin) {\n console.warn(\"Cannot send message: iframe not ready\");\n return;\n }\n\n try {\n this.iframe.contentWindow.postMessage(message, this.iframeOrigin);\n } catch (error) {\n console.error(\"Error sending message to iframe:\", error);\n this.emitError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Emit event to registered listeners\n */\n private emit<K extends EventName>(event: K, data: SophiEventMap[K]): void {\n const handlers = this.eventListeners.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(data);\n } catch (error) {\n console.error(`Error in ${event} event handler:`, error);\n }\n });\n }\n }\n\n /**\n * Emit error event\n */\n private emitError(error: Error): void {\n this.emit(\"error\", error);\n\n // Also call onError callback if provided\n if (this.config?.onError) {\n this.config.onError(error);\n }\n }\n}\n"]}
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- var f={ADD_TO_CART:"add_to_cart",READY:"ready",ERROR:"error",SEND_TO_CHECKOUT:"send_to_checkout"},o={USER_DATA:"user_data",CONFIG:"config",UPDATE_USER_CART:"update_user_cart",DESTROY:"destroy",SESSION_DATA:"session_data",CLIENT_ID_UPDATED:"client_id_updated",LAYOUT_CONFIG:"layout_config",TOGGLE_HISTORY:"toggle_history"};var s=class s{constructor(e,t){this.namespace=s.sanitizeNamespace(e),this.maxAgeSeconds=t?.maxAgeSeconds??s.DEFAULT_MAX_AGE_SECONDS,this.keys={...s.DEFAULT_KEYS,...t?.keys??{}};}static buildNamespace(e,t){return s.sanitizeNamespace(`sophi-widget-${e}-${t}`)}static canUseCookies(){return typeof document<"u"&&typeof document.cookie=="string"}set(e,t){s.canUseCookies()&&(document.cookie=`${this.formatName(e)}=${encodeURIComponent(t)}; path=/; max-age=${this.maxAgeSeconds}; samesite=lax`);}get(e){return s.canUseCookies()?s.readRawCookie(this.formatName(e)):null}delete(e){s.canUseCookies()&&(document.cookie=`${this.formatName(e)}=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; samesite=lax`);}clearAll(){Object.keys(this.keys).forEach(e=>{this.delete(e);});}formatName(e){return `${this.namespace}-${this.keys[e]}`}static readRawCookie(e){let t=document.cookie.split(";").map(i=>i.trim());for(let i of t){if(!i)continue;let[r,...n]=i.split("=");if(r===e)return decodeURIComponent(n.join("="))}return null}static sanitizeNamespace(e){let t=e.replace(/[^a-zA-Z0-9_-]/g,"");return t.length?t:"sophi-widget"}};s.DEFAULT_MAX_AGE_SECONDS=3600*24*30,s.DEFAULT_KEYS={clientId:"client-id",externalUserId:"external-user-id",sessionData:"session-data",metadataHash:"metadata-hash"};var d=s;var c=class{constructor(e,t,i){this.clientId=null;this.userId=void 0;this.storedUserId=null;this.baseUrl=e,this.apiKey=t,this.userId=i,this.cookieManager=new d(d.buildNamespace(e,t)),this.restoreSessionFromCookies();}async createSession(e){let t=`${this.baseUrl}/api/v1/auth/client/session`;try{let i={"Content-Type":"application/json",Accept:"application/json","x-api-key":this.apiKey};if(this.clientId){i["x-sophi-client-id"]=this.clientId;let g=this.storedUserId||null,l=this.userId||null;g!==l&&l&&(await this.mergeUser({userId:l}),this.storedUserId=l);}let r=await fetch(t,{method:"POST",headers:i,body:JSON.stringify({externalUserId:this.userId,metadata:e.metadata})});if(!r.ok){let g=await r.text();throw new Error(`Failed to create session: ${r.status} ${r.statusText}. ${g}`)}let n=await r.json();if(!n.success)throw new Error(`Session creation failed: ${n.message||"Unknown error"}`);if(!n.data)throw new Error("Session data is missing from response");return this.persistClientInfo(n.data.clientId,this.userId),n.data}catch(i){throw i instanceof Error?i:new Error(`Unexpected error during session creation: ${String(i)}`)}}validateSessionData(e){return !!(e.accessToken&&e.sessionId&&e.clientId&&e.companyCode&&e.expiresAt)}async mergeUser(e){let t=`${this.baseUrl}/api/v1/auth/client/info`;try{if(!this.clientId)throw new Error("Client ID is not set. Please create a session first.");let i=await fetch(t,{method:"PATCH",headers:{"Content-Type":"application/json",Accept:"application/json","x-api-key":this.apiKey,"x-sophi-client-id":this.clientId},body:JSON.stringify({externalUserId:e.userId})});if(!i.ok){let n=await i.text();throw new Error(`Failed to merge user: ${i.status} ${i.statusText}. ${n}`)}let r=await i.json();if(!r.success)throw new Error(`User merge failed: ${r.message||"Unknown error"}`);if(!r.data)throw new Error("Merge data is missing from response");return r.data}catch(i){throw i instanceof Error?i:new Error(`Unexpected error during user merge: ${String(i)}`)}}persistClientInfo(e,t){this.clientId=e,this.userId=t,this.storedUserId=t||null,d.canUseCookies()&&(this.cookieManager.set("clientId",e),this.cookieManager.set("externalUserId",t||""));}restoreSessionFromCookies(){if(!d.canUseCookies())return;let e=this.cookieManager.get("externalUserId"),t=this.cookieManager.get("clientId");if(this.storedUserId=e||null,!t)return;let i=e||null,r=this.userId||null;if(i===r){this.clientId=t,!this.userId&&e&&(this.userId=e);return}if(i&&!r){this.clearStoredClientInfo();return}if(i&&r&&i!==r){this.clearStoredClientInfo();return}if(!i&&r){this.clientId=t;return}}clearStoredClientInfo(){this.clientId=null,this.storedUserId=null,d.canUseCookies()&&this.cookieManager.clearAll();}};var m={WIDTH:"100%",HEIGHT:"600px"},p={test:"http://10.0.2.127:80",production:"https://api.usesophi.com"},I={CREATE_SESSION:"/api/v1/auth/client/session"},a={MISSING_API_KEY:"API key is required and must be a string",MISSING_CLIENT_ID:"Client ID is required and must be a string",MISSING_USER_ID:"User ID is required and must be a string",MISSING_CONTAINER:"Container is required",MISSING_IFRAME_URL:"Iframe URL is required and must be a string",INVALID_IFRAME_URL:"Invalid iframe URL",INVALID_ENVIRONMENT:"Invalid environment. Must be 'dev', 'test', 'staging', or 'production'",CONTAINER_NOT_FOUND:"Container element not found",NOT_INITIALIZED:"Widget not initialized. Call init() first.",ALREADY_INITIALIZED:"Sophi Widget is already initialized. Call destroy() first to reinitialize.",SESSION_CREATION_FAILED:"Failed to create authentication session",INVALID_SESSION_DATA:"Invalid session data received from API",YOU_NEED_TO_INIT_THE_WIDGET_FIRST:"You need to initialize the widget first. Call init() before calling this method."};var h=class{constructor(){this.config=null;this.iframe=null;this.container=null;this.eventListeners=new Map;this.messageHandler=null;this.isInitialized=false;this.iframeOrigin=null;this.sessionData=null;this.apiService=null;this.apiBaseUrl=null;}async init(e){if(this.isInitialized){console.warn(a.ALREADY_INITIALIZED);return}try{this.validateConfig(e),this.config=this.formatConfig(e),this.apiBaseUrl=p[e.environment||"production"],this.apiService=new c(this.apiBaseUrl,e.apiKey,e.userId),await this.createAuthSession(),this.isInitialized=!0;try{let t=new URL(this.getIframeUrl());this.iframeOrigin=t.origin;}catch{let i=new Error(`${a.INVALID_IFRAME_URL}: ${this.getIframeUrl()}`);throw this.emitError(i),i}if(this.container=this.resolveContainer(e.container),!this.container){let t=new Error(a.CONTAINER_NOT_FOUND);throw this.emitError(t),t}this.createIframe(),this.setupMessageListener(),this.iframe?.addEventListener("load",()=>{setTimeout(()=>{this.sendSessionData(),this.config?.layout&&this.sendLayoutConfig();},100);}),e.onReady&&e.onReady();}catch(t){this.isInitialized=false,this.config=null,this.apiService=null,this.sessionData=null;let i=t instanceof Error?t:new Error(String(t));throw this.emitError(i),i}}sendUserData(e){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let t={type:o.USER_DATA,data:e};this.postMessage(t);}sendToggleHistory(){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let e={type:o.TOGGLE_HISTORY};this.postMessage(e);}updateUserCart(e){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let t={type:o.UPDATE_USER_CART,data:e};this.postMessage(t);}onDestroy(){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let e={type:o.DESTROY};this.postMessage(e);}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t);}off(e,t){let i=this.eventListeners.get(e);i&&i.delete(t);}show(){this.iframe&&(this.iframe.style.display="block");}hide(){this.iframe&&(this.iframe.style.display="none");}async destroy(){this.onDestroy(),await new Promise(e=>setTimeout(e,300)),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.iframe&&this.iframe.parentNode&&(this.iframe.parentNode.removeChild(this.iframe),this.iframe=null),this.eventListeners.clear(),this.config=null,this.container=null,this.isInitialized=false,this.iframeOrigin=null,this.sessionData=null,this.apiService=null;}isReady(){return this.isInitialized&&this.iframe!==null}validateConfig(e){if(!e.apiKey||typeof e.apiKey!="string")throw new Error(a.MISSING_API_KEY);if(e.userId&&typeof e.userId!="string")throw new Error(a.MISSING_USER_ID);if(!e.container)throw new Error(a.MISSING_CONTAINER)}formatConfig(e){return {...e,userId:e.userId||void 0}}async createAuthSession(){if(!this.config||!this.apiService)throw new Error(a.NOT_INITIALIZED);try{if(this.sessionData=await this.apiService.createSession({externalUserId:this.config.userId,metadata:this.config.metadata}),!this.apiService.validateSessionData(this.sessionData))throw new Error(a.INVALID_SESSION_DATA)}catch(e){throw e instanceof Error?e:new Error(a.SESSION_CREATION_FAILED)}}sendSessionData(){if(!this.sessionData){console.warn("Session data not available");return}let e={type:o.SESSION_DATA,data:{...this.sessionData,userName:this.config?.userName}};this.postMessage(e);}sendLayoutConfig(){if(!this.config?.layout)return;let e={type:o.LAYOUT_CONFIG,data:this.config.layout};this.postMessage(e);}resolveContainer(e){return typeof e=="string"?document.querySelector(e):e}createIframe(){if(!this.container||!this.config)return;let e=document.createElement("iframe");e.src=this.buildIframeUrl(),e.style.width=this.config.width||"100%",e.style.height=this.config.height||"600px",e.style.border="none",e.title="Sophi AI Widget",e.allow="microphone; camera",this.container.appendChild(e),this.iframe=e;}buildIframeUrl(){return this.config?new URL(this.getIframeUrl()).toString():""}getIframeUrl(){return this.config?this.config.environment==="production"?"https://app.usesophi.com":"http://localhost:5173":""}setupMessageListener(){this.messageHandler=e=>{if(this.iframeOrigin&&e.origin!==this.iframeOrigin){console.warn(`Received message from untrusted origin: ${e.origin}`);return}try{let t=typeof e.data=="string"?JSON.parse(e.data):e.data;this.handleIncomingMessage(t);}catch(t){console.error("Error processing message from iframe:",t);}},window.addEventListener("message",this.messageHandler);}handleIncomingMessage(e){switch(e.type){case "add_to_cart":this.isValidAddToCartMessage(e.data)?this.emit("add_to_cart",e.data):(console.error("Invalid add_to_cart message structure:",e.data),this.emitError(new Error("Invalid add_to_cart message format")));break;case "send_to_checkout":this.emit("send_to_checkout",void 0);break;case "ready":this.emit("ready",void 0);break;case "error":let t=e.data instanceof Error?e.data:new Error(String(e.data));this.emitError(t);break;default:console.warn("Unknown message type:",e);}}isValidAddToCartMessage(e){if(!e||typeof e!="object")return false;let t=e;return Array.isArray(t.products)?t.products.every(i=>{if(!i||typeof i!="object")return false;let r=i;return !(typeof r.productId!="string"||r.variantId!==void 0&&typeof r.variantId!="string")}):false}postMessage(e){if(!this.iframe||!this.iframe.contentWindow||!this.iframeOrigin){console.warn("Cannot send message: iframe not ready");return}try{this.iframe.contentWindow.postMessage(e,this.iframeOrigin);}catch(t){console.error("Error sending message to iframe:",t),this.emitError(t instanceof Error?t:new Error(String(t)));}}emit(e,t){let i=this.eventListeners.get(e);i&&i.forEach(r=>{try{r(t);}catch(n){console.error(`Error in ${e} event handler:`,n);}});}emitError(e){this.emit("error",e),this.config?.onError&&this.config.onError(e);}};
1
+ var f={ADD_TO_CART:"add_to_cart",READY:"ready",ERROR:"error",SEND_TO_CHECKOUT:"send_to_checkout"},o={USER_DATA:"user_data",CONFIG:"config",UPDATE_USER_CART:"update_user_cart",DESTROY:"destroy",SESSION_DATA:"session_data",CLIENT_ID_UPDATED:"client_id_updated",LAYOUT_CONFIG:"layout_config",TOGGLE_HISTORY:"toggle_history"};var s=class s{constructor(e,t){this.namespace=s.sanitizeNamespace(e),this.maxAgeSeconds=t?.maxAgeSeconds??s.DEFAULT_MAX_AGE_SECONDS,this.keys={...s.DEFAULT_KEYS,...t?.keys??{}};}static buildNamespace(e,t){return s.sanitizeNamespace(`sophi-widget-${e}-${t}`)}static canUseCookies(){return typeof document<"u"&&typeof document.cookie=="string"}set(e,t){s.canUseCookies()&&(document.cookie=`${this.formatName(e)}=${encodeURIComponent(t)}; path=/; max-age=${this.maxAgeSeconds}; samesite=lax`);}get(e){return s.canUseCookies()?s.readRawCookie(this.formatName(e)):null}delete(e){s.canUseCookies()&&(document.cookie=`${this.formatName(e)}=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; samesite=lax`);}clearAll(){Object.keys(this.keys).forEach(e=>{this.delete(e);});}formatName(e){return `${this.namespace}-${this.keys[e]}`}static readRawCookie(e){let t=document.cookie.split(";").map(i=>i.trim());for(let i of t){if(!i)continue;let[r,...n]=i.split("=");if(r===e)return decodeURIComponent(n.join("="))}return null}static sanitizeNamespace(e){let t=e.replace(/[^a-zA-Z0-9_-]/g,"");return t.length?t:"sophi-widget"}};s.DEFAULT_MAX_AGE_SECONDS=3600*24*30,s.DEFAULT_KEYS={clientId:"client-id",externalUserId:"external-user-id",sessionData:"session-data",metadataHash:"metadata-hash"};var d=s;var c=class{constructor(e,t,i){this.clientId=null;this.userId=void 0;this.storedUserId=null;this.baseUrl=e,this.apiKey=t,this.userId=i,this.cookieManager=new d(d.buildNamespace(e,t)),this.restoreSessionFromCookies();}async createSession(e){let t=`${this.baseUrl}/api/v1/auth/client/session`;try{let i={"Content-Type":"application/json",Accept:"application/json","x-api-key":this.apiKey};if(this.clientId){i["x-sophi-client-id"]=this.clientId;let g=this.storedUserId||null,l=this.userId||null;g!==l&&l&&(await this.mergeUser({userId:l}),this.storedUserId=l);}let r=await fetch(t,{method:"POST",headers:i,body:JSON.stringify({externalUserId:this.userId,metadata:e.metadata})});if(!r.ok){let g=await r.text();throw new Error(`Failed to create session: ${r.status} ${r.statusText}. ${g}`)}let n=await r.json();if(!n.success)throw new Error(`Session creation failed: ${n.message||"Unknown error"}`);if(!n.data)throw new Error("Session data is missing from response");return this.persistClientInfo(n.data.clientId,this.userId),n.data}catch(i){throw i instanceof Error?i:new Error(`Unexpected error during session creation: ${String(i)}`)}}validateSessionData(e){return !!(e.accessToken&&e.sessionId&&e.clientId&&e.companyCode&&e.expiresAt)}async mergeUser(e){let t=`${this.baseUrl}/api/v1/auth/client/info`;try{if(!this.clientId)throw new Error("Client ID is not set. Please create a session first.");let i=await fetch(t,{method:"PATCH",headers:{"Content-Type":"application/json",Accept:"application/json","x-api-key":this.apiKey,"x-sophi-client-id":this.clientId},body:JSON.stringify({externalUserId:e.userId})});if(!i.ok){let n=await i.text();throw new Error(`Failed to merge user: ${i.status} ${i.statusText}. ${n}`)}let r=await i.json();if(!r.success)throw new Error(`User merge failed: ${r.message||"Unknown error"}`);if(!r.data)throw new Error("Merge data is missing from response");return r.data}catch(i){throw i instanceof Error?i:new Error(`Unexpected error during user merge: ${String(i)}`)}}persistClientInfo(e,t){this.clientId=e,this.userId=t,this.storedUserId=t||null,d.canUseCookies()&&(this.cookieManager.set("clientId",e),this.cookieManager.set("externalUserId",t||""));}restoreSessionFromCookies(){if(!d.canUseCookies())return;let e=this.cookieManager.get("externalUserId"),t=this.cookieManager.get("clientId");if(this.storedUserId=e||null,!t)return;let i=e||null,r=this.userId||null;if(i===r){this.clientId=t,!this.userId&&e&&(this.userId=e);return}if(i&&!r){this.clearStoredClientInfo();return}if(i&&r&&i!==r){this.clearStoredClientInfo();return}if(!i&&r){this.clientId=t;return}}clearStoredClientInfo(){this.clientId=null,this.storedUserId=null,d.canUseCookies()&&this.cookieManager.clearAll();}};var m={WIDTH:"100%",HEIGHT:"600px"},p={test:"http://10.0.2.127:80",production:"https://api.usesophi.com"},I={CREATE_SESSION:"/api/v1/auth/client/session"},a={MISSING_API_KEY:"API key is required and must be a string",MISSING_CLIENT_ID:"Client ID is required and must be a string",MISSING_USER_ID:"User ID is required and must be a string",MISSING_CONTAINER:"Container is required",MISSING_IFRAME_URL:"Iframe URL is required and must be a string",INVALID_IFRAME_URL:"Invalid iframe URL",INVALID_ENVIRONMENT:"Invalid environment. Must be 'dev', 'test', 'staging', or 'production'",CONTAINER_NOT_FOUND:"Container element not found",NOT_INITIALIZED:"Widget not initialized. Call init() first.",ALREADY_INITIALIZED:"Sophi Widget is already initialized. Call destroy() first to reinitialize.",SESSION_CREATION_FAILED:"Failed to create authentication session",INVALID_SESSION_DATA:"Invalid session data received from API",YOU_NEED_TO_INIT_THE_WIDGET_FIRST:"You need to initialize the widget first. Call init() before calling this method."};var h=class{constructor(){this.config=null;this.iframe=null;this.container=null;this.eventListeners=new Map;this.messageHandler=null;this.isInitialized=false;this.iframeOrigin=null;this.sessionData=null;this.apiService=null;this.apiBaseUrl=null;}async init(e){if(this.isInitialized){console.warn(a.ALREADY_INITIALIZED);return}try{this.validateConfig(e),this.config=this.formatConfig(e),this.apiBaseUrl=p[e.environment||"production"],this.apiService=new c(this.apiBaseUrl,e.apiKey,e.userId),await this.createAuthSession(),this.isInitialized=!0;try{let t=new URL(this.getIframeUrl());this.iframeOrigin=t.origin;}catch{let i=new Error(`${a.INVALID_IFRAME_URL}: ${this.getIframeUrl()}`);throw this.emitError(i),i}if(this.container=this.resolveContainer(e.container),!this.container){let t=new Error(a.CONTAINER_NOT_FOUND);throw this.emitError(t),t}this.createIframe(),this.setupMessageListener(),this.iframe?.addEventListener("load",()=>{setTimeout(()=>{this.sendSessionData(),this.config?.layout&&this.sendLayoutConfig();},100);}),e.onReady&&e.onReady();}catch(t){this.isInitialized=false,this.config=null,this.apiService=null,this.sessionData=null;let i=t instanceof Error?t:new Error(String(t));throw this.emitError(i),i}}sendUserData(e){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let t={type:o.USER_DATA,data:e};this.postMessage(t);}sendToggleHistory(){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let e={type:o.TOGGLE_HISTORY};this.postMessage(e);}updateUserCart(e){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let t={type:o.UPDATE_USER_CART,data:e};this.postMessage(t);}onDestroy(){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let e={type:o.DESTROY};this.postMessage(e);}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t);}off(e,t){let i=this.eventListeners.get(e);i&&i.delete(t);}show(){this.iframe&&(this.iframe.style.display="block");}hide(){this.iframe&&(this.iframe.style.display="none");}async destroy(){this.onDestroy(),await new Promise(e=>setTimeout(e,300)),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.iframe&&this.iframe.parentNode&&(this.iframe.parentNode.removeChild(this.iframe),this.iframe=null),this.eventListeners.clear(),this.config=null,this.container=null,this.isInitialized=false,this.iframeOrigin=null,this.sessionData=null,this.apiService=null;}isReady(){return this.isInitialized&&this.iframe!==null}validateConfig(e){if(!e.apiKey||typeof e.apiKey!="string")throw new Error(a.MISSING_API_KEY);if(e.userId&&typeof e.userId!="string")throw new Error(a.MISSING_USER_ID);if(!e.container)throw new Error(a.MISSING_CONTAINER)}formatConfig(e){return {...e,userId:e.userId||void 0}}async createAuthSession(){if(!this.config||!this.apiService)throw new Error(a.NOT_INITIALIZED);try{if(this.sessionData=await this.apiService.createSession({externalUserId:this.config.userId,metadata:this.config.metadata}),!this.apiService.validateSessionData(this.sessionData))throw new Error(a.INVALID_SESSION_DATA)}catch(e){throw e instanceof Error?e:new Error(a.SESSION_CREATION_FAILED)}}sendSessionData(){if(!this.sessionData){console.warn("Session data not available");return}let e={type:o.SESSION_DATA,data:{...this.sessionData,userName:this.config?.userName}};this.postMessage(e);}sendLayoutConfig(){if(!this.config?.layout)return;let e={type:o.LAYOUT_CONFIG,data:this.config.layout};this.postMessage(e);}resolveContainer(e){return typeof e=="string"?document.querySelector(e):e}createIframe(){if(!this.container||!this.config)return;let e=document.createElement("iframe");e.src=this.buildIframeUrl(),e.style.width=this.config.width||"100%",e.style.height=this.config.height||"600px",e.style.border="none",e.title="Sophi AI Widget",e.allow="microphone; camera; clipboard-write",this.container.appendChild(e),this.iframe=e;}buildIframeUrl(){return this.config?new URL(this.getIframeUrl()).toString():""}getIframeUrl(){return this.config?this.config.environment==="production"?"https://app.usesophi.com":"http://localhost:5173":""}setupMessageListener(){this.messageHandler=e=>{if(this.iframeOrigin&&e.origin!==this.iframeOrigin){console.warn(`Received message from untrusted origin: ${e.origin}`);return}try{let t=typeof e.data=="string"?JSON.parse(e.data):e.data;this.handleIncomingMessage(t);}catch(t){console.error("Error processing message from iframe:",t);}},window.addEventListener("message",this.messageHandler);}handleIncomingMessage(e){switch(e.type){case "add_to_cart":this.isValidAddToCartMessage(e.data)?this.emit("add_to_cart",e.data):(console.error("Invalid add_to_cart message structure:",e.data),this.emitError(new Error("Invalid add_to_cart message format")));break;case "send_to_checkout":this.emit("send_to_checkout",void 0);break;case "ready":this.emit("ready",void 0);break;case "error":let t=e.data instanceof Error?e.data:new Error(String(e.data));this.emitError(t);break;default:console.warn("Unknown message type:",e);}}isValidAddToCartMessage(e){if(!e||typeof e!="object")return false;let t=e;return Array.isArray(t.products)?t.products.every(i=>{if(!i||typeof i!="object")return false;let r=i;return !(typeof r.productId!="string"||r.variantId!==void 0&&typeof r.variantId!="string")}):false}postMessage(e){if(!this.iframe||!this.iframe.contentWindow||!this.iframeOrigin){console.warn("Cannot send message: iframe not ready");return}try{this.iframe.contentWindow.postMessage(e,this.iframeOrigin);}catch(t){console.error("Error sending message to iframe:",t),this.emitError(t instanceof Error?t:new Error(String(t)));}}emit(e,t){let i=this.eventListeners.get(e);i&&i.forEach(r=>{try{r(t);}catch(n){console.error(`Error in ${e} event handler:`,n);}});}emitError(e){this.emit("error",e),this.config?.onError&&this.config.onError(e);}};
2
2
  export{p as API_BASE_URLS,I as API_ENDPOINTS,c as ApiService,m as DEFAULT_CONFIG,a as ERROR_MESSAGES,f as IncomingMessageTypes,o as OutgoingMessageTypes,h as SophiWidget};//# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/services/cookie.utils.ts","../src/services/api.service.ts","../src/constants/config.ts","../src/SophiWidget.ts"],"names":["IncomingMessageTypes","OutgoingMessageTypes","_CookieManager","namespace","options","baseUrl","apiKey","key","value","name","cookies","cookie","cookieName","cookieValueParts","sanitized","CookieManager","ApiService","userId","request","url","headers","normalizedStored","normalizedCurrent","response","errorText","data","error","sessionData","clientId","storedUserId","storedClientId","normalizedStoredUserId","normalizedCurrentUserId","DEFAULT_CONFIG","API_BASE_URLS","API_ENDPOINTS","ERROR_MESSAGES","SophiWidget","config","err","message","cart","event","handler","handlers","resolve","container","iframe","product","prod"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Layout options sent to the iframe on init so the child app can adjust its layout.\n */\nexport interface LayoutConfig {\n /**\n * When true, show the header; when false, hide it.\n * Omitted/undefined means use the child app's default.\n */\n header?: boolean;\n}\n\n/**\n * Configuration for initializing the Sophi Widget\n */\nexport interface SophiConfig {\n /**\n * API key for authentication with Sophi services (x-api-key header)\n * This comes from the parent application\n */\n apiKey: string;\n\n /**\n * External user ID for authentication (x-sophi-external-user-id header)\n * This comes from the parent application\n */\n userId?: string;\n\n /**\n * User name for the user\n */\n userName?: string;\n\n /**\n * Container element selector (e.g., '#widget') or HTMLElement where the widget will be mounted\n */\n container: string | HTMLElement;\n\n /**\n * Optional metadata to send with the session request\n */\n metadata?: Record<string, unknown>;\n\n /**\n * Width of the widget iframe\n * @default '100%'\n */\n width?: string;\n\n /**\n * Height of the widget iframe\n * @default '600px'\n */\n height?: string;\n\n /**\n * Callback fired when the widget is ready\n */\n onReady?: () => void;\n\n /**\n * Callback fired when an error occurs\n */\n onError?: (error: Error) => void;\n\n /**\n * Environment to use for the API\n */\n environment?: \"test\" | \"production\";\n\n /**\n * Layout options sent to the iframe on init. The child app receives these via a\n * postMessage and can show/hide header (and future layout options) accordingly.\n */\n layout?: LayoutConfig;\n}\n\n/**\n * Product information for add to cart events\n */\nexport interface Product {\n /**\n * Unique product identifier\n */\n productId: string;\n\n /**\n * Optional variant identifier\n */\n variantId?: string;\n}\n\n/**\n * Add to cart event data\n */\nexport interface AddToCartEvent {\n /**\n * List of products to add to cart\n */\n products: Product[];\n}\n\n/**\n * User data that can be sent to the widget\n */\nexport interface UserData {\n /**\n * User ID\n */\n userId?: string;\n\n /**\n * User email\n */\n email?: string;\n\n /**\n * User name\n */\n name?: string;\n\n /**\n * Additional custom data\n */\n [key: string]: unknown;\n}\n\nexport interface IUserCartItem {\n productId: string;\n variantId: string;\n quantity?: number;\n}\n\nexport interface IUserCart {\n cardId: string;\n items: IUserCartItem[];\n}\n\n/**\n * Message types that can be received from the iframe\n */\nexport type IncomingMessageType = \"add_to_cart\" | \"send_to_checkout\" | \"ready\" | \"error\";\n\n/**\n * Incoming message type constants for easy access\n * @example\n * widget.on(IncomingMessageTypes.ADD_TO_CART, (data) => {...})\n */\nexport const IncomingMessageTypes = {\n ADD_TO_CART: \"add_to_cart\",\n READY: \"ready\",\n ERROR: \"error\",\n SEND_TO_CHECKOUT: \"send_to_checkout\",\n} as const;\n\n/**\n * Message types that can be sent to the iframe\n */\nexport type OutgoingMessageType = \"user_data\" | \"config\" | \"update_user_cart\" | \"destroy\" | \"session_data\" | \"client_id_updated\" | \"layout_config\" | \"toggle_history\";\n\n/**\n * Outgoing message type constants for easy access\n * @example\n * widget.sendMessage({ type: OutgoingMessageTypes.USER_DATA, data: {...} })\n */\nexport const OutgoingMessageTypes = {\n USER_DATA: \"user_data\",\n CONFIG: \"config\",\n UPDATE_USER_CART: \"update_user_cart\",\n DESTROY: \"destroy\",\n SESSION_DATA: \"session_data\",\n CLIENT_ID_UPDATED: \"client_id_updated\",\n LAYOUT_CONFIG: \"layout_config\",\n TOGGLE_HISTORY: \"toggle_history\",\n} as const;\n\n/**\n * Incoming message structure from iframe\n */\nexport interface IncomingMessage {\n type: IncomingMessageType;\n data?: unknown;\n}\n\n/**\n * Outgoing message structure to iframe\n */\nexport interface OutgoingMessage {\n type: OutgoingMessageType;\n data?: unknown;\n}\n\n/**\n * Event map for type-safe event handling\n */\nexport interface SophiEventMap {\n /**\n * Fired when products should be added to cart\n */\n add_to_cart: AddToCartEvent;\n\n /**\n * Fired when the widget is ready\n */\n ready: void;\n\n /**\n * Fired when an error occurs\n */\n error: Error;\n\n /**\n * Fired when the user should be sent to checkout\n */\n send_to_checkout: void;\n}\n\n/**\n * Event handler type\n */\nexport type EventHandler<T> = (data: T) => void;\n\n/**\n * Event name type\n */\nexport type EventName = keyof SophiEventMap;\n\n/**\n * Authentication session request payload\n */\nexport interface AuthSessionRequest {\n /**\n * External user ID from the parent application\n */\n externalUserId?: string;\n\n /**\n * Optional metadata to include with the session\n */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Session data returned from the authentication API\n */\nexport interface SessionData {\n /**\n * JWT access token for authenticating requests\n */\n accessToken: string;\n\n /**\n * Unique session identifier\n */\n sessionId: string;\n\n /**\n * Client ID\n */\n clientId: string;\n\n /**\n * Company code\n */\n companyCode: string;\n\n /**\n * Session expiration timestamp\n */\n expiresAt: string;\n\n /**\n * userName of the user\n */\n userName: string;\n}\n\n/**\n * Authentication session API response\n */\nexport interface AuthSessionResponse {\n /**\n * Whether the request was successful\n */\n success: boolean;\n\n /**\n * Response message\n */\n message: string;\n\n /**\n * Session data\n */\n data?: SessionData;\n}\n\n/**\n * Merge user request payload\n */\nexport interface MergeUserRequest {\n /**\n * The logged-in user ID to merge to\n */\n userId: string;\n}\n\n/**\n * Merge user data returned from the API\n */\nexport interface MergeUserData {\n /**\n * The resulting client ID after merge\n */\n clientId: string;\n\n /**\n * The external user ID\n */\n externalUserId: string;\n}\n\n/**\n * Merge user API response\n */\nexport interface MergeUserResponse {\n /**\n * Whether the request was successful\n */\n success: boolean;\n\n /**\n * Response message\n */\n message: string;\n\n /**\n * Merge result data\n */\n data?: MergeUserData;\n}\n","export type CookieKey = \"clientId\" | \"externalUserId\" | \"sessionData\" | \"metadataHash\";\n\nexport interface CookieManagerOptions {\n readonly maxAgeSeconds?: number;\n readonly keys?: Partial<Record<CookieKey, string>>;\n}\n\nexport class CookieManager {\n static readonly DEFAULT_MAX_AGE_SECONDS = 60 * 60 * 24 * 30; // 30 days\n static readonly DEFAULT_KEYS: Record<CookieKey, string> = {\n clientId: \"client-id\",\n externalUserId: \"external-user-id\",\n sessionData: \"session-data\",\n metadataHash: \"metadata-hash\",\n };\n\n constructor(namespace: string, options?: CookieManagerOptions) {\n this.namespace = CookieManager.sanitizeNamespace(namespace);\n this.maxAgeSeconds = options?.maxAgeSeconds ?? CookieManager.DEFAULT_MAX_AGE_SECONDS;\n this.keys = { ...CookieManager.DEFAULT_KEYS, ...(options?.keys ?? {}) };\n }\n\n private readonly namespace: string;\n private readonly maxAgeSeconds: number;\n private readonly keys: Record<CookieKey, string>;\n\n static buildNamespace(baseUrl: string, apiKey: string): string {\n return CookieManager.sanitizeNamespace(`sophi-widget-${baseUrl}-${apiKey}`);\n }\n\n static canUseCookies(): boolean {\n return typeof document !== \"undefined\" && typeof document.cookie === \"string\";\n }\n\n set(key: CookieKey, value: string): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n document.cookie = `${this.formatName(key)}=${encodeURIComponent(value)}; path=/; max-age=${this.maxAgeSeconds}; samesite=lax`;\n }\n\n get(key: CookieKey): string | null {\n if (!CookieManager.canUseCookies()) {\n return null;\n }\n\n return CookieManager.readRawCookie(this.formatName(key));\n }\n\n delete(key: CookieKey): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n document.cookie = `${this.formatName(key)}=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; samesite=lax`;\n }\n\n clearAll(): void {\n Object.keys(this.keys).forEach((key) => {\n this.delete(key as CookieKey);\n });\n }\n\n private formatName(key: CookieKey): string {\n return `${this.namespace}-${this.keys[key]}`;\n }\n\n private static readRawCookie(name: string): string | null {\n const cookies = document.cookie.split(\";\").map((cookie) => cookie.trim());\n for (const cookie of cookies) {\n if (!cookie) {\n continue;\n }\n const [cookieName, ...cookieValueParts] = cookie.split(\"=\");\n if (cookieName === name) {\n return decodeURIComponent(cookieValueParts.join(\"=\"));\n }\n }\n return null;\n }\n\n private static sanitizeNamespace(value: string): string {\n const sanitized = value.replace(/[^a-zA-Z0-9_-]/g, \"\");\n return sanitized.length ? sanitized : \"sophi-widget\";\n }\n}\n","import type { AuthSessionRequest, AuthSessionResponse, SessionData, MergeUserRequest, MergeUserResponse, MergeUserData } from \"../types\";\nimport { CookieManager } from \"./cookie.utils\";\n\n/**\n * API Service for Sophi authentication and session management\n */\nexport class ApiService {\n private baseUrl: string;\n private apiKey: string;\n private clientId: string | null = null;\n private userId: string | undefined = undefined;\n private storedUserId: string | null = null; // Track the userId from cookies for merge detection\n private cookieManager: CookieManager;\n\n constructor(baseUrl: string, apiKey: string, userId?: string) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.userId = userId;\n this.cookieManager = new CookieManager(CookieManager.buildNamespace(baseUrl, apiKey));\n this.restoreSessionFromCookies();\n }\n\n /**\n * Create a client session by calling the authentication endpoint\n * @param request - Session request with optional externalUserId and metadata\n * @returns Session data including accessToken, sessionId, etc.\n */\n async createSession(request: AuthSessionRequest): Promise<SessionData> {\n const url = `${this.baseUrl}/api/v1/auth/client/session`;\n\n try {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"x-api-key\": this.apiKey,\n };\n if (this.clientId) {\n headers[\"x-sophi-client-id\"] = this.clientId;\n // Check if we need to merge: user changed from stored (could be empty) to current\n const normalizedStored = this.storedUserId || null;\n const normalizedCurrent = this.userId || null;\n if (normalizedStored !== normalizedCurrent && normalizedCurrent) {\n await this.mergeUser({ userId: normalizedCurrent });\n // Update storedUserId after successful merge\n this.storedUserId = normalizedCurrent;\n }\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n externalUserId: this.userId,\n metadata: request.metadata,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to create session: ${response.status} ${response.statusText}. ${errorText}`);\n }\n\n const data: AuthSessionResponse = await response.json();\n\n if (!data.success) {\n throw new Error(`Session creation failed: ${data.message || \"Unknown error\"}`);\n }\n\n if (!data.data) {\n throw new Error(\"Session data is missing from response\");\n }\n this.persistClientInfo(data.data.clientId, this.userId);\n return data.data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error during session creation: ${String(error)}`);\n }\n }\n\n /**\n * Validate session data\n */\n validateSessionData(sessionData: SessionData): boolean {\n return !!(sessionData.accessToken && sessionData.sessionId && sessionData.clientId && sessionData.companyCode && sessionData.expiresAt);\n }\n\n /**\n * Merge guest user with logged-in user\n * @param request - Merge request with guestId and userId\n * @returns Merge result data including the resulting clientId\n */\n async mergeUser(request: MergeUserRequest): Promise<MergeUserData> {\n const url = `${this.baseUrl}/api/v1/auth/client/info`;\n\n try {\n if (!this.clientId) {\n throw new Error(\"Client ID is not set. Please create a session first.\");\n }\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"x-api-key\": this.apiKey,\n \"x-sophi-client-id\": this.clientId,\n },\n body: JSON.stringify({\n externalUserId: request.userId,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to merge user: ${response.status} ${response.statusText}. ${errorText}`);\n }\n\n const data: MergeUserResponse = await response.json();\n\n if (!data.success) {\n throw new Error(`User merge failed: ${data.message || \"Unknown error\"}`);\n }\n\n if (!data.data) {\n throw new Error(\"Merge data is missing from response\");\n }\n\n return data.data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error during user merge: ${String(error)}`);\n }\n }\n\n private persistClientInfo(clientId: string, userId?: string): void {\n this.clientId = clientId;\n this.userId = userId;\n this.storedUserId = userId || null; // Update stored userId to match current state\n\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n this.cookieManager.set(\"clientId\", clientId);\n // Always save externalUserId (even if empty) to track the session state\n this.cookieManager.set(\"externalUserId\", userId || \"\");\n }\n\n private restoreSessionFromCookies(): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n const storedUserId = this.cookieManager.get(\"externalUserId\");\n const storedClientId = this.cookieManager.get(\"clientId\");\n\n // Store the userId from cookies for merge detection later\n this.storedUserId = storedUserId || null;\n\n // If no clientId in cookies, nothing to restore\n if (!storedClientId) {\n return;\n }\n\n // Normalize empty values (undefined, null, empty string) to null for comparison\n const normalizedStoredUserId = storedUserId || null;\n const normalizedCurrentUserId = this.userId || null;\n\n // If userIds match, restore both clientId and userId\n if (normalizedStoredUserId === normalizedCurrentUserId) {\n this.clientId = storedClientId;\n if (!this.userId && storedUserId) {\n this.userId = storedUserId;\n }\n return;\n }\n\n // UserIds don't match - determine if we should clear or keep clientId\n \n // Case 1: Logout (filled -> empty) - clear session\n if (normalizedStoredUserId && !normalizedCurrentUserId) {\n this.clearStoredClientInfo();\n return;\n }\n\n // Case 2: Different logged-in users (filled -> different filled) - clear session for new user\n if (normalizedStoredUserId && normalizedCurrentUserId && normalizedStoredUserId !== normalizedCurrentUserId) {\n this.clearStoredClientInfo();\n return;\n }\n\n // Case 3: Guest -> Logged-in user (empty -> filled) - keep clientId for merge\n if (!normalizedStoredUserId && normalizedCurrentUserId) {\n this.clientId = storedClientId;\n return;\n }\n }\n\n private clearStoredClientInfo(): void {\n this.clientId = null;\n this.storedUserId = null;\n\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n this.cookieManager.clearAll();\n }\n}\n","/**\n * Default configuration constants for Sophi Widget\n */\nexport const DEFAULT_CONFIG = {\n /**\n * Default width of the widget iframe\n */\n WIDTH: \"100%\",\n\n /**\n * Default height of the widget iframe\n */\n HEIGHT: \"600px\",\n} as const;\n\n/**\n * API base URLs for different environments\n *\n * Note: These URLs will be visible in the client-side bundle.\n * This is normal and safe - the real security is in your API key validation.\n *\n * To use different URLs, modify these values before building the SDK.\n *\n * Production API URL - update before building for production\n */\nexport const API_BASE_URLS = {\n test: \"http://10.0.2.127:80\",\n production: \"https://api.usesophi.com\",\n} as const;\n\n/**\n * API endpoints configuration\n */\nexport const API_ENDPOINTS = {\n /**\n * Session creation endpoint path\n */\n CREATE_SESSION: \"/api/v1/auth/client/session\",\n} as const;\n\n/**\n * Error messages\n */\nexport const ERROR_MESSAGES = {\n MISSING_API_KEY: \"API key is required and must be a string\",\n MISSING_CLIENT_ID: \"Client ID is required and must be a string\",\n MISSING_USER_ID: \"User ID is required and must be a string\",\n MISSING_CONTAINER: \"Container is required\",\n MISSING_IFRAME_URL: \"Iframe URL is required and must be a string\",\n INVALID_IFRAME_URL: \"Invalid iframe URL\",\n INVALID_ENVIRONMENT: \"Invalid environment. Must be 'dev', 'test', 'staging', or 'production'\",\n CONTAINER_NOT_FOUND: \"Container element not found\",\n NOT_INITIALIZED: \"Widget not initialized. Call init() first.\",\n ALREADY_INITIALIZED: \"Sophi Widget is already initialized. Call destroy() first to reinitialize.\",\n SESSION_CREATION_FAILED: \"Failed to create authentication session\",\n INVALID_SESSION_DATA: \"Invalid session data received from API\",\n YOU_NEED_TO_INIT_THE_WIDGET_FIRST: \"You need to initialize the widget first. Call init() before calling this method.\",\n} as const;\n","import { type SophiConfig, type UserData, type EventHandler, type EventName, type SophiEventMap, type IncomingMessage, type OutgoingMessage, type AddToCartEvent, type IUserCart, type SessionData, type MergeUserRequest, type MergeUserData, OutgoingMessageTypes } from \"./types\";\nimport { ApiService } from \"./services/api.service\";\nimport { DEFAULT_CONFIG, ERROR_MESSAGES, API_BASE_URLS } from \"./constants/config\";\n\n/**\n * Main Sophi Widget SDK class\n * Provides a framework-agnostic way to embed and interact with the Sophi AI widget\n */\nexport class SophiWidget {\n private config: SophiConfig | null = null;\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLElement | null = null;\n private eventListeners: Map<EventName, Set<EventHandler<any>>> = new Map();\n private messageHandler: ((event: MessageEvent) => void) | null = null;\n private isInitialized = false;\n private iframeOrigin: string | null = null;\n private sessionData: SessionData | null = null;\n private apiService: ApiService | null = null;\n private apiBaseUrl: string | null = null;\n\n /**\n * Initialize the widget with configuration\n * @param config - Widget configuration\n */\n public async init(config: SophiConfig): Promise<void> {\n if (this.isInitialized) {\n console.warn(ERROR_MESSAGES.ALREADY_INITIALIZED);\n return;\n }\n\n try {\n // Validate configuration\n this.validateConfig(config);\n\n this.config = this.formatConfig(config);\n\n // Determine API URL based on environment\n this.apiBaseUrl = API_BASE_URLS[config.environment || \"production\"];\n\n // Initialize API service\n this.apiService = new ApiService(this.apiBaseUrl, config.apiKey, config.userId);\n\n // Create authentication session\n await this.createAuthSession();\n\n this.isInitialized = true;\n\n // Extract origin from iframe URL for security\n try {\n const url = new URL(this.getIframeUrl());\n this.iframeOrigin = url.origin;\n } catch (error) {\n const err = new Error(`${ERROR_MESSAGES.INVALID_IFRAME_URL}: ${this.getIframeUrl()}`);\n this.emitError(err);\n throw err;\n }\n\n // Resolve container element\n this.container = this.resolveContainer(config.container);\n\n if (!this.container) {\n const err = new Error(ERROR_MESSAGES.CONTAINER_NOT_FOUND);\n this.emitError(err);\n throw err;\n }\n\n // Create and mount iframe\n this.createIframe();\n\n // Setup postMessage listener\n this.setupMessageListener();\n\n // Send session data to iframe after it's loaded\n this.iframe?.addEventListener(\"load\", () => {\n // Small delay to ensure iframe is fully ready\n setTimeout(() => {\n this.sendSessionData();\n if (this.config?.layout) {\n this.sendLayoutConfig();\n }\n }, 100);\n });\n\n // Call onReady callback if provided\n if (config.onReady) {\n config.onReady();\n }\n } catch (error) {\n // Reset state on error\n this.isInitialized = false;\n this.config = null;\n this.apiService = null;\n this.sessionData = null;\n\n const err = error instanceof Error ? error : new Error(String(error));\n this.emitError(err);\n throw err;\n }\n }\n\n /**\n * Send user data to the widget\n * @param data - User data object\n */\n public sendUserData(data: UserData): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.USER_DATA,\n data,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Toggle chat history visibility in the iframe child app.\n */\n public sendToggleHistory(): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.TOGGLE_HISTORY,\n };\n\n this.postMessage(message);\n }\n\n public updateUserCart(cart: IUserCart): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.UPDATE_USER_CART,\n data: cart,\n };\n\n this.postMessage(message);\n }\n\n private onDestroy(): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.DESTROY,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Register an event listener\n * @param event - Event name\n * @param handler - Event handler function\n */\n public on<K extends EventName>(event: K, handler: EventHandler<SophiEventMap[K]>): void {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n /**\n * Unregister an event listener\n * @param event - Event name\n * @param handler - Event handler function to remove\n */\n public off<K extends EventName>(event: K, handler: EventHandler<SophiEventMap[K]>): void {\n const handlers = this.eventListeners.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n }\n\n /**\n * Show the widget\n */\n public show(): void {\n if (this.iframe) {\n this.iframe.style.display = \"block\";\n }\n }\n\n /**\n * Hide the widget\n */\n public hide(): void {\n if (this.iframe) {\n this.iframe.style.display = \"none\";\n }\n }\n\n /**\n * Destroy the widget and cleanup resources\n * Waits 300ms after sending destroy message to give iframe time to cleanup\n */\n public async destroy(): Promise<void> {\n this.onDestroy();\n\n // Wait 300ms to give iframe time to process the destroy event and cleanup\n await new Promise((resolve) => setTimeout(resolve, 300));\n\n // Remove message listener\n if (this.messageHandler) {\n window.removeEventListener(\"message\", this.messageHandler);\n this.messageHandler = null;\n }\n\n // Remove iframe\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n this.iframe = null;\n }\n\n // Clear event listeners\n this.eventListeners.clear();\n\n // Reset state\n this.config = null;\n this.container = null;\n this.isInitialized = false;\n this.iframeOrigin = null;\n this.sessionData = null;\n this.apiService = null;\n }\n\n /**\n * Check if widget is initialized\n */\n public isReady(): boolean {\n return this.isInitialized && this.iframe !== null;\n }\n\n /**\n * Validate configuration\n */\n private validateConfig(config: SophiConfig): void {\n if (!config.apiKey || typeof config.apiKey !== \"string\") {\n throw new Error(ERROR_MESSAGES.MISSING_API_KEY);\n }\n\n if (config.userId && typeof config.userId !== \"string\") {\n throw new Error(ERROR_MESSAGES.MISSING_USER_ID);\n }\n\n if (!config.container) {\n throw new Error(ERROR_MESSAGES.MISSING_CONTAINER);\n }\n }\n\n /**\n * Format configuration\n */\n private formatConfig(config: SophiConfig): SophiConfig {\n return {\n ...config,\n userId: config.userId || undefined,\n };\n }\n\n /**\n * Create authentication session with the API\n */\n private async createAuthSession(): Promise<void> {\n if (!this.config || !this.apiService) {\n throw new Error(ERROR_MESSAGES.NOT_INITIALIZED);\n }\n\n try {\n this.sessionData = await this.apiService.createSession({\n externalUserId: this.config.userId,\n metadata: this.config.metadata,\n });\n\n // Validate session data\n if (!this.apiService.validateSessionData(this.sessionData)) {\n throw new Error(ERROR_MESSAGES.INVALID_SESSION_DATA);\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(ERROR_MESSAGES.SESSION_CREATION_FAILED);\n throw err;\n }\n }\n\n /**\n * Send session data to iframe\n */\n private sendSessionData(): void {\n if (!this.sessionData) {\n console.warn(\"Session data not available\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.SESSION_DATA,\n data: { ...this.sessionData, userName: this.config?.userName },\n };\n\n this.postMessage(message);\n }\n\n /**\n * Send layout config to iframe so the child app can apply layout options (e.g. show/hide header).\n */\n private sendLayoutConfig(): void {\n if (!this.config?.layout) {\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.LAYOUT_CONFIG,\n data: this.config.layout,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Resolve container element from selector or element\n */\n private resolveContainer(container: string | HTMLElement): HTMLElement | null {\n if (typeof container === \"string\") {\n return document.querySelector(container);\n }\n return container;\n }\n\n /**\n * Create and mount the iframe\n */\n private createIframe(): void {\n if (!this.container || !this.config) {\n return;\n }\n\n const iframe = document.createElement(\"iframe\");\n\n // Set iframe attributes\n iframe.src = this.buildIframeUrl();\n iframe.style.width = this.config.width || \"100%\";\n iframe.style.height = this.config.height || \"600px\";\n iframe.style.border = \"none\";\n iframe.title = \"Sophi AI Widget\";\n iframe.allow = \"microphone; camera\";\n\n // Append to container\n this.container.appendChild(iframe);\n this.iframe = iframe;\n }\n\n /**\n * Build iframe URL with query parameters\n */\n private buildIframeUrl(): string {\n if (!this.config) {\n return \"\";\n }\n const url = new URL(this.getIframeUrl());\n\n return url.toString();\n }\n\n private getIframeUrl(): string {\n if (!this.config) {\n return \"\";\n }\n if (this.config.environment === \"production\") {\n return \"https://app.usesophi.com\";\n }\n return \"http://localhost:5173\";\n }\n\n /**\n * Setup postMessage listener for iframe communication\n */\n private setupMessageListener(): void {\n this.messageHandler = (event: MessageEvent) => {\n // Validate origin for security\n if (this.iframeOrigin && event.origin !== this.iframeOrigin) {\n console.warn(`Received message from untrusted origin: ${event.origin}`);\n return;\n }\n\n try {\n // Parse message\n const message: IncomingMessage = typeof event.data === \"string\" ? JSON.parse(event.data) : event.data;\n\n // Handle different message types\n this.handleIncomingMessage(message);\n } catch (error) {\n console.error(\"Error processing message from iframe:\", error);\n }\n };\n\n window.addEventListener(\"message\", this.messageHandler);\n }\n\n /**\n * Handle incoming messages from iframe\n */\n private handleIncomingMessage(message: IncomingMessage): void {\n switch (message.type) {\n case \"add_to_cart\":\n if (this.isValidAddToCartMessage(message.data)) {\n this.emit(\"add_to_cart\", message.data);\n } else {\n console.error(\"Invalid add_to_cart message structure:\", message.data);\n this.emitError(new Error(\"Invalid add_to_cart message format\"));\n }\n break;\n\n case \"send_to_checkout\":\n this.emit(\"send_to_checkout\", undefined);\n break;\n case \"ready\":\n this.emit(\"ready\", undefined);\n break;\n\n case \"error\":\n const error = message.data instanceof Error ? message.data : new Error(String(message.data));\n this.emitError(error);\n break;\n\n default:\n console.warn(\"Unknown message type:\", message);\n }\n }\n\n /**\n * Validate add_to_cart message structure\n */\n private isValidAddToCartMessage(data: unknown): data is AddToCartEvent {\n if (!data || typeof data !== \"object\") {\n return false;\n }\n\n const event = data as Record<string, unknown>;\n\n // Check products array exists and is an array\n if (!Array.isArray(event.products)) {\n return false;\n }\n\n // Validate each product in the array\n return event.products.every((product) => {\n if (!product || typeof product !== \"object\") {\n return false;\n }\n const prod = product as Record<string, unknown>;\n\n // productId is required and must be a string\n if (typeof prod.productId !== \"string\") {\n return false;\n }\n\n // variantId is optional, but if present must be a string\n if (prod.variantId !== undefined && typeof prod.variantId !== \"string\") {\n return false;\n }\n\n return true;\n });\n }\n\n /**\n * Post message to iframe\n */\n private postMessage(message: OutgoingMessage): void {\n if (!this.iframe || !this.iframe.contentWindow || !this.iframeOrigin) {\n console.warn(\"Cannot send message: iframe not ready\");\n return;\n }\n\n try {\n this.iframe.contentWindow.postMessage(message, this.iframeOrigin);\n } catch (error) {\n console.error(\"Error sending message to iframe:\", error);\n this.emitError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Emit event to registered listeners\n */\n private emit<K extends EventName>(event: K, data: SophiEventMap[K]): void {\n const handlers = this.eventListeners.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(data);\n } catch (error) {\n console.error(`Error in ${event} event handler:`, error);\n }\n });\n }\n }\n\n /**\n * Emit error event\n */\n private emitError(error: Error): void {\n this.emit(\"error\", error);\n\n // Also call onError callback if provided\n if (this.config?.onError) {\n this.config.onError(error);\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/services/cookie.utils.ts","../src/services/api.service.ts","../src/constants/config.ts","../src/SophiWidget.ts"],"names":["IncomingMessageTypes","OutgoingMessageTypes","_CookieManager","namespace","options","baseUrl","apiKey","key","value","name","cookies","cookie","cookieName","cookieValueParts","sanitized","CookieManager","ApiService","userId","request","url","headers","normalizedStored","normalizedCurrent","response","errorText","data","error","sessionData","clientId","storedUserId","storedClientId","normalizedStoredUserId","normalizedCurrentUserId","DEFAULT_CONFIG","API_BASE_URLS","API_ENDPOINTS","ERROR_MESSAGES","SophiWidget","config","err","message","cart","event","handler","handlers","resolve","container","iframe","product","prod"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Layout options sent to the iframe on init so the child app can adjust its layout.\n */\nexport interface LayoutConfig {\n /**\n * When true, show the header; when false, hide it.\n * Omitted/undefined means use the child app's default.\n */\n header?: boolean;\n}\n\n/**\n * Configuration for initializing the Sophi Widget\n */\nexport interface SophiConfig {\n /**\n * API key for authentication with Sophi services (x-api-key header)\n * This comes from the parent application\n */\n apiKey: string;\n\n /**\n * External user ID for authentication (x-sophi-external-user-id header)\n * This comes from the parent application\n */\n userId?: string;\n\n /**\n * User name for the user\n */\n userName?: string;\n\n /**\n * Container element selector (e.g., '#widget') or HTMLElement where the widget will be mounted\n */\n container: string | HTMLElement;\n\n /**\n * Optional metadata to send with the session request\n */\n metadata?: Record<string, unknown>;\n\n /**\n * Width of the widget iframe\n * @default '100%'\n */\n width?: string;\n\n /**\n * Height of the widget iframe\n * @default '600px'\n */\n height?: string;\n\n /**\n * Callback fired when the widget is ready\n */\n onReady?: () => void;\n\n /**\n * Callback fired when an error occurs\n */\n onError?: (error: Error) => void;\n\n /**\n * Environment to use for the API\n */\n environment?: \"test\" | \"production\";\n\n /**\n * Layout options sent to the iframe on init. The child app receives these via a\n * postMessage and can show/hide header (and future layout options) accordingly.\n */\n layout?: LayoutConfig;\n}\n\n/**\n * Product information for add to cart events\n */\nexport interface Product {\n /**\n * Unique product identifier\n */\n productId: string;\n\n /**\n * Optional variant identifier\n */\n variantId?: string;\n}\n\n/**\n * Add to cart event data\n */\nexport interface AddToCartEvent {\n /**\n * List of products to add to cart\n */\n products: Product[];\n}\n\n/**\n * User data that can be sent to the widget\n */\nexport interface UserData {\n /**\n * User ID\n */\n userId?: string;\n\n /**\n * User email\n */\n email?: string;\n\n /**\n * User name\n */\n name?: string;\n\n /**\n * Additional custom data\n */\n [key: string]: unknown;\n}\n\nexport interface IUserCartItem {\n productId: string;\n variantId: string;\n quantity?: number;\n}\n\nexport interface IUserCart {\n cardId: string;\n items: IUserCartItem[];\n}\n\n/**\n * Message types that can be received from the iframe\n */\nexport type IncomingMessageType = \"add_to_cart\" | \"send_to_checkout\" | \"ready\" | \"error\";\n\n/**\n * Incoming message type constants for easy access\n * @example\n * widget.on(IncomingMessageTypes.ADD_TO_CART, (data) => {...})\n */\nexport const IncomingMessageTypes = {\n ADD_TO_CART: \"add_to_cart\",\n READY: \"ready\",\n ERROR: \"error\",\n SEND_TO_CHECKOUT: \"send_to_checkout\",\n} as const;\n\n/**\n * Message types that can be sent to the iframe\n */\nexport type OutgoingMessageType = \"user_data\" | \"config\" | \"update_user_cart\" | \"destroy\" | \"session_data\" | \"client_id_updated\" | \"layout_config\" | \"toggle_history\";\n\n/**\n * Outgoing message type constants for easy access\n * @example\n * widget.sendMessage({ type: OutgoingMessageTypes.USER_DATA, data: {...} })\n */\nexport const OutgoingMessageTypes = {\n USER_DATA: \"user_data\",\n CONFIG: \"config\",\n UPDATE_USER_CART: \"update_user_cart\",\n DESTROY: \"destroy\",\n SESSION_DATA: \"session_data\",\n CLIENT_ID_UPDATED: \"client_id_updated\",\n LAYOUT_CONFIG: \"layout_config\",\n TOGGLE_HISTORY: \"toggle_history\",\n} as const;\n\n/**\n * Incoming message structure from iframe\n */\nexport interface IncomingMessage {\n type: IncomingMessageType;\n data?: unknown;\n}\n\n/**\n * Outgoing message structure to iframe\n */\nexport interface OutgoingMessage {\n type: OutgoingMessageType;\n data?: unknown;\n}\n\n/**\n * Event map for type-safe event handling\n */\nexport interface SophiEventMap {\n /**\n * Fired when products should be added to cart\n */\n add_to_cart: AddToCartEvent;\n\n /**\n * Fired when the widget is ready\n */\n ready: void;\n\n /**\n * Fired when an error occurs\n */\n error: Error;\n\n /**\n * Fired when the user should be sent to checkout\n */\n send_to_checkout: void;\n}\n\n/**\n * Event handler type\n */\nexport type EventHandler<T> = (data: T) => void;\n\n/**\n * Event name type\n */\nexport type EventName = keyof SophiEventMap;\n\n/**\n * Authentication session request payload\n */\nexport interface AuthSessionRequest {\n /**\n * External user ID from the parent application\n */\n externalUserId?: string;\n\n /**\n * Optional metadata to include with the session\n */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Session data returned from the authentication API\n */\nexport interface SessionData {\n /**\n * JWT access token for authenticating requests\n */\n accessToken: string;\n\n /**\n * Unique session identifier\n */\n sessionId: string;\n\n /**\n * Client ID\n */\n clientId: string;\n\n /**\n * Company code\n */\n companyCode: string;\n\n /**\n * Session expiration timestamp\n */\n expiresAt: string;\n\n /**\n * userName of the user\n */\n userName: string;\n}\n\n/**\n * Authentication session API response\n */\nexport interface AuthSessionResponse {\n /**\n * Whether the request was successful\n */\n success: boolean;\n\n /**\n * Response message\n */\n message: string;\n\n /**\n * Session data\n */\n data?: SessionData;\n}\n\n/**\n * Merge user request payload\n */\nexport interface MergeUserRequest {\n /**\n * The logged-in user ID to merge to\n */\n userId: string;\n}\n\n/**\n * Merge user data returned from the API\n */\nexport interface MergeUserData {\n /**\n * The resulting client ID after merge\n */\n clientId: string;\n\n /**\n * The external user ID\n */\n externalUserId: string;\n}\n\n/**\n * Merge user API response\n */\nexport interface MergeUserResponse {\n /**\n * Whether the request was successful\n */\n success: boolean;\n\n /**\n * Response message\n */\n message: string;\n\n /**\n * Merge result data\n */\n data?: MergeUserData;\n}\n","export type CookieKey = \"clientId\" | \"externalUserId\" | \"sessionData\" | \"metadataHash\";\n\nexport interface CookieManagerOptions {\n readonly maxAgeSeconds?: number;\n readonly keys?: Partial<Record<CookieKey, string>>;\n}\n\nexport class CookieManager {\n static readonly DEFAULT_MAX_AGE_SECONDS = 60 * 60 * 24 * 30; // 30 days\n static readonly DEFAULT_KEYS: Record<CookieKey, string> = {\n clientId: \"client-id\",\n externalUserId: \"external-user-id\",\n sessionData: \"session-data\",\n metadataHash: \"metadata-hash\",\n };\n\n constructor(namespace: string, options?: CookieManagerOptions) {\n this.namespace = CookieManager.sanitizeNamespace(namespace);\n this.maxAgeSeconds = options?.maxAgeSeconds ?? CookieManager.DEFAULT_MAX_AGE_SECONDS;\n this.keys = { ...CookieManager.DEFAULT_KEYS, ...(options?.keys ?? {}) };\n }\n\n private readonly namespace: string;\n private readonly maxAgeSeconds: number;\n private readonly keys: Record<CookieKey, string>;\n\n static buildNamespace(baseUrl: string, apiKey: string): string {\n return CookieManager.sanitizeNamespace(`sophi-widget-${baseUrl}-${apiKey}`);\n }\n\n static canUseCookies(): boolean {\n return typeof document !== \"undefined\" && typeof document.cookie === \"string\";\n }\n\n set(key: CookieKey, value: string): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n document.cookie = `${this.formatName(key)}=${encodeURIComponent(value)}; path=/; max-age=${this.maxAgeSeconds}; samesite=lax`;\n }\n\n get(key: CookieKey): string | null {\n if (!CookieManager.canUseCookies()) {\n return null;\n }\n\n return CookieManager.readRawCookie(this.formatName(key));\n }\n\n delete(key: CookieKey): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n document.cookie = `${this.formatName(key)}=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; samesite=lax`;\n }\n\n clearAll(): void {\n Object.keys(this.keys).forEach((key) => {\n this.delete(key as CookieKey);\n });\n }\n\n private formatName(key: CookieKey): string {\n return `${this.namespace}-${this.keys[key]}`;\n }\n\n private static readRawCookie(name: string): string | null {\n const cookies = document.cookie.split(\";\").map((cookie) => cookie.trim());\n for (const cookie of cookies) {\n if (!cookie) {\n continue;\n }\n const [cookieName, ...cookieValueParts] = cookie.split(\"=\");\n if (cookieName === name) {\n return decodeURIComponent(cookieValueParts.join(\"=\"));\n }\n }\n return null;\n }\n\n private static sanitizeNamespace(value: string): string {\n const sanitized = value.replace(/[^a-zA-Z0-9_-]/g, \"\");\n return sanitized.length ? sanitized : \"sophi-widget\";\n }\n}\n","import type { AuthSessionRequest, AuthSessionResponse, SessionData, MergeUserRequest, MergeUserResponse, MergeUserData } from \"../types\";\nimport { CookieManager } from \"./cookie.utils\";\n\n/**\n * API Service for Sophi authentication and session management\n */\nexport class ApiService {\n private baseUrl: string;\n private apiKey: string;\n private clientId: string | null = null;\n private userId: string | undefined = undefined;\n private storedUserId: string | null = null; // Track the userId from cookies for merge detection\n private cookieManager: CookieManager;\n\n constructor(baseUrl: string, apiKey: string, userId?: string) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.userId = userId;\n this.cookieManager = new CookieManager(CookieManager.buildNamespace(baseUrl, apiKey));\n this.restoreSessionFromCookies();\n }\n\n /**\n * Create a client session by calling the authentication endpoint\n * @param request - Session request with optional externalUserId and metadata\n * @returns Session data including accessToken, sessionId, etc.\n */\n async createSession(request: AuthSessionRequest): Promise<SessionData> {\n const url = `${this.baseUrl}/api/v1/auth/client/session`;\n\n try {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"x-api-key\": this.apiKey,\n };\n if (this.clientId) {\n headers[\"x-sophi-client-id\"] = this.clientId;\n // Check if we need to merge: user changed from stored (could be empty) to current\n const normalizedStored = this.storedUserId || null;\n const normalizedCurrent = this.userId || null;\n if (normalizedStored !== normalizedCurrent && normalizedCurrent) {\n await this.mergeUser({ userId: normalizedCurrent });\n // Update storedUserId after successful merge\n this.storedUserId = normalizedCurrent;\n }\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n externalUserId: this.userId,\n metadata: request.metadata,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to create session: ${response.status} ${response.statusText}. ${errorText}`);\n }\n\n const data: AuthSessionResponse = await response.json();\n\n if (!data.success) {\n throw new Error(`Session creation failed: ${data.message || \"Unknown error\"}`);\n }\n\n if (!data.data) {\n throw new Error(\"Session data is missing from response\");\n }\n this.persistClientInfo(data.data.clientId, this.userId);\n return data.data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error during session creation: ${String(error)}`);\n }\n }\n\n /**\n * Validate session data\n */\n validateSessionData(sessionData: SessionData): boolean {\n return !!(sessionData.accessToken && sessionData.sessionId && sessionData.clientId && sessionData.companyCode && sessionData.expiresAt);\n }\n\n /**\n * Merge guest user with logged-in user\n * @param request - Merge request with guestId and userId\n * @returns Merge result data including the resulting clientId\n */\n async mergeUser(request: MergeUserRequest): Promise<MergeUserData> {\n const url = `${this.baseUrl}/api/v1/auth/client/info`;\n\n try {\n if (!this.clientId) {\n throw new Error(\"Client ID is not set. Please create a session first.\");\n }\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"x-api-key\": this.apiKey,\n \"x-sophi-client-id\": this.clientId,\n },\n body: JSON.stringify({\n externalUserId: request.userId,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to merge user: ${response.status} ${response.statusText}. ${errorText}`);\n }\n\n const data: MergeUserResponse = await response.json();\n\n if (!data.success) {\n throw new Error(`User merge failed: ${data.message || \"Unknown error\"}`);\n }\n\n if (!data.data) {\n throw new Error(\"Merge data is missing from response\");\n }\n\n return data.data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error during user merge: ${String(error)}`);\n }\n }\n\n private persistClientInfo(clientId: string, userId?: string): void {\n this.clientId = clientId;\n this.userId = userId;\n this.storedUserId = userId || null; // Update stored userId to match current state\n\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n this.cookieManager.set(\"clientId\", clientId);\n // Always save externalUserId (even if empty) to track the session state\n this.cookieManager.set(\"externalUserId\", userId || \"\");\n }\n\n private restoreSessionFromCookies(): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n const storedUserId = this.cookieManager.get(\"externalUserId\");\n const storedClientId = this.cookieManager.get(\"clientId\");\n\n // Store the userId from cookies for merge detection later\n this.storedUserId = storedUserId || null;\n\n // If no clientId in cookies, nothing to restore\n if (!storedClientId) {\n return;\n }\n\n // Normalize empty values (undefined, null, empty string) to null for comparison\n const normalizedStoredUserId = storedUserId || null;\n const normalizedCurrentUserId = this.userId || null;\n\n // If userIds match, restore both clientId and userId\n if (normalizedStoredUserId === normalizedCurrentUserId) {\n this.clientId = storedClientId;\n if (!this.userId && storedUserId) {\n this.userId = storedUserId;\n }\n return;\n }\n\n // UserIds don't match - determine if we should clear or keep clientId\n \n // Case 1: Logout (filled -> empty) - clear session\n if (normalizedStoredUserId && !normalizedCurrentUserId) {\n this.clearStoredClientInfo();\n return;\n }\n\n // Case 2: Different logged-in users (filled -> different filled) - clear session for new user\n if (normalizedStoredUserId && normalizedCurrentUserId && normalizedStoredUserId !== normalizedCurrentUserId) {\n this.clearStoredClientInfo();\n return;\n }\n\n // Case 3: Guest -> Logged-in user (empty -> filled) - keep clientId for merge\n if (!normalizedStoredUserId && normalizedCurrentUserId) {\n this.clientId = storedClientId;\n return;\n }\n }\n\n private clearStoredClientInfo(): void {\n this.clientId = null;\n this.storedUserId = null;\n\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n this.cookieManager.clearAll();\n }\n}\n","/**\n * Default configuration constants for Sophi Widget\n */\nexport const DEFAULT_CONFIG = {\n /**\n * Default width of the widget iframe\n */\n WIDTH: \"100%\",\n\n /**\n * Default height of the widget iframe\n */\n HEIGHT: \"600px\",\n} as const;\n\n/**\n * API base URLs for different environments\n *\n * Note: These URLs will be visible in the client-side bundle.\n * This is normal and safe - the real security is in your API key validation.\n *\n * To use different URLs, modify these values before building the SDK.\n *\n * Production API URL - update before building for production\n */\nexport const API_BASE_URLS = {\n test: \"http://10.0.2.127:80\",\n production: \"https://api.usesophi.com\",\n} as const;\n\n/**\n * API endpoints configuration\n */\nexport const API_ENDPOINTS = {\n /**\n * Session creation endpoint path\n */\n CREATE_SESSION: \"/api/v1/auth/client/session\",\n} as const;\n\n/**\n * Error messages\n */\nexport const ERROR_MESSAGES = {\n MISSING_API_KEY: \"API key is required and must be a string\",\n MISSING_CLIENT_ID: \"Client ID is required and must be a string\",\n MISSING_USER_ID: \"User ID is required and must be a string\",\n MISSING_CONTAINER: \"Container is required\",\n MISSING_IFRAME_URL: \"Iframe URL is required and must be a string\",\n INVALID_IFRAME_URL: \"Invalid iframe URL\",\n INVALID_ENVIRONMENT: \"Invalid environment. Must be 'dev', 'test', 'staging', or 'production'\",\n CONTAINER_NOT_FOUND: \"Container element not found\",\n NOT_INITIALIZED: \"Widget not initialized. Call init() first.\",\n ALREADY_INITIALIZED: \"Sophi Widget is already initialized. Call destroy() first to reinitialize.\",\n SESSION_CREATION_FAILED: \"Failed to create authentication session\",\n INVALID_SESSION_DATA: \"Invalid session data received from API\",\n YOU_NEED_TO_INIT_THE_WIDGET_FIRST: \"You need to initialize the widget first. Call init() before calling this method.\",\n} as const;\n","import { type SophiConfig, type UserData, type EventHandler, type EventName, type SophiEventMap, type IncomingMessage, type OutgoingMessage, type AddToCartEvent, type IUserCart, type SessionData, type MergeUserRequest, type MergeUserData, OutgoingMessageTypes } from \"./types\";\nimport { ApiService } from \"./services/api.service\";\nimport { DEFAULT_CONFIG, ERROR_MESSAGES, API_BASE_URLS } from \"./constants/config\";\n\n/**\n * Main Sophi Widget SDK class\n * Provides a framework-agnostic way to embed and interact with the Sophi AI widget\n */\nexport class SophiWidget {\n private config: SophiConfig | null = null;\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLElement | null = null;\n private eventListeners: Map<EventName, Set<EventHandler<any>>> = new Map();\n private messageHandler: ((event: MessageEvent) => void) | null = null;\n private isInitialized = false;\n private iframeOrigin: string | null = null;\n private sessionData: SessionData | null = null;\n private apiService: ApiService | null = null;\n private apiBaseUrl: string | null = null;\n\n /**\n * Initialize the widget with configuration\n * @param config - Widget configuration\n */\n public async init(config: SophiConfig): Promise<void> {\n if (this.isInitialized) {\n console.warn(ERROR_MESSAGES.ALREADY_INITIALIZED);\n return;\n }\n\n try {\n // Validate configuration\n this.validateConfig(config);\n\n this.config = this.formatConfig(config);\n\n // Determine API URL based on environment\n this.apiBaseUrl = API_BASE_URLS[config.environment || \"production\"];\n\n // Initialize API service\n this.apiService = new ApiService(this.apiBaseUrl, config.apiKey, config.userId);\n\n // Create authentication session\n await this.createAuthSession();\n\n this.isInitialized = true;\n\n // Extract origin from iframe URL for security\n try {\n const url = new URL(this.getIframeUrl());\n this.iframeOrigin = url.origin;\n } catch (error) {\n const err = new Error(`${ERROR_MESSAGES.INVALID_IFRAME_URL}: ${this.getIframeUrl()}`);\n this.emitError(err);\n throw err;\n }\n\n // Resolve container element\n this.container = this.resolveContainer(config.container);\n\n if (!this.container) {\n const err = new Error(ERROR_MESSAGES.CONTAINER_NOT_FOUND);\n this.emitError(err);\n throw err;\n }\n\n // Create and mount iframe\n this.createIframe();\n\n // Setup postMessage listener\n this.setupMessageListener();\n\n // Send session data to iframe after it's loaded\n this.iframe?.addEventListener(\"load\", () => {\n // Small delay to ensure iframe is fully ready\n setTimeout(() => {\n this.sendSessionData();\n if (this.config?.layout) {\n this.sendLayoutConfig();\n }\n }, 100);\n });\n\n // Call onReady callback if provided\n if (config.onReady) {\n config.onReady();\n }\n } catch (error) {\n // Reset state on error\n this.isInitialized = false;\n this.config = null;\n this.apiService = null;\n this.sessionData = null;\n\n const err = error instanceof Error ? error : new Error(String(error));\n this.emitError(err);\n throw err;\n }\n }\n\n /**\n * Send user data to the widget\n * @param data - User data object\n */\n public sendUserData(data: UserData): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.USER_DATA,\n data,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Toggle chat history visibility in the iframe child app.\n */\n public sendToggleHistory(): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.TOGGLE_HISTORY,\n };\n\n this.postMessage(message);\n }\n\n public updateUserCart(cart: IUserCart): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.UPDATE_USER_CART,\n data: cart,\n };\n\n this.postMessage(message);\n }\n\n private onDestroy(): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.DESTROY,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Register an event listener\n * @param event - Event name\n * @param handler - Event handler function\n */\n public on<K extends EventName>(event: K, handler: EventHandler<SophiEventMap[K]>): void {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n /**\n * Unregister an event listener\n * @param event - Event name\n * @param handler - Event handler function to remove\n */\n public off<K extends EventName>(event: K, handler: EventHandler<SophiEventMap[K]>): void {\n const handlers = this.eventListeners.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n }\n\n /**\n * Show the widget\n */\n public show(): void {\n if (this.iframe) {\n this.iframe.style.display = \"block\";\n }\n }\n\n /**\n * Hide the widget\n */\n public hide(): void {\n if (this.iframe) {\n this.iframe.style.display = \"none\";\n }\n }\n\n /**\n * Destroy the widget and cleanup resources\n * Waits 300ms after sending destroy message to give iframe time to cleanup\n */\n public async destroy(): Promise<void> {\n this.onDestroy();\n\n // Wait 300ms to give iframe time to process the destroy event and cleanup\n await new Promise((resolve) => setTimeout(resolve, 300));\n\n // Remove message listener\n if (this.messageHandler) {\n window.removeEventListener(\"message\", this.messageHandler);\n this.messageHandler = null;\n }\n\n // Remove iframe\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n this.iframe = null;\n }\n\n // Clear event listeners\n this.eventListeners.clear();\n\n // Reset state\n this.config = null;\n this.container = null;\n this.isInitialized = false;\n this.iframeOrigin = null;\n this.sessionData = null;\n this.apiService = null;\n }\n\n /**\n * Check if widget is initialized\n */\n public isReady(): boolean {\n return this.isInitialized && this.iframe !== null;\n }\n\n /**\n * Validate configuration\n */\n private validateConfig(config: SophiConfig): void {\n if (!config.apiKey || typeof config.apiKey !== \"string\") {\n throw new Error(ERROR_MESSAGES.MISSING_API_KEY);\n }\n\n if (config.userId && typeof config.userId !== \"string\") {\n throw new Error(ERROR_MESSAGES.MISSING_USER_ID);\n }\n\n if (!config.container) {\n throw new Error(ERROR_MESSAGES.MISSING_CONTAINER);\n }\n }\n\n /**\n * Format configuration\n */\n private formatConfig(config: SophiConfig): SophiConfig {\n return {\n ...config,\n userId: config.userId || undefined,\n };\n }\n\n /**\n * Create authentication session with the API\n */\n private async createAuthSession(): Promise<void> {\n if (!this.config || !this.apiService) {\n throw new Error(ERROR_MESSAGES.NOT_INITIALIZED);\n }\n\n try {\n this.sessionData = await this.apiService.createSession({\n externalUserId: this.config.userId,\n metadata: this.config.metadata,\n });\n\n // Validate session data\n if (!this.apiService.validateSessionData(this.sessionData)) {\n throw new Error(ERROR_MESSAGES.INVALID_SESSION_DATA);\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(ERROR_MESSAGES.SESSION_CREATION_FAILED);\n throw err;\n }\n }\n\n /**\n * Send session data to iframe\n */\n private sendSessionData(): void {\n if (!this.sessionData) {\n console.warn(\"Session data not available\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.SESSION_DATA,\n data: { ...this.sessionData, userName: this.config?.userName },\n };\n\n this.postMessage(message);\n }\n\n /**\n * Send layout config to iframe so the child app can apply layout options (e.g. show/hide header).\n */\n private sendLayoutConfig(): void {\n if (!this.config?.layout) {\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.LAYOUT_CONFIG,\n data: this.config.layout,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Resolve container element from selector or element\n */\n private resolveContainer(container: string | HTMLElement): HTMLElement | null {\n if (typeof container === \"string\") {\n return document.querySelector(container);\n }\n return container;\n }\n\n /**\n * Create and mount the iframe\n */\n private createIframe(): void {\n if (!this.container || !this.config) {\n return;\n }\n\n const iframe = document.createElement(\"iframe\");\n\n // Set iframe attributes\n iframe.src = this.buildIframeUrl();\n iframe.style.width = this.config.width || \"100%\";\n iframe.style.height = this.config.height || \"600px\";\n iframe.style.border = \"none\";\n iframe.title = \"Sophi AI Widget\";\n iframe.allow = \"microphone; camera; clipboard-write\";\n\n // Append to container\n this.container.appendChild(iframe);\n this.iframe = iframe;\n }\n\n /**\n * Build iframe URL with query parameters\n */\n private buildIframeUrl(): string {\n if (!this.config) {\n return \"\";\n }\n const url = new URL(this.getIframeUrl());\n\n return url.toString();\n }\n\n private getIframeUrl(): string {\n if (!this.config) {\n return \"\";\n }\n if (this.config.environment === \"production\") {\n return \"https://app.usesophi.com\";\n }\n return \"http://localhost:5173\";\n }\n\n /**\n * Setup postMessage listener for iframe communication\n */\n private setupMessageListener(): void {\n this.messageHandler = (event: MessageEvent) => {\n // Validate origin for security\n if (this.iframeOrigin && event.origin !== this.iframeOrigin) {\n console.warn(`Received message from untrusted origin: ${event.origin}`);\n return;\n }\n\n try {\n // Parse message\n const message: IncomingMessage = typeof event.data === \"string\" ? JSON.parse(event.data) : event.data;\n\n // Handle different message types\n this.handleIncomingMessage(message);\n } catch (error) {\n console.error(\"Error processing message from iframe:\", error);\n }\n };\n\n window.addEventListener(\"message\", this.messageHandler);\n }\n\n /**\n * Handle incoming messages from iframe\n */\n private handleIncomingMessage(message: IncomingMessage): void {\n switch (message.type) {\n case \"add_to_cart\":\n if (this.isValidAddToCartMessage(message.data)) {\n this.emit(\"add_to_cart\", message.data);\n } else {\n console.error(\"Invalid add_to_cart message structure:\", message.data);\n this.emitError(new Error(\"Invalid add_to_cart message format\"));\n }\n break;\n\n case \"send_to_checkout\":\n this.emit(\"send_to_checkout\", undefined);\n break;\n case \"ready\":\n this.emit(\"ready\", undefined);\n break;\n\n case \"error\":\n const error = message.data instanceof Error ? message.data : new Error(String(message.data));\n this.emitError(error);\n break;\n\n default:\n console.warn(\"Unknown message type:\", message);\n }\n }\n\n /**\n * Validate add_to_cart message structure\n */\n private isValidAddToCartMessage(data: unknown): data is AddToCartEvent {\n if (!data || typeof data !== \"object\") {\n return false;\n }\n\n const event = data as Record<string, unknown>;\n\n // Check products array exists and is an array\n if (!Array.isArray(event.products)) {\n return false;\n }\n\n // Validate each product in the array\n return event.products.every((product) => {\n if (!product || typeof product !== \"object\") {\n return false;\n }\n const prod = product as Record<string, unknown>;\n\n // productId is required and must be a string\n if (typeof prod.productId !== \"string\") {\n return false;\n }\n\n // variantId is optional, but if present must be a string\n if (prod.variantId !== undefined && typeof prod.variantId !== \"string\") {\n return false;\n }\n\n return true;\n });\n }\n\n /**\n * Post message to iframe\n */\n private postMessage(message: OutgoingMessage): void {\n if (!this.iframe || !this.iframe.contentWindow || !this.iframeOrigin) {\n console.warn(\"Cannot send message: iframe not ready\");\n return;\n }\n\n try {\n this.iframe.contentWindow.postMessage(message, this.iframeOrigin);\n } catch (error) {\n console.error(\"Error sending message to iframe:\", error);\n this.emitError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Emit event to registered listeners\n */\n private emit<K extends EventName>(event: K, data: SophiEventMap[K]): void {\n const handlers = this.eventListeners.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(data);\n } catch (error) {\n console.error(`Error in ${event} event handler:`, error);\n }\n });\n }\n }\n\n /**\n * Emit error event\n */\n private emitError(error: Error): void {\n this.emit(\"error\", error);\n\n // Also call onError callback if provided\n if (this.config?.onError) {\n this.config.onError(error);\n }\n }\n}\n"]}
package/dist/index.umd.js CHANGED
@@ -1,3 +1,3 @@
1
- var SophiWebSDK=(function(exports){'use strict';var f={ADD_TO_CART:"add_to_cart",READY:"ready",ERROR:"error",SEND_TO_CHECKOUT:"send_to_checkout"},o={USER_DATA:"user_data",CONFIG:"config",UPDATE_USER_CART:"update_user_cart",DESTROY:"destroy",SESSION_DATA:"session_data",CLIENT_ID_UPDATED:"client_id_updated",LAYOUT_CONFIG:"layout_config",TOGGLE_HISTORY:"toggle_history"};var s=class s{constructor(e,t){this.namespace=s.sanitizeNamespace(e),this.maxAgeSeconds=t?.maxAgeSeconds??s.DEFAULT_MAX_AGE_SECONDS,this.keys={...s.DEFAULT_KEYS,...t?.keys??{}};}static buildNamespace(e,t){return s.sanitizeNamespace(`sophi-widget-${e}-${t}`)}static canUseCookies(){return typeof document<"u"&&typeof document.cookie=="string"}set(e,t){s.canUseCookies()&&(document.cookie=`${this.formatName(e)}=${encodeURIComponent(t)}; path=/; max-age=${this.maxAgeSeconds}; samesite=lax`);}get(e){return s.canUseCookies()?s.readRawCookie(this.formatName(e)):null}delete(e){s.canUseCookies()&&(document.cookie=`${this.formatName(e)}=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; samesite=lax`);}clearAll(){Object.keys(this.keys).forEach(e=>{this.delete(e);});}formatName(e){return `${this.namespace}-${this.keys[e]}`}static readRawCookie(e){let t=document.cookie.split(";").map(i=>i.trim());for(let i of t){if(!i)continue;let[r,...n]=i.split("=");if(r===e)return decodeURIComponent(n.join("="))}return null}static sanitizeNamespace(e){let t=e.replace(/[^a-zA-Z0-9_-]/g,"");return t.length?t:"sophi-widget"}};s.DEFAULT_MAX_AGE_SECONDS=3600*24*30,s.DEFAULT_KEYS={clientId:"client-id",externalUserId:"external-user-id",sessionData:"session-data",metadataHash:"metadata-hash"};var d=s;var c=class{constructor(e,t,i){this.clientId=null;this.userId=void 0;this.storedUserId=null;this.baseUrl=e,this.apiKey=t,this.userId=i,this.cookieManager=new d(d.buildNamespace(e,t)),this.restoreSessionFromCookies();}async createSession(e){let t=`${this.baseUrl}/api/v1/auth/client/session`;try{let i={"Content-Type":"application/json",Accept:"application/json","x-api-key":this.apiKey};if(this.clientId){i["x-sophi-client-id"]=this.clientId;let g=this.storedUserId||null,l=this.userId||null;g!==l&&l&&(await this.mergeUser({userId:l}),this.storedUserId=l);}let r=await fetch(t,{method:"POST",headers:i,body:JSON.stringify({externalUserId:this.userId,metadata:e.metadata})});if(!r.ok){let g=await r.text();throw new Error(`Failed to create session: ${r.status} ${r.statusText}. ${g}`)}let n=await r.json();if(!n.success)throw new Error(`Session creation failed: ${n.message||"Unknown error"}`);if(!n.data)throw new Error("Session data is missing from response");return this.persistClientInfo(n.data.clientId,this.userId),n.data}catch(i){throw i instanceof Error?i:new Error(`Unexpected error during session creation: ${String(i)}`)}}validateSessionData(e){return !!(e.accessToken&&e.sessionId&&e.clientId&&e.companyCode&&e.expiresAt)}async mergeUser(e){let t=`${this.baseUrl}/api/v1/auth/client/info`;try{if(!this.clientId)throw new Error("Client ID is not set. Please create a session first.");let i=await fetch(t,{method:"PATCH",headers:{"Content-Type":"application/json",Accept:"application/json","x-api-key":this.apiKey,"x-sophi-client-id":this.clientId},body:JSON.stringify({externalUserId:e.userId})});if(!i.ok){let n=await i.text();throw new Error(`Failed to merge user: ${i.status} ${i.statusText}. ${n}`)}let r=await i.json();if(!r.success)throw new Error(`User merge failed: ${r.message||"Unknown error"}`);if(!r.data)throw new Error("Merge data is missing from response");return r.data}catch(i){throw i instanceof Error?i:new Error(`Unexpected error during user merge: ${String(i)}`)}}persistClientInfo(e,t){this.clientId=e,this.userId=t,this.storedUserId=t||null,d.canUseCookies()&&(this.cookieManager.set("clientId",e),this.cookieManager.set("externalUserId",t||""));}restoreSessionFromCookies(){if(!d.canUseCookies())return;let e=this.cookieManager.get("externalUserId"),t=this.cookieManager.get("clientId");if(this.storedUserId=e||null,!t)return;let i=e||null,r=this.userId||null;if(i===r){this.clientId=t,!this.userId&&e&&(this.userId=e);return}if(i&&!r){this.clearStoredClientInfo();return}if(i&&r&&i!==r){this.clearStoredClientInfo();return}if(!i&&r){this.clientId=t;return}}clearStoredClientInfo(){this.clientId=null,this.storedUserId=null,d.canUseCookies()&&this.cookieManager.clearAll();}};var m={WIDTH:"100%",HEIGHT:"600px"},p={test:"http://10.0.2.127:80",production:"https://api.usesophi.com"},I={CREATE_SESSION:"/api/v1/auth/client/session"},a={MISSING_API_KEY:"API key is required and must be a string",MISSING_CLIENT_ID:"Client ID is required and must be a string",MISSING_USER_ID:"User ID is required and must be a string",MISSING_CONTAINER:"Container is required",MISSING_IFRAME_URL:"Iframe URL is required and must be a string",INVALID_IFRAME_URL:"Invalid iframe URL",INVALID_ENVIRONMENT:"Invalid environment. Must be 'dev', 'test', 'staging', or 'production'",CONTAINER_NOT_FOUND:"Container element not found",NOT_INITIALIZED:"Widget not initialized. Call init() first.",ALREADY_INITIALIZED:"Sophi Widget is already initialized. Call destroy() first to reinitialize.",SESSION_CREATION_FAILED:"Failed to create authentication session",INVALID_SESSION_DATA:"Invalid session data received from API",YOU_NEED_TO_INIT_THE_WIDGET_FIRST:"You need to initialize the widget first. Call init() before calling this method."};var h=class{constructor(){this.config=null;this.iframe=null;this.container=null;this.eventListeners=new Map;this.messageHandler=null;this.isInitialized=false;this.iframeOrigin=null;this.sessionData=null;this.apiService=null;this.apiBaseUrl=null;}async init(e){if(this.isInitialized){console.warn(a.ALREADY_INITIALIZED);return}try{this.validateConfig(e),this.config=this.formatConfig(e),this.apiBaseUrl=p[e.environment||"production"],this.apiService=new c(this.apiBaseUrl,e.apiKey,e.userId),await this.createAuthSession(),this.isInitialized=!0;try{let t=new URL(this.getIframeUrl());this.iframeOrigin=t.origin;}catch{let i=new Error(`${a.INVALID_IFRAME_URL}: ${this.getIframeUrl()}`);throw this.emitError(i),i}if(this.container=this.resolveContainer(e.container),!this.container){let t=new Error(a.CONTAINER_NOT_FOUND);throw this.emitError(t),t}this.createIframe(),this.setupMessageListener(),this.iframe?.addEventListener("load",()=>{setTimeout(()=>{this.sendSessionData(),this.config?.layout&&this.sendLayoutConfig();},100);}),e.onReady&&e.onReady();}catch(t){this.isInitialized=false,this.config=null,this.apiService=null,this.sessionData=null;let i=t instanceof Error?t:new Error(String(t));throw this.emitError(i),i}}sendUserData(e){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let t={type:o.USER_DATA,data:e};this.postMessage(t);}sendToggleHistory(){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let e={type:o.TOGGLE_HISTORY};this.postMessage(e);}updateUserCart(e){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let t={type:o.UPDATE_USER_CART,data:e};this.postMessage(t);}onDestroy(){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let e={type:o.DESTROY};this.postMessage(e);}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t);}off(e,t){let i=this.eventListeners.get(e);i&&i.delete(t);}show(){this.iframe&&(this.iframe.style.display="block");}hide(){this.iframe&&(this.iframe.style.display="none");}async destroy(){this.onDestroy(),await new Promise(e=>setTimeout(e,300)),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.iframe&&this.iframe.parentNode&&(this.iframe.parentNode.removeChild(this.iframe),this.iframe=null),this.eventListeners.clear(),this.config=null,this.container=null,this.isInitialized=false,this.iframeOrigin=null,this.sessionData=null,this.apiService=null;}isReady(){return this.isInitialized&&this.iframe!==null}validateConfig(e){if(!e.apiKey||typeof e.apiKey!="string")throw new Error(a.MISSING_API_KEY);if(e.userId&&typeof e.userId!="string")throw new Error(a.MISSING_USER_ID);if(!e.container)throw new Error(a.MISSING_CONTAINER)}formatConfig(e){return {...e,userId:e.userId||void 0}}async createAuthSession(){if(!this.config||!this.apiService)throw new Error(a.NOT_INITIALIZED);try{if(this.sessionData=await this.apiService.createSession({externalUserId:this.config.userId,metadata:this.config.metadata}),!this.apiService.validateSessionData(this.sessionData))throw new Error(a.INVALID_SESSION_DATA)}catch(e){throw e instanceof Error?e:new Error(a.SESSION_CREATION_FAILED)}}sendSessionData(){if(!this.sessionData){console.warn("Session data not available");return}let e={type:o.SESSION_DATA,data:{...this.sessionData,userName:this.config?.userName}};this.postMessage(e);}sendLayoutConfig(){if(!this.config?.layout)return;let e={type:o.LAYOUT_CONFIG,data:this.config.layout};this.postMessage(e);}resolveContainer(e){return typeof e=="string"?document.querySelector(e):e}createIframe(){if(!this.container||!this.config)return;let e=document.createElement("iframe");e.src=this.buildIframeUrl(),e.style.width=this.config.width||"100%",e.style.height=this.config.height||"600px",e.style.border="none",e.title="Sophi AI Widget",e.allow="microphone; camera",this.container.appendChild(e),this.iframe=e;}buildIframeUrl(){return this.config?new URL(this.getIframeUrl()).toString():""}getIframeUrl(){return this.config?this.config.environment==="production"?"https://app.usesophi.com":"http://localhost:5173":""}setupMessageListener(){this.messageHandler=e=>{if(this.iframeOrigin&&e.origin!==this.iframeOrigin){console.warn(`Received message from untrusted origin: ${e.origin}`);return}try{let t=typeof e.data=="string"?JSON.parse(e.data):e.data;this.handleIncomingMessage(t);}catch(t){console.error("Error processing message from iframe:",t);}},window.addEventListener("message",this.messageHandler);}handleIncomingMessage(e){switch(e.type){case "add_to_cart":this.isValidAddToCartMessage(e.data)?this.emit("add_to_cart",e.data):(console.error("Invalid add_to_cart message structure:",e.data),this.emitError(new Error("Invalid add_to_cart message format")));break;case "send_to_checkout":this.emit("send_to_checkout",void 0);break;case "ready":this.emit("ready",void 0);break;case "error":let t=e.data instanceof Error?e.data:new Error(String(e.data));this.emitError(t);break;default:console.warn("Unknown message type:",e);}}isValidAddToCartMessage(e){if(!e||typeof e!="object")return false;let t=e;return Array.isArray(t.products)?t.products.every(i=>{if(!i||typeof i!="object")return false;let r=i;return !(typeof r.productId!="string"||r.variantId!==void 0&&typeof r.variantId!="string")}):false}postMessage(e){if(!this.iframe||!this.iframe.contentWindow||!this.iframeOrigin){console.warn("Cannot send message: iframe not ready");return}try{this.iframe.contentWindow.postMessage(e,this.iframeOrigin);}catch(t){console.error("Error sending message to iframe:",t),this.emitError(t instanceof Error?t:new Error(String(t)));}}emit(e,t){let i=this.eventListeners.get(e);i&&i.forEach(r=>{try{r(t);}catch(n){console.error(`Error in ${e} event handler:`,n);}});}emitError(e){this.emit("error",e),this.config?.onError&&this.config.onError(e);}};
1
+ var SophiWebSDK=(function(exports){'use strict';var f={ADD_TO_CART:"add_to_cart",READY:"ready",ERROR:"error",SEND_TO_CHECKOUT:"send_to_checkout"},o={USER_DATA:"user_data",CONFIG:"config",UPDATE_USER_CART:"update_user_cart",DESTROY:"destroy",SESSION_DATA:"session_data",CLIENT_ID_UPDATED:"client_id_updated",LAYOUT_CONFIG:"layout_config",TOGGLE_HISTORY:"toggle_history"};var s=class s{constructor(e,t){this.namespace=s.sanitizeNamespace(e),this.maxAgeSeconds=t?.maxAgeSeconds??s.DEFAULT_MAX_AGE_SECONDS,this.keys={...s.DEFAULT_KEYS,...t?.keys??{}};}static buildNamespace(e,t){return s.sanitizeNamespace(`sophi-widget-${e}-${t}`)}static canUseCookies(){return typeof document<"u"&&typeof document.cookie=="string"}set(e,t){s.canUseCookies()&&(document.cookie=`${this.formatName(e)}=${encodeURIComponent(t)}; path=/; max-age=${this.maxAgeSeconds}; samesite=lax`);}get(e){return s.canUseCookies()?s.readRawCookie(this.formatName(e)):null}delete(e){s.canUseCookies()&&(document.cookie=`${this.formatName(e)}=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; samesite=lax`);}clearAll(){Object.keys(this.keys).forEach(e=>{this.delete(e);});}formatName(e){return `${this.namespace}-${this.keys[e]}`}static readRawCookie(e){let t=document.cookie.split(";").map(i=>i.trim());for(let i of t){if(!i)continue;let[r,...n]=i.split("=");if(r===e)return decodeURIComponent(n.join("="))}return null}static sanitizeNamespace(e){let t=e.replace(/[^a-zA-Z0-9_-]/g,"");return t.length?t:"sophi-widget"}};s.DEFAULT_MAX_AGE_SECONDS=3600*24*30,s.DEFAULT_KEYS={clientId:"client-id",externalUserId:"external-user-id",sessionData:"session-data",metadataHash:"metadata-hash"};var d=s;var c=class{constructor(e,t,i){this.clientId=null;this.userId=void 0;this.storedUserId=null;this.baseUrl=e,this.apiKey=t,this.userId=i,this.cookieManager=new d(d.buildNamespace(e,t)),this.restoreSessionFromCookies();}async createSession(e){let t=`${this.baseUrl}/api/v1/auth/client/session`;try{let i={"Content-Type":"application/json",Accept:"application/json","x-api-key":this.apiKey};if(this.clientId){i["x-sophi-client-id"]=this.clientId;let g=this.storedUserId||null,l=this.userId||null;g!==l&&l&&(await this.mergeUser({userId:l}),this.storedUserId=l);}let r=await fetch(t,{method:"POST",headers:i,body:JSON.stringify({externalUserId:this.userId,metadata:e.metadata})});if(!r.ok){let g=await r.text();throw new Error(`Failed to create session: ${r.status} ${r.statusText}. ${g}`)}let n=await r.json();if(!n.success)throw new Error(`Session creation failed: ${n.message||"Unknown error"}`);if(!n.data)throw new Error("Session data is missing from response");return this.persistClientInfo(n.data.clientId,this.userId),n.data}catch(i){throw i instanceof Error?i:new Error(`Unexpected error during session creation: ${String(i)}`)}}validateSessionData(e){return !!(e.accessToken&&e.sessionId&&e.clientId&&e.companyCode&&e.expiresAt)}async mergeUser(e){let t=`${this.baseUrl}/api/v1/auth/client/info`;try{if(!this.clientId)throw new Error("Client ID is not set. Please create a session first.");let i=await fetch(t,{method:"PATCH",headers:{"Content-Type":"application/json",Accept:"application/json","x-api-key":this.apiKey,"x-sophi-client-id":this.clientId},body:JSON.stringify({externalUserId:e.userId})});if(!i.ok){let n=await i.text();throw new Error(`Failed to merge user: ${i.status} ${i.statusText}. ${n}`)}let r=await i.json();if(!r.success)throw new Error(`User merge failed: ${r.message||"Unknown error"}`);if(!r.data)throw new Error("Merge data is missing from response");return r.data}catch(i){throw i instanceof Error?i:new Error(`Unexpected error during user merge: ${String(i)}`)}}persistClientInfo(e,t){this.clientId=e,this.userId=t,this.storedUserId=t||null,d.canUseCookies()&&(this.cookieManager.set("clientId",e),this.cookieManager.set("externalUserId",t||""));}restoreSessionFromCookies(){if(!d.canUseCookies())return;let e=this.cookieManager.get("externalUserId"),t=this.cookieManager.get("clientId");if(this.storedUserId=e||null,!t)return;let i=e||null,r=this.userId||null;if(i===r){this.clientId=t,!this.userId&&e&&(this.userId=e);return}if(i&&!r){this.clearStoredClientInfo();return}if(i&&r&&i!==r){this.clearStoredClientInfo();return}if(!i&&r){this.clientId=t;return}}clearStoredClientInfo(){this.clientId=null,this.storedUserId=null,d.canUseCookies()&&this.cookieManager.clearAll();}};var m={WIDTH:"100%",HEIGHT:"600px"},p={test:"http://10.0.2.127:80",production:"https://api.usesophi.com"},I={CREATE_SESSION:"/api/v1/auth/client/session"},a={MISSING_API_KEY:"API key is required and must be a string",MISSING_CLIENT_ID:"Client ID is required and must be a string",MISSING_USER_ID:"User ID is required and must be a string",MISSING_CONTAINER:"Container is required",MISSING_IFRAME_URL:"Iframe URL is required and must be a string",INVALID_IFRAME_URL:"Invalid iframe URL",INVALID_ENVIRONMENT:"Invalid environment. Must be 'dev', 'test', 'staging', or 'production'",CONTAINER_NOT_FOUND:"Container element not found",NOT_INITIALIZED:"Widget not initialized. Call init() first.",ALREADY_INITIALIZED:"Sophi Widget is already initialized. Call destroy() first to reinitialize.",SESSION_CREATION_FAILED:"Failed to create authentication session",INVALID_SESSION_DATA:"Invalid session data received from API",YOU_NEED_TO_INIT_THE_WIDGET_FIRST:"You need to initialize the widget first. Call init() before calling this method."};var h=class{constructor(){this.config=null;this.iframe=null;this.container=null;this.eventListeners=new Map;this.messageHandler=null;this.isInitialized=false;this.iframeOrigin=null;this.sessionData=null;this.apiService=null;this.apiBaseUrl=null;}async init(e){if(this.isInitialized){console.warn(a.ALREADY_INITIALIZED);return}try{this.validateConfig(e),this.config=this.formatConfig(e),this.apiBaseUrl=p[e.environment||"production"],this.apiService=new c(this.apiBaseUrl,e.apiKey,e.userId),await this.createAuthSession(),this.isInitialized=!0;try{let t=new URL(this.getIframeUrl());this.iframeOrigin=t.origin;}catch{let i=new Error(`${a.INVALID_IFRAME_URL}: ${this.getIframeUrl()}`);throw this.emitError(i),i}if(this.container=this.resolveContainer(e.container),!this.container){let t=new Error(a.CONTAINER_NOT_FOUND);throw this.emitError(t),t}this.createIframe(),this.setupMessageListener(),this.iframe?.addEventListener("load",()=>{setTimeout(()=>{this.sendSessionData(),this.config?.layout&&this.sendLayoutConfig();},100);}),e.onReady&&e.onReady();}catch(t){this.isInitialized=false,this.config=null,this.apiService=null,this.sessionData=null;let i=t instanceof Error?t:new Error(String(t));throw this.emitError(i),i}}sendUserData(e){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let t={type:o.USER_DATA,data:e};this.postMessage(t);}sendToggleHistory(){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let e={type:o.TOGGLE_HISTORY};this.postMessage(e);}updateUserCart(e){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let t={type:o.UPDATE_USER_CART,data:e};this.postMessage(t);}onDestroy(){if(!this.isInitialized||!this.iframe){console.warn("Widget not initialized. Call init() first.");return}let e={type:o.DESTROY};this.postMessage(e);}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t);}off(e,t){let i=this.eventListeners.get(e);i&&i.delete(t);}show(){this.iframe&&(this.iframe.style.display="block");}hide(){this.iframe&&(this.iframe.style.display="none");}async destroy(){this.onDestroy(),await new Promise(e=>setTimeout(e,300)),this.messageHandler&&(window.removeEventListener("message",this.messageHandler),this.messageHandler=null),this.iframe&&this.iframe.parentNode&&(this.iframe.parentNode.removeChild(this.iframe),this.iframe=null),this.eventListeners.clear(),this.config=null,this.container=null,this.isInitialized=false,this.iframeOrigin=null,this.sessionData=null,this.apiService=null;}isReady(){return this.isInitialized&&this.iframe!==null}validateConfig(e){if(!e.apiKey||typeof e.apiKey!="string")throw new Error(a.MISSING_API_KEY);if(e.userId&&typeof e.userId!="string")throw new Error(a.MISSING_USER_ID);if(!e.container)throw new Error(a.MISSING_CONTAINER)}formatConfig(e){return {...e,userId:e.userId||void 0}}async createAuthSession(){if(!this.config||!this.apiService)throw new Error(a.NOT_INITIALIZED);try{if(this.sessionData=await this.apiService.createSession({externalUserId:this.config.userId,metadata:this.config.metadata}),!this.apiService.validateSessionData(this.sessionData))throw new Error(a.INVALID_SESSION_DATA)}catch(e){throw e instanceof Error?e:new Error(a.SESSION_CREATION_FAILED)}}sendSessionData(){if(!this.sessionData){console.warn("Session data not available");return}let e={type:o.SESSION_DATA,data:{...this.sessionData,userName:this.config?.userName}};this.postMessage(e);}sendLayoutConfig(){if(!this.config?.layout)return;let e={type:o.LAYOUT_CONFIG,data:this.config.layout};this.postMessage(e);}resolveContainer(e){return typeof e=="string"?document.querySelector(e):e}createIframe(){if(!this.container||!this.config)return;let e=document.createElement("iframe");e.src=this.buildIframeUrl(),e.style.width=this.config.width||"100%",e.style.height=this.config.height||"600px",e.style.border="none",e.title="Sophi AI Widget",e.allow="microphone; camera; clipboard-write",this.container.appendChild(e),this.iframe=e;}buildIframeUrl(){return this.config?new URL(this.getIframeUrl()).toString():""}getIframeUrl(){return this.config?this.config.environment==="production"?"https://app.usesophi.com":"http://localhost:5173":""}setupMessageListener(){this.messageHandler=e=>{if(this.iframeOrigin&&e.origin!==this.iframeOrigin){console.warn(`Received message from untrusted origin: ${e.origin}`);return}try{let t=typeof e.data=="string"?JSON.parse(e.data):e.data;this.handleIncomingMessage(t);}catch(t){console.error("Error processing message from iframe:",t);}},window.addEventListener("message",this.messageHandler);}handleIncomingMessage(e){switch(e.type){case "add_to_cart":this.isValidAddToCartMessage(e.data)?this.emit("add_to_cart",e.data):(console.error("Invalid add_to_cart message structure:",e.data),this.emitError(new Error("Invalid add_to_cart message format")));break;case "send_to_checkout":this.emit("send_to_checkout",void 0);break;case "ready":this.emit("ready",void 0);break;case "error":let t=e.data instanceof Error?e.data:new Error(String(e.data));this.emitError(t);break;default:console.warn("Unknown message type:",e);}}isValidAddToCartMessage(e){if(!e||typeof e!="object")return false;let t=e;return Array.isArray(t.products)?t.products.every(i=>{if(!i||typeof i!="object")return false;let r=i;return !(typeof r.productId!="string"||r.variantId!==void 0&&typeof r.variantId!="string")}):false}postMessage(e){if(!this.iframe||!this.iframe.contentWindow||!this.iframeOrigin){console.warn("Cannot send message: iframe not ready");return}try{this.iframe.contentWindow.postMessage(e,this.iframeOrigin);}catch(t){console.error("Error sending message to iframe:",t),this.emitError(t instanceof Error?t:new Error(String(t)));}}emit(e,t){let i=this.eventListeners.get(e);i&&i.forEach(r=>{try{r(t);}catch(n){console.error(`Error in ${e} event handler:`,n);}});}emitError(e){this.emit("error",e),this.config?.onError&&this.config.onError(e);}};
2
2
  exports.API_BASE_URLS=p;exports.API_ENDPOINTS=I;exports.ApiService=c;exports.DEFAULT_CONFIG=m;exports.ERROR_MESSAGES=a;exports.IncomingMessageTypes=f;exports.OutgoingMessageTypes=o;exports.SophiWidget=h;return exports;})({});//# sourceMappingURL=index.umd.js.map
3
3
  //# sourceMappingURL=index.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/services/cookie.utils.ts","../src/services/api.service.ts","../src/constants/config.ts","../src/SophiWidget.ts"],"names":["IncomingMessageTypes","OutgoingMessageTypes","_CookieManager","namespace","options","baseUrl","apiKey","key","value","name","cookies","cookie","cookieName","cookieValueParts","sanitized","CookieManager","ApiService","userId","request","url","headers","normalizedStored","normalizedCurrent","response","errorText","data","error","sessionData","clientId","storedUserId","storedClientId","normalizedStoredUserId","normalizedCurrentUserId","DEFAULT_CONFIG","API_BASE_URLS","API_ENDPOINTS","ERROR_MESSAGES","SophiWidget","config","err","message","cart","event","handler","handlers","resolve","container","iframe","product","prod"],"mappings":"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","file":"index.umd.js","sourcesContent":["/**\n * Layout options sent to the iframe on init so the child app can adjust its layout.\n */\nexport interface LayoutConfig {\n /**\n * When true, show the header; when false, hide it.\n * Omitted/undefined means use the child app's default.\n */\n header?: boolean;\n}\n\n/**\n * Configuration for initializing the Sophi Widget\n */\nexport interface SophiConfig {\n /**\n * API key for authentication with Sophi services (x-api-key header)\n * This comes from the parent application\n */\n apiKey: string;\n\n /**\n * External user ID for authentication (x-sophi-external-user-id header)\n * This comes from the parent application\n */\n userId?: string;\n\n /**\n * User name for the user\n */\n userName?: string;\n\n /**\n * Container element selector (e.g., '#widget') or HTMLElement where the widget will be mounted\n */\n container: string | HTMLElement;\n\n /**\n * Optional metadata to send with the session request\n */\n metadata?: Record<string, unknown>;\n\n /**\n * Width of the widget iframe\n * @default '100%'\n */\n width?: string;\n\n /**\n * Height of the widget iframe\n * @default '600px'\n */\n height?: string;\n\n /**\n * Callback fired when the widget is ready\n */\n onReady?: () => void;\n\n /**\n * Callback fired when an error occurs\n */\n onError?: (error: Error) => void;\n\n /**\n * Environment to use for the API\n */\n environment?: \"test\" | \"production\";\n\n /**\n * Layout options sent to the iframe on init. The child app receives these via a\n * postMessage and can show/hide header (and future layout options) accordingly.\n */\n layout?: LayoutConfig;\n}\n\n/**\n * Product information for add to cart events\n */\nexport interface Product {\n /**\n * Unique product identifier\n */\n productId: string;\n\n /**\n * Optional variant identifier\n */\n variantId?: string;\n}\n\n/**\n * Add to cart event data\n */\nexport interface AddToCartEvent {\n /**\n * List of products to add to cart\n */\n products: Product[];\n}\n\n/**\n * User data that can be sent to the widget\n */\nexport interface UserData {\n /**\n * User ID\n */\n userId?: string;\n\n /**\n * User email\n */\n email?: string;\n\n /**\n * User name\n */\n name?: string;\n\n /**\n * Additional custom data\n */\n [key: string]: unknown;\n}\n\nexport interface IUserCartItem {\n productId: string;\n variantId: string;\n quantity?: number;\n}\n\nexport interface IUserCart {\n cardId: string;\n items: IUserCartItem[];\n}\n\n/**\n * Message types that can be received from the iframe\n */\nexport type IncomingMessageType = \"add_to_cart\" | \"send_to_checkout\" | \"ready\" | \"error\";\n\n/**\n * Incoming message type constants for easy access\n * @example\n * widget.on(IncomingMessageTypes.ADD_TO_CART, (data) => {...})\n */\nexport const IncomingMessageTypes = {\n ADD_TO_CART: \"add_to_cart\",\n READY: \"ready\",\n ERROR: \"error\",\n SEND_TO_CHECKOUT: \"send_to_checkout\",\n} as const;\n\n/**\n * Message types that can be sent to the iframe\n */\nexport type OutgoingMessageType = \"user_data\" | \"config\" | \"update_user_cart\" | \"destroy\" | \"session_data\" | \"client_id_updated\" | \"layout_config\" | \"toggle_history\";\n\n/**\n * Outgoing message type constants for easy access\n * @example\n * widget.sendMessage({ type: OutgoingMessageTypes.USER_DATA, data: {...} })\n */\nexport const OutgoingMessageTypes = {\n USER_DATA: \"user_data\",\n CONFIG: \"config\",\n UPDATE_USER_CART: \"update_user_cart\",\n DESTROY: \"destroy\",\n SESSION_DATA: \"session_data\",\n CLIENT_ID_UPDATED: \"client_id_updated\",\n LAYOUT_CONFIG: \"layout_config\",\n TOGGLE_HISTORY: \"toggle_history\",\n} as const;\n\n/**\n * Incoming message structure from iframe\n */\nexport interface IncomingMessage {\n type: IncomingMessageType;\n data?: unknown;\n}\n\n/**\n * Outgoing message structure to iframe\n */\nexport interface OutgoingMessage {\n type: OutgoingMessageType;\n data?: unknown;\n}\n\n/**\n * Event map for type-safe event handling\n */\nexport interface SophiEventMap {\n /**\n * Fired when products should be added to cart\n */\n add_to_cart: AddToCartEvent;\n\n /**\n * Fired when the widget is ready\n */\n ready: void;\n\n /**\n * Fired when an error occurs\n */\n error: Error;\n\n /**\n * Fired when the user should be sent to checkout\n */\n send_to_checkout: void;\n}\n\n/**\n * Event handler type\n */\nexport type EventHandler<T> = (data: T) => void;\n\n/**\n * Event name type\n */\nexport type EventName = keyof SophiEventMap;\n\n/**\n * Authentication session request payload\n */\nexport interface AuthSessionRequest {\n /**\n * External user ID from the parent application\n */\n externalUserId?: string;\n\n /**\n * Optional metadata to include with the session\n */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Session data returned from the authentication API\n */\nexport interface SessionData {\n /**\n * JWT access token for authenticating requests\n */\n accessToken: string;\n\n /**\n * Unique session identifier\n */\n sessionId: string;\n\n /**\n * Client ID\n */\n clientId: string;\n\n /**\n * Company code\n */\n companyCode: string;\n\n /**\n * Session expiration timestamp\n */\n expiresAt: string;\n\n /**\n * userName of the user\n */\n userName: string;\n}\n\n/**\n * Authentication session API response\n */\nexport interface AuthSessionResponse {\n /**\n * Whether the request was successful\n */\n success: boolean;\n\n /**\n * Response message\n */\n message: string;\n\n /**\n * Session data\n */\n data?: SessionData;\n}\n\n/**\n * Merge user request payload\n */\nexport interface MergeUserRequest {\n /**\n * The logged-in user ID to merge to\n */\n userId: string;\n}\n\n/**\n * Merge user data returned from the API\n */\nexport interface MergeUserData {\n /**\n * The resulting client ID after merge\n */\n clientId: string;\n\n /**\n * The external user ID\n */\n externalUserId: string;\n}\n\n/**\n * Merge user API response\n */\nexport interface MergeUserResponse {\n /**\n * Whether the request was successful\n */\n success: boolean;\n\n /**\n * Response message\n */\n message: string;\n\n /**\n * Merge result data\n */\n data?: MergeUserData;\n}\n","export type CookieKey = \"clientId\" | \"externalUserId\" | \"sessionData\" | \"metadataHash\";\n\nexport interface CookieManagerOptions {\n readonly maxAgeSeconds?: number;\n readonly keys?: Partial<Record<CookieKey, string>>;\n}\n\nexport class CookieManager {\n static readonly DEFAULT_MAX_AGE_SECONDS = 60 * 60 * 24 * 30; // 30 days\n static readonly DEFAULT_KEYS: Record<CookieKey, string> = {\n clientId: \"client-id\",\n externalUserId: \"external-user-id\",\n sessionData: \"session-data\",\n metadataHash: \"metadata-hash\",\n };\n\n constructor(namespace: string, options?: CookieManagerOptions) {\n this.namespace = CookieManager.sanitizeNamespace(namespace);\n this.maxAgeSeconds = options?.maxAgeSeconds ?? CookieManager.DEFAULT_MAX_AGE_SECONDS;\n this.keys = { ...CookieManager.DEFAULT_KEYS, ...(options?.keys ?? {}) };\n }\n\n private readonly namespace: string;\n private readonly maxAgeSeconds: number;\n private readonly keys: Record<CookieKey, string>;\n\n static buildNamespace(baseUrl: string, apiKey: string): string {\n return CookieManager.sanitizeNamespace(`sophi-widget-${baseUrl}-${apiKey}`);\n }\n\n static canUseCookies(): boolean {\n return typeof document !== \"undefined\" && typeof document.cookie === \"string\";\n }\n\n set(key: CookieKey, value: string): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n document.cookie = `${this.formatName(key)}=${encodeURIComponent(value)}; path=/; max-age=${this.maxAgeSeconds}; samesite=lax`;\n }\n\n get(key: CookieKey): string | null {\n if (!CookieManager.canUseCookies()) {\n return null;\n }\n\n return CookieManager.readRawCookie(this.formatName(key));\n }\n\n delete(key: CookieKey): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n document.cookie = `${this.formatName(key)}=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; samesite=lax`;\n }\n\n clearAll(): void {\n Object.keys(this.keys).forEach((key) => {\n this.delete(key as CookieKey);\n });\n }\n\n private formatName(key: CookieKey): string {\n return `${this.namespace}-${this.keys[key]}`;\n }\n\n private static readRawCookie(name: string): string | null {\n const cookies = document.cookie.split(\";\").map((cookie) => cookie.trim());\n for (const cookie of cookies) {\n if (!cookie) {\n continue;\n }\n const [cookieName, ...cookieValueParts] = cookie.split(\"=\");\n if (cookieName === name) {\n return decodeURIComponent(cookieValueParts.join(\"=\"));\n }\n }\n return null;\n }\n\n private static sanitizeNamespace(value: string): string {\n const sanitized = value.replace(/[^a-zA-Z0-9_-]/g, \"\");\n return sanitized.length ? sanitized : \"sophi-widget\";\n }\n}\n","import type { AuthSessionRequest, AuthSessionResponse, SessionData, MergeUserRequest, MergeUserResponse, MergeUserData } from \"../types\";\nimport { CookieManager } from \"./cookie.utils\";\n\n/**\n * API Service for Sophi authentication and session management\n */\nexport class ApiService {\n private baseUrl: string;\n private apiKey: string;\n private clientId: string | null = null;\n private userId: string | undefined = undefined;\n private storedUserId: string | null = null; // Track the userId from cookies for merge detection\n private cookieManager: CookieManager;\n\n constructor(baseUrl: string, apiKey: string, userId?: string) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.userId = userId;\n this.cookieManager = new CookieManager(CookieManager.buildNamespace(baseUrl, apiKey));\n this.restoreSessionFromCookies();\n }\n\n /**\n * Create a client session by calling the authentication endpoint\n * @param request - Session request with optional externalUserId and metadata\n * @returns Session data including accessToken, sessionId, etc.\n */\n async createSession(request: AuthSessionRequest): Promise<SessionData> {\n const url = `${this.baseUrl}/api/v1/auth/client/session`;\n\n try {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"x-api-key\": this.apiKey,\n };\n if (this.clientId) {\n headers[\"x-sophi-client-id\"] = this.clientId;\n // Check if we need to merge: user changed from stored (could be empty) to current\n const normalizedStored = this.storedUserId || null;\n const normalizedCurrent = this.userId || null;\n if (normalizedStored !== normalizedCurrent && normalizedCurrent) {\n await this.mergeUser({ userId: normalizedCurrent });\n // Update storedUserId after successful merge\n this.storedUserId = normalizedCurrent;\n }\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n externalUserId: this.userId,\n metadata: request.metadata,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to create session: ${response.status} ${response.statusText}. ${errorText}`);\n }\n\n const data: AuthSessionResponse = await response.json();\n\n if (!data.success) {\n throw new Error(`Session creation failed: ${data.message || \"Unknown error\"}`);\n }\n\n if (!data.data) {\n throw new Error(\"Session data is missing from response\");\n }\n this.persistClientInfo(data.data.clientId, this.userId);\n return data.data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error during session creation: ${String(error)}`);\n }\n }\n\n /**\n * Validate session data\n */\n validateSessionData(sessionData: SessionData): boolean {\n return !!(sessionData.accessToken && sessionData.sessionId && sessionData.clientId && sessionData.companyCode && sessionData.expiresAt);\n }\n\n /**\n * Merge guest user with logged-in user\n * @param request - Merge request with guestId and userId\n * @returns Merge result data including the resulting clientId\n */\n async mergeUser(request: MergeUserRequest): Promise<MergeUserData> {\n const url = `${this.baseUrl}/api/v1/auth/client/info`;\n\n try {\n if (!this.clientId) {\n throw new Error(\"Client ID is not set. Please create a session first.\");\n }\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"x-api-key\": this.apiKey,\n \"x-sophi-client-id\": this.clientId,\n },\n body: JSON.stringify({\n externalUserId: request.userId,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to merge user: ${response.status} ${response.statusText}. ${errorText}`);\n }\n\n const data: MergeUserResponse = await response.json();\n\n if (!data.success) {\n throw new Error(`User merge failed: ${data.message || \"Unknown error\"}`);\n }\n\n if (!data.data) {\n throw new Error(\"Merge data is missing from response\");\n }\n\n return data.data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error during user merge: ${String(error)}`);\n }\n }\n\n private persistClientInfo(clientId: string, userId?: string): void {\n this.clientId = clientId;\n this.userId = userId;\n this.storedUserId = userId || null; // Update stored userId to match current state\n\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n this.cookieManager.set(\"clientId\", clientId);\n // Always save externalUserId (even if empty) to track the session state\n this.cookieManager.set(\"externalUserId\", userId || \"\");\n }\n\n private restoreSessionFromCookies(): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n const storedUserId = this.cookieManager.get(\"externalUserId\");\n const storedClientId = this.cookieManager.get(\"clientId\");\n\n // Store the userId from cookies for merge detection later\n this.storedUserId = storedUserId || null;\n\n // If no clientId in cookies, nothing to restore\n if (!storedClientId) {\n return;\n }\n\n // Normalize empty values (undefined, null, empty string) to null for comparison\n const normalizedStoredUserId = storedUserId || null;\n const normalizedCurrentUserId = this.userId || null;\n\n // If userIds match, restore both clientId and userId\n if (normalizedStoredUserId === normalizedCurrentUserId) {\n this.clientId = storedClientId;\n if (!this.userId && storedUserId) {\n this.userId = storedUserId;\n }\n return;\n }\n\n // UserIds don't match - determine if we should clear or keep clientId\n \n // Case 1: Logout (filled -> empty) - clear session\n if (normalizedStoredUserId && !normalizedCurrentUserId) {\n this.clearStoredClientInfo();\n return;\n }\n\n // Case 2: Different logged-in users (filled -> different filled) - clear session for new user\n if (normalizedStoredUserId && normalizedCurrentUserId && normalizedStoredUserId !== normalizedCurrentUserId) {\n this.clearStoredClientInfo();\n return;\n }\n\n // Case 3: Guest -> Logged-in user (empty -> filled) - keep clientId for merge\n if (!normalizedStoredUserId && normalizedCurrentUserId) {\n this.clientId = storedClientId;\n return;\n }\n }\n\n private clearStoredClientInfo(): void {\n this.clientId = null;\n this.storedUserId = null;\n\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n this.cookieManager.clearAll();\n }\n}\n","/**\n * Default configuration constants for Sophi Widget\n */\nexport const DEFAULT_CONFIG = {\n /**\n * Default width of the widget iframe\n */\n WIDTH: \"100%\",\n\n /**\n * Default height of the widget iframe\n */\n HEIGHT: \"600px\",\n} as const;\n\n/**\n * API base URLs for different environments\n *\n * Note: These URLs will be visible in the client-side bundle.\n * This is normal and safe - the real security is in your API key validation.\n *\n * To use different URLs, modify these values before building the SDK.\n *\n * Production API URL - update before building for production\n */\nexport const API_BASE_URLS = {\n test: \"http://10.0.2.127:80\",\n production: \"https://api.usesophi.com\",\n} as const;\n\n/**\n * API endpoints configuration\n */\nexport const API_ENDPOINTS = {\n /**\n * Session creation endpoint path\n */\n CREATE_SESSION: \"/api/v1/auth/client/session\",\n} as const;\n\n/**\n * Error messages\n */\nexport const ERROR_MESSAGES = {\n MISSING_API_KEY: \"API key is required and must be a string\",\n MISSING_CLIENT_ID: \"Client ID is required and must be a string\",\n MISSING_USER_ID: \"User ID is required and must be a string\",\n MISSING_CONTAINER: \"Container is required\",\n MISSING_IFRAME_URL: \"Iframe URL is required and must be a string\",\n INVALID_IFRAME_URL: \"Invalid iframe URL\",\n INVALID_ENVIRONMENT: \"Invalid environment. Must be 'dev', 'test', 'staging', or 'production'\",\n CONTAINER_NOT_FOUND: \"Container element not found\",\n NOT_INITIALIZED: \"Widget not initialized. Call init() first.\",\n ALREADY_INITIALIZED: \"Sophi Widget is already initialized. Call destroy() first to reinitialize.\",\n SESSION_CREATION_FAILED: \"Failed to create authentication session\",\n INVALID_SESSION_DATA: \"Invalid session data received from API\",\n YOU_NEED_TO_INIT_THE_WIDGET_FIRST: \"You need to initialize the widget first. Call init() before calling this method.\",\n} as const;\n","import { type SophiConfig, type UserData, type EventHandler, type EventName, type SophiEventMap, type IncomingMessage, type OutgoingMessage, type AddToCartEvent, type IUserCart, type SessionData, type MergeUserRequest, type MergeUserData, OutgoingMessageTypes } from \"./types\";\nimport { ApiService } from \"./services/api.service\";\nimport { DEFAULT_CONFIG, ERROR_MESSAGES, API_BASE_URLS } from \"./constants/config\";\n\n/**\n * Main Sophi Widget SDK class\n * Provides a framework-agnostic way to embed and interact with the Sophi AI widget\n */\nexport class SophiWidget {\n private config: SophiConfig | null = null;\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLElement | null = null;\n private eventListeners: Map<EventName, Set<EventHandler<any>>> = new Map();\n private messageHandler: ((event: MessageEvent) => void) | null = null;\n private isInitialized = false;\n private iframeOrigin: string | null = null;\n private sessionData: SessionData | null = null;\n private apiService: ApiService | null = null;\n private apiBaseUrl: string | null = null;\n\n /**\n * Initialize the widget with configuration\n * @param config - Widget configuration\n */\n public async init(config: SophiConfig): Promise<void> {\n if (this.isInitialized) {\n console.warn(ERROR_MESSAGES.ALREADY_INITIALIZED);\n return;\n }\n\n try {\n // Validate configuration\n this.validateConfig(config);\n\n this.config = this.formatConfig(config);\n\n // Determine API URL based on environment\n this.apiBaseUrl = API_BASE_URLS[config.environment || \"production\"];\n\n // Initialize API service\n this.apiService = new ApiService(this.apiBaseUrl, config.apiKey, config.userId);\n\n // Create authentication session\n await this.createAuthSession();\n\n this.isInitialized = true;\n\n // Extract origin from iframe URL for security\n try {\n const url = new URL(this.getIframeUrl());\n this.iframeOrigin = url.origin;\n } catch (error) {\n const err = new Error(`${ERROR_MESSAGES.INVALID_IFRAME_URL}: ${this.getIframeUrl()}`);\n this.emitError(err);\n throw err;\n }\n\n // Resolve container element\n this.container = this.resolveContainer(config.container);\n\n if (!this.container) {\n const err = new Error(ERROR_MESSAGES.CONTAINER_NOT_FOUND);\n this.emitError(err);\n throw err;\n }\n\n // Create and mount iframe\n this.createIframe();\n\n // Setup postMessage listener\n this.setupMessageListener();\n\n // Send session data to iframe after it's loaded\n this.iframe?.addEventListener(\"load\", () => {\n // Small delay to ensure iframe is fully ready\n setTimeout(() => {\n this.sendSessionData();\n if (this.config?.layout) {\n this.sendLayoutConfig();\n }\n }, 100);\n });\n\n // Call onReady callback if provided\n if (config.onReady) {\n config.onReady();\n }\n } catch (error) {\n // Reset state on error\n this.isInitialized = false;\n this.config = null;\n this.apiService = null;\n this.sessionData = null;\n\n const err = error instanceof Error ? error : new Error(String(error));\n this.emitError(err);\n throw err;\n }\n }\n\n /**\n * Send user data to the widget\n * @param data - User data object\n */\n public sendUserData(data: UserData): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.USER_DATA,\n data,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Toggle chat history visibility in the iframe child app.\n */\n public sendToggleHistory(): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.TOGGLE_HISTORY,\n };\n\n this.postMessage(message);\n }\n\n public updateUserCart(cart: IUserCart): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.UPDATE_USER_CART,\n data: cart,\n };\n\n this.postMessage(message);\n }\n\n private onDestroy(): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.DESTROY,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Register an event listener\n * @param event - Event name\n * @param handler - Event handler function\n */\n public on<K extends EventName>(event: K, handler: EventHandler<SophiEventMap[K]>): void {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n /**\n * Unregister an event listener\n * @param event - Event name\n * @param handler - Event handler function to remove\n */\n public off<K extends EventName>(event: K, handler: EventHandler<SophiEventMap[K]>): void {\n const handlers = this.eventListeners.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n }\n\n /**\n * Show the widget\n */\n public show(): void {\n if (this.iframe) {\n this.iframe.style.display = \"block\";\n }\n }\n\n /**\n * Hide the widget\n */\n public hide(): void {\n if (this.iframe) {\n this.iframe.style.display = \"none\";\n }\n }\n\n /**\n * Destroy the widget and cleanup resources\n * Waits 300ms after sending destroy message to give iframe time to cleanup\n */\n public async destroy(): Promise<void> {\n this.onDestroy();\n\n // Wait 300ms to give iframe time to process the destroy event and cleanup\n await new Promise((resolve) => setTimeout(resolve, 300));\n\n // Remove message listener\n if (this.messageHandler) {\n window.removeEventListener(\"message\", this.messageHandler);\n this.messageHandler = null;\n }\n\n // Remove iframe\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n this.iframe = null;\n }\n\n // Clear event listeners\n this.eventListeners.clear();\n\n // Reset state\n this.config = null;\n this.container = null;\n this.isInitialized = false;\n this.iframeOrigin = null;\n this.sessionData = null;\n this.apiService = null;\n }\n\n /**\n * Check if widget is initialized\n */\n public isReady(): boolean {\n return this.isInitialized && this.iframe !== null;\n }\n\n /**\n * Validate configuration\n */\n private validateConfig(config: SophiConfig): void {\n if (!config.apiKey || typeof config.apiKey !== \"string\") {\n throw new Error(ERROR_MESSAGES.MISSING_API_KEY);\n }\n\n if (config.userId && typeof config.userId !== \"string\") {\n throw new Error(ERROR_MESSAGES.MISSING_USER_ID);\n }\n\n if (!config.container) {\n throw new Error(ERROR_MESSAGES.MISSING_CONTAINER);\n }\n }\n\n /**\n * Format configuration\n */\n private formatConfig(config: SophiConfig): SophiConfig {\n return {\n ...config,\n userId: config.userId || undefined,\n };\n }\n\n /**\n * Create authentication session with the API\n */\n private async createAuthSession(): Promise<void> {\n if (!this.config || !this.apiService) {\n throw new Error(ERROR_MESSAGES.NOT_INITIALIZED);\n }\n\n try {\n this.sessionData = await this.apiService.createSession({\n externalUserId: this.config.userId,\n metadata: this.config.metadata,\n });\n\n // Validate session data\n if (!this.apiService.validateSessionData(this.sessionData)) {\n throw new Error(ERROR_MESSAGES.INVALID_SESSION_DATA);\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(ERROR_MESSAGES.SESSION_CREATION_FAILED);\n throw err;\n }\n }\n\n /**\n * Send session data to iframe\n */\n private sendSessionData(): void {\n if (!this.sessionData) {\n console.warn(\"Session data not available\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.SESSION_DATA,\n data: { ...this.sessionData, userName: this.config?.userName },\n };\n\n this.postMessage(message);\n }\n\n /**\n * Send layout config to iframe so the child app can apply layout options (e.g. show/hide header).\n */\n private sendLayoutConfig(): void {\n if (!this.config?.layout) {\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.LAYOUT_CONFIG,\n data: this.config.layout,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Resolve container element from selector or element\n */\n private resolveContainer(container: string | HTMLElement): HTMLElement | null {\n if (typeof container === \"string\") {\n return document.querySelector(container);\n }\n return container;\n }\n\n /**\n * Create and mount the iframe\n */\n private createIframe(): void {\n if (!this.container || !this.config) {\n return;\n }\n\n const iframe = document.createElement(\"iframe\");\n\n // Set iframe attributes\n iframe.src = this.buildIframeUrl();\n iframe.style.width = this.config.width || \"100%\";\n iframe.style.height = this.config.height || \"600px\";\n iframe.style.border = \"none\";\n iframe.title = \"Sophi AI Widget\";\n iframe.allow = \"microphone; camera\";\n\n // Append to container\n this.container.appendChild(iframe);\n this.iframe = iframe;\n }\n\n /**\n * Build iframe URL with query parameters\n */\n private buildIframeUrl(): string {\n if (!this.config) {\n return \"\";\n }\n const url = new URL(this.getIframeUrl());\n\n return url.toString();\n }\n\n private getIframeUrl(): string {\n if (!this.config) {\n return \"\";\n }\n if (this.config.environment === \"production\") {\n return \"https://app.usesophi.com\";\n }\n return \"http://localhost:5173\";\n }\n\n /**\n * Setup postMessage listener for iframe communication\n */\n private setupMessageListener(): void {\n this.messageHandler = (event: MessageEvent) => {\n // Validate origin for security\n if (this.iframeOrigin && event.origin !== this.iframeOrigin) {\n console.warn(`Received message from untrusted origin: ${event.origin}`);\n return;\n }\n\n try {\n // Parse message\n const message: IncomingMessage = typeof event.data === \"string\" ? JSON.parse(event.data) : event.data;\n\n // Handle different message types\n this.handleIncomingMessage(message);\n } catch (error) {\n console.error(\"Error processing message from iframe:\", error);\n }\n };\n\n window.addEventListener(\"message\", this.messageHandler);\n }\n\n /**\n * Handle incoming messages from iframe\n */\n private handleIncomingMessage(message: IncomingMessage): void {\n switch (message.type) {\n case \"add_to_cart\":\n if (this.isValidAddToCartMessage(message.data)) {\n this.emit(\"add_to_cart\", message.data);\n } else {\n console.error(\"Invalid add_to_cart message structure:\", message.data);\n this.emitError(new Error(\"Invalid add_to_cart message format\"));\n }\n break;\n\n case \"send_to_checkout\":\n this.emit(\"send_to_checkout\", undefined);\n break;\n case \"ready\":\n this.emit(\"ready\", undefined);\n break;\n\n case \"error\":\n const error = message.data instanceof Error ? message.data : new Error(String(message.data));\n this.emitError(error);\n break;\n\n default:\n console.warn(\"Unknown message type:\", message);\n }\n }\n\n /**\n * Validate add_to_cart message structure\n */\n private isValidAddToCartMessage(data: unknown): data is AddToCartEvent {\n if (!data || typeof data !== \"object\") {\n return false;\n }\n\n const event = data as Record<string, unknown>;\n\n // Check products array exists and is an array\n if (!Array.isArray(event.products)) {\n return false;\n }\n\n // Validate each product in the array\n return event.products.every((product) => {\n if (!product || typeof product !== \"object\") {\n return false;\n }\n const prod = product as Record<string, unknown>;\n\n // productId is required and must be a string\n if (typeof prod.productId !== \"string\") {\n return false;\n }\n\n // variantId is optional, but if present must be a string\n if (prod.variantId !== undefined && typeof prod.variantId !== \"string\") {\n return false;\n }\n\n return true;\n });\n }\n\n /**\n * Post message to iframe\n */\n private postMessage(message: OutgoingMessage): void {\n if (!this.iframe || !this.iframe.contentWindow || !this.iframeOrigin) {\n console.warn(\"Cannot send message: iframe not ready\");\n return;\n }\n\n try {\n this.iframe.contentWindow.postMessage(message, this.iframeOrigin);\n } catch (error) {\n console.error(\"Error sending message to iframe:\", error);\n this.emitError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Emit event to registered listeners\n */\n private emit<K extends EventName>(event: K, data: SophiEventMap[K]): void {\n const handlers = this.eventListeners.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(data);\n } catch (error) {\n console.error(`Error in ${event} event handler:`, error);\n }\n });\n }\n }\n\n /**\n * Emit error event\n */\n private emitError(error: Error): void {\n this.emit(\"error\", error);\n\n // Also call onError callback if provided\n if (this.config?.onError) {\n this.config.onError(error);\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/services/cookie.utils.ts","../src/services/api.service.ts","../src/constants/config.ts","../src/SophiWidget.ts"],"names":["IncomingMessageTypes","OutgoingMessageTypes","_CookieManager","namespace","options","baseUrl","apiKey","key","value","name","cookies","cookie","cookieName","cookieValueParts","sanitized","CookieManager","ApiService","userId","request","url","headers","normalizedStored","normalizedCurrent","response","errorText","data","error","sessionData","clientId","storedUserId","storedClientId","normalizedStoredUserId","normalizedCurrentUserId","DEFAULT_CONFIG","API_BASE_URLS","API_ENDPOINTS","ERROR_MESSAGES","SophiWidget","config","err","message","cart","event","handler","handlers","resolve","container","iframe","product","prod"],"mappings":"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","file":"index.umd.js","sourcesContent":["/**\n * Layout options sent to the iframe on init so the child app can adjust its layout.\n */\nexport interface LayoutConfig {\n /**\n * When true, show the header; when false, hide it.\n * Omitted/undefined means use the child app's default.\n */\n header?: boolean;\n}\n\n/**\n * Configuration for initializing the Sophi Widget\n */\nexport interface SophiConfig {\n /**\n * API key for authentication with Sophi services (x-api-key header)\n * This comes from the parent application\n */\n apiKey: string;\n\n /**\n * External user ID for authentication (x-sophi-external-user-id header)\n * This comes from the parent application\n */\n userId?: string;\n\n /**\n * User name for the user\n */\n userName?: string;\n\n /**\n * Container element selector (e.g., '#widget') or HTMLElement where the widget will be mounted\n */\n container: string | HTMLElement;\n\n /**\n * Optional metadata to send with the session request\n */\n metadata?: Record<string, unknown>;\n\n /**\n * Width of the widget iframe\n * @default '100%'\n */\n width?: string;\n\n /**\n * Height of the widget iframe\n * @default '600px'\n */\n height?: string;\n\n /**\n * Callback fired when the widget is ready\n */\n onReady?: () => void;\n\n /**\n * Callback fired when an error occurs\n */\n onError?: (error: Error) => void;\n\n /**\n * Environment to use for the API\n */\n environment?: \"test\" | \"production\";\n\n /**\n * Layout options sent to the iframe on init. The child app receives these via a\n * postMessage and can show/hide header (and future layout options) accordingly.\n */\n layout?: LayoutConfig;\n}\n\n/**\n * Product information for add to cart events\n */\nexport interface Product {\n /**\n * Unique product identifier\n */\n productId: string;\n\n /**\n * Optional variant identifier\n */\n variantId?: string;\n}\n\n/**\n * Add to cart event data\n */\nexport interface AddToCartEvent {\n /**\n * List of products to add to cart\n */\n products: Product[];\n}\n\n/**\n * User data that can be sent to the widget\n */\nexport interface UserData {\n /**\n * User ID\n */\n userId?: string;\n\n /**\n * User email\n */\n email?: string;\n\n /**\n * User name\n */\n name?: string;\n\n /**\n * Additional custom data\n */\n [key: string]: unknown;\n}\n\nexport interface IUserCartItem {\n productId: string;\n variantId: string;\n quantity?: number;\n}\n\nexport interface IUserCart {\n cardId: string;\n items: IUserCartItem[];\n}\n\n/**\n * Message types that can be received from the iframe\n */\nexport type IncomingMessageType = \"add_to_cart\" | \"send_to_checkout\" | \"ready\" | \"error\";\n\n/**\n * Incoming message type constants for easy access\n * @example\n * widget.on(IncomingMessageTypes.ADD_TO_CART, (data) => {...})\n */\nexport const IncomingMessageTypes = {\n ADD_TO_CART: \"add_to_cart\",\n READY: \"ready\",\n ERROR: \"error\",\n SEND_TO_CHECKOUT: \"send_to_checkout\",\n} as const;\n\n/**\n * Message types that can be sent to the iframe\n */\nexport type OutgoingMessageType = \"user_data\" | \"config\" | \"update_user_cart\" | \"destroy\" | \"session_data\" | \"client_id_updated\" | \"layout_config\" | \"toggle_history\";\n\n/**\n * Outgoing message type constants for easy access\n * @example\n * widget.sendMessage({ type: OutgoingMessageTypes.USER_DATA, data: {...} })\n */\nexport const OutgoingMessageTypes = {\n USER_DATA: \"user_data\",\n CONFIG: \"config\",\n UPDATE_USER_CART: \"update_user_cart\",\n DESTROY: \"destroy\",\n SESSION_DATA: \"session_data\",\n CLIENT_ID_UPDATED: \"client_id_updated\",\n LAYOUT_CONFIG: \"layout_config\",\n TOGGLE_HISTORY: \"toggle_history\",\n} as const;\n\n/**\n * Incoming message structure from iframe\n */\nexport interface IncomingMessage {\n type: IncomingMessageType;\n data?: unknown;\n}\n\n/**\n * Outgoing message structure to iframe\n */\nexport interface OutgoingMessage {\n type: OutgoingMessageType;\n data?: unknown;\n}\n\n/**\n * Event map for type-safe event handling\n */\nexport interface SophiEventMap {\n /**\n * Fired when products should be added to cart\n */\n add_to_cart: AddToCartEvent;\n\n /**\n * Fired when the widget is ready\n */\n ready: void;\n\n /**\n * Fired when an error occurs\n */\n error: Error;\n\n /**\n * Fired when the user should be sent to checkout\n */\n send_to_checkout: void;\n}\n\n/**\n * Event handler type\n */\nexport type EventHandler<T> = (data: T) => void;\n\n/**\n * Event name type\n */\nexport type EventName = keyof SophiEventMap;\n\n/**\n * Authentication session request payload\n */\nexport interface AuthSessionRequest {\n /**\n * External user ID from the parent application\n */\n externalUserId?: string;\n\n /**\n * Optional metadata to include with the session\n */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Session data returned from the authentication API\n */\nexport interface SessionData {\n /**\n * JWT access token for authenticating requests\n */\n accessToken: string;\n\n /**\n * Unique session identifier\n */\n sessionId: string;\n\n /**\n * Client ID\n */\n clientId: string;\n\n /**\n * Company code\n */\n companyCode: string;\n\n /**\n * Session expiration timestamp\n */\n expiresAt: string;\n\n /**\n * userName of the user\n */\n userName: string;\n}\n\n/**\n * Authentication session API response\n */\nexport interface AuthSessionResponse {\n /**\n * Whether the request was successful\n */\n success: boolean;\n\n /**\n * Response message\n */\n message: string;\n\n /**\n * Session data\n */\n data?: SessionData;\n}\n\n/**\n * Merge user request payload\n */\nexport interface MergeUserRequest {\n /**\n * The logged-in user ID to merge to\n */\n userId: string;\n}\n\n/**\n * Merge user data returned from the API\n */\nexport interface MergeUserData {\n /**\n * The resulting client ID after merge\n */\n clientId: string;\n\n /**\n * The external user ID\n */\n externalUserId: string;\n}\n\n/**\n * Merge user API response\n */\nexport interface MergeUserResponse {\n /**\n * Whether the request was successful\n */\n success: boolean;\n\n /**\n * Response message\n */\n message: string;\n\n /**\n * Merge result data\n */\n data?: MergeUserData;\n}\n","export type CookieKey = \"clientId\" | \"externalUserId\" | \"sessionData\" | \"metadataHash\";\n\nexport interface CookieManagerOptions {\n readonly maxAgeSeconds?: number;\n readonly keys?: Partial<Record<CookieKey, string>>;\n}\n\nexport class CookieManager {\n static readonly DEFAULT_MAX_AGE_SECONDS = 60 * 60 * 24 * 30; // 30 days\n static readonly DEFAULT_KEYS: Record<CookieKey, string> = {\n clientId: \"client-id\",\n externalUserId: \"external-user-id\",\n sessionData: \"session-data\",\n metadataHash: \"metadata-hash\",\n };\n\n constructor(namespace: string, options?: CookieManagerOptions) {\n this.namespace = CookieManager.sanitizeNamespace(namespace);\n this.maxAgeSeconds = options?.maxAgeSeconds ?? CookieManager.DEFAULT_MAX_AGE_SECONDS;\n this.keys = { ...CookieManager.DEFAULT_KEYS, ...(options?.keys ?? {}) };\n }\n\n private readonly namespace: string;\n private readonly maxAgeSeconds: number;\n private readonly keys: Record<CookieKey, string>;\n\n static buildNamespace(baseUrl: string, apiKey: string): string {\n return CookieManager.sanitizeNamespace(`sophi-widget-${baseUrl}-${apiKey}`);\n }\n\n static canUseCookies(): boolean {\n return typeof document !== \"undefined\" && typeof document.cookie === \"string\";\n }\n\n set(key: CookieKey, value: string): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n document.cookie = `${this.formatName(key)}=${encodeURIComponent(value)}; path=/; max-age=${this.maxAgeSeconds}; samesite=lax`;\n }\n\n get(key: CookieKey): string | null {\n if (!CookieManager.canUseCookies()) {\n return null;\n }\n\n return CookieManager.readRawCookie(this.formatName(key));\n }\n\n delete(key: CookieKey): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n document.cookie = `${this.formatName(key)}=; path=/; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT; samesite=lax`;\n }\n\n clearAll(): void {\n Object.keys(this.keys).forEach((key) => {\n this.delete(key as CookieKey);\n });\n }\n\n private formatName(key: CookieKey): string {\n return `${this.namespace}-${this.keys[key]}`;\n }\n\n private static readRawCookie(name: string): string | null {\n const cookies = document.cookie.split(\";\").map((cookie) => cookie.trim());\n for (const cookie of cookies) {\n if (!cookie) {\n continue;\n }\n const [cookieName, ...cookieValueParts] = cookie.split(\"=\");\n if (cookieName === name) {\n return decodeURIComponent(cookieValueParts.join(\"=\"));\n }\n }\n return null;\n }\n\n private static sanitizeNamespace(value: string): string {\n const sanitized = value.replace(/[^a-zA-Z0-9_-]/g, \"\");\n return sanitized.length ? sanitized : \"sophi-widget\";\n }\n}\n","import type { AuthSessionRequest, AuthSessionResponse, SessionData, MergeUserRequest, MergeUserResponse, MergeUserData } from \"../types\";\nimport { CookieManager } from \"./cookie.utils\";\n\n/**\n * API Service for Sophi authentication and session management\n */\nexport class ApiService {\n private baseUrl: string;\n private apiKey: string;\n private clientId: string | null = null;\n private userId: string | undefined = undefined;\n private storedUserId: string | null = null; // Track the userId from cookies for merge detection\n private cookieManager: CookieManager;\n\n constructor(baseUrl: string, apiKey: string, userId?: string) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.userId = userId;\n this.cookieManager = new CookieManager(CookieManager.buildNamespace(baseUrl, apiKey));\n this.restoreSessionFromCookies();\n }\n\n /**\n * Create a client session by calling the authentication endpoint\n * @param request - Session request with optional externalUserId and metadata\n * @returns Session data including accessToken, sessionId, etc.\n */\n async createSession(request: AuthSessionRequest): Promise<SessionData> {\n const url = `${this.baseUrl}/api/v1/auth/client/session`;\n\n try {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"x-api-key\": this.apiKey,\n };\n if (this.clientId) {\n headers[\"x-sophi-client-id\"] = this.clientId;\n // Check if we need to merge: user changed from stored (could be empty) to current\n const normalizedStored = this.storedUserId || null;\n const normalizedCurrent = this.userId || null;\n if (normalizedStored !== normalizedCurrent && normalizedCurrent) {\n await this.mergeUser({ userId: normalizedCurrent });\n // Update storedUserId after successful merge\n this.storedUserId = normalizedCurrent;\n }\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n externalUserId: this.userId,\n metadata: request.metadata,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to create session: ${response.status} ${response.statusText}. ${errorText}`);\n }\n\n const data: AuthSessionResponse = await response.json();\n\n if (!data.success) {\n throw new Error(`Session creation failed: ${data.message || \"Unknown error\"}`);\n }\n\n if (!data.data) {\n throw new Error(\"Session data is missing from response\");\n }\n this.persistClientInfo(data.data.clientId, this.userId);\n return data.data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error during session creation: ${String(error)}`);\n }\n }\n\n /**\n * Validate session data\n */\n validateSessionData(sessionData: SessionData): boolean {\n return !!(sessionData.accessToken && sessionData.sessionId && sessionData.clientId && sessionData.companyCode && sessionData.expiresAt);\n }\n\n /**\n * Merge guest user with logged-in user\n * @param request - Merge request with guestId and userId\n * @returns Merge result data including the resulting clientId\n */\n async mergeUser(request: MergeUserRequest): Promise<MergeUserData> {\n const url = `${this.baseUrl}/api/v1/auth/client/info`;\n\n try {\n if (!this.clientId) {\n throw new Error(\"Client ID is not set. Please create a session first.\");\n }\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n \"x-api-key\": this.apiKey,\n \"x-sophi-client-id\": this.clientId,\n },\n body: JSON.stringify({\n externalUserId: request.userId,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Failed to merge user: ${response.status} ${response.statusText}. ${errorText}`);\n }\n\n const data: MergeUserResponse = await response.json();\n\n if (!data.success) {\n throw new Error(`User merge failed: ${data.message || \"Unknown error\"}`);\n }\n\n if (!data.data) {\n throw new Error(\"Merge data is missing from response\");\n }\n\n return data.data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Unexpected error during user merge: ${String(error)}`);\n }\n }\n\n private persistClientInfo(clientId: string, userId?: string): void {\n this.clientId = clientId;\n this.userId = userId;\n this.storedUserId = userId || null; // Update stored userId to match current state\n\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n this.cookieManager.set(\"clientId\", clientId);\n // Always save externalUserId (even if empty) to track the session state\n this.cookieManager.set(\"externalUserId\", userId || \"\");\n }\n\n private restoreSessionFromCookies(): void {\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n const storedUserId = this.cookieManager.get(\"externalUserId\");\n const storedClientId = this.cookieManager.get(\"clientId\");\n\n // Store the userId from cookies for merge detection later\n this.storedUserId = storedUserId || null;\n\n // If no clientId in cookies, nothing to restore\n if (!storedClientId) {\n return;\n }\n\n // Normalize empty values (undefined, null, empty string) to null for comparison\n const normalizedStoredUserId = storedUserId || null;\n const normalizedCurrentUserId = this.userId || null;\n\n // If userIds match, restore both clientId and userId\n if (normalizedStoredUserId === normalizedCurrentUserId) {\n this.clientId = storedClientId;\n if (!this.userId && storedUserId) {\n this.userId = storedUserId;\n }\n return;\n }\n\n // UserIds don't match - determine if we should clear or keep clientId\n \n // Case 1: Logout (filled -> empty) - clear session\n if (normalizedStoredUserId && !normalizedCurrentUserId) {\n this.clearStoredClientInfo();\n return;\n }\n\n // Case 2: Different logged-in users (filled -> different filled) - clear session for new user\n if (normalizedStoredUserId && normalizedCurrentUserId && normalizedStoredUserId !== normalizedCurrentUserId) {\n this.clearStoredClientInfo();\n return;\n }\n\n // Case 3: Guest -> Logged-in user (empty -> filled) - keep clientId for merge\n if (!normalizedStoredUserId && normalizedCurrentUserId) {\n this.clientId = storedClientId;\n return;\n }\n }\n\n private clearStoredClientInfo(): void {\n this.clientId = null;\n this.storedUserId = null;\n\n if (!CookieManager.canUseCookies()) {\n return;\n }\n\n this.cookieManager.clearAll();\n }\n}\n","/**\n * Default configuration constants for Sophi Widget\n */\nexport const DEFAULT_CONFIG = {\n /**\n * Default width of the widget iframe\n */\n WIDTH: \"100%\",\n\n /**\n * Default height of the widget iframe\n */\n HEIGHT: \"600px\",\n} as const;\n\n/**\n * API base URLs for different environments\n *\n * Note: These URLs will be visible in the client-side bundle.\n * This is normal and safe - the real security is in your API key validation.\n *\n * To use different URLs, modify these values before building the SDK.\n *\n * Production API URL - update before building for production\n */\nexport const API_BASE_URLS = {\n test: \"http://10.0.2.127:80\",\n production: \"https://api.usesophi.com\",\n} as const;\n\n/**\n * API endpoints configuration\n */\nexport const API_ENDPOINTS = {\n /**\n * Session creation endpoint path\n */\n CREATE_SESSION: \"/api/v1/auth/client/session\",\n} as const;\n\n/**\n * Error messages\n */\nexport const ERROR_MESSAGES = {\n MISSING_API_KEY: \"API key is required and must be a string\",\n MISSING_CLIENT_ID: \"Client ID is required and must be a string\",\n MISSING_USER_ID: \"User ID is required and must be a string\",\n MISSING_CONTAINER: \"Container is required\",\n MISSING_IFRAME_URL: \"Iframe URL is required and must be a string\",\n INVALID_IFRAME_URL: \"Invalid iframe URL\",\n INVALID_ENVIRONMENT: \"Invalid environment. Must be 'dev', 'test', 'staging', or 'production'\",\n CONTAINER_NOT_FOUND: \"Container element not found\",\n NOT_INITIALIZED: \"Widget not initialized. Call init() first.\",\n ALREADY_INITIALIZED: \"Sophi Widget is already initialized. Call destroy() first to reinitialize.\",\n SESSION_CREATION_FAILED: \"Failed to create authentication session\",\n INVALID_SESSION_DATA: \"Invalid session data received from API\",\n YOU_NEED_TO_INIT_THE_WIDGET_FIRST: \"You need to initialize the widget first. Call init() before calling this method.\",\n} as const;\n","import { type SophiConfig, type UserData, type EventHandler, type EventName, type SophiEventMap, type IncomingMessage, type OutgoingMessage, type AddToCartEvent, type IUserCart, type SessionData, type MergeUserRequest, type MergeUserData, OutgoingMessageTypes } from \"./types\";\nimport { ApiService } from \"./services/api.service\";\nimport { DEFAULT_CONFIG, ERROR_MESSAGES, API_BASE_URLS } from \"./constants/config\";\n\n/**\n * Main Sophi Widget SDK class\n * Provides a framework-agnostic way to embed and interact with the Sophi AI widget\n */\nexport class SophiWidget {\n private config: SophiConfig | null = null;\n private iframe: HTMLIFrameElement | null = null;\n private container: HTMLElement | null = null;\n private eventListeners: Map<EventName, Set<EventHandler<any>>> = new Map();\n private messageHandler: ((event: MessageEvent) => void) | null = null;\n private isInitialized = false;\n private iframeOrigin: string | null = null;\n private sessionData: SessionData | null = null;\n private apiService: ApiService | null = null;\n private apiBaseUrl: string | null = null;\n\n /**\n * Initialize the widget with configuration\n * @param config - Widget configuration\n */\n public async init(config: SophiConfig): Promise<void> {\n if (this.isInitialized) {\n console.warn(ERROR_MESSAGES.ALREADY_INITIALIZED);\n return;\n }\n\n try {\n // Validate configuration\n this.validateConfig(config);\n\n this.config = this.formatConfig(config);\n\n // Determine API URL based on environment\n this.apiBaseUrl = API_BASE_URLS[config.environment || \"production\"];\n\n // Initialize API service\n this.apiService = new ApiService(this.apiBaseUrl, config.apiKey, config.userId);\n\n // Create authentication session\n await this.createAuthSession();\n\n this.isInitialized = true;\n\n // Extract origin from iframe URL for security\n try {\n const url = new URL(this.getIframeUrl());\n this.iframeOrigin = url.origin;\n } catch (error) {\n const err = new Error(`${ERROR_MESSAGES.INVALID_IFRAME_URL}: ${this.getIframeUrl()}`);\n this.emitError(err);\n throw err;\n }\n\n // Resolve container element\n this.container = this.resolveContainer(config.container);\n\n if (!this.container) {\n const err = new Error(ERROR_MESSAGES.CONTAINER_NOT_FOUND);\n this.emitError(err);\n throw err;\n }\n\n // Create and mount iframe\n this.createIframe();\n\n // Setup postMessage listener\n this.setupMessageListener();\n\n // Send session data to iframe after it's loaded\n this.iframe?.addEventListener(\"load\", () => {\n // Small delay to ensure iframe is fully ready\n setTimeout(() => {\n this.sendSessionData();\n if (this.config?.layout) {\n this.sendLayoutConfig();\n }\n }, 100);\n });\n\n // Call onReady callback if provided\n if (config.onReady) {\n config.onReady();\n }\n } catch (error) {\n // Reset state on error\n this.isInitialized = false;\n this.config = null;\n this.apiService = null;\n this.sessionData = null;\n\n const err = error instanceof Error ? error : new Error(String(error));\n this.emitError(err);\n throw err;\n }\n }\n\n /**\n * Send user data to the widget\n * @param data - User data object\n */\n public sendUserData(data: UserData): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.USER_DATA,\n data,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Toggle chat history visibility in the iframe child app.\n */\n public sendToggleHistory(): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.TOGGLE_HISTORY,\n };\n\n this.postMessage(message);\n }\n\n public updateUserCart(cart: IUserCart): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.UPDATE_USER_CART,\n data: cart,\n };\n\n this.postMessage(message);\n }\n\n private onDestroy(): void {\n if (!this.isInitialized || !this.iframe) {\n console.warn(\"Widget not initialized. Call init() first.\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.DESTROY,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Register an event listener\n * @param event - Event name\n * @param handler - Event handler function\n */\n public on<K extends EventName>(event: K, handler: EventHandler<SophiEventMap[K]>): void {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n /**\n * Unregister an event listener\n * @param event - Event name\n * @param handler - Event handler function to remove\n */\n public off<K extends EventName>(event: K, handler: EventHandler<SophiEventMap[K]>): void {\n const handlers = this.eventListeners.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n }\n\n /**\n * Show the widget\n */\n public show(): void {\n if (this.iframe) {\n this.iframe.style.display = \"block\";\n }\n }\n\n /**\n * Hide the widget\n */\n public hide(): void {\n if (this.iframe) {\n this.iframe.style.display = \"none\";\n }\n }\n\n /**\n * Destroy the widget and cleanup resources\n * Waits 300ms after sending destroy message to give iframe time to cleanup\n */\n public async destroy(): Promise<void> {\n this.onDestroy();\n\n // Wait 300ms to give iframe time to process the destroy event and cleanup\n await new Promise((resolve) => setTimeout(resolve, 300));\n\n // Remove message listener\n if (this.messageHandler) {\n window.removeEventListener(\"message\", this.messageHandler);\n this.messageHandler = null;\n }\n\n // Remove iframe\n if (this.iframe && this.iframe.parentNode) {\n this.iframe.parentNode.removeChild(this.iframe);\n this.iframe = null;\n }\n\n // Clear event listeners\n this.eventListeners.clear();\n\n // Reset state\n this.config = null;\n this.container = null;\n this.isInitialized = false;\n this.iframeOrigin = null;\n this.sessionData = null;\n this.apiService = null;\n }\n\n /**\n * Check if widget is initialized\n */\n public isReady(): boolean {\n return this.isInitialized && this.iframe !== null;\n }\n\n /**\n * Validate configuration\n */\n private validateConfig(config: SophiConfig): void {\n if (!config.apiKey || typeof config.apiKey !== \"string\") {\n throw new Error(ERROR_MESSAGES.MISSING_API_KEY);\n }\n\n if (config.userId && typeof config.userId !== \"string\") {\n throw new Error(ERROR_MESSAGES.MISSING_USER_ID);\n }\n\n if (!config.container) {\n throw new Error(ERROR_MESSAGES.MISSING_CONTAINER);\n }\n }\n\n /**\n * Format configuration\n */\n private formatConfig(config: SophiConfig): SophiConfig {\n return {\n ...config,\n userId: config.userId || undefined,\n };\n }\n\n /**\n * Create authentication session with the API\n */\n private async createAuthSession(): Promise<void> {\n if (!this.config || !this.apiService) {\n throw new Error(ERROR_MESSAGES.NOT_INITIALIZED);\n }\n\n try {\n this.sessionData = await this.apiService.createSession({\n externalUserId: this.config.userId,\n metadata: this.config.metadata,\n });\n\n // Validate session data\n if (!this.apiService.validateSessionData(this.sessionData)) {\n throw new Error(ERROR_MESSAGES.INVALID_SESSION_DATA);\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(ERROR_MESSAGES.SESSION_CREATION_FAILED);\n throw err;\n }\n }\n\n /**\n * Send session data to iframe\n */\n private sendSessionData(): void {\n if (!this.sessionData) {\n console.warn(\"Session data not available\");\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.SESSION_DATA,\n data: { ...this.sessionData, userName: this.config?.userName },\n };\n\n this.postMessage(message);\n }\n\n /**\n * Send layout config to iframe so the child app can apply layout options (e.g. show/hide header).\n */\n private sendLayoutConfig(): void {\n if (!this.config?.layout) {\n return;\n }\n\n const message: OutgoingMessage = {\n type: OutgoingMessageTypes.LAYOUT_CONFIG,\n data: this.config.layout,\n };\n\n this.postMessage(message);\n }\n\n /**\n * Resolve container element from selector or element\n */\n private resolveContainer(container: string | HTMLElement): HTMLElement | null {\n if (typeof container === \"string\") {\n return document.querySelector(container);\n }\n return container;\n }\n\n /**\n * Create and mount the iframe\n */\n private createIframe(): void {\n if (!this.container || !this.config) {\n return;\n }\n\n const iframe = document.createElement(\"iframe\");\n\n // Set iframe attributes\n iframe.src = this.buildIframeUrl();\n iframe.style.width = this.config.width || \"100%\";\n iframe.style.height = this.config.height || \"600px\";\n iframe.style.border = \"none\";\n iframe.title = \"Sophi AI Widget\";\n iframe.allow = \"microphone; camera; clipboard-write\";\n\n // Append to container\n this.container.appendChild(iframe);\n this.iframe = iframe;\n }\n\n /**\n * Build iframe URL with query parameters\n */\n private buildIframeUrl(): string {\n if (!this.config) {\n return \"\";\n }\n const url = new URL(this.getIframeUrl());\n\n return url.toString();\n }\n\n private getIframeUrl(): string {\n if (!this.config) {\n return \"\";\n }\n if (this.config.environment === \"production\") {\n return \"https://app.usesophi.com\";\n }\n return \"http://localhost:5173\";\n }\n\n /**\n * Setup postMessage listener for iframe communication\n */\n private setupMessageListener(): void {\n this.messageHandler = (event: MessageEvent) => {\n // Validate origin for security\n if (this.iframeOrigin && event.origin !== this.iframeOrigin) {\n console.warn(`Received message from untrusted origin: ${event.origin}`);\n return;\n }\n\n try {\n // Parse message\n const message: IncomingMessage = typeof event.data === \"string\" ? JSON.parse(event.data) : event.data;\n\n // Handle different message types\n this.handleIncomingMessage(message);\n } catch (error) {\n console.error(\"Error processing message from iframe:\", error);\n }\n };\n\n window.addEventListener(\"message\", this.messageHandler);\n }\n\n /**\n * Handle incoming messages from iframe\n */\n private handleIncomingMessage(message: IncomingMessage): void {\n switch (message.type) {\n case \"add_to_cart\":\n if (this.isValidAddToCartMessage(message.data)) {\n this.emit(\"add_to_cart\", message.data);\n } else {\n console.error(\"Invalid add_to_cart message structure:\", message.data);\n this.emitError(new Error(\"Invalid add_to_cart message format\"));\n }\n break;\n\n case \"send_to_checkout\":\n this.emit(\"send_to_checkout\", undefined);\n break;\n case \"ready\":\n this.emit(\"ready\", undefined);\n break;\n\n case \"error\":\n const error = message.data instanceof Error ? message.data : new Error(String(message.data));\n this.emitError(error);\n break;\n\n default:\n console.warn(\"Unknown message type:\", message);\n }\n }\n\n /**\n * Validate add_to_cart message structure\n */\n private isValidAddToCartMessage(data: unknown): data is AddToCartEvent {\n if (!data || typeof data !== \"object\") {\n return false;\n }\n\n const event = data as Record<string, unknown>;\n\n // Check products array exists and is an array\n if (!Array.isArray(event.products)) {\n return false;\n }\n\n // Validate each product in the array\n return event.products.every((product) => {\n if (!product || typeof product !== \"object\") {\n return false;\n }\n const prod = product as Record<string, unknown>;\n\n // productId is required and must be a string\n if (typeof prod.productId !== \"string\") {\n return false;\n }\n\n // variantId is optional, but if present must be a string\n if (prod.variantId !== undefined && typeof prod.variantId !== \"string\") {\n return false;\n }\n\n return true;\n });\n }\n\n /**\n * Post message to iframe\n */\n private postMessage(message: OutgoingMessage): void {\n if (!this.iframe || !this.iframe.contentWindow || !this.iframeOrigin) {\n console.warn(\"Cannot send message: iframe not ready\");\n return;\n }\n\n try {\n this.iframe.contentWindow.postMessage(message, this.iframeOrigin);\n } catch (error) {\n console.error(\"Error sending message to iframe:\", error);\n this.emitError(error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Emit event to registered listeners\n */\n private emit<K extends EventName>(event: K, data: SophiEventMap[K]): void {\n const handlers = this.eventListeners.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(data);\n } catch (error) {\n console.error(`Error in ${event} event handler:`, error);\n }\n });\n }\n }\n\n /**\n * Emit error event\n */\n private emitError(error: Error): void {\n this.emit(\"error\", error);\n\n // Also call onError callback if provided\n if (this.config?.onError) {\n this.config.onError(error);\n }\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usesophi/sophi-web-sdk",
3
- "version": "0.1.0",
3
+ "version": "1.0.1",
4
4
  "description": "Framework-agnostic SDK for embedding Sophi AI widget",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",