@formbricks/js
Advanced tools
Comparing version 1.5.0 to 1.5.1
@@ -1,2 +0,2 @@ | ||
var formbricks=function(){"use strict";const e=e=>({ok:!1,error:e});async function t(t,n,s,i){const r=new URL(n,t),o=JSON.stringify(i),a=(d=fetch,(...e)=>{try{return{ok:!0,data:d(...e)}}catch(t){return{ok:!1,error:t}}})(r.toString(),{method:s,headers:{"Content-Type":"application/json"},body:o});var d;if(!1===a.ok)return e(a.error);const c=await a.data,{data:u}=await c.json();return c.ok?(e=>({ok:!0,data:e}))(u):e({code:"network_error",message:c.statusText,status:c.status,url:r})}class n{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/actions`,"POST",e)}}class s{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/displays`,"POST",e)}async update(e,n){return t(this.apiHost,`/api/v1/client/${this.environmentId}/displays/${e}`,"PUT",n)}}class i{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/people`,"POST",{environmentId:this.environmentId,userId:e})}async update(e,n){return t(this.apiHost,`/api/v1/client/${this.environmentId}/people/${e}`,"POST",n)}}class r{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/responses`,"POST",e)}async update({responseId:e,finished:n,data:s,ttc:i}){return t(this.apiHost,`/api/v1/client/${this.environmentId}/responses/${e}`,"PUT",{finished:n,data:s,ttc:i})}}class o{constructor(e,t){this.apiHost=e,this.environmentId=t}async uploadFile(e,{allowedFileExtensions:t,surveyId:n}={}){if(!(e instanceof Blob&&e instanceof File))throw new Error("Invalid file type. Expected Blob or File, but received "+typeof e);const s={fileName:e.name,fileType:e.type,allowedFileExtensions:t,surveyId:n},i=await fetch(`${this.apiHost}/api/v1/client/${this.environmentId}/storage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!i.ok)throw new Error(`Upload failed with status: ${i.status}`);const r=await i.json(),{data:o}=r,{signedUrl:a,fileUrl:d,signingData:c,presignedFields:u,updatedFileName:l}=o;let g={};if(c){const{signature:t,timestamp:s,uuid:i}=c;g={"X-File-Type":e.type,"X-File-Name":encodeURIComponent(l),"X-Survey-ID":n??"","X-Signature":t,"X-Timestamp":String(s),"X-UUID":i}}const p=new FormData;u&&Object.keys(u).forEach((e=>{p.append(e,u[e])})),p.append("file",e);const h=await fetch(a,{method:"POST",...c?{headers:g}:{},body:p});if(!h.ok){if(c){const e=await h.json(),t=new Error(e.message);throw t.name="FileTooLargeError",t}const e=await h.text();if(u&&e&&e.includes("EntityTooLarge")){const e=new Error("File size exceeds the size limit for your plan");throw e.name="FileTooLargeError",e}throw new Error(`Upload failed with status: ${h.status}`)}return d}}class a{constructor(e){const{apiHost:t,environmentId:a}=e;this.response=new r(t,a),this.display=new s(t,a),this.action=new n(t,a),this.people=new i(t,a),this.storage=new o(t,a)}}class d{constructor(e){this.client=new a(e)}}class c{constructor(){this.logLevel="error"}static getInstance(){return c.instance||(c.instance=new c),c.instance}configure(e){e&&void 0!==e.logLevel&&(this.logLevel=e.logLevel)}logger(e,t){if("debug"===t&&"debug"!==this.logLevel)return;const n=`🧱 Formbricks - ${(new Date).toISOString()} [${t.toUpperCase()}] - ${e}`;"error"===t?console.error(n):console.log(n)}debug(e){this.logger(e,"debug")}error(e){this.logger(e,"error")}}const u=e=>({ok:!0,value:e}),l=e=>({ok:!1,error:e});const g=e=>(...t)=>{try{return{ok:!0,value:e(...t)}}catch(n){return{ok:!1,error:n}}},p=c.getInstance(),h=class e{constructor(e){this.customized=!1,e?(this.handleError=e,this.customized=!0):this.handleError=e=>c.getInstance().error(JSON.stringify(e))}static getInstance(){return e.instance||(e.instance=new e),e.instance}static init(t){this.initialized=!0,e.instance=new e(t)}printStatus(){p.debug("Custom error handler: "+(this.customized?"yes":"no"))}handle(e){console.warn("🧱 Formbricks - Global error: ",e),this.handleError(e)}};h.initialized=!1;let v=h;const f="formbricks-js";class w{constructor(){this.config=null;const e=this.loadFromLocalStorage();e.ok&&(this.config=e.value)}static getInstance(){return w.instance||(w.instance=new w),w.instance}update(e){if(e){const t=new Date((new Date).getTime()+9e5);this.config={...this.config,...e,expiresAt:t},this.saveToLocalStorage()}}get(){if(!this.config)throw new Error("config is null, maybe the init function was not called?");return this.config}loadFromLocalStorage(){if("undefined"!=typeof window){const e=localStorage.getItem(f);if(e){const t=JSON.parse(e);return t.expiresAt&&new Date(t.expiresAt)<=new Date?l(new Error("Config in local storage has expired")):u(JSON.parse(e))}}return l(new Error("No or invalid config in local storage"))}saveToLocalStorage(){return g((()=>localStorage.setItem(f,JSON.stringify(this.config))))()}resetConfig(){return this.config=null,g((()=>localStorage.removeItem(f)))()}}const m=e=>new Promise((t=>setTimeout(t,e)));class y{constructor(e,t){this.queue=[],this.isRequestInProgress=!1,this.config=e,this.surveyState=t,this.api=new d({apiHost:e.apiHost,environmentId:e.environmentId})}add(e){this.surveyState.accumulateResponse(e),this.config.setSurveyState&&this.config.setSurveyState(this.surveyState),this.queue.push(e),this.processQueue()}async processQueue(){if(this.isRequestInProgress)return;if(0===this.queue.length)return;this.isRequestInProgress=!0;const e=this.queue[0];let t=0;for(;t<this.config.retryAttempts;){if(await this.sendResponse(e)){this.queue.shift();break}console.error("Formbricks: Failed to send response. Retrying...",t),await m(1e3),t++}t>=this.config.retryAttempts?(console.error("Failed to send response after 2 attempts."),this.config.onResponseSendingFailed&&this.config.onResponseSendingFailed(e),this.isRequestInProgress=!1):(this.isRequestInProgress=!1,this.processQueue())}async sendResponse(e){try{if(null!==this.surveyState.responseId)await this.api.client.response.update({...e,responseId:this.surveyState.responseId});else{const t=await this.api.client.response.create({...e,surveyId:this.surveyState.surveyId,userId:this.surveyState.userId||null,singleUseId:this.surveyState.singleUseId||null});if(!t.ok)throw new Error("Could not create response");this.surveyState.displayId&&await this.api.client.display.update(this.surveyState.displayId,{responseId:t.data.id}),this.surveyState.updateResponseId(t.data.id),this.config.setSurveyState&&this.config.setSurveyState(this.surveyState)}return!0}catch(t){return console.error(t),!1}}updateSurveyState(e){this.surveyState=e}}class I{constructor(e,t,n,s){this.responseId=null,this.displayId=null,this.userId=null,this.responseAcc={finished:!1,data:{},ttc:{}},this.surveyId=e,this.userId=s??null,this.singleUseId=t??null,this.responseId=n??null}setSurveyId(e){this.surveyId=e,this.clear()}copy(){const e=new I(this.surveyId,this.singleUseId??void 0,this.responseId??void 0,this.userId??void 0);return e.responseId=this.responseId,e.responseAcc=this.responseAcc,e}updateResponseId(e){this.responseId=e}updateDisplayId(e){this.displayId=e}updateUserId(e){this.userId=e}accumulateResponse(e){this.responseAcc={finished:e.finished,ttc:e.ttc,data:{...this.responseAcc.data,...e.data}}}isResponseFinished(){return this.responseAcc.finished}clear(){this.responseId=null,this.responseAcc={finished:!1,data:{},ttc:{}}}}const b=I,k=(e,t)=>{const n=Math.abs(t.getTime()-e.getTime());return Math.floor(n/864e5)},S=w.getInstance(),H=c.getInstance();let E=null;const C=async e=>{try{const n=await(async({apiHost:e,environmentId:t,userId:n})=>{const s=`${e}/api/v1/client/${t}/in-app/sync/${n}`,i=`${e}/api/v1/client/${t}/in-app/sync`;if(!n){const e=await fetch(i);if(!e.ok){const t=await e.json();return l({code:"network_error",status:e.status,message:"Error syncing with backend",url:s,responseMessage:t.message})}return u((await e.json()).data)}const r=await fetch(s);if(!r.ok){const e=await r.json();return l({code:"network_error",status:r.status,message:"Error syncing with backend",url:s,responseMessage:e.message})}const o=await r.json(),{data:a}=o;return u(a)})(e);if(!0!==(null==n?void 0:n.ok))throw H.error(`Sync failed: ${JSON.stringify(n.error)}`),n.error;let s;try{s=S.get().state}catch(t){}let i={surveys:n.value.surveys,noCodeActionClasses:n.value.noCodeActionClasses,product:n.value.product,attributes:(null==s?void 0:s.attributes)||{}};if(e.userId){const e=i.surveys.map((e=>e.name));H.debug("Fetched "+e.length+" surveys during sync: "+e.join(", "))}else{i={...i,displays:(null==s?void 0:s.displays)||[]},i=$(i);const e=i.surveys.map((e=>e.name));H.debug("Fetched "+e.length+" surveys during sync: "+e.join(", "))}S.update({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId,state:i})}catch(n){throw H.error(`Error during sync: ${n}`),n}},$=e=>{const{displays:t,product:n}=e;let{surveys:s}=e;if(!t)return e;let i=s.filter((e=>{if("respondMultiple"===e.displayOption)return!0;if("displayOnce"===e.displayOption)return 0===t.filter((t=>t.surveyId===e.id)).length;if("displayMultiple"===e.displayOption)return 0===t.filter((t=>t.surveyId===e.id&&t.responded)).length;throw Error("Invalid displayOption")}));const r=t.length>0?t[t.length-1]:void 0;return i=i.filter((e=>{if(r){if(null!==e.recontactDays){const n=t.filter((t=>t.surveyId===e.id))[0];return!n||k(new Date,new Date(n.createdAt))>=e.recontactDays}return null===n.recontactDays||k(new Date,new Date(r.createdAt))>=n.recontactDays}return!0})),{...e,surveys:i}},A=()=>{"undefined"!=typeof window&&null!==E&&(window.clearInterval(E),E=null)},F="formbricks-web-container",L=w.getInstance(),O=c.getInstance(),D=v.getInstance();let U=!1,P=e=>{};const x=async e=>{if(U)return void O.debug("A survey is already running. Skipping.");U=!0,e.delay&&O.debug(`Delaying survey by ${e.delay} seconds.`);const t=L.get().state.product,n=new b(e.id,null,null,L.get().userId),s=new y({apiHost:L.get().apiHost,environmentId:L.get().environmentId,retryAttempts:2,onResponseSendingFailed:()=>{P(!0)}},n),i=e.productOverwrites??{},r=i.brandColor??t.brandColor,o=i.highlightBorderColor??t.highlightBorderColor,a=i.clickOutsideClose??t.clickOutsideClose,c=i.darkOverlay??t.darkOverlay,u=i.placement??t.placement,l=t.inAppSurveyBranding,g=await R();setTimeout((()=>{g.renderSurveyModal({survey:e,brandColor:r,isBrandingEnabled:l,clickOutside:a,darkOverlay:c,highlightBorderColor:o,placement:u,getSetIsError:e=>{P=e},onDisplay:async()=>{const{userId:t}=L.get();if(!t){const t={createdAt:new Date,surveyId:e.id,responded:!1},n=L.get().state.displays,s=n?[...n,t]:[t],i=L.get();let r=$({...i.state,displays:s});L.update({...i,state:r})}const i=new d({apiHost:L.get().apiHost,environmentId:L.get().environmentId}),r=await i.client.display.create({surveyId:e.id,userId:t});if(!r.ok)throw new Error("Could not create display");const{id:o}=r.data;n.updateDisplayId(o),s.updateSurveyState(n)},onResponse:e=>{const{userId:t}=L.get();if(!t){const e=L.get().state.displays,t=e&&e[e.length-1];if(!t)throw new Error("No lastDisplay found");if(!t.responded){t.responded=!0;const n=L.get();let s=$({...n.state,displays:e});L.update({...n,state:s})}}t&&n.updateUserId(t),s.updateSurveyState(n),s.add({data:e.data,ttc:e.ttc,finished:e.finished})},onClose:T,onFileUpload:async(e,t)=>{const n=new d({apiHost:L.get().apiHost,environmentId:L.get().environmentId});return await n.client.storage.uploadFile(e,t)},onRetry:()=>{P(!1),s.processQueue()}})}),1e3*e.delay)},T=async()=>{var e;if(null==(e=document.getElementById(F))||e.remove(),N(),!L.get().userId){const e=L.get().state,t=$(e);return L.update({...L.get(),state:t}),void(U=!1)}try{await C({apiHost:L.get().apiHost,environmentId:L.get().environmentId,userId:L.get().userId}),U=!1}catch(t){D.handle(t)}},N=()=>{const e=document.createElement("div");e.id=F,document.body.appendChild(e)},R=()=>new Promise(((e,t)=>{if(window.formbricksSurveys)e(window.formbricksSurveys);else{const n=document.createElement("script");n.src="https://unpkg.com/@formbricks/surveys@^1.5.0/dist/index.umd.js",n.async=!0,n.onload=()=>e(window.formbricksSurveys),n.onerror=e=>{console.error("Failed to load Formbricks Surveys library:",e),t(e)},document.head.appendChild(n)}})),z=c.getInstance(),j=w.getInstance(),q=["Exit Intent (Desktop)","50% Scroll"],M=async(e,t={})=>{var n;const{userId:s}=j.get(),i={environmentId:j.get().environmentId,userId:s,name:e,properties:t||{}};if(s&&!q.includes(e)){z.debug(`Sending action "${e}" to backend`);const t=new d({apiHost:j.get().apiHost,environmentId:j.get().environmentId}),n=await t.client.action.create({...i,userId:s});if(!n.ok)return l({code:"network_error",message:`Error tracking action ${e}`,status:500,url:`${j.get().apiHost}/api/v1/client/${j.get().environmentId}/actions`,responseMessage:n.error.message})}z.debug(`Formbricks: Action "${e}" tracked`);const r=null==(n=j.get().state)?void 0:n.surveys;return r&&r.length>0?await _(e,r):z.debug("No active surveys to display"),{ok:!0,value:void 0}},_=async(e,t)=>{for(const n of t)for(const t of n.triggers)if(t===e)return z.debug(`Formbricks: survey ${n.id} triggered by action "${e}"`),void(await x(n))},B=e=>async(...t)=>{try{return{ok:!0,data:await e(...t)}}catch(n){return{ok:!1,error:n}}};let J=!1,X=async function(e){if(e.clientY<=0){const e=await M("Exit Intent (Desktop)");if(!0!==e.ok)return l(e.error)}};const Q=()=>{J&&(document.removeEventListener("mouseleave",X),J=!1)};let W=!1,Y=!1,G=async()=>{const e=window.scrollY,t=window.innerHeight,n=document.documentElement.scrollHeight;if(0===e&&(Y=!1),!Y&&e/(n-t)>=.5){Y=!0;const e=await M("50% Scroll");if(!0!==e.ok)return l(e.error)}};const K=()=>{W&&(window.removeEventListener("scroll",G),W=!1)},V=w.getInstance(),Z=c.getInstance(),ee=v.getInstance(),te=async()=>{var e;Z.debug(`Checking page url: ${window.location.href}`);const{state:t}=V.get();if(void 0===(null==t?void 0:t.noCodeActionClasses))return{ok:!0,value:void 0};const n=((null==t?void 0:t.noCodeActionClasses)||[]).filter((e=>{const{innerHtml:t,cssSelector:n,pageUrl:s}=e.noCodeConfig||{};return s&&!t&&!n}));if(0===n.length)return{ok:!0,value:void 0};for(const s of n){if(!(null==(e=s.noCodeConfig)?void 0:e.pageUrl))continue;const{noCodeConfig:{pageUrl:t}}=s,n=re(window.location.href,t.value,t.rule);if(!0!==n.ok)return l(n.error);if(!1===n.value)continue;const i=await M(s.name);if(!0!==i.ok)return l(i.error)}return{ok:!0,value:void 0}};let ne=!1;const se=()=>te(),ie=()=>{"undefined"!=typeof window&&ne&&(window.removeEventListener("hashchange",se),window.removeEventListener("popstate",se),window.removeEventListener("pushstate",se),window.removeEventListener("replacestate",se),window.removeEventListener("load",se),ne=!1)};function re(e,t,n){switch(n){case"exactMatch":return u(e===t);case"contains":return u(e.includes(t));case"startsWith":return u(e.startsWith(t));case"endsWith":return u(e.endsWith(t));case"notMatch":return u(e!==t);case"notContains":return u(!e.includes(t));default:return l({code:"invalid_match_type",message:"Invalid match type"})}}let oe=!1;const ae=e=>(e=>{const{state:t}=V.get();if(!t)return;const n=e.target;((null==t?void 0:t.noCodeActionClasses)||[]).forEach((e=>{var t,s,i,r,o,a,d,c;const u=null==(s=null==(t=e.noCodeConfig)?void 0:t.innerHtml)?void 0:s.value,l=null==(r=null==(i=e.noCodeConfig)?void 0:i.cssSelector)?void 0:r.value,g=null==(a=null==(o=e.noCodeConfig)?void 0:o.pageUrl)?void 0:a.value,p=null==(c=null==(d=e.noCodeConfig)?void 0:d.pageUrl)?void 0:c.rule;if((u||l||g)&&(!u||n.innerHTML===u)){if(l){const e=l.split(/\s*(?=[.#])/);for(let t of e)if(!n.matches(t))return}if(g&&p){const e=re(window.location.href,g,p);if(!e.ok||!e.value)return}M(e.name).then((e=>{var t,n,s;n=e=>{},s=e=>{ee.handle(e)},!0===(t=e).ok?n(t.value):s(t.error)}))}}))})(e),de=()=>{oe&&(document.removeEventListener("click",ae),oe=!1)};let ce=!1;const ue=()=>{"undefined"!=typeof window&&null===E&&(E=window.setInterval((async()=>{S.get().expiresAt&&new Date(S.get().expiresAt)>=new Date||(H.debug("Config has expired. Starting sync."),await C({apiHost:S.get().apiHost,environmentId:S.get().environmentId,userId:S.get().userId}))}),6e4)),"undefined"==typeof window||ne||(window.addEventListener("hashchange",se),window.addEventListener("popstate",se),window.addEventListener("pushstate",se),window.addEventListener("replacestate",se),window.addEventListener("load",se),ne=!0),"undefined"==typeof window||oe||(document.addEventListener("click",ae),oe=!0),"undefined"==typeof document||J||(document.querySelector("body").addEventListener("mouseleave",X),J=!0),"undefined"==typeof window||W||(window.addEventListener("load",(()=>{window.addEventListener("scroll",G)})),W=!0)},le=()=>{A(),ie(),de(),Q(),K(),ce&&(window.removeEventListener("beforeunload",(()=>{A(),ie(),de(),Q(),K()})),ce=!1)},ge=w.getInstance(),pe=c.getInstance(),he=async()=>(pe.error("'setUserId' is no longer supported. Please set the userId in the init call instead."),{ok:!0,value:void 0}),ve=async(e,t)=>{if(pe.debug("Setting attribute: "+e+" to value: "+t),((e,t)=>ge.get().state.attributes[e]===t)(e,t.toString()))return pe.debug("Attribute already set to this value. Skipping update."),{ok:!0,value:void 0};const n=await(async(e,t)=>{const{apiHost:n,environmentId:s,userId:i}=ge.get();if(!i)return l({code:"missing_person",message:"Unable to update attribute. User identification deactivated. No userId set."});const r={attributes:{[e]:t}},o=new d({apiHost:ge.get().apiHost,environmentId:ge.get().environmentId}),a=await o.client.people.update(i,r);return a.ok?(pe.debug("Attribute updated. Syncing..."),await C({environmentId:s,apiHost:n,userId:i}),{ok:!0,value:void 0}):l({code:"network_error",status:500,message:`Error updating person with userId ${i}`,url:`${ge.get().apiHost}/api/v1/client/${s}/people/${i}`,responseMessage:a.error.message})})(e,t.toString());return n.ok?(ge.update({environmentId:ge.get().environmentId,apiHost:ge.get().apiHost,userId:ge.get().userId,state:{...ge.get().state,attributes:{...ge.get().state.attributes,[e]:t.toString()}}}),{ok:!0,value:void 0}):l(n.error)},fe=async()=>{ke()},we=async()=>{pe.debug("Resetting state & getting new state from backend"),T();const e={environmentId:ge.get().environmentId,apiHost:ge.get().apiHost,userId:ge.get().userId};await fe();try{return await be(e),{ok:!0,value:void 0}}catch(t){return l(t)}},me=w.getInstance(),ye=c.getInstance();let Ie=!1;const be=async e=>{if(Ie)return ye.debug("Already initialized, skipping initialization."),{ok:!0,value:void 0};if((e=>{e.debug&&(ye.debug("Setting log level to debug"),ye.configure({logLevel:"debug"}))})(e),v.getInstance().printStatus(),ye.debug("Start initialize"),!e.environmentId)return ye.debug("No environmentId provided"),l({code:"missing_field",field:"environmentId"});if(!e.apiHost)return ye.debug("No apiHost provided"),l({code:"missing_field",field:"apiHost"});if(ye.debug("Adding widget container to DOM"),N(),!e.userId&&e.attributes)return ye.error("No userId provided but attributes. Cannot update attributes without userId."),l({code:"missing_field",field:"userId"});let t,n=null;if(e.userId&&e.attributes){const t=await(async(e,t,n,s)=>{var i,r;if(!n)return l({code:"missing_person",message:"Unable to update attribute. User identification deactivated. No userId set."});const o={...s};try{const e=null==(r=null==(i=ge.get())?void 0:i.state)?void 0:r.attributes;if(e)for(const[t,n]of Object.entries(e))o[t]===n&&delete o[t]}catch(p){pe.debug("config not set; sending all attributes to backend")}if(0===Object.keys(o).length)return pe.debug("No attributes to update. Skipping update."),u(o);pe.debug("Updating attributes: "+JSON.stringify(o));const a={attributes:o},c=new d({apiHost:e,environmentId:t}),g=await c.client.people.update(n,a);return g.ok?u(o):l({code:"network_error",status:500,message:`Error updating person with userId ${n}`,url:`${e}/api/v1/client/${t}/people/${n}`,responseMessage:g.error.message})})(e.apiHost,e.environmentId,e.userId,e.attributes);if(!0!==t.ok)return l(t.error);n=t.value}try{t=me.get()}catch(s){ye.debug("No existing configuration found.")}return t&&t.state&&t.environmentId===e.environmentId&&t.apiHost===e.apiHost&&t.userId===e.userId&&t.expiresAt?(ye.debug("Found existing configuration."),t.expiresAt<new Date?(ye.debug("Configuration expired."),await C({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId})):(ye.debug("Configuration not expired. Extending expiration."),me.update(t))):(ye.debug("No valid configuration found or it has been expired. Creating new config."),ye.debug("Syncing."),await C({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId}),await M("New Session")),n&&Object.keys(n).length>0&&me.update({environmentId:me.get().environmentId,apiHost:me.get().apiHost,userId:me.get().userId,state:{...me.get().state,attributes:{...me.get().state.attributes,...e.attributes}}}),ye.debug("Adding event listeners"),ue(),ce||(window.addEventListener("beforeunload",(()=>{A(),ie(),de(),Q(),K()})),ce=!0),Ie=!0,ye.debug("Initialized"),te(),{ok:!0,value:void 0}},ke=()=>{ye.debug("Deinitializing"),T(),le(),me.resetConfig(),Ie=!1};c.getInstance().debug("Create command queue");const Se=new class{constructor(){this.queue=[],this.running=!1,this.resolvePromise=null,this.commandPromise=null}add(e=!0,t,...n){this.queue.push({command:t,checkInitialized:e,commandArgs:n}),this.running||(this.commandPromise=new Promise((e=>{this.resolvePromise=e,this.run()})))}async wait(){this.running&&await this.commandPromise}async run(){for(this.running=!0;this.queue.length>0;){const e=v.getInstance(),t=this.queue.shift();if(!t)continue;if(t.checkInitialized){const t=(ye.debug("Check if initialized"),Ie&&v.initialized?{ok:!0,value:void 0}:l({code:"not_initialized",message:"Formbricks not initialized. Call initialize() first."}));t&&!0!==t.ok&&e.handle(t.error)}const n=async()=>await(null==t?void 0:t.command.apply(null,null==t?void 0:t.commandArgs)),s=await B(n)();s&&(s.ok&&s.data&&!s.data.ok&&e.handle(s.data.error),!0!==s.ok&&e.handle(s.error))}this.running=!1,this.resolvePromise&&(this.resolvePromise(),this.resolvePromise=null,this.commandPromise=null)}},He=async(e,t)=>{Se.add(!0,ve,e,t),await Se.wait()};return{init:async e=>{v.init(e.errorHandler),Se.add(!1,be,e),await Se.wait()},setUserId:async()=>{Se.add(!0,he),await Se.wait()},setEmail:async e=>{He("email",e),await Se.wait()},setAttribute:He,track:async(e,t={})=>{Se.add(!0,M,e,t),await Se.wait()},logout:async()=>{Se.add(!0,fe),await Se.wait()},reset:async()=>{Se.add(!0,we),await Se.wait()},registerRouteChange:async()=>{Se.add(!0,te),await Se.wait()},getApi:()=>{const e=w.getInstance(),{environmentId:t,apiHost:n}=e.get();if(!t||!n)throw new Error("formbricks.init() must be called before getApi()");return new d({apiHost:n,environmentId:t})}}}(); | ||
var formbricks=function(){"use strict";const e=e=>({ok:!1,error:e});async function t(t,n,s,i){const r=new URL(n,t),o=JSON.stringify(i),a=(d=fetch,(...e)=>{try{return{ok:!0,data:d(...e)}}catch(t){return{ok:!1,error:t}}})(r.toString(),{method:s,headers:{"Content-Type":"application/json"},body:o});var d;if(!1===a.ok)return e(a.error);const c=await a.data,{data:u}=await c.json();return c.ok?(e=>({ok:!0,data:e}))(u):e({code:"network_error",message:c.statusText,status:c.status,url:r})}class n{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/actions`,"POST",e)}}class s{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/displays`,"POST",e)}async update(e,n){return t(this.apiHost,`/api/v1/client/${this.environmentId}/displays/${e}`,"PUT",n)}}class i{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/people`,"POST",{environmentId:this.environmentId,userId:e})}async update(e,n){return t(this.apiHost,`/api/v1/client/${this.environmentId}/people/${e}`,"POST",n)}}class r{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/responses`,"POST",e)}async update({responseId:e,finished:n,data:s,ttc:i}){return t(this.apiHost,`/api/v1/client/${this.environmentId}/responses/${e}`,"PUT",{finished:n,data:s,ttc:i})}}class o{constructor(e,t){this.apiHost=e,this.environmentId=t}async uploadFile(e,{allowedFileExtensions:t,surveyId:n}={}){if(!(e instanceof Blob&&e instanceof File))throw new Error("Invalid file type. Expected Blob or File, but received "+typeof e);const s={fileName:e.name,fileType:e.type,allowedFileExtensions:t,surveyId:n},i=await fetch(`${this.apiHost}/api/v1/client/${this.environmentId}/storage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!i.ok)throw new Error(`Upload failed with status: ${i.status}`);const r=await i.json(),{data:o}=r,{signedUrl:a,fileUrl:d,signingData:c,presignedFields:u,updatedFileName:l}=o;let g={};if(c){const{signature:t,timestamp:s,uuid:i}=c;g={"X-File-Type":e.type,"X-File-Name":encodeURIComponent(l),"X-Survey-ID":n??"","X-Signature":t,"X-Timestamp":String(s),"X-UUID":i}}const p=new FormData;u&&Object.keys(u).forEach((e=>{p.append(e,u[e])})),p.append("file",e);const h=await fetch(a,{method:"POST",...c?{headers:g}:{},body:p});if(!h.ok){if(c){const e=await h.json(),t=new Error(e.message);throw t.name="FileTooLargeError",t}const e=await h.text();if(u&&e&&e.includes("EntityTooLarge")){const e=new Error("File size exceeds the size limit for your plan");throw e.name="FileTooLargeError",e}throw new Error(`Upload failed with status: ${h.status}`)}return d}}class a{constructor(e){const{apiHost:t,environmentId:a}=e;this.response=new r(t,a),this.display=new s(t,a),this.action=new n(t,a),this.people=new i(t,a),this.storage=new o(t,a)}}class d{constructor(e){this.client=new a(e)}}class c{constructor(){this.logLevel="error"}static getInstance(){return c.instance||(c.instance=new c),c.instance}configure(e){e&&void 0!==e.logLevel&&(this.logLevel=e.logLevel)}logger(e,t){if("debug"===t&&"debug"!==this.logLevel)return;const n=`🧱 Formbricks - ${(new Date).toISOString()} [${t.toUpperCase()}] - ${e}`;"error"===t?console.error(n):console.log(n)}debug(e){this.logger(e,"debug")}error(e){this.logger(e,"error")}}const u=e=>({ok:!0,value:e}),l=e=>({ok:!1,error:e});const g=e=>(...t)=>{try{return{ok:!0,value:e(...t)}}catch(n){return{ok:!1,error:n}}},p=c.getInstance(),h=class e{constructor(e){this.customized=!1,e?(this.handleError=e,this.customized=!0):this.handleError=e=>c.getInstance().error(JSON.stringify(e))}static getInstance(){return e.instance||(e.instance=new e),e.instance}static init(t){this.initialized=!0,e.instance=new e(t)}printStatus(){p.debug("Custom error handler: "+(this.customized?"yes":"no"))}handle(e){console.warn("🧱 Formbricks - Global error: ",e),this.handleError(e)}};h.initialized=!1;let v=h;const f="formbricks-js";class y{constructor(){this.config=null;const e=this.loadFromLocalStorage();e.ok&&(this.config=e.value)}static getInstance(){return y.instance||(y.instance=new y),y.instance}update(e){if(e){const t=new Date((new Date).getTime()+9e5);this.config={...this.config,...e,expiresAt:t},this.saveToLocalStorage()}}get(){if(!this.config)throw new Error("config is null, maybe the init function was not called?");return this.config}loadFromLocalStorage(){if("undefined"!=typeof window){const e=localStorage.getItem(f);if(e){const t=JSON.parse(e);return t.expiresAt&&new Date(t.expiresAt)<=new Date?l(new Error("Config in local storage has expired")):u(JSON.parse(e))}}return l(new Error("No or invalid config in local storage"))}saveToLocalStorage(){return g((()=>localStorage.setItem(f,JSON.stringify(this.config))))()}resetConfig(){return this.config=null,g((()=>localStorage.removeItem(f)))()}}const m=e=>new Promise((t=>setTimeout(t,e)));class w{constructor(e,t){this.queue=[],this.isRequestInProgress=!1,this.config=e,this.surveyState=t,this.api=new d({apiHost:e.apiHost,environmentId:e.environmentId})}add(e){this.surveyState.accumulateResponse(e),this.config.setSurveyState&&this.config.setSurveyState(this.surveyState),this.queue.push(e),this.processQueue()}async processQueue(){if(this.isRequestInProgress)return;if(0===this.queue.length)return;this.isRequestInProgress=!0;const e=this.queue[0];let t=0;for(;t<this.config.retryAttempts;){if(await this.sendResponse(e)){this.queue.shift();break}console.error("Formbricks: Failed to send response. Retrying...",t),await m(1e3),t++}t>=this.config.retryAttempts?(console.error("Failed to send response after 2 attempts."),this.config.onResponseSendingFailed&&this.config.onResponseSendingFailed(e),this.isRequestInProgress=!1):(this.isRequestInProgress=!1,this.processQueue())}async sendResponse(e){try{if(null!==this.surveyState.responseId)await this.api.client.response.update({...e,responseId:this.surveyState.responseId});else{const t=await this.api.client.response.create({...e,surveyId:this.surveyState.surveyId,userId:this.surveyState.userId||null,singleUseId:this.surveyState.singleUseId||null});if(!t.ok)throw new Error("Could not create response");this.surveyState.displayId&&await this.api.client.display.update(this.surveyState.displayId,{responseId:t.data.id}),this.surveyState.updateResponseId(t.data.id),this.config.setSurveyState&&this.config.setSurveyState(this.surveyState)}return!0}catch(t){return console.error(t),!1}}updateSurveyState(e){this.surveyState=e}}class I{constructor(e,t,n,s){this.responseId=null,this.displayId=null,this.userId=null,this.responseAcc={finished:!1,data:{},ttc:{}},this.surveyId=e,this.userId=s??null,this.singleUseId=t??null,this.responseId=n??null}setSurveyId(e){this.surveyId=e,this.clear()}copy(){const e=new I(this.surveyId,this.singleUseId??void 0,this.responseId??void 0,this.userId??void 0);return e.responseId=this.responseId,e.responseAcc=this.responseAcc,e}updateResponseId(e){this.responseId=e}updateDisplayId(e){this.displayId=e}updateUserId(e){this.userId=e}accumulateResponse(e){this.responseAcc={finished:e.finished,ttc:e.ttc,data:{...this.responseAcc.data,...e.data}}}isResponseFinished(){return this.responseAcc.finished}clear(){this.responseId=null,this.responseAcc={finished:!1,data:{},ttc:{}}}}const b=I,k=(e,t)=>{const n=Math.abs(t.getTime()-e.getTime());return Math.floor(n/864e5)},S=y.getInstance(),H=c.getInstance();let E=null;const C=async e=>{try{const n=await(async({apiHost:e,environmentId:t,userId:n})=>{const s=`${e}/api/v1/client/${t}/in-app/sync/${n}`,i=`${e}/api/v1/client/${t}/in-app/sync`;if(!n){const e=await fetch(i);if(!e.ok){const t=await e.json();return l({code:"network_error",status:e.status,message:"Error syncing with backend",url:s,responseMessage:t.message})}return u((await e.json()).data)}const r=await fetch(s);if(!r.ok){const e=await r.json();return l({code:"network_error",status:r.status,message:"Error syncing with backend",url:s,responseMessage:e.message})}const o=await r.json(),{data:a}=o;return u(a)})(e);if(!0!==(null==n?void 0:n.ok))throw H.error(`Sync failed: ${JSON.stringify(n.error)}`),n.error;let s;try{s=S.get().state}catch(t){}let i={surveys:n.value.surveys,noCodeActionClasses:n.value.noCodeActionClasses,product:n.value.product,attributes:(null==s?void 0:s.attributes)||{}};if(e.userId){const e=i.surveys.map((e=>e.name));H.debug("Fetched "+e.length+" surveys during sync: "+e.join(", "))}else{i={...i,displays:(null==s?void 0:s.displays)||[]},i=$(i);const e=i.surveys.map((e=>e.name));H.debug("Fetched "+e.length+" surveys during sync: "+e.join(", "))}S.update({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId,state:i})}catch(n){throw H.error(`Error during sync: ${n}`),n}},$=e=>{const{displays:t,product:n}=e;let{surveys:s}=e;if(!t)return e;let i=s.filter((e=>{if("respondMultiple"===e.displayOption)return!0;if("displayOnce"===e.displayOption)return 0===t.filter((t=>t.surveyId===e.id)).length;if("displayMultiple"===e.displayOption)return 0===t.filter((t=>t.surveyId===e.id&&t.responded)).length;throw Error("Invalid displayOption")}));const r=t.length>0?t[t.length-1]:void 0;return i=i.filter((e=>{if(r){if(null!==e.recontactDays){const n=t.filter((t=>t.surveyId===e.id))[0];return!n||k(new Date,new Date(n.createdAt))>=e.recontactDays}return null===n.recontactDays||k(new Date,new Date(r.createdAt))>=n.recontactDays}return!0})),{...e,surveys:i}},A=()=>{"undefined"!=typeof window&&null!==E&&(window.clearInterval(E),E=null)},F="formbricks-web-container",L=y.getInstance(),O=c.getInstance(),D=v.getInstance();let P=!1,U=e=>{};const x=async e=>{if(P)return void O.debug("A survey is already running. Skipping.");P=!0,e.delay&&O.debug(`Delaying survey by ${e.delay} seconds.`);const t=L.get().state.product,n=new b(e.id,null,null,L.get().userId),s=new w({apiHost:L.get().apiHost,environmentId:L.get().environmentId,retryAttempts:2,onResponseSendingFailed:()=>{U(!0)}},n),i=e.productOverwrites??{},r=i.brandColor??t.brandColor,o=i.highlightBorderColor??t.highlightBorderColor,a=i.clickOutsideClose??t.clickOutsideClose,c=i.darkOverlay??t.darkOverlay,u=i.placement??t.placement,l=t.inAppSurveyBranding,g=await R();setTimeout((()=>{g.renderSurveyModal({survey:e,brandColor:r,isBrandingEnabled:l,clickOutside:a,darkOverlay:c,highlightBorderColor:o,placement:u,getSetIsError:e=>{U=e},onDisplay:async()=>{const{userId:t}=L.get();if(!t){const t={createdAt:new Date,surveyId:e.id,responded:!1},n=L.get().state.displays,s=n?[...n,t]:[t],i=L.get();let r=$({...i.state,displays:s});L.update({...i,state:r})}const i=new d({apiHost:L.get().apiHost,environmentId:L.get().environmentId}),r=await i.client.display.create({surveyId:e.id,userId:t});if(!r.ok)throw new Error("Could not create display");const{id:o}=r.data;n.updateDisplayId(o),s.updateSurveyState(n)},onResponse:e=>{const{userId:t}=L.get();if(!t){const e=L.get().state.displays,t=e&&e[e.length-1];if(!t)throw new Error("No lastDisplay found");if(!t.responded){t.responded=!0;const n=L.get();let s=$({...n.state,displays:e});L.update({...n,state:s})}}t&&n.updateUserId(t),s.updateSurveyState(n),s.add({data:e.data,ttc:e.ttc,finished:e.finished})},onClose:T,onFileUpload:async(e,t)=>{const n=new d({apiHost:L.get().apiHost,environmentId:L.get().environmentId});return await n.client.storage.uploadFile(e,t)},onRetry:()=>{U(!1),s.processQueue()}})}),1e3*e.delay)},T=async()=>{var e;if(null==(e=document.getElementById(F))||e.remove(),N(),!L.get().userId){const e=L.get().state,t=$(e);return L.update({...L.get(),state:t}),void(P=!1)}try{await C({apiHost:L.get().apiHost,environmentId:L.get().environmentId,userId:L.get().userId}),P=!1}catch(t){D.handle(t)}},N=()=>{const e=document.createElement("div");e.id=F,document.body.appendChild(e)},R=()=>new Promise(((e,t)=>{if(window.formbricksSurveys)e(window.formbricksSurveys);else{const n=document.createElement("script");n.src="https://unpkg.com/@formbricks/surveys@^1.5.1/dist/index.umd.js",n.async=!0,n.onload=()=>e(window.formbricksSurveys),n.onerror=e=>{console.error("Failed to load Formbricks Surveys library:",e),t(e)},document.head.appendChild(n)}})),z=c.getInstance(),j=y.getInstance(),q=["Exit Intent (Desktop)","50% Scroll"],M=async(e,t={})=>{var n;const{userId:s}=j.get(),i={environmentId:j.get().environmentId,userId:s,name:e,properties:t||{}};if(s&&!q.includes(e)){z.debug(`Sending action "${e}" to backend`);const t=new d({apiHost:j.get().apiHost,environmentId:j.get().environmentId}),n=await t.client.action.create({...i,userId:s});if(!n.ok)return l({code:"network_error",message:`Error tracking action ${e}`,status:500,url:`${j.get().apiHost}/api/v1/client/${j.get().environmentId}/actions`,responseMessage:n.error.message})}z.debug(`Formbricks: Action "${e}" tracked`);const r=null==(n=j.get().state)?void 0:n.surveys;return r&&r.length>0?await _(e,r):z.debug("No active surveys to display"),{ok:!0,value:void 0}},_=async(e,t)=>{for(const s of t){if(s.displayPercentage){if(!(n=s.displayPercentage,Math.floor(100*Math.random())+1<=n)){z.debug("Survey display skipped based on displayPercentage.");continue}}for(const t of s.triggers)if(t===e)return z.debug(`Formbricks: survey ${s.id} triggered by action "${e}"`),void(await x(s))}var n},B=e=>async(...t)=>{try{return{ok:!0,data:await e(...t)}}catch(n){return{ok:!1,error:n}}};let J=!1,X=async function(e){if(e.clientY<=0){const e=await M("Exit Intent (Desktop)");if(!0!==e.ok)return l(e.error)}};const Q=()=>{J&&(document.removeEventListener("mouseleave",X),J=!1)};let W=!1,Y=!1,G=async()=>{const e=window.scrollY,t=window.innerHeight,n=document.documentElement.scrollHeight;if(0===e&&(Y=!1),!Y&&e/(n-t)>=.5){Y=!0;const e=await M("50% Scroll");if(!0!==e.ok)return l(e.error)}};const K=()=>{W&&(window.removeEventListener("scroll",G),W=!1)},V=y.getInstance(),Z=c.getInstance(),ee=v.getInstance(),te=async()=>{var e;Z.debug(`Checking page url: ${window.location.href}`);const{state:t}=V.get();if(void 0===(null==t?void 0:t.noCodeActionClasses))return{ok:!0,value:void 0};const n=((null==t?void 0:t.noCodeActionClasses)||[]).filter((e=>{const{innerHtml:t,cssSelector:n,pageUrl:s}=e.noCodeConfig||{};return s&&!t&&!n}));if(0===n.length)return{ok:!0,value:void 0};for(const s of n){if(!(null==(e=s.noCodeConfig)?void 0:e.pageUrl))continue;const{noCodeConfig:{pageUrl:t}}=s,n=re(window.location.href,t.value,t.rule);if(!0!==n.ok)return l(n.error);if(!1===n.value)continue;const i=await M(s.name);if(!0!==i.ok)return l(i.error)}return{ok:!0,value:void 0}};let ne=!1;const se=()=>te(),ie=()=>{"undefined"!=typeof window&&ne&&(window.removeEventListener("hashchange",se),window.removeEventListener("popstate",se),window.removeEventListener("pushstate",se),window.removeEventListener("replacestate",se),window.removeEventListener("load",se),ne=!1)};function re(e,t,n){switch(n){case"exactMatch":return u(e===t);case"contains":return u(e.includes(t));case"startsWith":return u(e.startsWith(t));case"endsWith":return u(e.endsWith(t));case"notMatch":return u(e!==t);case"notContains":return u(!e.includes(t));default:return l({code:"invalid_match_type",message:"Invalid match type"})}}let oe=!1;const ae=e=>(e=>{const{state:t}=V.get();if(!t)return;const n=e.target;((null==t?void 0:t.noCodeActionClasses)||[]).forEach((e=>{var t,s,i,r,o,a,d,c;const u=null==(s=null==(t=e.noCodeConfig)?void 0:t.innerHtml)?void 0:s.value,l=null==(r=null==(i=e.noCodeConfig)?void 0:i.cssSelector)?void 0:r.value,g=null==(a=null==(o=e.noCodeConfig)?void 0:o.pageUrl)?void 0:a.value,p=null==(c=null==(d=e.noCodeConfig)?void 0:d.pageUrl)?void 0:c.rule;if((u||l||g)&&(!u||n.innerHTML===u)){if(l){const e=l.split(/\s*(?=[.#])/);for(let t of e)if(!n.matches(t))return}if(g&&p){const e=re(window.location.href,g,p);if(!e.ok||!e.value)return}M(e.name).then((e=>{var t,n,s;n=e=>{},s=e=>{ee.handle(e)},!0===(t=e).ok?n(t.value):s(t.error)}))}}))})(e),de=()=>{oe&&(document.removeEventListener("click",ae),oe=!1)};let ce=!1;const ue=()=>{"undefined"!=typeof window&&null===E&&(E=window.setInterval((async()=>{S.get().expiresAt&&new Date(S.get().expiresAt)>=new Date||(H.debug("Config has expired. Starting sync."),await C({apiHost:S.get().apiHost,environmentId:S.get().environmentId,userId:S.get().userId}))}),6e4)),"undefined"==typeof window||ne||(window.addEventListener("hashchange",se),window.addEventListener("popstate",se),window.addEventListener("pushstate",se),window.addEventListener("replacestate",se),window.addEventListener("load",se),ne=!0),"undefined"==typeof window||oe||(document.addEventListener("click",ae),oe=!0),"undefined"==typeof document||J||(document.querySelector("body").addEventListener("mouseleave",X),J=!0),"undefined"==typeof window||W||(window.addEventListener("load",(()=>{window.addEventListener("scroll",G)})),W=!0)},le=()=>{A(),ie(),de(),Q(),K(),ce&&(window.removeEventListener("beforeunload",(()=>{A(),ie(),de(),Q(),K()})),ce=!1)},ge=y.getInstance(),pe=c.getInstance(),he=async()=>(pe.error("'setUserId' is no longer supported. Please set the userId in the init call instead."),{ok:!0,value:void 0}),ve=async(e,t)=>{if(pe.debug("Setting attribute: "+e+" to value: "+t),((e,t)=>ge.get().state.attributes[e]===t)(e,t.toString()))return pe.debug("Attribute already set to this value. Skipping update."),{ok:!0,value:void 0};const n=await(async(e,t)=>{const{apiHost:n,environmentId:s,userId:i}=ge.get();if(!i)return l({code:"missing_person",message:"Unable to update attribute. User identification deactivated. No userId set."});const r={attributes:{[e]:t}},o=new d({apiHost:ge.get().apiHost,environmentId:ge.get().environmentId}),a=await o.client.people.update(i,r);return a.ok?(pe.debug("Attribute updated. Syncing..."),await C({environmentId:s,apiHost:n,userId:i}),{ok:!0,value:void 0}):l({code:"network_error",status:500,message:`Error updating person with userId ${i}`,url:`${ge.get().apiHost}/api/v1/client/${s}/people/${i}`,responseMessage:a.error.message})})(e,t.toString());return n.ok?(ge.update({environmentId:ge.get().environmentId,apiHost:ge.get().apiHost,userId:ge.get().userId,state:{...ge.get().state,attributes:{...ge.get().state.attributes,[e]:t.toString()}}}),{ok:!0,value:void 0}):l(n.error)},fe=async()=>{ke()},ye=async()=>{pe.debug("Resetting state & getting new state from backend"),T();const e={environmentId:ge.get().environmentId,apiHost:ge.get().apiHost,userId:ge.get().userId};await fe();try{return await be(e),{ok:!0,value:void 0}}catch(t){return l(t)}},me=y.getInstance(),we=c.getInstance();let Ie=!1;const be=async e=>{if(Ie)return we.debug("Already initialized, skipping initialization."),{ok:!0,value:void 0};if((e=>{e.debug&&(we.debug("Setting log level to debug"),we.configure({logLevel:"debug"}))})(e),v.getInstance().printStatus(),we.debug("Start initialize"),!e.environmentId)return we.debug("No environmentId provided"),l({code:"missing_field",field:"environmentId"});if(!e.apiHost)return we.debug("No apiHost provided"),l({code:"missing_field",field:"apiHost"});if(we.debug("Adding widget container to DOM"),N(),!e.userId&&e.attributes)return we.error("No userId provided but attributes. Cannot update attributes without userId."),l({code:"missing_field",field:"userId"});let t,n=null;if(e.userId&&e.attributes){const t=await(async(e,t,n,s)=>{var i,r;if(!n)return l({code:"missing_person",message:"Unable to update attribute. User identification deactivated. No userId set."});const o={...s};try{const e=null==(r=null==(i=ge.get())?void 0:i.state)?void 0:r.attributes;if(e)for(const[t,n]of Object.entries(e))o[t]===n&&delete o[t]}catch(p){pe.debug("config not set; sending all attributes to backend")}if(0===Object.keys(o).length)return pe.debug("No attributes to update. Skipping update."),u(o);pe.debug("Updating attributes: "+JSON.stringify(o));const a={attributes:o},c=new d({apiHost:e,environmentId:t}),g=await c.client.people.update(n,a);return g.ok?u(o):l({code:"network_error",status:500,message:`Error updating person with userId ${n}`,url:`${e}/api/v1/client/${t}/people/${n}`,responseMessage:g.error.message})})(e.apiHost,e.environmentId,e.userId,e.attributes);if(!0!==t.ok)return l(t.error);n=t.value}try{t=me.get()}catch(s){we.debug("No existing configuration found.")}return t&&t.state&&t.environmentId===e.environmentId&&t.apiHost===e.apiHost&&t.userId===e.userId&&t.expiresAt?(we.debug("Found existing configuration."),t.expiresAt<new Date?(we.debug("Configuration expired."),await C({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId})):(we.debug("Configuration not expired. Extending expiration."),me.update(t))):(we.debug("No valid configuration found or it has been expired. Creating new config."),we.debug("Syncing."),await C({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId}),await M("New Session")),n&&Object.keys(n).length>0&&me.update({environmentId:me.get().environmentId,apiHost:me.get().apiHost,userId:me.get().userId,state:{...me.get().state,attributes:{...me.get().state.attributes,...e.attributes}}}),we.debug("Adding event listeners"),ue(),ce||(window.addEventListener("beforeunload",(()=>{A(),ie(),de(),Q(),K()})),ce=!0),Ie=!0,we.debug("Initialized"),te(),{ok:!0,value:void 0}},ke=()=>{we.debug("Deinitializing"),T(),le(),me.resetConfig(),Ie=!1};c.getInstance().debug("Create command queue");const Se=new class{constructor(){this.queue=[],this.running=!1,this.resolvePromise=null,this.commandPromise=null}add(e=!0,t,...n){this.queue.push({command:t,checkInitialized:e,commandArgs:n}),this.running||(this.commandPromise=new Promise((e=>{this.resolvePromise=e,this.run()})))}async wait(){this.running&&await this.commandPromise}async run(){for(this.running=!0;this.queue.length>0;){const e=v.getInstance(),t=this.queue.shift();if(!t)continue;if(t.checkInitialized){const t=(we.debug("Check if initialized"),Ie&&v.initialized?{ok:!0,value:void 0}:l({code:"not_initialized",message:"Formbricks not initialized. Call initialize() first."}));t&&!0!==t.ok&&e.handle(t.error)}const n=async()=>await(null==t?void 0:t.command.apply(null,null==t?void 0:t.commandArgs)),s=await B(n)();s&&(s.ok&&s.data&&!s.data.ok&&e.handle(s.data.error),!0!==s.ok&&e.handle(s.error))}this.running=!1,this.resolvePromise&&(this.resolvePromise(),this.resolvePromise=null,this.commandPromise=null)}},He=async(e,t)=>{Se.add(!0,ve,e,t),await Se.wait()};return{init:async e=>{v.init(e.errorHandler),Se.add(!1,be,e),await Se.wait()},setUserId:async()=>{Se.add(!0,he),await Se.wait()},setEmail:async e=>{He("email",e),await Se.wait()},setAttribute:He,track:async(e,t={})=>{Se.add(!0,M,e,t),await Se.wait()},logout:async()=>{Se.add(!0,fe),await Se.wait()},reset:async()=>{Se.add(!0,ye),await Se.wait()},registerRouteChange:async()=>{Se.add(!0,te),await Se.wait()},getApi:()=>{const e=y.getInstance(),{environmentId:t,apiHost:n}=e.get();if(!t||!n)throw new Error("formbricks.init() must be called before getApi()");return new d({apiHost:n,environmentId:t})}}}(); | ||
//# sourceMappingURL=index.iife.js.map |
@@ -1,2 +0,2 @@ | ||
"use strict";const e=e=>({ok:!1,error:e});async function t(t,n,s,i){const r=new URL(n,t),o=JSON.stringify(i),a=(d=fetch,(...e)=>{try{return{ok:!0,data:d(...e)}}catch(t){return{ok:!1,error:t}}})(r.toString(),{method:s,headers:{"Content-Type":"application/json"},body:o});var d;if(!1===a.ok)return e(a.error);const c=await a.data,{data:u}=await c.json();return c.ok?(e=>({ok:!0,data:e}))(u):e({code:"network_error",message:c.statusText,status:c.status,url:r})}class n{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/actions`,"POST",e)}}class s{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/displays`,"POST",e)}async update(e,n){return t(this.apiHost,`/api/v1/client/${this.environmentId}/displays/${e}`,"PUT",n)}}class i{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/people`,"POST",{environmentId:this.environmentId,userId:e})}async update(e,n){return t(this.apiHost,`/api/v1/client/${this.environmentId}/people/${e}`,"POST",n)}}class r{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/responses`,"POST",e)}async update({responseId:e,finished:n,data:s,ttc:i}){return t(this.apiHost,`/api/v1/client/${this.environmentId}/responses/${e}`,"PUT",{finished:n,data:s,ttc:i})}}class o{constructor(e,t){this.apiHost=e,this.environmentId=t}async uploadFile(e,{allowedFileExtensions:t,surveyId:n}={}){if(!(e instanceof Blob&&e instanceof File))throw new Error("Invalid file type. Expected Blob or File, but received "+typeof e);const s={fileName:e.name,fileType:e.type,allowedFileExtensions:t,surveyId:n},i=await fetch(`${this.apiHost}/api/v1/client/${this.environmentId}/storage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!i.ok)throw new Error(`Upload failed with status: ${i.status}`);const r=await i.json(),{data:o}=r,{signedUrl:a,fileUrl:d,signingData:c,presignedFields:u,updatedFileName:l}=o;let g={};if(c){const{signature:t,timestamp:s,uuid:i}=c;g={"X-File-Type":e.type,"X-File-Name":encodeURIComponent(l),"X-Survey-ID":n??"","X-Signature":t,"X-Timestamp":String(s),"X-UUID":i}}const p=new FormData;u&&Object.keys(u).forEach((e=>{p.append(e,u[e])})),p.append("file",e);const h=await fetch(a,{method:"POST",...c?{headers:g}:{},body:p});if(!h.ok){if(c){const e=await h.json(),t=new Error(e.message);throw t.name="FileTooLargeError",t}const e=await h.text();if(u&&e&&e.includes("EntityTooLarge")){const e=new Error("File size exceeds the size limit for your plan");throw e.name="FileTooLargeError",e}throw new Error(`Upload failed with status: ${h.status}`)}return d}}class a{constructor(e){const{apiHost:t,environmentId:a}=e;this.response=new r(t,a),this.display=new s(t,a),this.action=new n(t,a),this.people=new i(t,a),this.storage=new o(t,a)}}class d{constructor(e){this.client=new a(e)}}class c{constructor(){this.logLevel="error"}static getInstance(){return c.instance||(c.instance=new c),c.instance}configure(e){e&&void 0!==e.logLevel&&(this.logLevel=e.logLevel)}logger(e,t){if("debug"===t&&"debug"!==this.logLevel)return;const n=`🧱 Formbricks - ${(new Date).toISOString()} [${t.toUpperCase()}] - ${e}`;"error"===t?console.error(n):console.log(n)}debug(e){this.logger(e,"debug")}error(e){this.logger(e,"error")}}const u=e=>({ok:!0,value:e}),l=e=>({ok:!1,error:e});const g=e=>(...t)=>{try{return{ok:!0,value:e(...t)}}catch(n){return{ok:!1,error:n}}},p=c.getInstance(),h=class e{constructor(e){this.customized=!1,e?(this.handleError=e,this.customized=!0):this.handleError=e=>c.getInstance().error(JSON.stringify(e))}static getInstance(){return e.instance||(e.instance=new e),e.instance}static init(t){this.initialized=!0,e.instance=new e(t)}printStatus(){p.debug("Custom error handler: "+(this.customized?"yes":"no"))}handle(e){console.warn("🧱 Formbricks - Global error: ",e),this.handleError(e)}};h.initialized=!1;let v=h;const w="formbricks-js";class f{constructor(){this.config=null;const e=this.loadFromLocalStorage();e.ok&&(this.config=e.value)}static getInstance(){return f.instance||(f.instance=new f),f.instance}update(e){if(e){const t=new Date((new Date).getTime()+9e5);this.config={...this.config,...e,expiresAt:t},this.saveToLocalStorage()}}get(){if(!this.config)throw new Error("config is null, maybe the init function was not called?");return this.config}loadFromLocalStorage(){if("undefined"!=typeof window){const e=localStorage.getItem(w);if(e){const t=JSON.parse(e);return t.expiresAt&&new Date(t.expiresAt)<=new Date?l(new Error("Config in local storage has expired")):u(JSON.parse(e))}}return l(new Error("No or invalid config in local storage"))}saveToLocalStorage(){return g((()=>localStorage.setItem(w,JSON.stringify(this.config))))()}resetConfig(){return this.config=null,g((()=>localStorage.removeItem(w)))()}}const m=e=>new Promise((t=>setTimeout(t,e)));class y{constructor(e,t){this.queue=[],this.isRequestInProgress=!1,this.config=e,this.surveyState=t,this.api=new d({apiHost:e.apiHost,environmentId:e.environmentId})}add(e){this.surveyState.accumulateResponse(e),this.config.setSurveyState&&this.config.setSurveyState(this.surveyState),this.queue.push(e),this.processQueue()}async processQueue(){if(this.isRequestInProgress)return;if(0===this.queue.length)return;this.isRequestInProgress=!0;const e=this.queue[0];let t=0;for(;t<this.config.retryAttempts;){if(await this.sendResponse(e)){this.queue.shift();break}console.error("Formbricks: Failed to send response. Retrying...",t),await m(1e3),t++}t>=this.config.retryAttempts?(console.error("Failed to send response after 2 attempts."),this.config.onResponseSendingFailed&&this.config.onResponseSendingFailed(e),this.isRequestInProgress=!1):(this.isRequestInProgress=!1,this.processQueue())}async sendResponse(e){try{if(null!==this.surveyState.responseId)await this.api.client.response.update({...e,responseId:this.surveyState.responseId});else{const t=await this.api.client.response.create({...e,surveyId:this.surveyState.surveyId,userId:this.surveyState.userId||null,singleUseId:this.surveyState.singleUseId||null});if(!t.ok)throw new Error("Could not create response");this.surveyState.displayId&&await this.api.client.display.update(this.surveyState.displayId,{responseId:t.data.id}),this.surveyState.updateResponseId(t.data.id),this.config.setSurveyState&&this.config.setSurveyState(this.surveyState)}return!0}catch(t){return console.error(t),!1}}updateSurveyState(e){this.surveyState=e}}class I{constructor(e,t,n,s){this.responseId=null,this.displayId=null,this.userId=null,this.responseAcc={finished:!1,data:{},ttc:{}},this.surveyId=e,this.userId=s??null,this.singleUseId=t??null,this.responseId=n??null}setSurveyId(e){this.surveyId=e,this.clear()}copy(){const e=new I(this.surveyId,this.singleUseId??void 0,this.responseId??void 0,this.userId??void 0);return e.responseId=this.responseId,e.responseAcc=this.responseAcc,e}updateResponseId(e){this.responseId=e}updateDisplayId(e){this.displayId=e}updateUserId(e){this.userId=e}accumulateResponse(e){this.responseAcc={finished:e.finished,ttc:e.ttc,data:{...this.responseAcc.data,...e.data}}}isResponseFinished(){return this.responseAcc.finished}clear(){this.responseId=null,this.responseAcc={finished:!1,data:{},ttc:{}}}}const b=I,k=(e,t)=>{const n=Math.abs(t.getTime()-e.getTime());return Math.floor(n/864e5)},S=f.getInstance(),H=c.getInstance();let E=null;const C=async e=>{try{const n=await(async({apiHost:e,environmentId:t,userId:n})=>{const s=`${e}/api/v1/client/${t}/in-app/sync/${n}`,i=`${e}/api/v1/client/${t}/in-app/sync`;if(!n){const e=await fetch(i);if(!e.ok){const t=await e.json();return l({code:"network_error",status:e.status,message:"Error syncing with backend",url:s,responseMessage:t.message})}return u((await e.json()).data)}const r=await fetch(s);if(!r.ok){const e=await r.json();return l({code:"network_error",status:r.status,message:"Error syncing with backend",url:s,responseMessage:e.message})}const o=await r.json(),{data:a}=o;return u(a)})(e);if(!0!==(null==n?void 0:n.ok))throw H.error(`Sync failed: ${JSON.stringify(n.error)}`),n.error;let s;try{s=S.get().state}catch(t){}let i={surveys:n.value.surveys,noCodeActionClasses:n.value.noCodeActionClasses,product:n.value.product,attributes:(null==s?void 0:s.attributes)||{}};if(e.userId){const e=i.surveys.map((e=>e.name));H.debug("Fetched "+e.length+" surveys during sync: "+e.join(", "))}else{i={...i,displays:(null==s?void 0:s.displays)||[]},i=$(i);const e=i.surveys.map((e=>e.name));H.debug("Fetched "+e.length+" surveys during sync: "+e.join(", "))}S.update({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId,state:i})}catch(n){throw H.error(`Error during sync: ${n}`),n}},$=e=>{const{displays:t,product:n}=e;let{surveys:s}=e;if(!t)return e;let i=s.filter((e=>{if("respondMultiple"===e.displayOption)return!0;if("displayOnce"===e.displayOption)return 0===t.filter((t=>t.surveyId===e.id)).length;if("displayMultiple"===e.displayOption)return 0===t.filter((t=>t.surveyId===e.id&&t.responded)).length;throw Error("Invalid displayOption")}));const r=t.length>0?t[t.length-1]:void 0;return i=i.filter((e=>{if(r){if(null!==e.recontactDays){const n=t.filter((t=>t.surveyId===e.id))[0];return!n||k(new Date,new Date(n.createdAt))>=e.recontactDays}return null===n.recontactDays||k(new Date,new Date(r.createdAt))>=n.recontactDays}return!0})),{...e,surveys:i}},A=()=>{"undefined"!=typeof window&&null!==E&&(window.clearInterval(E),E=null)},F="formbricks-web-container",L=f.getInstance(),O=c.getInstance(),D=v.getInstance();let U=!1,x=e=>{};const P=async e=>{if(U)return void O.debug("A survey is already running. Skipping.");U=!0,e.delay&&O.debug(`Delaying survey by ${e.delay} seconds.`);const t=L.get().state.product,n=new b(e.id,null,null,L.get().userId),s=new y({apiHost:L.get().apiHost,environmentId:L.get().environmentId,retryAttempts:2,onResponseSendingFailed:()=>{x(!0)}},n),i=e.productOverwrites??{},r=i.brandColor??t.brandColor,o=i.highlightBorderColor??t.highlightBorderColor,a=i.clickOutsideClose??t.clickOutsideClose,c=i.darkOverlay??t.darkOverlay,u=i.placement??t.placement,l=t.inAppSurveyBranding,g=await R();setTimeout((()=>{g.renderSurveyModal({survey:e,brandColor:r,isBrandingEnabled:l,clickOutside:a,darkOverlay:c,highlightBorderColor:o,placement:u,getSetIsError:e=>{x=e},onDisplay:async()=>{const{userId:t}=L.get();if(!t){const t={createdAt:new Date,surveyId:e.id,responded:!1},n=L.get().state.displays,s=n?[...n,t]:[t],i=L.get();let r=$({...i.state,displays:s});L.update({...i,state:r})}const i=new d({apiHost:L.get().apiHost,environmentId:L.get().environmentId}),r=await i.client.display.create({surveyId:e.id,userId:t});if(!r.ok)throw new Error("Could not create display");const{id:o}=r.data;n.updateDisplayId(o),s.updateSurveyState(n)},onResponse:e=>{const{userId:t}=L.get();if(!t){const e=L.get().state.displays,t=e&&e[e.length-1];if(!t)throw new Error("No lastDisplay found");if(!t.responded){t.responded=!0;const n=L.get();let s=$({...n.state,displays:e});L.update({...n,state:s})}}t&&n.updateUserId(t),s.updateSurveyState(n),s.add({data:e.data,ttc:e.ttc,finished:e.finished})},onClose:T,onFileUpload:async(e,t)=>{const n=new d({apiHost:L.get().apiHost,environmentId:L.get().environmentId});return await n.client.storage.uploadFile(e,t)},onRetry:()=>{x(!1),s.processQueue()}})}),1e3*e.delay)},T=async()=>{var e;if(null==(e=document.getElementById(F))||e.remove(),N(),!L.get().userId){const e=L.get().state,t=$(e);return L.update({...L.get(),state:t}),void(U=!1)}try{await C({apiHost:L.get().apiHost,environmentId:L.get().environmentId,userId:L.get().userId}),U=!1}catch(t){D.handle(t)}},N=()=>{const e=document.createElement("div");e.id=F,document.body.appendChild(e)},R=()=>new Promise(((e,t)=>{if(window.formbricksSurveys)e(window.formbricksSurveys);else{const n=document.createElement("script");n.src="https://unpkg.com/@formbricks/surveys@^1.5.0/dist/index.umd.js",n.async=!0,n.onload=()=>e(window.formbricksSurveys),n.onerror=e=>{console.error("Failed to load Formbricks Surveys library:",e),t(e)},document.head.appendChild(n)}})),z=c.getInstance(),j=f.getInstance(),q=["Exit Intent (Desktop)","50% Scroll"],M=async(e,t={})=>{var n;const{userId:s}=j.get(),i={environmentId:j.get().environmentId,userId:s,name:e,properties:t||{}};if(s&&!q.includes(e)){z.debug(`Sending action "${e}" to backend`);const t=new d({apiHost:j.get().apiHost,environmentId:j.get().environmentId}),n=await t.client.action.create({...i,userId:s});if(!n.ok)return l({code:"network_error",message:`Error tracking action ${e}`,status:500,url:`${j.get().apiHost}/api/v1/client/${j.get().environmentId}/actions`,responseMessage:n.error.message})}z.debug(`Formbricks: Action "${e}" tracked`);const r=null==(n=j.get().state)?void 0:n.surveys;return r&&r.length>0?await _(e,r):z.debug("No active surveys to display"),{ok:!0,value:void 0}},_=async(e,t)=>{for(const n of t)for(const t of n.triggers)if(t===e)return z.debug(`Formbricks: survey ${n.id} triggered by action "${e}"`),void(await P(n))},B=e=>async(...t)=>{try{return{ok:!0,data:await e(...t)}}catch(n){return{ok:!1,error:n}}};let J=!1,X=async function(e){if(e.clientY<=0){const e=await M("Exit Intent (Desktop)");if(!0!==e.ok)return l(e.error)}};const Q=()=>{J&&(document.removeEventListener("mouseleave",X),J=!1)};let W=!1,Y=!1,G=async()=>{const e=window.scrollY,t=window.innerHeight,n=document.documentElement.scrollHeight;if(0===e&&(Y=!1),!Y&&e/(n-t)>=.5){Y=!0;const e=await M("50% Scroll");if(!0!==e.ok)return l(e.error)}};const K=()=>{W&&(window.removeEventListener("scroll",G),W=!1)},V=f.getInstance(),Z=c.getInstance(),ee=v.getInstance(),te=async()=>{var e;Z.debug(`Checking page url: ${window.location.href}`);const{state:t}=V.get();if(void 0===(null==t?void 0:t.noCodeActionClasses))return{ok:!0,value:void 0};const n=((null==t?void 0:t.noCodeActionClasses)||[]).filter((e=>{const{innerHtml:t,cssSelector:n,pageUrl:s}=e.noCodeConfig||{};return s&&!t&&!n}));if(0===n.length)return{ok:!0,value:void 0};for(const s of n){if(!(null==(e=s.noCodeConfig)?void 0:e.pageUrl))continue;const{noCodeConfig:{pageUrl:t}}=s,n=re(window.location.href,t.value,t.rule);if(!0!==n.ok)return l(n.error);if(!1===n.value)continue;const i=await M(s.name);if(!0!==i.ok)return l(i.error)}return{ok:!0,value:void 0}};let ne=!1;const se=()=>te(),ie=()=>{"undefined"!=typeof window&&ne&&(window.removeEventListener("hashchange",se),window.removeEventListener("popstate",se),window.removeEventListener("pushstate",se),window.removeEventListener("replacestate",se),window.removeEventListener("load",se),ne=!1)};function re(e,t,n){switch(n){case"exactMatch":return u(e===t);case"contains":return u(e.includes(t));case"startsWith":return u(e.startsWith(t));case"endsWith":return u(e.endsWith(t));case"notMatch":return u(e!==t);case"notContains":return u(!e.includes(t));default:return l({code:"invalid_match_type",message:"Invalid match type"})}}let oe=!1;const ae=e=>(e=>{const{state:t}=V.get();if(!t)return;const n=e.target;((null==t?void 0:t.noCodeActionClasses)||[]).forEach((e=>{var t,s,i,r,o,a,d,c;const u=null==(s=null==(t=e.noCodeConfig)?void 0:t.innerHtml)?void 0:s.value,l=null==(r=null==(i=e.noCodeConfig)?void 0:i.cssSelector)?void 0:r.value,g=null==(a=null==(o=e.noCodeConfig)?void 0:o.pageUrl)?void 0:a.value,p=null==(c=null==(d=e.noCodeConfig)?void 0:d.pageUrl)?void 0:c.rule;if((u||l||g)&&(!u||n.innerHTML===u)){if(l){const e=l.split(/\s*(?=[.#])/);for(let t of e)if(!n.matches(t))return}if(g&&p){const e=re(window.location.href,g,p);if(!e.ok||!e.value)return}M(e.name).then((e=>{var t,n,s;n=e=>{},s=e=>{ee.handle(e)},!0===(t=e).ok?n(t.value):s(t.error)}))}}))})(e),de=()=>{oe&&(document.removeEventListener("click",ae),oe=!1)};let ce=!1;const ue=()=>{"undefined"!=typeof window&&null===E&&(E=window.setInterval((async()=>{S.get().expiresAt&&new Date(S.get().expiresAt)>=new Date||(H.debug("Config has expired. Starting sync."),await C({apiHost:S.get().apiHost,environmentId:S.get().environmentId,userId:S.get().userId}))}),6e4)),"undefined"==typeof window||ne||(window.addEventListener("hashchange",se),window.addEventListener("popstate",se),window.addEventListener("pushstate",se),window.addEventListener("replacestate",se),window.addEventListener("load",se),ne=!0),"undefined"==typeof window||oe||(document.addEventListener("click",ae),oe=!0),"undefined"==typeof document||J||(document.querySelector("body").addEventListener("mouseleave",X),J=!0),"undefined"==typeof window||W||(window.addEventListener("load",(()=>{window.addEventListener("scroll",G)})),W=!0)},le=()=>{A(),ie(),de(),Q(),K(),ce&&(window.removeEventListener("beforeunload",(()=>{A(),ie(),de(),Q(),K()})),ce=!1)},ge=f.getInstance(),pe=c.getInstance(),he=async()=>(pe.error("'setUserId' is no longer supported. Please set the userId in the init call instead."),{ok:!0,value:void 0}),ve=async(e,t)=>{if(pe.debug("Setting attribute: "+e+" to value: "+t),((e,t)=>ge.get().state.attributes[e]===t)(e,t.toString()))return pe.debug("Attribute already set to this value. Skipping update."),{ok:!0,value:void 0};const n=await(async(e,t)=>{const{apiHost:n,environmentId:s,userId:i}=ge.get();if(!i)return l({code:"missing_person",message:"Unable to update attribute. User identification deactivated. No userId set."});const r={attributes:{[e]:t}},o=new d({apiHost:ge.get().apiHost,environmentId:ge.get().environmentId}),a=await o.client.people.update(i,r);return a.ok?(pe.debug("Attribute updated. Syncing..."),await C({environmentId:s,apiHost:n,userId:i}),{ok:!0,value:void 0}):l({code:"network_error",status:500,message:`Error updating person with userId ${i}`,url:`${ge.get().apiHost}/api/v1/client/${s}/people/${i}`,responseMessage:a.error.message})})(e,t.toString());return n.ok?(ge.update({environmentId:ge.get().environmentId,apiHost:ge.get().apiHost,userId:ge.get().userId,state:{...ge.get().state,attributes:{...ge.get().state.attributes,[e]:t.toString()}}}),{ok:!0,value:void 0}):l(n.error)},we=async()=>{ke()},fe=async()=>{pe.debug("Resetting state & getting new state from backend"),T();const e={environmentId:ge.get().environmentId,apiHost:ge.get().apiHost,userId:ge.get().userId};await we();try{return await be(e),{ok:!0,value:void 0}}catch(t){return l(t)}},me=f.getInstance(),ye=c.getInstance();let Ie=!1;const be=async e=>{if(Ie)return ye.debug("Already initialized, skipping initialization."),{ok:!0,value:void 0};if((e=>{e.debug&&(ye.debug("Setting log level to debug"),ye.configure({logLevel:"debug"}))})(e),v.getInstance().printStatus(),ye.debug("Start initialize"),!e.environmentId)return ye.debug("No environmentId provided"),l({code:"missing_field",field:"environmentId"});if(!e.apiHost)return ye.debug("No apiHost provided"),l({code:"missing_field",field:"apiHost"});if(ye.debug("Adding widget container to DOM"),N(),!e.userId&&e.attributes)return ye.error("No userId provided but attributes. Cannot update attributes without userId."),l({code:"missing_field",field:"userId"});let t,n=null;if(e.userId&&e.attributes){const t=await(async(e,t,n,s)=>{var i,r;if(!n)return l({code:"missing_person",message:"Unable to update attribute. User identification deactivated. No userId set."});const o={...s};try{const e=null==(r=null==(i=ge.get())?void 0:i.state)?void 0:r.attributes;if(e)for(const[t,n]of Object.entries(e))o[t]===n&&delete o[t]}catch(p){pe.debug("config not set; sending all attributes to backend")}if(0===Object.keys(o).length)return pe.debug("No attributes to update. Skipping update."),u(o);pe.debug("Updating attributes: "+JSON.stringify(o));const a={attributes:o},c=new d({apiHost:e,environmentId:t}),g=await c.client.people.update(n,a);return g.ok?u(o):l({code:"network_error",status:500,message:`Error updating person with userId ${n}`,url:`${e}/api/v1/client/${t}/people/${n}`,responseMessage:g.error.message})})(e.apiHost,e.environmentId,e.userId,e.attributes);if(!0!==t.ok)return l(t.error);n=t.value}try{t=me.get()}catch(s){ye.debug("No existing configuration found.")}return t&&t.state&&t.environmentId===e.environmentId&&t.apiHost===e.apiHost&&t.userId===e.userId&&t.expiresAt?(ye.debug("Found existing configuration."),t.expiresAt<new Date?(ye.debug("Configuration expired."),await C({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId})):(ye.debug("Configuration not expired. Extending expiration."),me.update(t))):(ye.debug("No valid configuration found or it has been expired. Creating new config."),ye.debug("Syncing."),await C({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId}),await M("New Session")),n&&Object.keys(n).length>0&&me.update({environmentId:me.get().environmentId,apiHost:me.get().apiHost,userId:me.get().userId,state:{...me.get().state,attributes:{...me.get().state.attributes,...e.attributes}}}),ye.debug("Adding event listeners"),ue(),ce||(window.addEventListener("beforeunload",(()=>{A(),ie(),de(),Q(),K()})),ce=!0),Ie=!0,ye.debug("Initialized"),te(),{ok:!0,value:void 0}},ke=()=>{ye.debug("Deinitializing"),T(),le(),me.resetConfig(),Ie=!1};c.getInstance().debug("Create command queue");const Se=new class{constructor(){this.queue=[],this.running=!1,this.resolvePromise=null,this.commandPromise=null}add(e=!0,t,...n){this.queue.push({command:t,checkInitialized:e,commandArgs:n}),this.running||(this.commandPromise=new Promise((e=>{this.resolvePromise=e,this.run()})))}async wait(){this.running&&await this.commandPromise}async run(){for(this.running=!0;this.queue.length>0;){const e=v.getInstance(),t=this.queue.shift();if(!t)continue;if(t.checkInitialized){const t=(ye.debug("Check if initialized"),Ie&&v.initialized?{ok:!0,value:void 0}:l({code:"not_initialized",message:"Formbricks not initialized. Call initialize() first."}));t&&!0!==t.ok&&e.handle(t.error)}const n=async()=>await(null==t?void 0:t.command.apply(null,null==t?void 0:t.commandArgs)),s=await B(n)();s&&(s.ok&&s.data&&!s.data.ok&&e.handle(s.data.error),!0!==s.ok&&e.handle(s.error))}this.running=!1,this.resolvePromise&&(this.resolvePromise(),this.resolvePromise=null,this.commandPromise=null)}},He=async(e,t)=>{Se.add(!0,ve,e,t),await Se.wait()},Ee={init:async e=>{v.init(e.errorHandler),Se.add(!1,be,e),await Se.wait()},setUserId:async()=>{Se.add(!0,he),await Se.wait()},setEmail:async e=>{He("email",e),await Se.wait()},setAttribute:He,track:async(e,t={})=>{Se.add(!0,M,e,t),await Se.wait()},logout:async()=>{Se.add(!0,we),await Se.wait()},reset:async()=>{Se.add(!0,fe),await Se.wait()},registerRouteChange:async()=>{Se.add(!0,te),await Se.wait()},getApi:()=>{const e=f.getInstance(),{environmentId:t,apiHost:n}=e.get();if(!t||!n)throw new Error("formbricks.init() must be called before getApi()");return new d({apiHost:n,environmentId:t})}};module.exports=Ee; | ||
"use strict";const e=e=>({ok:!1,error:e});async function t(t,n,s,i){const r=new URL(n,t),o=JSON.stringify(i),a=(d=fetch,(...e)=>{try{return{ok:!0,data:d(...e)}}catch(t){return{ok:!1,error:t}}})(r.toString(),{method:s,headers:{"Content-Type":"application/json"},body:o});var d;if(!1===a.ok)return e(a.error);const c=await a.data,{data:u}=await c.json();return c.ok?(e=>({ok:!0,data:e}))(u):e({code:"network_error",message:c.statusText,status:c.status,url:r})}class n{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/actions`,"POST",e)}}class s{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/displays`,"POST",e)}async update(e,n){return t(this.apiHost,`/api/v1/client/${this.environmentId}/displays/${e}`,"PUT",n)}}class i{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/people`,"POST",{environmentId:this.environmentId,userId:e})}async update(e,n){return t(this.apiHost,`/api/v1/client/${this.environmentId}/people/${e}`,"POST",n)}}class r{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/responses`,"POST",e)}async update({responseId:e,finished:n,data:s,ttc:i}){return t(this.apiHost,`/api/v1/client/${this.environmentId}/responses/${e}`,"PUT",{finished:n,data:s,ttc:i})}}class o{constructor(e,t){this.apiHost=e,this.environmentId=t}async uploadFile(e,{allowedFileExtensions:t,surveyId:n}={}){if(!(e instanceof Blob&&e instanceof File))throw new Error("Invalid file type. Expected Blob or File, but received "+typeof e);const s={fileName:e.name,fileType:e.type,allowedFileExtensions:t,surveyId:n},i=await fetch(`${this.apiHost}/api/v1/client/${this.environmentId}/storage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!i.ok)throw new Error(`Upload failed with status: ${i.status}`);const r=await i.json(),{data:o}=r,{signedUrl:a,fileUrl:d,signingData:c,presignedFields:u,updatedFileName:l}=o;let g={};if(c){const{signature:t,timestamp:s,uuid:i}=c;g={"X-File-Type":e.type,"X-File-Name":encodeURIComponent(l),"X-Survey-ID":n??"","X-Signature":t,"X-Timestamp":String(s),"X-UUID":i}}const p=new FormData;u&&Object.keys(u).forEach((e=>{p.append(e,u[e])})),p.append("file",e);const h=await fetch(a,{method:"POST",...c?{headers:g}:{},body:p});if(!h.ok){if(c){const e=await h.json(),t=new Error(e.message);throw t.name="FileTooLargeError",t}const e=await h.text();if(u&&e&&e.includes("EntityTooLarge")){const e=new Error("File size exceeds the size limit for your plan");throw e.name="FileTooLargeError",e}throw new Error(`Upload failed with status: ${h.status}`)}return d}}class a{constructor(e){const{apiHost:t,environmentId:a}=e;this.response=new r(t,a),this.display=new s(t,a),this.action=new n(t,a),this.people=new i(t,a),this.storage=new o(t,a)}}class d{constructor(e){this.client=new a(e)}}class c{constructor(){this.logLevel="error"}static getInstance(){return c.instance||(c.instance=new c),c.instance}configure(e){e&&void 0!==e.logLevel&&(this.logLevel=e.logLevel)}logger(e,t){if("debug"===t&&"debug"!==this.logLevel)return;const n=`🧱 Formbricks - ${(new Date).toISOString()} [${t.toUpperCase()}] - ${e}`;"error"===t?console.error(n):console.log(n)}debug(e){this.logger(e,"debug")}error(e){this.logger(e,"error")}}const u=e=>({ok:!0,value:e}),l=e=>({ok:!1,error:e});const g=e=>(...t)=>{try{return{ok:!0,value:e(...t)}}catch(n){return{ok:!1,error:n}}},p=c.getInstance(),h=class e{constructor(e){this.customized=!1,e?(this.handleError=e,this.customized=!0):this.handleError=e=>c.getInstance().error(JSON.stringify(e))}static getInstance(){return e.instance||(e.instance=new e),e.instance}static init(t){this.initialized=!0,e.instance=new e(t)}printStatus(){p.debug("Custom error handler: "+(this.customized?"yes":"no"))}handle(e){console.warn("🧱 Formbricks - Global error: ",e),this.handleError(e)}};h.initialized=!1;let v=h;const f="formbricks-js";class y{constructor(){this.config=null;const e=this.loadFromLocalStorage();e.ok&&(this.config=e.value)}static getInstance(){return y.instance||(y.instance=new y),y.instance}update(e){if(e){const t=new Date((new Date).getTime()+9e5);this.config={...this.config,...e,expiresAt:t},this.saveToLocalStorage()}}get(){if(!this.config)throw new Error("config is null, maybe the init function was not called?");return this.config}loadFromLocalStorage(){if("undefined"!=typeof window){const e=localStorage.getItem(f);if(e){const t=JSON.parse(e);return t.expiresAt&&new Date(t.expiresAt)<=new Date?l(new Error("Config in local storage has expired")):u(JSON.parse(e))}}return l(new Error("No or invalid config in local storage"))}saveToLocalStorage(){return g((()=>localStorage.setItem(f,JSON.stringify(this.config))))()}resetConfig(){return this.config=null,g((()=>localStorage.removeItem(f)))()}}const m=e=>new Promise((t=>setTimeout(t,e)));class w{constructor(e,t){this.queue=[],this.isRequestInProgress=!1,this.config=e,this.surveyState=t,this.api=new d({apiHost:e.apiHost,environmentId:e.environmentId})}add(e){this.surveyState.accumulateResponse(e),this.config.setSurveyState&&this.config.setSurveyState(this.surveyState),this.queue.push(e),this.processQueue()}async processQueue(){if(this.isRequestInProgress)return;if(0===this.queue.length)return;this.isRequestInProgress=!0;const e=this.queue[0];let t=0;for(;t<this.config.retryAttempts;){if(await this.sendResponse(e)){this.queue.shift();break}console.error("Formbricks: Failed to send response. Retrying...",t),await m(1e3),t++}t>=this.config.retryAttempts?(console.error("Failed to send response after 2 attempts."),this.config.onResponseSendingFailed&&this.config.onResponseSendingFailed(e),this.isRequestInProgress=!1):(this.isRequestInProgress=!1,this.processQueue())}async sendResponse(e){try{if(null!==this.surveyState.responseId)await this.api.client.response.update({...e,responseId:this.surveyState.responseId});else{const t=await this.api.client.response.create({...e,surveyId:this.surveyState.surveyId,userId:this.surveyState.userId||null,singleUseId:this.surveyState.singleUseId||null});if(!t.ok)throw new Error("Could not create response");this.surveyState.displayId&&await this.api.client.display.update(this.surveyState.displayId,{responseId:t.data.id}),this.surveyState.updateResponseId(t.data.id),this.config.setSurveyState&&this.config.setSurveyState(this.surveyState)}return!0}catch(t){return console.error(t),!1}}updateSurveyState(e){this.surveyState=e}}class I{constructor(e,t,n,s){this.responseId=null,this.displayId=null,this.userId=null,this.responseAcc={finished:!1,data:{},ttc:{}},this.surveyId=e,this.userId=s??null,this.singleUseId=t??null,this.responseId=n??null}setSurveyId(e){this.surveyId=e,this.clear()}copy(){const e=new I(this.surveyId,this.singleUseId??void 0,this.responseId??void 0,this.userId??void 0);return e.responseId=this.responseId,e.responseAcc=this.responseAcc,e}updateResponseId(e){this.responseId=e}updateDisplayId(e){this.displayId=e}updateUserId(e){this.userId=e}accumulateResponse(e){this.responseAcc={finished:e.finished,ttc:e.ttc,data:{...this.responseAcc.data,...e.data}}}isResponseFinished(){return this.responseAcc.finished}clear(){this.responseId=null,this.responseAcc={finished:!1,data:{},ttc:{}}}}const b=I,k=(e,t)=>{const n=Math.abs(t.getTime()-e.getTime());return Math.floor(n/864e5)},S=y.getInstance(),H=c.getInstance();let E=null;const C=async e=>{try{const n=await(async({apiHost:e,environmentId:t,userId:n})=>{const s=`${e}/api/v1/client/${t}/in-app/sync/${n}`,i=`${e}/api/v1/client/${t}/in-app/sync`;if(!n){const e=await fetch(i);if(!e.ok){const t=await e.json();return l({code:"network_error",status:e.status,message:"Error syncing with backend",url:s,responseMessage:t.message})}return u((await e.json()).data)}const r=await fetch(s);if(!r.ok){const e=await r.json();return l({code:"network_error",status:r.status,message:"Error syncing with backend",url:s,responseMessage:e.message})}const o=await r.json(),{data:a}=o;return u(a)})(e);if(!0!==(null==n?void 0:n.ok))throw H.error(`Sync failed: ${JSON.stringify(n.error)}`),n.error;let s;try{s=S.get().state}catch(t){}let i={surveys:n.value.surveys,noCodeActionClasses:n.value.noCodeActionClasses,product:n.value.product,attributes:(null==s?void 0:s.attributes)||{}};if(e.userId){const e=i.surveys.map((e=>e.name));H.debug("Fetched "+e.length+" surveys during sync: "+e.join(", "))}else{i={...i,displays:(null==s?void 0:s.displays)||[]},i=$(i);const e=i.surveys.map((e=>e.name));H.debug("Fetched "+e.length+" surveys during sync: "+e.join(", "))}S.update({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId,state:i})}catch(n){throw H.error(`Error during sync: ${n}`),n}},$=e=>{const{displays:t,product:n}=e;let{surveys:s}=e;if(!t)return e;let i=s.filter((e=>{if("respondMultiple"===e.displayOption)return!0;if("displayOnce"===e.displayOption)return 0===t.filter((t=>t.surveyId===e.id)).length;if("displayMultiple"===e.displayOption)return 0===t.filter((t=>t.surveyId===e.id&&t.responded)).length;throw Error("Invalid displayOption")}));const r=t.length>0?t[t.length-1]:void 0;return i=i.filter((e=>{if(r){if(null!==e.recontactDays){const n=t.filter((t=>t.surveyId===e.id))[0];return!n||k(new Date,new Date(n.createdAt))>=e.recontactDays}return null===n.recontactDays||k(new Date,new Date(r.createdAt))>=n.recontactDays}return!0})),{...e,surveys:i}},A=()=>{"undefined"!=typeof window&&null!==E&&(window.clearInterval(E),E=null)},F="formbricks-web-container",L=y.getInstance(),O=c.getInstance(),D=v.getInstance();let P=!1,U=e=>{};const x=async e=>{if(P)return void O.debug("A survey is already running. Skipping.");P=!0,e.delay&&O.debug(`Delaying survey by ${e.delay} seconds.`);const t=L.get().state.product,n=new b(e.id,null,null,L.get().userId),s=new w({apiHost:L.get().apiHost,environmentId:L.get().environmentId,retryAttempts:2,onResponseSendingFailed:()=>{U(!0)}},n),i=e.productOverwrites??{},r=i.brandColor??t.brandColor,o=i.highlightBorderColor??t.highlightBorderColor,a=i.clickOutsideClose??t.clickOutsideClose,c=i.darkOverlay??t.darkOverlay,u=i.placement??t.placement,l=t.inAppSurveyBranding,g=await R();setTimeout((()=>{g.renderSurveyModal({survey:e,brandColor:r,isBrandingEnabled:l,clickOutside:a,darkOverlay:c,highlightBorderColor:o,placement:u,getSetIsError:e=>{U=e},onDisplay:async()=>{const{userId:t}=L.get();if(!t){const t={createdAt:new Date,surveyId:e.id,responded:!1},n=L.get().state.displays,s=n?[...n,t]:[t],i=L.get();let r=$({...i.state,displays:s});L.update({...i,state:r})}const i=new d({apiHost:L.get().apiHost,environmentId:L.get().environmentId}),r=await i.client.display.create({surveyId:e.id,userId:t});if(!r.ok)throw new Error("Could not create display");const{id:o}=r.data;n.updateDisplayId(o),s.updateSurveyState(n)},onResponse:e=>{const{userId:t}=L.get();if(!t){const e=L.get().state.displays,t=e&&e[e.length-1];if(!t)throw new Error("No lastDisplay found");if(!t.responded){t.responded=!0;const n=L.get();let s=$({...n.state,displays:e});L.update({...n,state:s})}}t&&n.updateUserId(t),s.updateSurveyState(n),s.add({data:e.data,ttc:e.ttc,finished:e.finished})},onClose:T,onFileUpload:async(e,t)=>{const n=new d({apiHost:L.get().apiHost,environmentId:L.get().environmentId});return await n.client.storage.uploadFile(e,t)},onRetry:()=>{U(!1),s.processQueue()}})}),1e3*e.delay)},T=async()=>{var e;if(null==(e=document.getElementById(F))||e.remove(),N(),!L.get().userId){const e=L.get().state,t=$(e);return L.update({...L.get(),state:t}),void(P=!1)}try{await C({apiHost:L.get().apiHost,environmentId:L.get().environmentId,userId:L.get().userId}),P=!1}catch(t){D.handle(t)}},N=()=>{const e=document.createElement("div");e.id=F,document.body.appendChild(e)},R=()=>new Promise(((e,t)=>{if(window.formbricksSurveys)e(window.formbricksSurveys);else{const n=document.createElement("script");n.src="https://unpkg.com/@formbricks/surveys@^1.5.1/dist/index.umd.js",n.async=!0,n.onload=()=>e(window.formbricksSurveys),n.onerror=e=>{console.error("Failed to load Formbricks Surveys library:",e),t(e)},document.head.appendChild(n)}})),z=c.getInstance(),j=y.getInstance(),q=["Exit Intent (Desktop)","50% Scroll"],M=async(e,t={})=>{var n;const{userId:s}=j.get(),i={environmentId:j.get().environmentId,userId:s,name:e,properties:t||{}};if(s&&!q.includes(e)){z.debug(`Sending action "${e}" to backend`);const t=new d({apiHost:j.get().apiHost,environmentId:j.get().environmentId}),n=await t.client.action.create({...i,userId:s});if(!n.ok)return l({code:"network_error",message:`Error tracking action ${e}`,status:500,url:`${j.get().apiHost}/api/v1/client/${j.get().environmentId}/actions`,responseMessage:n.error.message})}z.debug(`Formbricks: Action "${e}" tracked`);const r=null==(n=j.get().state)?void 0:n.surveys;return r&&r.length>0?await _(e,r):z.debug("No active surveys to display"),{ok:!0,value:void 0}},_=async(e,t)=>{for(const s of t){if(s.displayPercentage){if(!(n=s.displayPercentage,Math.floor(100*Math.random())+1<=n)){z.debug("Survey display skipped based on displayPercentage.");continue}}for(const t of s.triggers)if(t===e)return z.debug(`Formbricks: survey ${s.id} triggered by action "${e}"`),void(await x(s))}var n},B=e=>async(...t)=>{try{return{ok:!0,data:await e(...t)}}catch(n){return{ok:!1,error:n}}};let J=!1,X=async function(e){if(e.clientY<=0){const e=await M("Exit Intent (Desktop)");if(!0!==e.ok)return l(e.error)}};const Q=()=>{J&&(document.removeEventListener("mouseleave",X),J=!1)};let W=!1,Y=!1,G=async()=>{const e=window.scrollY,t=window.innerHeight,n=document.documentElement.scrollHeight;if(0===e&&(Y=!1),!Y&&e/(n-t)>=.5){Y=!0;const e=await M("50% Scroll");if(!0!==e.ok)return l(e.error)}};const K=()=>{W&&(window.removeEventListener("scroll",G),W=!1)},V=y.getInstance(),Z=c.getInstance(),ee=v.getInstance(),te=async()=>{var e;Z.debug(`Checking page url: ${window.location.href}`);const{state:t}=V.get();if(void 0===(null==t?void 0:t.noCodeActionClasses))return{ok:!0,value:void 0};const n=((null==t?void 0:t.noCodeActionClasses)||[]).filter((e=>{const{innerHtml:t,cssSelector:n,pageUrl:s}=e.noCodeConfig||{};return s&&!t&&!n}));if(0===n.length)return{ok:!0,value:void 0};for(const s of n){if(!(null==(e=s.noCodeConfig)?void 0:e.pageUrl))continue;const{noCodeConfig:{pageUrl:t}}=s,n=re(window.location.href,t.value,t.rule);if(!0!==n.ok)return l(n.error);if(!1===n.value)continue;const i=await M(s.name);if(!0!==i.ok)return l(i.error)}return{ok:!0,value:void 0}};let ne=!1;const se=()=>te(),ie=()=>{"undefined"!=typeof window&&ne&&(window.removeEventListener("hashchange",se),window.removeEventListener("popstate",se),window.removeEventListener("pushstate",se),window.removeEventListener("replacestate",se),window.removeEventListener("load",se),ne=!1)};function re(e,t,n){switch(n){case"exactMatch":return u(e===t);case"contains":return u(e.includes(t));case"startsWith":return u(e.startsWith(t));case"endsWith":return u(e.endsWith(t));case"notMatch":return u(e!==t);case"notContains":return u(!e.includes(t));default:return l({code:"invalid_match_type",message:"Invalid match type"})}}let oe=!1;const ae=e=>(e=>{const{state:t}=V.get();if(!t)return;const n=e.target;((null==t?void 0:t.noCodeActionClasses)||[]).forEach((e=>{var t,s,i,r,o,a,d,c;const u=null==(s=null==(t=e.noCodeConfig)?void 0:t.innerHtml)?void 0:s.value,l=null==(r=null==(i=e.noCodeConfig)?void 0:i.cssSelector)?void 0:r.value,g=null==(a=null==(o=e.noCodeConfig)?void 0:o.pageUrl)?void 0:a.value,p=null==(c=null==(d=e.noCodeConfig)?void 0:d.pageUrl)?void 0:c.rule;if((u||l||g)&&(!u||n.innerHTML===u)){if(l){const e=l.split(/\s*(?=[.#])/);for(let t of e)if(!n.matches(t))return}if(g&&p){const e=re(window.location.href,g,p);if(!e.ok||!e.value)return}M(e.name).then((e=>{var t,n,s;n=e=>{},s=e=>{ee.handle(e)},!0===(t=e).ok?n(t.value):s(t.error)}))}}))})(e),de=()=>{oe&&(document.removeEventListener("click",ae),oe=!1)};let ce=!1;const ue=()=>{"undefined"!=typeof window&&null===E&&(E=window.setInterval((async()=>{S.get().expiresAt&&new Date(S.get().expiresAt)>=new Date||(H.debug("Config has expired. Starting sync."),await C({apiHost:S.get().apiHost,environmentId:S.get().environmentId,userId:S.get().userId}))}),6e4)),"undefined"==typeof window||ne||(window.addEventListener("hashchange",se),window.addEventListener("popstate",se),window.addEventListener("pushstate",se),window.addEventListener("replacestate",se),window.addEventListener("load",se),ne=!0),"undefined"==typeof window||oe||(document.addEventListener("click",ae),oe=!0),"undefined"==typeof document||J||(document.querySelector("body").addEventListener("mouseleave",X),J=!0),"undefined"==typeof window||W||(window.addEventListener("load",(()=>{window.addEventListener("scroll",G)})),W=!0)},le=()=>{A(),ie(),de(),Q(),K(),ce&&(window.removeEventListener("beforeunload",(()=>{A(),ie(),de(),Q(),K()})),ce=!1)},ge=y.getInstance(),pe=c.getInstance(),he=async()=>(pe.error("'setUserId' is no longer supported. Please set the userId in the init call instead."),{ok:!0,value:void 0}),ve=async(e,t)=>{if(pe.debug("Setting attribute: "+e+" to value: "+t),((e,t)=>ge.get().state.attributes[e]===t)(e,t.toString()))return pe.debug("Attribute already set to this value. Skipping update."),{ok:!0,value:void 0};const n=await(async(e,t)=>{const{apiHost:n,environmentId:s,userId:i}=ge.get();if(!i)return l({code:"missing_person",message:"Unable to update attribute. User identification deactivated. No userId set."});const r={attributes:{[e]:t}},o=new d({apiHost:ge.get().apiHost,environmentId:ge.get().environmentId}),a=await o.client.people.update(i,r);return a.ok?(pe.debug("Attribute updated. Syncing..."),await C({environmentId:s,apiHost:n,userId:i}),{ok:!0,value:void 0}):l({code:"network_error",status:500,message:`Error updating person with userId ${i}`,url:`${ge.get().apiHost}/api/v1/client/${s}/people/${i}`,responseMessage:a.error.message})})(e,t.toString());return n.ok?(ge.update({environmentId:ge.get().environmentId,apiHost:ge.get().apiHost,userId:ge.get().userId,state:{...ge.get().state,attributes:{...ge.get().state.attributes,[e]:t.toString()}}}),{ok:!0,value:void 0}):l(n.error)},fe=async()=>{ke()},ye=async()=>{pe.debug("Resetting state & getting new state from backend"),T();const e={environmentId:ge.get().environmentId,apiHost:ge.get().apiHost,userId:ge.get().userId};await fe();try{return await be(e),{ok:!0,value:void 0}}catch(t){return l(t)}},me=y.getInstance(),we=c.getInstance();let Ie=!1;const be=async e=>{if(Ie)return we.debug("Already initialized, skipping initialization."),{ok:!0,value:void 0};if((e=>{e.debug&&(we.debug("Setting log level to debug"),we.configure({logLevel:"debug"}))})(e),v.getInstance().printStatus(),we.debug("Start initialize"),!e.environmentId)return we.debug("No environmentId provided"),l({code:"missing_field",field:"environmentId"});if(!e.apiHost)return we.debug("No apiHost provided"),l({code:"missing_field",field:"apiHost"});if(we.debug("Adding widget container to DOM"),N(),!e.userId&&e.attributes)return we.error("No userId provided but attributes. Cannot update attributes without userId."),l({code:"missing_field",field:"userId"});let t,n=null;if(e.userId&&e.attributes){const t=await(async(e,t,n,s)=>{var i,r;if(!n)return l({code:"missing_person",message:"Unable to update attribute. User identification deactivated. No userId set."});const o={...s};try{const e=null==(r=null==(i=ge.get())?void 0:i.state)?void 0:r.attributes;if(e)for(const[t,n]of Object.entries(e))o[t]===n&&delete o[t]}catch(p){pe.debug("config not set; sending all attributes to backend")}if(0===Object.keys(o).length)return pe.debug("No attributes to update. Skipping update."),u(o);pe.debug("Updating attributes: "+JSON.stringify(o));const a={attributes:o},c=new d({apiHost:e,environmentId:t}),g=await c.client.people.update(n,a);return g.ok?u(o):l({code:"network_error",status:500,message:`Error updating person with userId ${n}`,url:`${e}/api/v1/client/${t}/people/${n}`,responseMessage:g.error.message})})(e.apiHost,e.environmentId,e.userId,e.attributes);if(!0!==t.ok)return l(t.error);n=t.value}try{t=me.get()}catch(s){we.debug("No existing configuration found.")}return t&&t.state&&t.environmentId===e.environmentId&&t.apiHost===e.apiHost&&t.userId===e.userId&&t.expiresAt?(we.debug("Found existing configuration."),t.expiresAt<new Date?(we.debug("Configuration expired."),await C({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId})):(we.debug("Configuration not expired. Extending expiration."),me.update(t))):(we.debug("No valid configuration found or it has been expired. Creating new config."),we.debug("Syncing."),await C({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId}),await M("New Session")),n&&Object.keys(n).length>0&&me.update({environmentId:me.get().environmentId,apiHost:me.get().apiHost,userId:me.get().userId,state:{...me.get().state,attributes:{...me.get().state.attributes,...e.attributes}}}),we.debug("Adding event listeners"),ue(),ce||(window.addEventListener("beforeunload",(()=>{A(),ie(),de(),Q(),K()})),ce=!0),Ie=!0,we.debug("Initialized"),te(),{ok:!0,value:void 0}},ke=()=>{we.debug("Deinitializing"),T(),le(),me.resetConfig(),Ie=!1};c.getInstance().debug("Create command queue");const Se=new class{constructor(){this.queue=[],this.running=!1,this.resolvePromise=null,this.commandPromise=null}add(e=!0,t,...n){this.queue.push({command:t,checkInitialized:e,commandArgs:n}),this.running||(this.commandPromise=new Promise((e=>{this.resolvePromise=e,this.run()})))}async wait(){this.running&&await this.commandPromise}async run(){for(this.running=!0;this.queue.length>0;){const e=v.getInstance(),t=this.queue.shift();if(!t)continue;if(t.checkInitialized){const t=(we.debug("Check if initialized"),Ie&&v.initialized?{ok:!0,value:void 0}:l({code:"not_initialized",message:"Formbricks not initialized. Call initialize() first."}));t&&!0!==t.ok&&e.handle(t.error)}const n=async()=>await(null==t?void 0:t.command.apply(null,null==t?void 0:t.commandArgs)),s=await B(n)();s&&(s.ok&&s.data&&!s.data.ok&&e.handle(s.data.error),!0!==s.ok&&e.handle(s.error))}this.running=!1,this.resolvePromise&&(this.resolvePromise(),this.resolvePromise=null,this.commandPromise=null)}},He=async(e,t)=>{Se.add(!0,ve,e,t),await Se.wait()},Ee={init:async e=>{v.init(e.errorHandler),Se.add(!1,be,e),await Se.wait()},setUserId:async()=>{Se.add(!0,he),await Se.wait()},setEmail:async e=>{He("email",e),await Se.wait()},setAttribute:He,track:async(e,t={})=>{Se.add(!0,M,e,t),await Se.wait()},logout:async()=>{Se.add(!0,fe),await Se.wait()},reset:async()=>{Se.add(!0,ye),await Se.wait()},registerRouteChange:async()=>{Se.add(!0,te),await Se.wait()},getApi:()=>{const e=y.getInstance(),{environmentId:t,apiHost:n}=e.get();if(!t||!n)throw new Error("formbricks.init() must be called before getApi()");return new d({apiHost:n,environmentId:t})}};module.exports=Ee; | ||
//# sourceMappingURL=index.js.map |
@@ -1,2 +0,2 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).formbricks=t()}(this,(function(){"use strict";const e=e=>({ok:!1,error:e});async function t(t,n,s,i){const r=new URL(n,t),o=JSON.stringify(i),a=(d=fetch,(...e)=>{try{return{ok:!0,data:d(...e)}}catch(t){return{ok:!1,error:t}}})(r.toString(),{method:s,headers:{"Content-Type":"application/json"},body:o});var d;if(!1===a.ok)return e(a.error);const u=await a.data,{data:c}=await u.json();return u.ok?(e=>({ok:!0,data:e}))(c):e({code:"network_error",message:u.statusText,status:u.status,url:r})}class n{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/actions`,"POST",e)}}class s{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/displays`,"POST",e)}async update(e,n){return t(this.apiHost,`/api/v1/client/${this.environmentId}/displays/${e}`,"PUT",n)}}class i{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/people`,"POST",{environmentId:this.environmentId,userId:e})}async update(e,n){return t(this.apiHost,`/api/v1/client/${this.environmentId}/people/${e}`,"POST",n)}}class r{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/responses`,"POST",e)}async update({responseId:e,finished:n,data:s,ttc:i}){return t(this.apiHost,`/api/v1/client/${this.environmentId}/responses/${e}`,"PUT",{finished:n,data:s,ttc:i})}}class o{constructor(e,t){this.apiHost=e,this.environmentId=t}async uploadFile(e,{allowedFileExtensions:t,surveyId:n}={}){if(!(e instanceof Blob&&e instanceof File))throw new Error("Invalid file type. Expected Blob or File, but received "+typeof e);const s={fileName:e.name,fileType:e.type,allowedFileExtensions:t,surveyId:n},i=await fetch(`${this.apiHost}/api/v1/client/${this.environmentId}/storage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!i.ok)throw new Error(`Upload failed with status: ${i.status}`);const r=await i.json(),{data:o}=r,{signedUrl:a,fileUrl:d,signingData:u,presignedFields:c,updatedFileName:l}=o;let p={};if(u){const{signature:t,timestamp:s,uuid:i}=u;p={"X-File-Type":e.type,"X-File-Name":encodeURIComponent(l),"X-Survey-ID":n??"","X-Signature":t,"X-Timestamp":String(s),"X-UUID":i}}const g=new FormData;c&&Object.keys(c).forEach((e=>{g.append(e,c[e])})),g.append("file",e);const h=await fetch(a,{method:"POST",...u?{headers:p}:{},body:g});if(!h.ok){if(u){const e=await h.json(),t=new Error(e.message);throw t.name="FileTooLargeError",t}const e=await h.text();if(c&&e&&e.includes("EntityTooLarge")){const e=new Error("File size exceeds the size limit for your plan");throw e.name="FileTooLargeError",e}throw new Error(`Upload failed with status: ${h.status}`)}return d}}class a{constructor(e){const{apiHost:t,environmentId:a}=e;this.response=new r(t,a),this.display=new s(t,a),this.action=new n(t,a),this.people=new i(t,a),this.storage=new o(t,a)}}class d{constructor(e){this.client=new a(e)}}class u{constructor(){this.logLevel="error"}static getInstance(){return u.instance||(u.instance=new u),u.instance}configure(e){e&&void 0!==e.logLevel&&(this.logLevel=e.logLevel)}logger(e,t){if("debug"===t&&"debug"!==this.logLevel)return;const n=`🧱 Formbricks - ${(new Date).toISOString()} [${t.toUpperCase()}] - ${e}`;"error"===t?console.error(n):console.log(n)}debug(e){this.logger(e,"debug")}error(e){this.logger(e,"error")}}const c=e=>({ok:!0,value:e}),l=e=>({ok:!1,error:e});const p=e=>(...t)=>{try{return{ok:!0,value:e(...t)}}catch(n){return{ok:!1,error:n}}},g=u.getInstance(),h=class e{constructor(e){this.customized=!1,e?(this.handleError=e,this.customized=!0):this.handleError=e=>u.getInstance().error(JSON.stringify(e))}static getInstance(){return e.instance||(e.instance=new e),e.instance}static init(t){this.initialized=!0,e.instance=new e(t)}printStatus(){g.debug("Custom error handler: "+(this.customized?"yes":"no"))}handle(e){console.warn("🧱 Formbricks - Global error: ",e),this.handleError(e)}};h.initialized=!1;let v=h;const f="formbricks-js";class m{constructor(){this.config=null;const e=this.loadFromLocalStorage();e.ok&&(this.config=e.value)}static getInstance(){return m.instance||(m.instance=new m),m.instance}update(e){if(e){const t=new Date((new Date).getTime()+9e5);this.config={...this.config,...e,expiresAt:t},this.saveToLocalStorage()}}get(){if(!this.config)throw new Error("config is null, maybe the init function was not called?");return this.config}loadFromLocalStorage(){if("undefined"!=typeof window){const e=localStorage.getItem(f);if(e){const t=JSON.parse(e);return t.expiresAt&&new Date(t.expiresAt)<=new Date?l(new Error("Config in local storage has expired")):c(JSON.parse(e))}}return l(new Error("No or invalid config in local storage"))}saveToLocalStorage(){return p((()=>localStorage.setItem(f,JSON.stringify(this.config))))()}resetConfig(){return this.config=null,p((()=>localStorage.removeItem(f)))()}}const w=e=>new Promise((t=>setTimeout(t,e)));class y{constructor(e,t){this.queue=[],this.isRequestInProgress=!1,this.config=e,this.surveyState=t,this.api=new d({apiHost:e.apiHost,environmentId:e.environmentId})}add(e){this.surveyState.accumulateResponse(e),this.config.setSurveyState&&this.config.setSurveyState(this.surveyState),this.queue.push(e),this.processQueue()}async processQueue(){if(this.isRequestInProgress)return;if(0===this.queue.length)return;this.isRequestInProgress=!0;const e=this.queue[0];let t=0;for(;t<this.config.retryAttempts;){if(await this.sendResponse(e)){this.queue.shift();break}console.error("Formbricks: Failed to send response. Retrying...",t),await w(1e3),t++}t>=this.config.retryAttempts?(console.error("Failed to send response after 2 attempts."),this.config.onResponseSendingFailed&&this.config.onResponseSendingFailed(e),this.isRequestInProgress=!1):(this.isRequestInProgress=!1,this.processQueue())}async sendResponse(e){try{if(null!==this.surveyState.responseId)await this.api.client.response.update({...e,responseId:this.surveyState.responseId});else{const t=await this.api.client.response.create({...e,surveyId:this.surveyState.surveyId,userId:this.surveyState.userId||null,singleUseId:this.surveyState.singleUseId||null});if(!t.ok)throw new Error("Could not create response");this.surveyState.displayId&&await this.api.client.display.update(this.surveyState.displayId,{responseId:t.data.id}),this.surveyState.updateResponseId(t.data.id),this.config.setSurveyState&&this.config.setSurveyState(this.surveyState)}return!0}catch(t){return console.error(t),!1}}updateSurveyState(e){this.surveyState=e}}class I{constructor(e,t,n,s){this.responseId=null,this.displayId=null,this.userId=null,this.responseAcc={finished:!1,data:{},ttc:{}},this.surveyId=e,this.userId=s??null,this.singleUseId=t??null,this.responseId=n??null}setSurveyId(e){this.surveyId=e,this.clear()}copy(){const e=new I(this.surveyId,this.singleUseId??void 0,this.responseId??void 0,this.userId??void 0);return e.responseId=this.responseId,e.responseAcc=this.responseAcc,e}updateResponseId(e){this.responseId=e}updateDisplayId(e){this.displayId=e}updateUserId(e){this.userId=e}accumulateResponse(e){this.responseAcc={finished:e.finished,ttc:e.ttc,data:{...this.responseAcc.data,...e.data}}}isResponseFinished(){return this.responseAcc.finished}clear(){this.responseId=null,this.responseAcc={finished:!1,data:{},ttc:{}}}}const b=I,k=(e,t)=>{const n=Math.abs(t.getTime()-e.getTime());return Math.floor(n/864e5)},S=m.getInstance(),H=u.getInstance();let E=null;const C=async e=>{try{const n=await(async({apiHost:e,environmentId:t,userId:n})=>{const s=`${e}/api/v1/client/${t}/in-app/sync/${n}`,i=`${e}/api/v1/client/${t}/in-app/sync`;if(!n){const e=await fetch(i);if(!e.ok){const t=await e.json();return l({code:"network_error",status:e.status,message:"Error syncing with backend",url:s,responseMessage:t.message})}return c((await e.json()).data)}const r=await fetch(s);if(!r.ok){const e=await r.json();return l({code:"network_error",status:r.status,message:"Error syncing with backend",url:s,responseMessage:e.message})}const o=await r.json(),{data:a}=o;return c(a)})(e);if(!0!==(null==n?void 0:n.ok))throw H.error(`Sync failed: ${JSON.stringify(n.error)}`),n.error;let s;try{s=S.get().state}catch(t){}let i={surveys:n.value.surveys,noCodeActionClasses:n.value.noCodeActionClasses,product:n.value.product,attributes:(null==s?void 0:s.attributes)||{}};if(e.userId){const e=i.surveys.map((e=>e.name));H.debug("Fetched "+e.length+" surveys during sync: "+e.join(", "))}else{i={...i,displays:(null==s?void 0:s.displays)||[]},i=$(i);const e=i.surveys.map((e=>e.name));H.debug("Fetched "+e.length+" surveys during sync: "+e.join(", "))}S.update({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId,state:i})}catch(n){throw H.error(`Error during sync: ${n}`),n}},$=e=>{const{displays:t,product:n}=e;let{surveys:s}=e;if(!t)return e;let i=s.filter((e=>{if("respondMultiple"===e.displayOption)return!0;if("displayOnce"===e.displayOption)return 0===t.filter((t=>t.surveyId===e.id)).length;if("displayMultiple"===e.displayOption)return 0===t.filter((t=>t.surveyId===e.id&&t.responded)).length;throw Error("Invalid displayOption")}));const r=t.length>0?t[t.length-1]:void 0;return i=i.filter((e=>{if(r){if(null!==e.recontactDays){const n=t.filter((t=>t.surveyId===e.id))[0];return!n||k(new Date,new Date(n.createdAt))>=e.recontactDays}return null===n.recontactDays||k(new Date,new Date(r.createdAt))>=n.recontactDays}return!0})),{...e,surveys:i}},A=()=>{"undefined"!=typeof window&&null!==E&&(window.clearInterval(E),E=null)},F="formbricks-web-container",L=m.getInstance(),O=u.getInstance(),D=v.getInstance();let U=!1,x=e=>{};const T=async e=>{if(U)return void O.debug("A survey is already running. Skipping.");U=!0,e.delay&&O.debug(`Delaying survey by ${e.delay} seconds.`);const t=L.get().state.product,n=new b(e.id,null,null,L.get().userId),s=new y({apiHost:L.get().apiHost,environmentId:L.get().environmentId,retryAttempts:2,onResponseSendingFailed:()=>{x(!0)}},n),i=e.productOverwrites??{},r=i.brandColor??t.brandColor,o=i.highlightBorderColor??t.highlightBorderColor,a=i.clickOutsideClose??t.clickOutsideClose,u=i.darkOverlay??t.darkOverlay,c=i.placement??t.placement,l=t.inAppSurveyBranding,p=await R();setTimeout((()=>{p.renderSurveyModal({survey:e,brandColor:r,isBrandingEnabled:l,clickOutside:a,darkOverlay:u,highlightBorderColor:o,placement:c,getSetIsError:e=>{x=e},onDisplay:async()=>{const{userId:t}=L.get();if(!t){const t={createdAt:new Date,surveyId:e.id,responded:!1},n=L.get().state.displays,s=n?[...n,t]:[t],i=L.get();let r=$({...i.state,displays:s});L.update({...i,state:r})}const i=new d({apiHost:L.get().apiHost,environmentId:L.get().environmentId}),r=await i.client.display.create({surveyId:e.id,userId:t});if(!r.ok)throw new Error("Could not create display");const{id:o}=r.data;n.updateDisplayId(o),s.updateSurveyState(n)},onResponse:e=>{const{userId:t}=L.get();if(!t){const e=L.get().state.displays,t=e&&e[e.length-1];if(!t)throw new Error("No lastDisplay found");if(!t.responded){t.responded=!0;const n=L.get();let s=$({...n.state,displays:e});L.update({...n,state:s})}}t&&n.updateUserId(t),s.updateSurveyState(n),s.add({data:e.data,ttc:e.ttc,finished:e.finished})},onClose:P,onFileUpload:async(e,t)=>{const n=new d({apiHost:L.get().apiHost,environmentId:L.get().environmentId});return await n.client.storage.uploadFile(e,t)},onRetry:()=>{x(!1),s.processQueue()}})}),1e3*e.delay)},P=async()=>{var e;if(null==(e=document.getElementById(F))||e.remove(),N(),!L.get().userId){const e=L.get().state,t=$(e);return L.update({...L.get(),state:t}),void(U=!1)}try{await C({apiHost:L.get().apiHost,environmentId:L.get().environmentId,userId:L.get().userId}),U=!1}catch(t){D.handle(t)}},N=()=>{const e=document.createElement("div");e.id=F,document.body.appendChild(e)},R=()=>new Promise(((e,t)=>{if(window.formbricksSurveys)e(window.formbricksSurveys);else{const n=document.createElement("script");n.src="https://unpkg.com/@formbricks/surveys@^1.5.0/dist/index.umd.js",n.async=!0,n.onload=()=>e(window.formbricksSurveys),n.onerror=e=>{console.error("Failed to load Formbricks Surveys library:",e),t(e)},document.head.appendChild(n)}})),z=u.getInstance(),j=m.getInstance(),q=["Exit Intent (Desktop)","50% Scroll"],M=async(e,t={})=>{var n;const{userId:s}=j.get(),i={environmentId:j.get().environmentId,userId:s,name:e,properties:t||{}};if(s&&!q.includes(e)){z.debug(`Sending action "${e}" to backend`);const t=new d({apiHost:j.get().apiHost,environmentId:j.get().environmentId}),n=await t.client.action.create({...i,userId:s});if(!n.ok)return l({code:"network_error",message:`Error tracking action ${e}`,status:500,url:`${j.get().apiHost}/api/v1/client/${j.get().environmentId}/actions`,responseMessage:n.error.message})}z.debug(`Formbricks: Action "${e}" tracked`);const r=null==(n=j.get().state)?void 0:n.surveys;return r&&r.length>0?await _(e,r):z.debug("No active surveys to display"),{ok:!0,value:void 0}},_=async(e,t)=>{for(const n of t)for(const t of n.triggers)if(t===e)return z.debug(`Formbricks: survey ${n.id} triggered by action "${e}"`),void(await T(n))},B=e=>async(...t)=>{try{return{ok:!0,data:await e(...t)}}catch(n){return{ok:!1,error:n}}};let J=!1,X=async function(e){if(e.clientY<=0){const e=await M("Exit Intent (Desktop)");if(!0!==e.ok)return l(e.error)}};const Q=()=>{J&&(document.removeEventListener("mouseleave",X),J=!1)};let W=!1,Y=!1,G=async()=>{const e=window.scrollY,t=window.innerHeight,n=document.documentElement.scrollHeight;if(0===e&&(Y=!1),!Y&&e/(n-t)>=.5){Y=!0;const e=await M("50% Scroll");if(!0!==e.ok)return l(e.error)}};const K=()=>{W&&(window.removeEventListener("scroll",G),W=!1)},V=m.getInstance(),Z=u.getInstance(),ee=v.getInstance(),te=async()=>{var e;Z.debug(`Checking page url: ${window.location.href}`);const{state:t}=V.get();if(void 0===(null==t?void 0:t.noCodeActionClasses))return{ok:!0,value:void 0};const n=((null==t?void 0:t.noCodeActionClasses)||[]).filter((e=>{const{innerHtml:t,cssSelector:n,pageUrl:s}=e.noCodeConfig||{};return s&&!t&&!n}));if(0===n.length)return{ok:!0,value:void 0};for(const s of n){if(!(null==(e=s.noCodeConfig)?void 0:e.pageUrl))continue;const{noCodeConfig:{pageUrl:t}}=s,n=re(window.location.href,t.value,t.rule);if(!0!==n.ok)return l(n.error);if(!1===n.value)continue;const i=await M(s.name);if(!0!==i.ok)return l(i.error)}return{ok:!0,value:void 0}};let ne=!1;const se=()=>te(),ie=()=>{"undefined"!=typeof window&&ne&&(window.removeEventListener("hashchange",se),window.removeEventListener("popstate",se),window.removeEventListener("pushstate",se),window.removeEventListener("replacestate",se),window.removeEventListener("load",se),ne=!1)};function re(e,t,n){switch(n){case"exactMatch":return c(e===t);case"contains":return c(e.includes(t));case"startsWith":return c(e.startsWith(t));case"endsWith":return c(e.endsWith(t));case"notMatch":return c(e!==t);case"notContains":return c(!e.includes(t));default:return l({code:"invalid_match_type",message:"Invalid match type"})}}let oe=!1;const ae=e=>(e=>{const{state:t}=V.get();if(!t)return;const n=e.target;((null==t?void 0:t.noCodeActionClasses)||[]).forEach((e=>{var t,s,i,r,o,a,d,u;const c=null==(s=null==(t=e.noCodeConfig)?void 0:t.innerHtml)?void 0:s.value,l=null==(r=null==(i=e.noCodeConfig)?void 0:i.cssSelector)?void 0:r.value,p=null==(a=null==(o=e.noCodeConfig)?void 0:o.pageUrl)?void 0:a.value,g=null==(u=null==(d=e.noCodeConfig)?void 0:d.pageUrl)?void 0:u.rule;if((c||l||p)&&(!c||n.innerHTML===c)){if(l){const e=l.split(/\s*(?=[.#])/);for(let t of e)if(!n.matches(t))return}if(p&&g){const e=re(window.location.href,p,g);if(!e.ok||!e.value)return}M(e.name).then((e=>{var t,n,s;n=e=>{},s=e=>{ee.handle(e)},!0===(t=e).ok?n(t.value):s(t.error)}))}}))})(e),de=()=>{oe&&(document.removeEventListener("click",ae),oe=!1)};let ue=!1;const ce=()=>{"undefined"!=typeof window&&null===E&&(E=window.setInterval((async()=>{S.get().expiresAt&&new Date(S.get().expiresAt)>=new Date||(H.debug("Config has expired. Starting sync."),await C({apiHost:S.get().apiHost,environmentId:S.get().environmentId,userId:S.get().userId}))}),6e4)),"undefined"==typeof window||ne||(window.addEventListener("hashchange",se),window.addEventListener("popstate",se),window.addEventListener("pushstate",se),window.addEventListener("replacestate",se),window.addEventListener("load",se),ne=!0),"undefined"==typeof window||oe||(document.addEventListener("click",ae),oe=!0),"undefined"==typeof document||J||(document.querySelector("body").addEventListener("mouseleave",X),J=!0),"undefined"==typeof window||W||(window.addEventListener("load",(()=>{window.addEventListener("scroll",G)})),W=!0)},le=()=>{A(),ie(),de(),Q(),K(),ue&&(window.removeEventListener("beforeunload",(()=>{A(),ie(),de(),Q(),K()})),ue=!1)},pe=m.getInstance(),ge=u.getInstance(),he=async()=>(ge.error("'setUserId' is no longer supported. Please set the userId in the init call instead."),{ok:!0,value:void 0}),ve=async(e,t)=>{if(ge.debug("Setting attribute: "+e+" to value: "+t),((e,t)=>pe.get().state.attributes[e]===t)(e,t.toString()))return ge.debug("Attribute already set to this value. Skipping update."),{ok:!0,value:void 0};const n=await(async(e,t)=>{const{apiHost:n,environmentId:s,userId:i}=pe.get();if(!i)return l({code:"missing_person",message:"Unable to update attribute. User identification deactivated. No userId set."});const r={attributes:{[e]:t}},o=new d({apiHost:pe.get().apiHost,environmentId:pe.get().environmentId}),a=await o.client.people.update(i,r);return a.ok?(ge.debug("Attribute updated. Syncing..."),await C({environmentId:s,apiHost:n,userId:i}),{ok:!0,value:void 0}):l({code:"network_error",status:500,message:`Error updating person with userId ${i}`,url:`${pe.get().apiHost}/api/v1/client/${s}/people/${i}`,responseMessage:a.error.message})})(e,t.toString());return n.ok?(pe.update({environmentId:pe.get().environmentId,apiHost:pe.get().apiHost,userId:pe.get().userId,state:{...pe.get().state,attributes:{...pe.get().state.attributes,[e]:t.toString()}}}),{ok:!0,value:void 0}):l(n.error)},fe=async()=>{ke()},me=async()=>{ge.debug("Resetting state & getting new state from backend"),P();const e={environmentId:pe.get().environmentId,apiHost:pe.get().apiHost,userId:pe.get().userId};await fe();try{return await be(e),{ok:!0,value:void 0}}catch(t){return l(t)}},we=m.getInstance(),ye=u.getInstance();let Ie=!1;const be=async e=>{if(Ie)return ye.debug("Already initialized, skipping initialization."),{ok:!0,value:void 0};if((e=>{e.debug&&(ye.debug("Setting log level to debug"),ye.configure({logLevel:"debug"}))})(e),v.getInstance().printStatus(),ye.debug("Start initialize"),!e.environmentId)return ye.debug("No environmentId provided"),l({code:"missing_field",field:"environmentId"});if(!e.apiHost)return ye.debug("No apiHost provided"),l({code:"missing_field",field:"apiHost"});if(ye.debug("Adding widget container to DOM"),N(),!e.userId&&e.attributes)return ye.error("No userId provided but attributes. Cannot update attributes without userId."),l({code:"missing_field",field:"userId"});let t,n=null;if(e.userId&&e.attributes){const t=await(async(e,t,n,s)=>{var i,r;if(!n)return l({code:"missing_person",message:"Unable to update attribute. User identification deactivated. No userId set."});const o={...s};try{const e=null==(r=null==(i=pe.get())?void 0:i.state)?void 0:r.attributes;if(e)for(const[t,n]of Object.entries(e))o[t]===n&&delete o[t]}catch(g){ge.debug("config not set; sending all attributes to backend")}if(0===Object.keys(o).length)return ge.debug("No attributes to update. Skipping update."),c(o);ge.debug("Updating attributes: "+JSON.stringify(o));const a={attributes:o},u=new d({apiHost:e,environmentId:t}),p=await u.client.people.update(n,a);return p.ok?c(o):l({code:"network_error",status:500,message:`Error updating person with userId ${n}`,url:`${e}/api/v1/client/${t}/people/${n}`,responseMessage:p.error.message})})(e.apiHost,e.environmentId,e.userId,e.attributes);if(!0!==t.ok)return l(t.error);n=t.value}try{t=we.get()}catch(s){ye.debug("No existing configuration found.")}return t&&t.state&&t.environmentId===e.environmentId&&t.apiHost===e.apiHost&&t.userId===e.userId&&t.expiresAt?(ye.debug("Found existing configuration."),t.expiresAt<new Date?(ye.debug("Configuration expired."),await C({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId})):(ye.debug("Configuration not expired. Extending expiration."),we.update(t))):(ye.debug("No valid configuration found or it has been expired. Creating new config."),ye.debug("Syncing."),await C({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId}),await M("New Session")),n&&Object.keys(n).length>0&&we.update({environmentId:we.get().environmentId,apiHost:we.get().apiHost,userId:we.get().userId,state:{...we.get().state,attributes:{...we.get().state.attributes,...e.attributes}}}),ye.debug("Adding event listeners"),ce(),ue||(window.addEventListener("beforeunload",(()=>{A(),ie(),de(),Q(),K()})),ue=!0),Ie=!0,ye.debug("Initialized"),te(),{ok:!0,value:void 0}},ke=()=>{ye.debug("Deinitializing"),P(),le(),we.resetConfig(),Ie=!1};u.getInstance().debug("Create command queue");const Se=new class{constructor(){this.queue=[],this.running=!1,this.resolvePromise=null,this.commandPromise=null}add(e=!0,t,...n){this.queue.push({command:t,checkInitialized:e,commandArgs:n}),this.running||(this.commandPromise=new Promise((e=>{this.resolvePromise=e,this.run()})))}async wait(){this.running&&await this.commandPromise}async run(){for(this.running=!0;this.queue.length>0;){const e=v.getInstance(),t=this.queue.shift();if(!t)continue;if(t.checkInitialized){const t=(ye.debug("Check if initialized"),Ie&&v.initialized?{ok:!0,value:void 0}:l({code:"not_initialized",message:"Formbricks not initialized. Call initialize() first."}));t&&!0!==t.ok&&e.handle(t.error)}const n=async()=>await(null==t?void 0:t.command.apply(null,null==t?void 0:t.commandArgs)),s=await B(n)();s&&(s.ok&&s.data&&!s.data.ok&&e.handle(s.data.error),!0!==s.ok&&e.handle(s.error))}this.running=!1,this.resolvePromise&&(this.resolvePromise(),this.resolvePromise=null,this.commandPromise=null)}},He=async(e,t)=>{Se.add(!0,ve,e,t),await Se.wait()};return{init:async e=>{v.init(e.errorHandler),Se.add(!1,be,e),await Se.wait()},setUserId:async()=>{Se.add(!0,he),await Se.wait()},setEmail:async e=>{He("email",e),await Se.wait()},setAttribute:He,track:async(e,t={})=>{Se.add(!0,M,e,t),await Se.wait()},logout:async()=>{Se.add(!0,fe),await Se.wait()},reset:async()=>{Se.add(!0,me),await Se.wait()},registerRouteChange:async()=>{Se.add(!0,te),await Se.wait()},getApi:()=>{const e=m.getInstance(),{environmentId:t,apiHost:n}=e.get();if(!t||!n)throw new Error("formbricks.init() must be called before getApi()");return new d({apiHost:n,environmentId:t})}}})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).formbricks=t()}(this,(function(){"use strict";const e=e=>({ok:!1,error:e});async function t(t,n,s,i){const r=new URL(n,t),o=JSON.stringify(i),a=(d=fetch,(...e)=>{try{return{ok:!0,data:d(...e)}}catch(t){return{ok:!1,error:t}}})(r.toString(),{method:s,headers:{"Content-Type":"application/json"},body:o});var d;if(!1===a.ok)return e(a.error);const u=await a.data,{data:c}=await u.json();return u.ok?(e=>({ok:!0,data:e}))(c):e({code:"network_error",message:u.statusText,status:u.status,url:r})}class n{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/actions`,"POST",e)}}class s{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/displays`,"POST",e)}async update(e,n){return t(this.apiHost,`/api/v1/client/${this.environmentId}/displays/${e}`,"PUT",n)}}class i{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/people`,"POST",{environmentId:this.environmentId,userId:e})}async update(e,n){return t(this.apiHost,`/api/v1/client/${this.environmentId}/people/${e}`,"POST",n)}}class r{constructor(e,t){this.apiHost=e,this.environmentId=t}async create(e){return t(this.apiHost,`/api/v1/client/${this.environmentId}/responses`,"POST",e)}async update({responseId:e,finished:n,data:s,ttc:i}){return t(this.apiHost,`/api/v1/client/${this.environmentId}/responses/${e}`,"PUT",{finished:n,data:s,ttc:i})}}class o{constructor(e,t){this.apiHost=e,this.environmentId=t}async uploadFile(e,{allowedFileExtensions:t,surveyId:n}={}){if(!(e instanceof Blob&&e instanceof File))throw new Error("Invalid file type. Expected Blob or File, but received "+typeof e);const s={fileName:e.name,fileType:e.type,allowedFileExtensions:t,surveyId:n},i=await fetch(`${this.apiHost}/api/v1/client/${this.environmentId}/storage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!i.ok)throw new Error(`Upload failed with status: ${i.status}`);const r=await i.json(),{data:o}=r,{signedUrl:a,fileUrl:d,signingData:u,presignedFields:c,updatedFileName:l}=o;let p={};if(u){const{signature:t,timestamp:s,uuid:i}=u;p={"X-File-Type":e.type,"X-File-Name":encodeURIComponent(l),"X-Survey-ID":n??"","X-Signature":t,"X-Timestamp":String(s),"X-UUID":i}}const g=new FormData;c&&Object.keys(c).forEach((e=>{g.append(e,c[e])})),g.append("file",e);const h=await fetch(a,{method:"POST",...u?{headers:p}:{},body:g});if(!h.ok){if(u){const e=await h.json(),t=new Error(e.message);throw t.name="FileTooLargeError",t}const e=await h.text();if(c&&e&&e.includes("EntityTooLarge")){const e=new Error("File size exceeds the size limit for your plan");throw e.name="FileTooLargeError",e}throw new Error(`Upload failed with status: ${h.status}`)}return d}}class a{constructor(e){const{apiHost:t,environmentId:a}=e;this.response=new r(t,a),this.display=new s(t,a),this.action=new n(t,a),this.people=new i(t,a),this.storage=new o(t,a)}}class d{constructor(e){this.client=new a(e)}}class u{constructor(){this.logLevel="error"}static getInstance(){return u.instance||(u.instance=new u),u.instance}configure(e){e&&void 0!==e.logLevel&&(this.logLevel=e.logLevel)}logger(e,t){if("debug"===t&&"debug"!==this.logLevel)return;const n=`🧱 Formbricks - ${(new Date).toISOString()} [${t.toUpperCase()}] - ${e}`;"error"===t?console.error(n):console.log(n)}debug(e){this.logger(e,"debug")}error(e){this.logger(e,"error")}}const c=e=>({ok:!0,value:e}),l=e=>({ok:!1,error:e});const p=e=>(...t)=>{try{return{ok:!0,value:e(...t)}}catch(n){return{ok:!1,error:n}}},g=u.getInstance(),h=class e{constructor(e){this.customized=!1,e?(this.handleError=e,this.customized=!0):this.handleError=e=>u.getInstance().error(JSON.stringify(e))}static getInstance(){return e.instance||(e.instance=new e),e.instance}static init(t){this.initialized=!0,e.instance=new e(t)}printStatus(){g.debug("Custom error handler: "+(this.customized?"yes":"no"))}handle(e){console.warn("🧱 Formbricks - Global error: ",e),this.handleError(e)}};h.initialized=!1;let v=h;const f="formbricks-js";class y{constructor(){this.config=null;const e=this.loadFromLocalStorage();e.ok&&(this.config=e.value)}static getInstance(){return y.instance||(y.instance=new y),y.instance}update(e){if(e){const t=new Date((new Date).getTime()+9e5);this.config={...this.config,...e,expiresAt:t},this.saveToLocalStorage()}}get(){if(!this.config)throw new Error("config is null, maybe the init function was not called?");return this.config}loadFromLocalStorage(){if("undefined"!=typeof window){const e=localStorage.getItem(f);if(e){const t=JSON.parse(e);return t.expiresAt&&new Date(t.expiresAt)<=new Date?l(new Error("Config in local storage has expired")):c(JSON.parse(e))}}return l(new Error("No or invalid config in local storage"))}saveToLocalStorage(){return p((()=>localStorage.setItem(f,JSON.stringify(this.config))))()}resetConfig(){return this.config=null,p((()=>localStorage.removeItem(f)))()}}const m=e=>new Promise((t=>setTimeout(t,e)));class w{constructor(e,t){this.queue=[],this.isRequestInProgress=!1,this.config=e,this.surveyState=t,this.api=new d({apiHost:e.apiHost,environmentId:e.environmentId})}add(e){this.surveyState.accumulateResponse(e),this.config.setSurveyState&&this.config.setSurveyState(this.surveyState),this.queue.push(e),this.processQueue()}async processQueue(){if(this.isRequestInProgress)return;if(0===this.queue.length)return;this.isRequestInProgress=!0;const e=this.queue[0];let t=0;for(;t<this.config.retryAttempts;){if(await this.sendResponse(e)){this.queue.shift();break}console.error("Formbricks: Failed to send response. Retrying...",t),await m(1e3),t++}t>=this.config.retryAttempts?(console.error("Failed to send response after 2 attempts."),this.config.onResponseSendingFailed&&this.config.onResponseSendingFailed(e),this.isRequestInProgress=!1):(this.isRequestInProgress=!1,this.processQueue())}async sendResponse(e){try{if(null!==this.surveyState.responseId)await this.api.client.response.update({...e,responseId:this.surveyState.responseId});else{const t=await this.api.client.response.create({...e,surveyId:this.surveyState.surveyId,userId:this.surveyState.userId||null,singleUseId:this.surveyState.singleUseId||null});if(!t.ok)throw new Error("Could not create response");this.surveyState.displayId&&await this.api.client.display.update(this.surveyState.displayId,{responseId:t.data.id}),this.surveyState.updateResponseId(t.data.id),this.config.setSurveyState&&this.config.setSurveyState(this.surveyState)}return!0}catch(t){return console.error(t),!1}}updateSurveyState(e){this.surveyState=e}}class I{constructor(e,t,n,s){this.responseId=null,this.displayId=null,this.userId=null,this.responseAcc={finished:!1,data:{},ttc:{}},this.surveyId=e,this.userId=s??null,this.singleUseId=t??null,this.responseId=n??null}setSurveyId(e){this.surveyId=e,this.clear()}copy(){const e=new I(this.surveyId,this.singleUseId??void 0,this.responseId??void 0,this.userId??void 0);return e.responseId=this.responseId,e.responseAcc=this.responseAcc,e}updateResponseId(e){this.responseId=e}updateDisplayId(e){this.displayId=e}updateUserId(e){this.userId=e}accumulateResponse(e){this.responseAcc={finished:e.finished,ttc:e.ttc,data:{...this.responseAcc.data,...e.data}}}isResponseFinished(){return this.responseAcc.finished}clear(){this.responseId=null,this.responseAcc={finished:!1,data:{},ttc:{}}}}const b=I,k=(e,t)=>{const n=Math.abs(t.getTime()-e.getTime());return Math.floor(n/864e5)},S=y.getInstance(),H=u.getInstance();let E=null;const C=async e=>{try{const n=await(async({apiHost:e,environmentId:t,userId:n})=>{const s=`${e}/api/v1/client/${t}/in-app/sync/${n}`,i=`${e}/api/v1/client/${t}/in-app/sync`;if(!n){const e=await fetch(i);if(!e.ok){const t=await e.json();return l({code:"network_error",status:e.status,message:"Error syncing with backend",url:s,responseMessage:t.message})}return c((await e.json()).data)}const r=await fetch(s);if(!r.ok){const e=await r.json();return l({code:"network_error",status:r.status,message:"Error syncing with backend",url:s,responseMessage:e.message})}const o=await r.json(),{data:a}=o;return c(a)})(e);if(!0!==(null==n?void 0:n.ok))throw H.error(`Sync failed: ${JSON.stringify(n.error)}`),n.error;let s;try{s=S.get().state}catch(t){}let i={surveys:n.value.surveys,noCodeActionClasses:n.value.noCodeActionClasses,product:n.value.product,attributes:(null==s?void 0:s.attributes)||{}};if(e.userId){const e=i.surveys.map((e=>e.name));H.debug("Fetched "+e.length+" surveys during sync: "+e.join(", "))}else{i={...i,displays:(null==s?void 0:s.displays)||[]},i=$(i);const e=i.surveys.map((e=>e.name));H.debug("Fetched "+e.length+" surveys during sync: "+e.join(", "))}S.update({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId,state:i})}catch(n){throw H.error(`Error during sync: ${n}`),n}},$=e=>{const{displays:t,product:n}=e;let{surveys:s}=e;if(!t)return e;let i=s.filter((e=>{if("respondMultiple"===e.displayOption)return!0;if("displayOnce"===e.displayOption)return 0===t.filter((t=>t.surveyId===e.id)).length;if("displayMultiple"===e.displayOption)return 0===t.filter((t=>t.surveyId===e.id&&t.responded)).length;throw Error("Invalid displayOption")}));const r=t.length>0?t[t.length-1]:void 0;return i=i.filter((e=>{if(r){if(null!==e.recontactDays){const n=t.filter((t=>t.surveyId===e.id))[0];return!n||k(new Date,new Date(n.createdAt))>=e.recontactDays}return null===n.recontactDays||k(new Date,new Date(r.createdAt))>=n.recontactDays}return!0})),{...e,surveys:i}},A=()=>{"undefined"!=typeof window&&null!==E&&(window.clearInterval(E),E=null)},F="formbricks-web-container",L=y.getInstance(),O=u.getInstance(),D=v.getInstance();let P=!1,U=e=>{};const x=async e=>{if(P)return void O.debug("A survey is already running. Skipping.");P=!0,e.delay&&O.debug(`Delaying survey by ${e.delay} seconds.`);const t=L.get().state.product,n=new b(e.id,null,null,L.get().userId),s=new w({apiHost:L.get().apiHost,environmentId:L.get().environmentId,retryAttempts:2,onResponseSendingFailed:()=>{U(!0)}},n),i=e.productOverwrites??{},r=i.brandColor??t.brandColor,o=i.highlightBorderColor??t.highlightBorderColor,a=i.clickOutsideClose??t.clickOutsideClose,u=i.darkOverlay??t.darkOverlay,c=i.placement??t.placement,l=t.inAppSurveyBranding,p=await R();setTimeout((()=>{p.renderSurveyModal({survey:e,brandColor:r,isBrandingEnabled:l,clickOutside:a,darkOverlay:u,highlightBorderColor:o,placement:c,getSetIsError:e=>{U=e},onDisplay:async()=>{const{userId:t}=L.get();if(!t){const t={createdAt:new Date,surveyId:e.id,responded:!1},n=L.get().state.displays,s=n?[...n,t]:[t],i=L.get();let r=$({...i.state,displays:s});L.update({...i,state:r})}const i=new d({apiHost:L.get().apiHost,environmentId:L.get().environmentId}),r=await i.client.display.create({surveyId:e.id,userId:t});if(!r.ok)throw new Error("Could not create display");const{id:o}=r.data;n.updateDisplayId(o),s.updateSurveyState(n)},onResponse:e=>{const{userId:t}=L.get();if(!t){const e=L.get().state.displays,t=e&&e[e.length-1];if(!t)throw new Error("No lastDisplay found");if(!t.responded){t.responded=!0;const n=L.get();let s=$({...n.state,displays:e});L.update({...n,state:s})}}t&&n.updateUserId(t),s.updateSurveyState(n),s.add({data:e.data,ttc:e.ttc,finished:e.finished})},onClose:T,onFileUpload:async(e,t)=>{const n=new d({apiHost:L.get().apiHost,environmentId:L.get().environmentId});return await n.client.storage.uploadFile(e,t)},onRetry:()=>{U(!1),s.processQueue()}})}),1e3*e.delay)},T=async()=>{var e;if(null==(e=document.getElementById(F))||e.remove(),N(),!L.get().userId){const e=L.get().state,t=$(e);return L.update({...L.get(),state:t}),void(P=!1)}try{await C({apiHost:L.get().apiHost,environmentId:L.get().environmentId,userId:L.get().userId}),P=!1}catch(t){D.handle(t)}},N=()=>{const e=document.createElement("div");e.id=F,document.body.appendChild(e)},R=()=>new Promise(((e,t)=>{if(window.formbricksSurveys)e(window.formbricksSurveys);else{const n=document.createElement("script");n.src="https://unpkg.com/@formbricks/surveys@^1.5.1/dist/index.umd.js",n.async=!0,n.onload=()=>e(window.formbricksSurveys),n.onerror=e=>{console.error("Failed to load Formbricks Surveys library:",e),t(e)},document.head.appendChild(n)}})),z=u.getInstance(),j=y.getInstance(),q=["Exit Intent (Desktop)","50% Scroll"],M=async(e,t={})=>{var n;const{userId:s}=j.get(),i={environmentId:j.get().environmentId,userId:s,name:e,properties:t||{}};if(s&&!q.includes(e)){z.debug(`Sending action "${e}" to backend`);const t=new d({apiHost:j.get().apiHost,environmentId:j.get().environmentId}),n=await t.client.action.create({...i,userId:s});if(!n.ok)return l({code:"network_error",message:`Error tracking action ${e}`,status:500,url:`${j.get().apiHost}/api/v1/client/${j.get().environmentId}/actions`,responseMessage:n.error.message})}z.debug(`Formbricks: Action "${e}" tracked`);const r=null==(n=j.get().state)?void 0:n.surveys;return r&&r.length>0?await _(e,r):z.debug("No active surveys to display"),{ok:!0,value:void 0}},_=async(e,t)=>{for(const s of t){if(s.displayPercentage){if(!(n=s.displayPercentage,Math.floor(100*Math.random())+1<=n)){z.debug("Survey display skipped based on displayPercentage.");continue}}for(const t of s.triggers)if(t===e)return z.debug(`Formbricks: survey ${s.id} triggered by action "${e}"`),void(await x(s))}var n},B=e=>async(...t)=>{try{return{ok:!0,data:await e(...t)}}catch(n){return{ok:!1,error:n}}};let J=!1,X=async function(e){if(e.clientY<=0){const e=await M("Exit Intent (Desktop)");if(!0!==e.ok)return l(e.error)}};const Q=()=>{J&&(document.removeEventListener("mouseleave",X),J=!1)};let W=!1,Y=!1,G=async()=>{const e=window.scrollY,t=window.innerHeight,n=document.documentElement.scrollHeight;if(0===e&&(Y=!1),!Y&&e/(n-t)>=.5){Y=!0;const e=await M("50% Scroll");if(!0!==e.ok)return l(e.error)}};const K=()=>{W&&(window.removeEventListener("scroll",G),W=!1)},V=y.getInstance(),Z=u.getInstance(),ee=v.getInstance(),te=async()=>{var e;Z.debug(`Checking page url: ${window.location.href}`);const{state:t}=V.get();if(void 0===(null==t?void 0:t.noCodeActionClasses))return{ok:!0,value:void 0};const n=((null==t?void 0:t.noCodeActionClasses)||[]).filter((e=>{const{innerHtml:t,cssSelector:n,pageUrl:s}=e.noCodeConfig||{};return s&&!t&&!n}));if(0===n.length)return{ok:!0,value:void 0};for(const s of n){if(!(null==(e=s.noCodeConfig)?void 0:e.pageUrl))continue;const{noCodeConfig:{pageUrl:t}}=s,n=re(window.location.href,t.value,t.rule);if(!0!==n.ok)return l(n.error);if(!1===n.value)continue;const i=await M(s.name);if(!0!==i.ok)return l(i.error)}return{ok:!0,value:void 0}};let ne=!1;const se=()=>te(),ie=()=>{"undefined"!=typeof window&&ne&&(window.removeEventListener("hashchange",se),window.removeEventListener("popstate",se),window.removeEventListener("pushstate",se),window.removeEventListener("replacestate",se),window.removeEventListener("load",se),ne=!1)};function re(e,t,n){switch(n){case"exactMatch":return c(e===t);case"contains":return c(e.includes(t));case"startsWith":return c(e.startsWith(t));case"endsWith":return c(e.endsWith(t));case"notMatch":return c(e!==t);case"notContains":return c(!e.includes(t));default:return l({code:"invalid_match_type",message:"Invalid match type"})}}let oe=!1;const ae=e=>(e=>{const{state:t}=V.get();if(!t)return;const n=e.target;((null==t?void 0:t.noCodeActionClasses)||[]).forEach((e=>{var t,s,i,r,o,a,d,u;const c=null==(s=null==(t=e.noCodeConfig)?void 0:t.innerHtml)?void 0:s.value,l=null==(r=null==(i=e.noCodeConfig)?void 0:i.cssSelector)?void 0:r.value,p=null==(a=null==(o=e.noCodeConfig)?void 0:o.pageUrl)?void 0:a.value,g=null==(u=null==(d=e.noCodeConfig)?void 0:d.pageUrl)?void 0:u.rule;if((c||l||p)&&(!c||n.innerHTML===c)){if(l){const e=l.split(/\s*(?=[.#])/);for(let t of e)if(!n.matches(t))return}if(p&&g){const e=re(window.location.href,p,g);if(!e.ok||!e.value)return}M(e.name).then((e=>{var t,n,s;n=e=>{},s=e=>{ee.handle(e)},!0===(t=e).ok?n(t.value):s(t.error)}))}}))})(e),de=()=>{oe&&(document.removeEventListener("click",ae),oe=!1)};let ue=!1;const ce=()=>{"undefined"!=typeof window&&null===E&&(E=window.setInterval((async()=>{S.get().expiresAt&&new Date(S.get().expiresAt)>=new Date||(H.debug("Config has expired. Starting sync."),await C({apiHost:S.get().apiHost,environmentId:S.get().environmentId,userId:S.get().userId}))}),6e4)),"undefined"==typeof window||ne||(window.addEventListener("hashchange",se),window.addEventListener("popstate",se),window.addEventListener("pushstate",se),window.addEventListener("replacestate",se),window.addEventListener("load",se),ne=!0),"undefined"==typeof window||oe||(document.addEventListener("click",ae),oe=!0),"undefined"==typeof document||J||(document.querySelector("body").addEventListener("mouseleave",X),J=!0),"undefined"==typeof window||W||(window.addEventListener("load",(()=>{window.addEventListener("scroll",G)})),W=!0)},le=()=>{A(),ie(),de(),Q(),K(),ue&&(window.removeEventListener("beforeunload",(()=>{A(),ie(),de(),Q(),K()})),ue=!1)},pe=y.getInstance(),ge=u.getInstance(),he=async()=>(ge.error("'setUserId' is no longer supported. Please set the userId in the init call instead."),{ok:!0,value:void 0}),ve=async(e,t)=>{if(ge.debug("Setting attribute: "+e+" to value: "+t),((e,t)=>pe.get().state.attributes[e]===t)(e,t.toString()))return ge.debug("Attribute already set to this value. Skipping update."),{ok:!0,value:void 0};const n=await(async(e,t)=>{const{apiHost:n,environmentId:s,userId:i}=pe.get();if(!i)return l({code:"missing_person",message:"Unable to update attribute. User identification deactivated. No userId set."});const r={attributes:{[e]:t}},o=new d({apiHost:pe.get().apiHost,environmentId:pe.get().environmentId}),a=await o.client.people.update(i,r);return a.ok?(ge.debug("Attribute updated. Syncing..."),await C({environmentId:s,apiHost:n,userId:i}),{ok:!0,value:void 0}):l({code:"network_error",status:500,message:`Error updating person with userId ${i}`,url:`${pe.get().apiHost}/api/v1/client/${s}/people/${i}`,responseMessage:a.error.message})})(e,t.toString());return n.ok?(pe.update({environmentId:pe.get().environmentId,apiHost:pe.get().apiHost,userId:pe.get().userId,state:{...pe.get().state,attributes:{...pe.get().state.attributes,[e]:t.toString()}}}),{ok:!0,value:void 0}):l(n.error)},fe=async()=>{ke()},ye=async()=>{ge.debug("Resetting state & getting new state from backend"),T();const e={environmentId:pe.get().environmentId,apiHost:pe.get().apiHost,userId:pe.get().userId};await fe();try{return await be(e),{ok:!0,value:void 0}}catch(t){return l(t)}},me=y.getInstance(),we=u.getInstance();let Ie=!1;const be=async e=>{if(Ie)return we.debug("Already initialized, skipping initialization."),{ok:!0,value:void 0};if((e=>{e.debug&&(we.debug("Setting log level to debug"),we.configure({logLevel:"debug"}))})(e),v.getInstance().printStatus(),we.debug("Start initialize"),!e.environmentId)return we.debug("No environmentId provided"),l({code:"missing_field",field:"environmentId"});if(!e.apiHost)return we.debug("No apiHost provided"),l({code:"missing_field",field:"apiHost"});if(we.debug("Adding widget container to DOM"),N(),!e.userId&&e.attributes)return we.error("No userId provided but attributes. Cannot update attributes without userId."),l({code:"missing_field",field:"userId"});let t,n=null;if(e.userId&&e.attributes){const t=await(async(e,t,n,s)=>{var i,r;if(!n)return l({code:"missing_person",message:"Unable to update attribute. User identification deactivated. No userId set."});const o={...s};try{const e=null==(r=null==(i=pe.get())?void 0:i.state)?void 0:r.attributes;if(e)for(const[t,n]of Object.entries(e))o[t]===n&&delete o[t]}catch(g){ge.debug("config not set; sending all attributes to backend")}if(0===Object.keys(o).length)return ge.debug("No attributes to update. Skipping update."),c(o);ge.debug("Updating attributes: "+JSON.stringify(o));const a={attributes:o},u=new d({apiHost:e,environmentId:t}),p=await u.client.people.update(n,a);return p.ok?c(o):l({code:"network_error",status:500,message:`Error updating person with userId ${n}`,url:`${e}/api/v1/client/${t}/people/${n}`,responseMessage:p.error.message})})(e.apiHost,e.environmentId,e.userId,e.attributes);if(!0!==t.ok)return l(t.error);n=t.value}try{t=me.get()}catch(s){we.debug("No existing configuration found.")}return t&&t.state&&t.environmentId===e.environmentId&&t.apiHost===e.apiHost&&t.userId===e.userId&&t.expiresAt?(we.debug("Found existing configuration."),t.expiresAt<new Date?(we.debug("Configuration expired."),await C({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId})):(we.debug("Configuration not expired. Extending expiration."),me.update(t))):(we.debug("No valid configuration found or it has been expired. Creating new config."),we.debug("Syncing."),await C({apiHost:e.apiHost,environmentId:e.environmentId,userId:e.userId}),await M("New Session")),n&&Object.keys(n).length>0&&me.update({environmentId:me.get().environmentId,apiHost:me.get().apiHost,userId:me.get().userId,state:{...me.get().state,attributes:{...me.get().state.attributes,...e.attributes}}}),we.debug("Adding event listeners"),ce(),ue||(window.addEventListener("beforeunload",(()=>{A(),ie(),de(),Q(),K()})),ue=!0),Ie=!0,we.debug("Initialized"),te(),{ok:!0,value:void 0}},ke=()=>{we.debug("Deinitializing"),T(),le(),me.resetConfig(),Ie=!1};u.getInstance().debug("Create command queue");const Se=new class{constructor(){this.queue=[],this.running=!1,this.resolvePromise=null,this.commandPromise=null}add(e=!0,t,...n){this.queue.push({command:t,checkInitialized:e,commandArgs:n}),this.running||(this.commandPromise=new Promise((e=>{this.resolvePromise=e,this.run()})))}async wait(){this.running&&await this.commandPromise}async run(){for(this.running=!0;this.queue.length>0;){const e=v.getInstance(),t=this.queue.shift();if(!t)continue;if(t.checkInitialized){const t=(we.debug("Check if initialized"),Ie&&v.initialized?{ok:!0,value:void 0}:l({code:"not_initialized",message:"Formbricks not initialized. Call initialize() first."}));t&&!0!==t.ok&&e.handle(t.error)}const n=async()=>await(null==t?void 0:t.command.apply(null,null==t?void 0:t.commandArgs)),s=await B(n)();s&&(s.ok&&s.data&&!s.data.ok&&e.handle(s.data.error),!0!==s.ok&&e.handle(s.error))}this.running=!1,this.resolvePromise&&(this.resolvePromise(),this.resolvePromise=null,this.commandPromise=null)}},He=async(e,t)=>{Se.add(!0,ve,e,t),await Se.wait()};return{init:async e=>{v.init(e.errorHandler),Se.add(!1,be,e),await Se.wait()},setUserId:async()=>{Se.add(!0,he),await Se.wait()},setEmail:async e=>{He("email",e),await Se.wait()},setAttribute:He,track:async(e,t={})=>{Se.add(!0,M,e,t),await Se.wait()},logout:async()=>{Se.add(!0,fe),await Se.wait()},reset:async()=>{Se.add(!0,ye),await Se.wait()},registerRouteChange:async()=>{Se.add(!0,te),await Se.wait()},getApi:()=>{const e=y.getInstance(),{environmentId:t,apiHost:n}=e.get();if(!t||!n)throw new Error("formbricks.init() must be called before getApi()");return new d({apiHost:n,environmentId:t})}}})); | ||
//# sourceMappingURL=index.umd.js.map |
{ | ||
"name": "@formbricks/js", | ||
"license": "MIT", | ||
"version": "1.5.0", | ||
"version": "1.5.1", | ||
"description": "Formbricks-js allows you to connect your app to Formbricks, display surveys and trigger events.", | ||
@@ -51,7 +51,7 @@ "homepage": "https://formbricks.com", | ||
"eslint-config-turbo": "1.10.12", | ||
"@formbricks/surveys": "1.5.1", | ||
"@formbricks/lib": "0.0.0", | ||
"@formbricks/tsconfig": "1.0.0", | ||
"@formbricks/api": "1.5.0", | ||
"@formbricks/surveys": "1.5.0", | ||
"@formbricks/types": "0.0.0" | ||
"@formbricks/types": "0.0.0", | ||
"@formbricks/api": "1.5.0" | ||
}, | ||
@@ -58,0 +58,0 @@ "jest": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
504328
1796
20