@frigade/js 0.2.20 → 0.2.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +164 -34
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -6
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
var q=Object.create;var _=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var tt=Object.getPrototypeOf,et=Object.prototype.hasOwnProperty;var it=(s,a)=>{for(var t in a)_(s,t,{get:a[t],enumerable:!0})},J=(s,a,t,e)=>{if(a&&typeof a=="object"||typeof a=="function")for(let i of Z(a))!et.call(s,i)&&i!==t&&_(s,i,{get:()=>a[i],enumerable:!(e=Q(a,i))||e.enumerable});return s};var st=(s,a,t)=>(t=s!=null?q(tt(s)):{},J(a||!s||!s.__esModule?_(t,"default",{value:s,enumerable:!0}):t,s)),ot=s=>J(_({},"__esModule",{value:!0}),s);var pt={};it(pt,{Flow:()=>w,Frigade:()=>P});module.exports=ot(pt);var V="0.2.20";var Y=st(require("cross-fetch"),1),X=require("uuid");var c={};function R(s){return`${s.__instanceId}-${s.apiKey}:${s.userId??""}:${s.groupId??""}`}var A=class{constructor(a){this.config={apiKey:"",apiUrl:"https://api.frigade.com/v1/public",userId:$(),__instanceId:Math.random().toString(36).substring(7)};let t=Object.fromEntries(Object.entries(a).filter(([e,i])=>i!=null));this.config={...this.config,...t}}async fetch(a,t){return this.config.__readOnly?f():K(`${this.config.apiUrl}${a}`,{...t??{},...k(this.config.apiKey)})}getGlobalState(){let a=R(this.config);if(!c[a])throw new Error("Frigade not initialized");return c[a]}};var w=class extends A{constructor(t,e){super(t);this.isVisible=!1;this.lastStepUpdate=new Map;this.lastUsedVariables={};this.flowDataRaw=e,this.initFromRawData(e)}reload(){this.initFromRawData(this.flowDataRaw)}initFromRawData(t){let e=JSON.parse(t.data),i=e.steps??e.data??[];this.id=t.slug,this.rawData=t,this.configYmlAsJson=e,this.title=this.configYmlAsJson.title,this.subtitle=this.configYmlAsJson.subtitle;let o=this.getUserFlowState();if(!o)return;this.userFlowStateRaw=o,this.isCompleted=o.flowState==D,this.isStarted=o.flowState==E,this.isSkipped=o.flowState==G;let p=this.isCompleted||this.isSkipped,n=t.targetingLogic&&o.shouldTrigger===!1;this.isVisible=!p&&!n,this.flowDataRaw.active===!1&&(this.isVisible=!1);let y=new Map;i.forEach((S,T)=>{let C=o.stepStates[S.id],I={...S,isCompleted:C.actionType==b,isStarted:C.actionType==u,isHidden:C.hidden,isBlocked:C.blocked,lastActionAt:C.lastActionAt?new Date(C.lastActionAt):void 0,order:T};I.start=async l=>{let r=this.steps.get(S.id);if(this.getCurrentStep().id===r.id&&r.isStarted)return;r.isStarted=!0;let g=F(this.getGlobalState().userFlowStates[this.id]);g.stepStates[r.id].actionType=u,g.stepStates[r.id].lastActionAt=new Date().toISOString(),g.lastStepId=r.id,this.getGlobalState().userFlowStates[this.id]=g,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:r.id,data:l??{},createdAt:new Date().toISOString(),actionType:u})}),await this.refreshUserFlowState();let h=this.getUserFlowState();r.isCompleted=h.stepStates[r.id].actionType==b,r.isStarted=h.stepStates[r.id].actionType==u,r.lastActionAt=new Date},I.complete=async l=>{let r=this.steps.get(S.id);if(r.isCompleted)return;let h=this.getNumberOfCompletedSteps()+1==this.steps.size;r.isCompleted=!0,this.isStarted=!0;let d=F(this.getGlobalState().userFlowStates[this.id]);d.stepStates[r.id].actionType=b,d.stepStates[r.id].lastActionAt=new Date().toISOString(),d.flowState=h?D:E;let O=Array.from(this.steps.keys())[T+1];if(O){d.lastStepId=O,d.stepStates[O].actionType=u;let W=new Date;d.stepStates[O].lastActionAt=W.toISOString(),this.steps.get(O).isStarted=!0,this.steps.get(O).lastActionAt=W}h&&this.optimisticallyMarkFlowCompleted(),this.getGlobalState().userFlowStates[this.id]=d,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:r.id,data:l??{},createdAt:new Date().toISOString(),actionType:b})}),await this.refreshUserFlowState();let M=this.getUserFlowState();r.isCompleted=M.stepStates[r.id].actionType==b,r.isStarted=M.stepStates[r.id].actionType==u,r.lastActionAt=new Date},I.reset=async()=>{let l=this.steps.get(S.id);if(!l.isCompleted)return;l.isCompleted=!1,l.isStarted=!1,l.lastActionAt=void 0;let r=F(this.getGlobalState().userFlowStates[this.id]);r.stepStates[l.id].actionType=v,r.stepStates[l.id].lastActionAt=void 0,r.flowState=E,this.getGlobalState().userFlowStates[this.id]=r,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:l.id,data:{},createdAt:new Date().toISOString(),actionType:v})}),await this.refreshUserFlowState();let g=this.getUserFlowState();l.isCompleted=g.stepStates[l.id].actionType==b,l.isStarted=g.stepStates[l.id].actionType==u,l.lastActionAt=void 0},I.onStateChange=l=>{let r=g=>{if(g.id!==this.id)return;let h=g.steps.get(S.id),d=this.lastStepUpdate.get(l);(h.isCompleted!==(d==null?void 0:d.isCompleted)||h.isStarted!==(d==null?void 0:d.isStarted)||h.isHidden!==(d==null?void 0:d.isHidden)||h.isBlocked!==(d==null?void 0:d.isBlocked))&&(l(h,d??F(h)),this.lastStepUpdate.set(l,F(h)))};this.getGlobalState().onStepStateChangeHandlerWrappers.set(l,r),this.getGlobalState().onFlowStateChangeHandlers.push(r)},I.removeStateChangeHandler=l=>{let r=this.getGlobalState().onStepStateChangeHandlerWrappers.get(l);r&&(this.getGlobalState().onFlowStateChangeHandlers=this.getGlobalState().onFlowStateChangeHandlers.filter(g=>g!==r))},y.set(S.id,I)}),this.steps=y,Object.keys(this.lastUsedVariables).length>0&&this.applyVariables(this.lastUsedVariables)}async start(t){if(this.isStarted||this.isCompleted)return;this.isStarted=!0;let e=F(this.getGlobalState().userFlowStates[this.id]);e.flowState=E,this.getGlobalState().userFlowStates[this.id]=e,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:this.getCurrentStep().id,data:t??{},createdAt:new Date().toISOString(),actionType:E})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw)}async complete(t){this.isCompleted||(this.optimisticallyMarkFlowCompleted(),await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:this.getCurrentStep().id,data:t??{},createdAt:new Date().toISOString(),actionType:D})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw))}optimisticallyMarkFlowCompleted(){this.isStarted=!0,this.isCompleted=!0;let t=F(this.getGlobalState().userFlowStates[this.id]);t.flowState=D,this.getGlobalState().userFlowStates[this.id]=t,this.isVisible=!1}async skip(t){await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:this.getCurrentStep().id,data:t??{},createdAt:new Date().toISOString(),actionType:G})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw)}async forward(t){let e=this.getStepByIndex(this.getCurrentStepIndex()+1);e&&await e.start(t)}async back(t){let e=this.getStepByIndex(this.getCurrentStepIndex()-1);e&&await e.start(t)}async restart(){await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:"unknown",data:{},createdAt:new Date().toISOString(),actionType:B})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw)}getStepByIndex(t){return this.steps.get(Array.from(this.steps.keys())[t])}getCurrentStep(){let t=Array.from(this.steps.keys()).find(i=>this.steps.get(i).isCompleted===!1&&this.steps.get(i).isHidden===!1);Array.from(this.steps.keys()).forEach(i=>{var o;this.steps.get(i).isStarted&&this.steps.get(i).lastActionAt&&this.steps.get(i).lastActionAt>(((o=this.steps.get(t))==null?void 0:o.lastActionAt)??new Date(0))&&(t=i)});let e=t??Array.from(this.steps.keys())[0];return this.steps.get(e)}getCurrentStepIndex(){let t=this.getCurrentStep();return Array.from(this.steps.keys()).indexOf(t.id)}getNumberOfCompletedSteps(){return Array.from(this.steps.values()).filter(t=>t.isCompleted).length}getNumberOfAvailableSteps(){return Array.from(this.steps.values()).filter(t=>!t.isHidden).length}onStateChange(t){let e=(i,o)=>{(i.id===this.id&&(i.isCompleted!==o.isCompleted||i.isStarted!==o.isStarted||i.isSkipped!==o.isSkipped||i.isVisible!==o.isVisible)||JSON.stringify(i.steps)!==JSON.stringify(o.steps))&&t(i,o)};this.getGlobalState().onFlowStateChangeHandlerWrappers.set(t,e),this.getGlobalState().onFlowStateChangeHandlers.push(e)}removeStateChangeHandler(t){let e=this.getGlobalState().onFlowStateChangeHandlerWrappers.get(t);e&&(this.getGlobalState().onFlowStateChangeHandlers=this.getGlobalState().onFlowStateChangeHandlers.filter(i=>i!==e))}applyVariables(t){let e=i=>{let o=i.match(/\${(.*?)}/g);return o&&o.forEach(p=>{let n=p.replace("${","").replace("}","");i=i.replace(p,t[n]??"")}),i};this.title=e(this.title??""),this.subtitle=e(this.subtitle??""),this.steps.forEach(i=>{Object.keys(i).forEach(o=>{typeof i[o]=="string"&&(i[o]=e(i[o]))})}),this.lastUsedVariables=t}getUserFlowState(){return this.getGlobalState().userFlowStates[this.id]}async refreshUserFlowState(){await this.getGlobalState().refreshUserFlowStates()}};var v="NOT_STARTED_STEP",D="COMPLETED_FLOW",G="SKIPPED_FLOW",E="STARTED_FLOW",B="NOT_STARTED_FLOW",b="COMPLETED_STEP",u="STARTED_STEP",at="frigade-last-call-at-",rt="frigade-last-call-data-",j="frigade-guest-key",nt="guest_",lt="get-cache-";var dt=1e3,H="fr-js-";function U(s){let a=new w(s.config,s.rawData);return a.isCompleted=s.isCompleted,a.isStarted=s.isStarted,a.isSkipped=s.isSkipped,a.isVisible=s.isVisible,a.steps=s.steps,a}function F(s){return JSON.parse(JSON.stringify(s))}function k(s){return{headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json","X-Frigade-SDK-Version":V,"X-Frigade-SDK-Platform":"Javascript"}}}function N(s){return m()?window.localStorage.getItem(`${H}${s}`):null}function L(s,a){m()&&window.localStorage.setItem(`${H}${s}`,a)}function x(){Object.keys(c).forEach(s=>{s.startsWith(lt)&&delete c[s]})}function z(){m()&&Object.keys(window.localStorage).forEach(s=>{s.startsWith(H)&&window.localStorage.removeItem(s)})}async function K(s,a){let t=at+s,e=rt+s;if(m()&&a&&a.body&&a.method==="POST"){let o=N(t),p=N(e);if(o&&p&&p==a.body){let n=new Date(o);if(new Date().getTime()-n.getTime()<dt)return f()}L(t,new Date().toISOString()),L(e,a.body),x()}let i;try{i=(0,Y.default)(s,a),i=await i}catch(o){return f(o)}if(!i)return f("Received an empty response");if(i.status>=400)return f(i.statusText);try{if(i.status===204||i.status===201)return f();let o=await i.json();return o.error?f(o.error):o}catch(o){return f(o)}}function f(s){return s&&console.log("Call to Frigade failed",s),{json:()=>({})}}function $(){if(m()){let s=N(j);return s||(s=`${nt}${(0,X.v4)()}`,L(j,s)),s}}function m(){return typeof window<"u"}var P=class extends A{constructor(t,e){super({apiKey:t,...e});this.flows=[];this.hasFailed=!1;this.visibilityChangeHandler=async()=>{document.visibilityState==="visible"&&(await this.refreshFlows(),await this.refreshUserFlowStates())};this.init(this.config),m()&&document.addEventListener("visibilitychange",this.visibilityChangeHandler)}destroy(){if(m()){document.removeEventListener("visibilitychange",this.visibilityChangeHandler);let t=R(this.config);c[t]&&(c[t].onFlowStateChangeHandlers=[])}}async init(t){return this.config={...this.config,...t},this.initPromise=(async()=>{await this.refreshUserFlowStates(),await this.refreshFlows()})(),this.initPromise}async identify(t,e){this.config={...this.config,userId:t},await this.initIfNeeded(),await this.fetch("/users",{method:"POST",body:JSON.stringify({foreignId:this.config.userId,properties:e})}),await this.refreshUserFlowStates()}async group(t,e){await this.initIfNeeded(),this.config.groupId=t,await this.fetch("/userGroups",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,properties:e})}),await this.refreshUserFlowStates()}async track(t,e){await this.initIfNeeded(),await this.fetch("/track",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,event:t,properties:e})})}isReady(){return!!(this.config.__instanceId&&this.config.apiKey&&this.initPromise)}async getFlow(t){return await this.initIfNeeded(),this.flows.find(e=>e.id==t)}async getFlows(){return await this.initIfNeeded(),this.flows}async reload(){z(),x(),await this.refreshUserFlowStates(),await this.refreshFlows(),this.initPromise=null,await this.init(this.config),this.flows.forEach(t=>{this.getGlobalState().onFlowStateChangeHandlers.forEach(e=>{let i=this.getGlobalState().previousFlows.get(t.id);e(t,i),this.getGlobalState().previousFlows.set(t.id,U(t))})})}onStateChange(t){this.getGlobalState().onFlowStateChangeHandlers.push(t)}hasFailedToLoad(){return this.hasFailed}removeStateChangeHandler(t){this.getGlobalState().onFlowStateChangeHandlers=this.getGlobalState().onFlowStateChangeHandlers.filter(e=>e!==t)}async initIfNeeded(){return this.initPromise!==null?this.initPromise:this.init(this.config)}async refreshUserFlowStates(){let t=R(this.config);if(!c[t]){let e=this,i={set:function(o,p,n){return o[p]&&o[p].flowState&&(JSON.stringify(o[p].flowState)!==JSON.stringify(n==null?void 0:n.flowState)||JSON.stringify(o[p].stepStates)!==JSON.stringify(n==null?void 0:n.stepStates)||JSON.stringify(o[p].shouldTrigger)!==JSON.stringify(n==null?void 0:n.shouldTrigger))&&e.triggerEventHandlers(o[p]),o[p]=n,!0}};if(c[t]={refreshUserFlowStates:async()=>{},userFlowStates:new Proxy({},i),onFlowStateChangeHandlerWrappers:new Map,onStepStateChangeHandlerWrappers:new Map,onFlowStateChangeHandlers:[],previousFlows:new Map},this.config.__readOnly&&this.config.__flowConfigOverrides){this.mockUserFlowStates(t);return}c[t].refreshUserFlowStates=async()=>{if(this.config.__readOnly)return;let o=await this.fetch(`/userFlowStates?foreignUserId=${encodeURIComponent(this.config.userId)}${this.config.groupId?`&foreignUserGroupId=${encodeURIComponent(this.config.groupId)}`:""}`);o&&o.data?(o.data.forEach(n=>{let y=!1,S=c[t].userFlowStates[n.flowId];S&&S.shouldTrigger==!1&&n.shouldTrigger==!0&&(y=!0),c[t].userFlowStates[n.flowId]=n,y&&this.flows.forEach(T=>{T.id==n.flowId&&(T.reload(),this.triggerEventHandlers(c[t].userFlowStates[T.id]))})}),this.hasFailed=!1):this.hasFailed=!0}}await c[t].refreshUserFlowStates()}async refreshFlows(){if(this.flows=[],this.config.__flowConfigOverrides){this.mockFlowConfigs();return}let t=await this.fetch("/flows");t&&t.data?t.data.forEach(i=>{this.flows.push(new w(this.config,i)),this.getGlobalState().previousFlows.set(i.slug,U(this.flows[this.flows.length-1]))}):this.hasFailed=!0}mockFlowConfigs(){Object.keys(this.config.__flowConfigOverrides).forEach(t=>{this.flows.push(new w(this.config,{id:-1,name:"",description:"",data:this.config.__flowConfigOverrides[t],createdAt:new Date().toISOString(),modifiedAt:new Date().toISOString(),slug:t,targetingLogic:"",type:"CHECKLIST",triggerType:"MANUAL",status:"ACTIVE",version:1,active:!0}))})}mockUserFlowStates(t){Object.keys(this.config.__flowConfigOverrides).forEach(e=>{var o;let i=JSON.parse(this.config.__flowConfigOverrides[e]);c[t].userFlowStates[e]={flowId:e,flowState:"NOT_STARTED_FLOW",lastStepId:null,userId:this.config.userId,foreignUserId:this.config.userId,stepStates:((o=i==null?void 0:i.steps)==null?void 0:o.reduce((p,n)=>(p[n.id]={stepId:n.id,flowSlug:e,actionType:"NOT_STARTED_STEP",createdAt:new Date().toISOString(),blocked:!1,hidden:!1},p),{}))??{},shouldTrigger:!1}})}async triggerEventHandlers(t){t&&this.flows.forEach(e=>{e.id==t.flowId&&this.getGlobalState().onFlowStateChangeHandlers.forEach(i=>{let o=this.getGlobalState().previousFlows.get(e.id);i(e,o),this.getGlobalState().previousFlows.set(e.id,U(e))})})}};0&&(module.exports={Flow,Frigade});
|
|
2
|
+
var q=Object.create;var _=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var tt=Object.getPrototypeOf,et=Object.prototype.hasOwnProperty;var it=(s,a)=>{for(var t in a)_(s,t,{get:a[t],enumerable:!0})},J=(s,a,t,e)=>{if(a&&typeof a=="object"||typeof a=="function")for(let i of Z(a))!et.call(s,i)&&i!==t&&_(s,i,{get:()=>a[i],enumerable:!(e=Q(a,i))||e.enumerable});return s};var st=(s,a,t)=>(t=s!=null?q(tt(s)):{},J(a||!s||!s.__esModule?_(t,"default",{value:s,enumerable:!0}):t,s)),ot=s=>J(_({},"__esModule",{value:!0}),s);var pt={};it(pt,{Flow:()=>w,Frigade:()=>P});module.exports=ot(pt);var V="0.2.20";var Y=st(require("cross-fetch"),1),X=require("uuid");var c={};function R(s){return`${s.__instanceId}-${s.apiKey}:${s.userId??""}:${s.groupId??""}`}var E=class{constructor(a){this.config={apiKey:"",apiUrl:"https://api.frigade.com/v1/public",userId:$(),__instanceId:Math.random().toString(36).substring(7)};let t=Object.fromEntries(Object.entries(a).filter(([e,i])=>i!=null));this.config={...this.config,...t}}async fetch(a,t){return this.config.__readOnly?S():K(`${this.config.apiUrl}${a}`,{...t??{},...k(this.config.apiKey)})}getGlobalState(){let a=R(this.config);if(!c[a])throw new Error("Frigade not initialized");return c[a]}};var w=class extends E{constructor(t,e){super(t);this.isVisible=!1;this.lastStepUpdate=new Map;this.lastUsedVariables={};this.flowDataRaw=e,this.initFromRawData(e)}reload(){this.initFromRawData(this.flowDataRaw)}initFromRawData(t){let e=JSON.parse(t.data),i=e.steps??e.data??[];this.id=t.slug,this.rawData=t,this.configYmlAsJson=e,this.title=this.configYmlAsJson.title,this.subtitle=this.configYmlAsJson.subtitle;let o=this.getUserFlowState();if(!o)return;this.userFlowStateRaw=o,this.isCompleted=o.flowState==D,this.isStarted=o.flowState==A,this.isSkipped=o.flowState==G;let p=this.isCompleted||this.isSkipped,n=t.targetingLogic&&o.shouldTrigger===!1;this.isVisible=!p&&!n,this.flowDataRaw.active===!1&&(this.isVisible=!1);let y=new Map;i.forEach((f,T)=>{let C=o.stepStates[f.id],I={...f,isCompleted:C.actionType==b,isStarted:C.actionType==u,isHidden:C.hidden,isBlocked:C.blocked,lastActionAt:C.lastActionAt?new Date(C.lastActionAt):void 0,order:T};I.start=async l=>{let r=this.steps.get(f.id);if(this.getCurrentStep().id===r.id&&r.isStarted)return;r.isStarted=!0;let g=F(this.getGlobalState().userFlowStates[this.id]);g.stepStates[r.id].actionType=u,g.stepStates[r.id].lastActionAt=new Date().toISOString(),g.lastStepId=r.id,this.getGlobalState().userFlowStates[this.id]=g,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:r.id,data:l??{},createdAt:new Date().toISOString(),actionType:u})}),await this.refreshUserFlowState();let h=this.getUserFlowState();r.isCompleted=h.stepStates[r.id].actionType==b,r.isStarted=h.stepStates[r.id].actionType==u,r.lastActionAt=new Date},I.complete=async l=>{let r=this.steps.get(f.id);if(r.isCompleted)return;let h=this.getNumberOfCompletedSteps()+1==this.steps.size;r.isCompleted=!0,this.isStarted=!0;let d=F(this.getGlobalState().userFlowStates[this.id]);d.stepStates[r.id].actionType=b,d.stepStates[r.id].lastActionAt=new Date().toISOString(),d.flowState=h?D:A;let O=Array.from(this.steps.keys())[T+1];if(O){d.lastStepId=O,d.stepStates[O].actionType=u;let W=new Date;d.stepStates[O].lastActionAt=W.toISOString(),this.steps.get(O).isStarted=!0,this.steps.get(O).lastActionAt=W}h&&this.optimisticallyMarkFlowCompleted(),this.getGlobalState().userFlowStates[this.id]=d,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:r.id,data:l??{},createdAt:new Date().toISOString(),actionType:b})}),await this.refreshUserFlowState();let M=this.getUserFlowState();r.isCompleted=M.stepStates[r.id].actionType==b,r.isStarted=M.stepStates[r.id].actionType==u,r.lastActionAt=new Date},I.reset=async()=>{let l=this.steps.get(f.id);if(!l.isCompleted)return;l.isCompleted=!1,l.isStarted=!1,l.lastActionAt=void 0;let r=F(this.getGlobalState().userFlowStates[this.id]);r.stepStates[l.id].actionType=v,r.stepStates[l.id].lastActionAt=void 0,r.flowState=A,this.getGlobalState().userFlowStates[this.id]=r,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:l.id,data:{},createdAt:new Date().toISOString(),actionType:v})}),await this.refreshUserFlowState();let g=this.getUserFlowState();l.isCompleted=g.stepStates[l.id].actionType==b,l.isStarted=g.stepStates[l.id].actionType==u,l.lastActionAt=void 0},I.onStateChange=l=>{let r=g=>{if(g.id!==this.id)return;let h=g.steps.get(f.id),d=this.lastStepUpdate.get(l);(h.isCompleted!==(d==null?void 0:d.isCompleted)||h.isStarted!==(d==null?void 0:d.isStarted)||h.isHidden!==(d==null?void 0:d.isHidden)||h.isBlocked!==(d==null?void 0:d.isBlocked))&&(l(h,d??F(h)),this.lastStepUpdate.set(l,F(h)))};this.getGlobalState().onStepStateChangeHandlerWrappers.set(l,r),this.getGlobalState().onFlowStateChangeHandlers.push(r)},I.removeStateChangeHandler=l=>{let r=this.getGlobalState().onStepStateChangeHandlerWrappers.get(l);r&&(this.getGlobalState().onFlowStateChangeHandlers=this.getGlobalState().onFlowStateChangeHandlers.filter(g=>g!==r))},y.set(f.id,I)}),this.steps=y,Object.keys(this.lastUsedVariables).length>0&&this.applyVariables(this.lastUsedVariables)}async start(t){if(this.isStarted||this.isCompleted)return;this.isStarted=!0;let e=F(this.getGlobalState().userFlowStates[this.id]);e.flowState=A,this.getGlobalState().userFlowStates[this.id]=e,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:this.getCurrentStep().id,data:t??{},createdAt:new Date().toISOString(),actionType:A})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw)}async complete(t){this.isCompleted||(this.optimisticallyMarkFlowCompleted(),await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:this.getCurrentStep().id,data:t??{},createdAt:new Date().toISOString(),actionType:D})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw))}optimisticallyMarkFlowCompleted(){this.isStarted=!0,this.isCompleted=!0;let t=F(this.getGlobalState().userFlowStates[this.id]);t.flowState=D,this.getGlobalState().userFlowStates[this.id]=t,this.isVisible=!1}async skip(t){await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:this.getCurrentStep().id,data:t??{},createdAt:new Date().toISOString(),actionType:G})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw)}async forward(t){let e=this.getStepByIndex(this.getCurrentStepIndex()+1);e&&await e.start(t)}async back(t){let e=this.getStepByIndex(this.getCurrentStepIndex()-1);e&&await e.start(t)}async restart(){await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:"unknown",data:{},createdAt:new Date().toISOString(),actionType:B})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw)}getStepByIndex(t){return this.steps.get(Array.from(this.steps.keys())[t])}getCurrentStep(){let t=Array.from(this.steps.keys()).find(i=>this.steps.get(i).isCompleted===!1&&this.steps.get(i).isHidden===!1);Array.from(this.steps.keys()).forEach(i=>{var o;this.steps.get(i).isStarted&&this.steps.get(i).lastActionAt&&this.steps.get(i).lastActionAt>(((o=this.steps.get(t))==null?void 0:o.lastActionAt)??new Date(0))&&(t=i)});let e=t??Array.from(this.steps.keys())[0];return this.steps.get(e)}getCurrentStepIndex(){let t=this.getCurrentStep();return Array.from(this.steps.keys()).indexOf(t.id)}getNumberOfCompletedSteps(){return Array.from(this.steps.values()).filter(t=>t.isCompleted).length}getNumberOfAvailableSteps(){return Array.from(this.steps.values()).filter(t=>!t.isHidden).length}onStateChange(t){let e=(i,o)=>{(i.id===this.id&&(i.isCompleted!==o.isCompleted||i.isStarted!==o.isStarted||i.isSkipped!==o.isSkipped||i.isVisible!==o.isVisible)||JSON.stringify(i.steps)!==JSON.stringify(o.steps))&&t(i,o)};this.getGlobalState().onFlowStateChangeHandlerWrappers.set(t,e),this.getGlobalState().onFlowStateChangeHandlers.push(e)}removeStateChangeHandler(t){let e=this.getGlobalState().onFlowStateChangeHandlerWrappers.get(t);e&&(this.getGlobalState().onFlowStateChangeHandlers=this.getGlobalState().onFlowStateChangeHandlers.filter(i=>i!==e))}applyVariables(t){let e=i=>{let o=i.match(/\${(.*?)}/g);return o&&o.forEach(p=>{let n=p.replace("${","").replace("}","");i=i.replace(p,t[n]??"")}),i};this.title=e(this.title??""),this.subtitle=e(this.subtitle??""),this.steps.forEach(i=>{Object.keys(i).forEach(o=>{typeof i[o]=="string"&&(i[o]=e(i[o]))})}),this.lastUsedVariables=t}getUserFlowState(){return this.getGlobalState().userFlowStates[this.id]}async refreshUserFlowState(){await this.getGlobalState().refreshUserFlowStates()}};var v="NOT_STARTED_STEP",D="COMPLETED_FLOW",G="SKIPPED_FLOW",A="STARTED_FLOW",B="NOT_STARTED_FLOW",b="COMPLETED_STEP",u="STARTED_STEP",at="frigade-last-call-at-",rt="frigade-last-call-data-",j="frigade-guest-key",nt="guest_",lt="get-cache-";var dt=1e3,H="fr-js-";function U(s){let a=new w(s.config,s.rawData);return a.isCompleted=s.isCompleted,a.isStarted=s.isStarted,a.isSkipped=s.isSkipped,a.isVisible=s.isVisible,a.steps=s.steps,a}function F(s){return JSON.parse(JSON.stringify(s))}function k(s){return{headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json","X-Frigade-SDK-Version":V,"X-Frigade-SDK-Platform":"Javascript"}}}function N(s){return m()?window.localStorage.getItem(`${H}${s}`):null}function L(s,a){m()&&window.localStorage.setItem(`${H}${s}`,a)}function x(){Object.keys(c).forEach(s=>{s.startsWith(lt)&&delete c[s]})}function z(){m()&&Object.keys(window.localStorage).forEach(s=>{s.startsWith(H)&&window.localStorage.removeItem(s)})}async function K(s,a){let t=at+s,e=rt+s;if(m()&&a&&a.body&&a.method==="POST"){let o=N(t),p=N(e);if(o&&p&&p==a.body){let n=new Date(o);if(new Date().getTime()-n.getTime()<dt)return S()}L(t,new Date().toISOString()),L(e,a.body),x()}let i;try{i=(0,Y.default)(s,a),i=await i}catch(o){return S(o)}if(!i)return S("Received an empty response");if(i.status>=400)return S(i.statusText);try{if(i.status===204||i.status===201)return S();let o=await i.json();return o.error?S(o.error):o}catch(o){return S(o)}}function S(s){return s&&console.log("Call to Frigade failed",s),{json:()=>({})}}function $(){if(m()){let s=N(j);return s||(s=`${nt}${(0,X.v4)()}`,L(j,s)),s}}function m(){return typeof window<"u"}var P=class extends E{constructor(t,e){super({apiKey:t,...e});this.flows=[];this.hasFailed=!1;this.visibilityChangeHandler=async()=>{document.visibilityState==="visible"&&(await this.refreshFlows(),await this.refreshUserFlowStates())};this.init(this.config),m()&&document.addEventListener("visibilitychange",this.visibilityChangeHandler)}destroy(){if(m()){document.removeEventListener("visibilitychange",this.visibilityChangeHandler);let t=R(this.config);c[t]&&(c[t].onFlowStateChangeHandlers=[])}}async init(t){return this.config={...this.config,...t},this.initPromise=(async()=>{await this.refreshUserFlowStates(),await this.refreshFlows()})(),this.initPromise}async identify(t,e){this.config={...this.config,userId:t},await this.initIfNeeded(),await this.fetch("/users",{method:"POST",body:JSON.stringify({foreignId:this.config.userId,properties:e})}),await this.refreshUserFlowStates()}async group(t,e){await this.initIfNeeded(),this.config.groupId=t,await this.fetch("/userGroups",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,properties:e})}),await this.refreshUserFlowStates()}async track(t,e){if(await this.initIfNeeded(),!t){console.error("Event name is required to track an event");return}this.config.userId&&this.config.groupId?await this.fetch("/userGroups",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,events:[{event:t,properties:e}]})}):this.config.userId&&await this.fetch("/users",{method:"POST",body:JSON.stringify({foreignId:this.config.userId,events:[{event:t,properties:e}]})})}isReady(){return!!(this.config.__instanceId&&this.config.apiKey&&this.initPromise)}async getFlow(t){return await this.initIfNeeded(),this.flows.find(e=>e.id==t)}async getFlows(){return await this.initIfNeeded(),this.flows}async reload(){z(),x(),await this.refreshUserFlowStates(),await this.refreshFlows(),this.initPromise=null,await this.init(this.config),this.flows.forEach(t=>{this.getGlobalState().onFlowStateChangeHandlers.forEach(e=>{let i=this.getGlobalState().previousFlows.get(t.id);e(t,i),this.getGlobalState().previousFlows.set(t.id,U(t))})})}onStateChange(t){this.getGlobalState().onFlowStateChangeHandlers.push(t)}hasFailedToLoad(){return this.hasFailed}removeStateChangeHandler(t){this.getGlobalState().onFlowStateChangeHandlers=this.getGlobalState().onFlowStateChangeHandlers.filter(e=>e!==t)}async initIfNeeded(){return this.initPromise!==null?this.initPromise:this.init(this.config)}async refreshUserFlowStates(){let t=R(this.config);if(!c[t]){let e=this,i={set:function(o,p,n){return o[p]&&o[p].flowState&&(JSON.stringify(o[p].flowState)!==JSON.stringify(n==null?void 0:n.flowState)||JSON.stringify(o[p].stepStates)!==JSON.stringify(n==null?void 0:n.stepStates)||JSON.stringify(o[p].shouldTrigger)!==JSON.stringify(n==null?void 0:n.shouldTrigger))&&e.triggerEventHandlers(o[p]),o[p]=n,!0}};if(c[t]={refreshUserFlowStates:async()=>{},userFlowStates:new Proxy({},i),onFlowStateChangeHandlerWrappers:new Map,onStepStateChangeHandlerWrappers:new Map,onFlowStateChangeHandlers:[],previousFlows:new Map},this.config.__readOnly&&this.config.__flowConfigOverrides){this.mockUserFlowStates(t);return}c[t].refreshUserFlowStates=async()=>{if(this.config.__readOnly)return;let o=await this.fetch(`/userFlowStates?foreignUserId=${encodeURIComponent(this.config.userId)}${this.config.groupId?`&foreignUserGroupId=${encodeURIComponent(this.config.groupId)}`:""}`);o&&o.data?(o.data.forEach(n=>{let y=!1,f=c[t].userFlowStates[n.flowId];f&&f.shouldTrigger==!1&&n.shouldTrigger==!0&&(y=!0),c[t].userFlowStates[n.flowId]=n,y&&this.flows.forEach(T=>{T.id==n.flowId&&(T.reload(),this.triggerEventHandlers(c[t].userFlowStates[T.id]))})}),this.hasFailed=!1):this.hasFailed=!0}}await c[t].refreshUserFlowStates()}async refreshFlows(){if(this.flows=[],this.config.__flowConfigOverrides){this.mockFlowConfigs();return}let t=await this.fetch("/flows");t&&t.data?t.data.forEach(i=>{this.flows.push(new w(this.config,i)),this.getGlobalState().previousFlows.set(i.slug,U(this.flows[this.flows.length-1]))}):this.hasFailed=!0}mockFlowConfigs(){Object.keys(this.config.__flowConfigOverrides).forEach(t=>{this.flows.push(new w(this.config,{id:-1,name:"",description:"",data:this.config.__flowConfigOverrides[t],createdAt:new Date().toISOString(),modifiedAt:new Date().toISOString(),slug:t,targetingLogic:"",type:"CHECKLIST",triggerType:"MANUAL",status:"ACTIVE",version:1,active:!0}))})}mockUserFlowStates(t){Object.keys(this.config.__flowConfigOverrides).forEach(e=>{var o;let i=JSON.parse(this.config.__flowConfigOverrides[e]);c[t].userFlowStates[e]={flowId:e,flowState:"NOT_STARTED_FLOW",lastStepId:null,userId:this.config.userId,foreignUserId:this.config.userId,stepStates:((o=i==null?void 0:i.steps)==null?void 0:o.reduce((p,n)=>(p[n.id]={stepId:n.id,flowSlug:e,actionType:"NOT_STARTED_STEP",createdAt:new Date().toISOString(),blocked:!1,hidden:!1},p),{}))??{},shouldTrigger:!1}})}async triggerEventHandlers(t){t&&this.flows.forEach(e=>{e.id==t.flowId&&this.getGlobalState().onFlowStateChangeHandlers.forEach(i=>{let o=this.getGlobalState().previousFlows.get(e.id);i(e,o),this.getGlobalState().previousFlows.set(e.id,U(e))})})}};0&&(module.exports={Flow,Frigade});
|
|
3
3
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/core/version.ts","../src/shared/utils.ts","../src/shared/state.ts","../src/shared/Fetchable.ts","../src/core/flow.ts","../src/core/frigade.ts"],"sourcesContent":["export { Frigade } from './core/frigade'\nexport { Flow } from './core/flow'\nexport { FlowStep } from './core/flow-step'\n\nexport * from './types'\n","export const VERSION_NUMBER = '0.2.20'\n","import { VERSION_NUMBER } from '../core/version'\nimport fetch from 'cross-fetch'\nimport { v4 as uuidv4 } from 'uuid'\nimport { Flow } from '../core/flow'\nimport { frigadeGlobalState } from './state'\n\nexport const NOT_STARTED_STEP = 'NOT_STARTED_STEP'\nexport const COMPLETED_FLOW = 'COMPLETED_FLOW'\nexport const SKIPPED_FLOW = 'SKIPPED_FLOW'\nexport const STARTED_FLOW = 'STARTED_FLOW'\nexport const NOT_STARTED_FLOW = 'NOT_STARTED_FLOW'\nexport const COMPLETED_STEP = 'COMPLETED_STEP'\nexport const STARTED_STEP = 'STARTED_STEP'\nexport type StepActionType = 'STARTED_STEP' | 'COMPLETED_STEP' | 'NOT_STARTED_STEP'\nexport type UserFlowStatus = 'NOT_STARTED_FLOW' | 'STARTED_FLOW' | 'COMPLETED_FLOW' | 'SKIPPED_FLOW'\nconst LAST_POST_CALL_AT = 'frigade-last-call-at-'\nconst LAST_POST_CALL_DATA = 'frigade-last-call-data-'\nconst GUEST_KEY = 'frigade-guest-key'\nconst GUEST_PREFIX = 'guest_'\nconst GET_CACHE_PREFIX = 'get-cache-'\nconst GET_CACHE_TTL_MS = 1000\nconst POST_CACHE_TTL_MS = 1000\nconst LOCAL_STORAGE_PREFIX = 'fr-js-'\n\nexport function cloneFlow(flow: Flow): Flow {\n const newFlow = new Flow(flow.config, flow.rawData)\n newFlow.isCompleted = flow.isCompleted\n newFlow.isStarted = flow.isStarted\n newFlow.isSkipped = flow.isSkipped\n newFlow.isVisible = flow.isVisible\n newFlow.steps = flow.steps\n return newFlow\n}\n\nexport function clone<T>(obj: T): T {\n return JSON.parse(JSON.stringify(obj))\n}\n\nexport function getHeaders(apiKey: string) {\n return {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n 'X-Frigade-SDK-Version': VERSION_NUMBER,\n 'X-Frigade-SDK-Platform': 'Javascript',\n },\n }\n}\n\nfunction getLocalStorage(key: string) {\n if (isWeb()) {\n return window.localStorage.getItem(`${LOCAL_STORAGE_PREFIX}${key}`)\n }\n return null\n}\n\nfunction setLocalStorage(key: string, value: string) {\n if (isWeb()) {\n window.localStorage.setItem(`${LOCAL_STORAGE_PREFIX}${key}`, value)\n }\n}\n\nfunction setGlobalState(key: string, value: any) {\n frigadeGlobalState[key] = value\n}\n\nfunction getGlobalState(key: string): any {\n return frigadeGlobalState[key]\n}\n\nexport function clearCache() {\n Object.keys(frigadeGlobalState).forEach((key) => {\n if (key.startsWith(GET_CACHE_PREFIX)) {\n delete frigadeGlobalState[key]\n }\n })\n}\n\nexport function resetAllLocalStorage() {\n if (isWeb()) {\n // Clear all local storage items that begin with `frigade-`\n Object.keys(window.localStorage).forEach((key) => {\n if (key.startsWith(LOCAL_STORAGE_PREFIX)) {\n window.localStorage.removeItem(key)\n }\n })\n }\n}\n\nexport async function gracefulFetch(url: string, options: any) {\n const lastCallAtKey = LAST_POST_CALL_AT + url\n const lastCallDataKey = LAST_POST_CALL_DATA + url\n if (isWeb() && options && options.body && options.method === 'POST') {\n const lastCall = getLocalStorage(lastCallAtKey)\n const lastCallData = getLocalStorage(lastCallDataKey)\n if (lastCall && lastCallData && lastCallData == options.body) {\n const lastCallDate = new Date(lastCall)\n const now = new Date()\n const diff = now.getTime() - lastCallDate.getTime()\n // Throttle consecutive POST calls to 1 second\n if (diff < POST_CACHE_TTL_MS) {\n return getEmptyResponse()\n }\n }\n setLocalStorage(lastCallAtKey, new Date().toISOString())\n setLocalStorage(lastCallDataKey, options.body)\n clearCache()\n }\n\n let response\n try {\n response = fetch(url, options)\n response = await response\n } catch (error) {\n return getEmptyResponse(error)\n }\n\n if (!response) {\n return getEmptyResponse('Received an empty response')\n }\n\n if (response.status >= 400) {\n return getEmptyResponse(response.statusText)\n }\n\n try {\n if (response.status === 204 || response.status === 201) {\n return getEmptyResponse()\n }\n\n const body = await response.json()\n if (body.error) {\n return getEmptyResponse(body.error)\n }\n return body\n } catch (e) {\n return getEmptyResponse(e)\n }\n}\n\nexport function getEmptyResponse(error?: any) {\n if (error) {\n console.log('Call to Frigade failed', error)\n }\n\n // Create empty response that contains the .json method and returns an empty object\n return {\n json: () => ({}),\n }\n}\n\nexport function generateGuestId() {\n if (isWeb()) {\n let guestId = getLocalStorage(GUEST_KEY)\n if (!guestId) {\n guestId = `${GUEST_PREFIX}${uuidv4()}`\n setLocalStorage(GUEST_KEY, guestId)\n }\n return guestId\n }\n}\n\nexport function fetcher(apiKey: string, path: string, options?: Record<any, any>) {\n return gracefulFetch(`//api.frigade.com/v1/public${path}`, {\n ...(options ?? {}),\n ...getHeaders(apiKey),\n })\n}\n\nexport function isWeb() {\n return typeof window !== 'undefined'\n}\n","import { FrigadeConfig, UserFlowState } from '../types'\nimport { Flow } from '../core/flow'\nimport { FlowStep } from '../core/flow-step'\n\nexport interface FrigadeGlobalState {\n refreshUserFlowStates: () => Promise<void>\n userFlowStates: Record<string, UserFlowState>\n onFlowStateChangeHandlerWrappers: Map<\n (flow: Flow, previousFlow: Flow) => void,\n (flow: Flow, previousFlow: Flow) => void\n >\n onStepStateChangeHandlerWrappers: Map<\n (step: FlowStep, previousStep: FlowStep) => void,\n (flow: Flow, previousFlow: Flow) => void\n >\n onFlowStateChangeHandlers: ((flow: Flow, previousFlow: Flow) => void)[]\n previousFlows: Map<string, Flow>\n}\n\nexport let frigadeGlobalState: Record<string, FrigadeGlobalState> = {}\n\nexport function getGlobalStateKey(internalConfig: FrigadeConfig): string {\n return `${internalConfig.__instanceId}-${internalConfig.apiKey}:${internalConfig.userId ?? ''}:${\n internalConfig.groupId ?? ''\n }`\n}\n","import { generateGuestId, getEmptyResponse, getHeaders, gracefulFetch } from './utils'\nimport { FrigadeConfig } from '../types'\nimport { frigadeGlobalState, FrigadeGlobalState, getGlobalStateKey } from './state'\n\nexport class Fetchable {\n public config: FrigadeConfig = {\n apiKey: '',\n apiUrl: 'https://api.frigade.com/v1/public',\n userId: generateGuestId(),\n __instanceId: Math.random().toString(36).substring(7),\n }\n\n constructor(config: FrigadeConfig) {\n const filteredConfig = Object.fromEntries(Object.entries(config).filter(([_, v]) => v != null))\n\n this.config = {\n ...this.config,\n ...filteredConfig,\n }\n }\n\n public async fetch(path: string, options?: Record<any, any>) {\n if (this.config.__readOnly) {\n return getEmptyResponse()\n }\n\n return gracefulFetch(`${this.config.apiUrl}${path}`, {\n ...(options ?? {}),\n ...getHeaders(this.config.apiKey),\n })\n }\n\n protected getGlobalState(): FrigadeGlobalState {\n const globalStateKey = getGlobalStateKey(this.config)\n if (!frigadeGlobalState[globalStateKey]) {\n throw new Error('Frigade not initialized')\n }\n return frigadeGlobalState[globalStateKey]\n }\n}\n","import { FrigadeConfig, UserFlowState } from '../types'\nimport { FlowDataRaw } from './types'\nimport {\n clone,\n COMPLETED_FLOW,\n COMPLETED_STEP,\n NOT_STARTED_FLOW,\n NOT_STARTED_STEP,\n SKIPPED_FLOW,\n STARTED_FLOW,\n STARTED_STEP,\n} from '../shared/utils'\nimport { FlowStep } from './flow-step'\nimport { Fetchable } from '../shared/Fetchable'\n\nexport class Flow extends Fetchable {\n /**\n * THe Flow ID / slug of the flow\n */\n public id: string\n /**\n * The raw data defined in `config.yml` as a JSON decoded object\n */\n public configYmlAsJson: any\n /**\n * Ordered map from Step ID to step data. The `steps` array in `config.yml`\n */\n public steps: Map<string, FlowStep>\n /**\n * The user-facing title of the flow, if defined at the top level of `config.yml`\n */\n public title?: string\n /**\n * The user-facing description of the flow, if defined at the top level of `config.yml`\n */\n public subtitle?: string\n /**\n * The metadata of the flow.\n */\n public rawData: FlowDataRaw\n /**\n * Whether the flow is completed or not\n */\n public isCompleted: boolean\n /**\n * Whether the flow is started or not\n */\n public isStarted: boolean\n /**\n * Whether the flow has been skipped or not\n */\n public isSkipped: boolean\n /**\n * Whether the flow is visible to the user based on the current user/group's state\n */\n public isVisible: boolean = false\n\n private readonly flowDataRaw: FlowDataRaw\n\n private userFlowStateRaw?: UserFlowState\n\n private lastStepUpdate: Map<(step: FlowStep, previousStep: FlowStep) => void, FlowStep> =\n new Map()\n\n private lastUsedVariables = {}\n\n constructor(config: FrigadeConfig, flowDataRaw: FlowDataRaw) {\n super(config)\n this.flowDataRaw = flowDataRaw\n this.initFromRawData(flowDataRaw)\n }\n\n reload() {\n this.initFromRawData(this.flowDataRaw)\n }\n\n private initFromRawData(flowDataRaw: FlowDataRaw) {\n const flowDataYml = JSON.parse(flowDataRaw.data)\n const steps = flowDataYml.steps ?? flowDataYml.data ?? []\n this.id = flowDataRaw.slug\n this.rawData = flowDataRaw\n this.configYmlAsJson = flowDataYml\n this.title = this.configYmlAsJson.title\n this.subtitle = this.configYmlAsJson.subtitle\n\n const userFlowState = this.getUserFlowState()\n if (!userFlowState) {\n return\n }\n this.userFlowStateRaw = userFlowState\n\n this.isCompleted = userFlowState.flowState == COMPLETED_FLOW\n this.isStarted = userFlowState.flowState == STARTED_FLOW\n this.isSkipped = userFlowState.flowState == SKIPPED_FLOW\n const hasCompleted = this.isCompleted || this.isSkipped\n const targetingShouldHideFlow =\n flowDataRaw.targetingLogic && userFlowState.shouldTrigger === false\n this.isVisible = !hasCompleted && !targetingShouldHideFlow\n if (this.flowDataRaw.active === false) {\n this.isVisible = false\n }\n const newSteps = new Map<string, FlowStep>()\n\n steps.forEach((step, index) => {\n const userFlowStateStep = userFlowState.stepStates[step.id]\n const stepObj = {\n ...step,\n isCompleted: userFlowStateStep.actionType == COMPLETED_STEP,\n isStarted: userFlowStateStep.actionType == STARTED_STEP,\n isHidden: userFlowStateStep.hidden,\n isBlocked: userFlowStateStep.blocked,\n lastActionAt: userFlowStateStep.lastActionAt\n ? new Date(userFlowStateStep.lastActionAt)\n : undefined,\n order: index,\n } as FlowStep\n\n stepObj.start = async (properties?: Record<string | number, any>) => {\n const thisStep = this.steps.get(step.id)\n\n if (this.getCurrentStep().id === thisStep.id && thisStep.isStarted) {\n return\n }\n\n thisStep.isStarted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.stepStates[thisStep.id].actionType = STARTED_STEP\n copy.stepStates[thisStep.id].lastActionAt = new Date().toISOString()\n copy.lastStepId = thisStep.id\n\n this.getGlobalState().userFlowStates[this.id] = copy\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: thisStep.id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: STARTED_STEP,\n }),\n })\n\n await this.refreshUserFlowState()\n\n const updatedUserFlowState = this.getUserFlowState()\n thisStep.isCompleted =\n updatedUserFlowState.stepStates[thisStep.id].actionType == COMPLETED_STEP\n thisStep.isStarted = updatedUserFlowState.stepStates[thisStep.id].actionType == STARTED_STEP\n thisStep.lastActionAt = new Date()\n }\n\n stepObj.complete = async (properties?: Record<string | number, any>) => {\n const thisStep = this.steps.get(step.id)\n\n if (thisStep.isCompleted) {\n return\n }\n\n const numberOfCompletedSteps = this.getNumberOfCompletedSteps()\n const isLastStep = numberOfCompletedSteps + 1 == this.steps.size\n\n thisStep.isCompleted = true\n this.isStarted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n\n copy.stepStates[thisStep.id].actionType = COMPLETED_STEP\n copy.stepStates[thisStep.id].lastActionAt = new Date().toISOString()\n copy.flowState = isLastStep ? COMPLETED_FLOW : STARTED_FLOW\n\n const nextStepId = Array.from(this.steps.keys())[index + 1]\n if (nextStepId) {\n copy.lastStepId = nextStepId\n copy.stepStates[nextStepId].actionType = STARTED_STEP\n const lastAction = new Date()\n copy.stepStates[nextStepId].lastActionAt = lastAction.toISOString()\n this.steps.get(nextStepId).isStarted = true\n this.steps.get(nextStepId).lastActionAt = lastAction\n }\n\n if (isLastStep) {\n this.optimisticallyMarkFlowCompleted()\n }\n\n this.getGlobalState().userFlowStates[this.id] = copy\n\n // if all steps are now completed, mark flow completed\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: thisStep.id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: COMPLETED_STEP,\n }),\n })\n\n await this.refreshUserFlowState()\n\n const updatedUserFlowState = this.getUserFlowState()\n thisStep.isCompleted =\n updatedUserFlowState.stepStates[thisStep.id].actionType == COMPLETED_STEP\n thisStep.isStarted = updatedUserFlowState.stepStates[thisStep.id].actionType == STARTED_STEP\n thisStep.lastActionAt = new Date()\n }\n\n stepObj.reset = async () => {\n const thisStep = this.steps.get(step.id)\n\n if (!thisStep.isCompleted) {\n return\n }\n\n thisStep.isCompleted = false\n thisStep.isStarted = false\n thisStep.lastActionAt = undefined\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.stepStates[thisStep.id].actionType = NOT_STARTED_STEP\n copy.stepStates[thisStep.id].lastActionAt = undefined\n copy.flowState = STARTED_FLOW\n this.getGlobalState().userFlowStates[this.id] = copy\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: thisStep.id,\n data: {},\n createdAt: new Date().toISOString(),\n actionType: NOT_STARTED_STEP,\n }),\n })\n\n await this.refreshUserFlowState()\n\n const updatedUserFlowState = this.getUserFlowState()\n thisStep.isCompleted =\n updatedUserFlowState.stepStates[thisStep.id].actionType == COMPLETED_STEP\n thisStep.isStarted = updatedUserFlowState.stepStates[thisStep.id].actionType == STARTED_STEP\n thisStep.lastActionAt = undefined\n }\n\n stepObj.onStateChange = (handler: (step: FlowStep, previousStep: FlowStep) => void) => {\n const wrapperHandler = (flow: Flow) => {\n if (flow.id !== this.id) {\n return\n }\n const thisStep = flow.steps.get(step.id)\n const previousStep = this.lastStepUpdate.get(handler)\n\n if (\n thisStep.isCompleted !== previousStep?.isCompleted ||\n thisStep.isStarted !== previousStep?.isStarted ||\n thisStep.isHidden !== previousStep?.isHidden ||\n thisStep.isBlocked !== previousStep?.isBlocked\n ) {\n handler(thisStep, previousStep ?? clone(thisStep))\n this.lastStepUpdate.set(handler, clone(thisStep))\n }\n }\n this.getGlobalState().onStepStateChangeHandlerWrappers.set(handler, wrapperHandler)\n this.getGlobalState().onFlowStateChangeHandlers.push(wrapperHandler)\n }\n\n stepObj.removeStateChangeHandler = (\n handler: (step: FlowStep, previousStep: FlowStep) => void\n ) => {\n const wrapperHandler = this.getGlobalState().onStepStateChangeHandlerWrappers.get(handler)\n if (wrapperHandler) {\n this.getGlobalState().onFlowStateChangeHandlers =\n this.getGlobalState().onFlowStateChangeHandlers.filter((h) => h !== wrapperHandler)\n }\n }\n\n newSteps.set(step.id, stepObj)\n })\n this.steps = newSteps\n // Check if empty object\n if (Object.keys(this.lastUsedVariables).length > 0) {\n this.applyVariables(this.lastUsedVariables)\n }\n }\n\n /**\n * Marks the flow started\n */\n public async start(properties?: Record<string | number, any>) {\n if (this.isStarted || this.isCompleted) {\n return\n }\n\n this.isStarted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.flowState = STARTED_FLOW\n this.getGlobalState().userFlowStates[this.id] = copy\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: this.getCurrentStep().id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: STARTED_FLOW,\n }),\n })\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * Marks the flow completed\n */\n public async complete(properties?: Record<string | number, any>) {\n if (this.isCompleted) {\n return\n }\n this.optimisticallyMarkFlowCompleted()\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: this.getCurrentStep().id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: COMPLETED_FLOW,\n }),\n })\n\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n private optimisticallyMarkFlowCompleted() {\n this.isStarted = true\n this.isCompleted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.flowState = COMPLETED_FLOW\n this.getGlobalState().userFlowStates[this.id] = copy\n this.isVisible = false\n }\n\n /**\n * Marks the flow skipped\n */\n public async skip(properties?: Record<string | number, any>) {\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: this.getCurrentStep().id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: SKIPPED_FLOW,\n }),\n })\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * Navigates the flow to the next step if one exists. This will mark that step started, but will not complete the previous step.\n */\n public async forward(properties?: Record<string | number, any>) {\n const nextStep = this.getStepByIndex(this.getCurrentStepIndex() + 1)\n if (nextStep) {\n await nextStep.start(properties)\n }\n }\n\n /**\n * Navigates the flow to the previous step if one exists. This will mark that step started, but will not complete the previous step.\n */\n public async back(properties?: Record<string | number, any>) {\n const previousStep = this.getStepByIndex(this.getCurrentStepIndex() - 1)\n if (previousStep) {\n await previousStep.start(properties)\n }\n }\n\n /**\n * Restarts the flow/marks it not started\n */\n public async restart() {\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: 'unknown',\n data: {},\n createdAt: new Date().toISOString(),\n actionType: NOT_STARTED_FLOW,\n }),\n })\n\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * Get a step by index\n * @param index\n */\n public getStepByIndex(index: number): FlowStep | undefined {\n return this.steps.get(Array.from(this.steps.keys())[index])\n }\n\n /**\n * Gets current step\n */\n public getCurrentStep(): FlowStep {\n let maybeCurrentStepId = Array.from(this.steps.keys()).find(\n (key) => this.steps.get(key).isCompleted === false && this.steps.get(key).isHidden === false\n )\n Array.from(this.steps.keys()).forEach((key) => {\n if (\n this.steps.get(key).isStarted &&\n this.steps.get(key).lastActionAt &&\n this.steps.get(key).lastActionAt >\n (this.steps.get(maybeCurrentStepId)?.lastActionAt ?? new Date(0))\n ) {\n maybeCurrentStepId = key\n }\n })\n\n const currentStepId = maybeCurrentStepId ?? Array.from(this.steps.keys())[0]\n return this.steps.get(currentStepId)\n }\n\n public getCurrentStepIndex(): number {\n const currentStep = this.getCurrentStep()\n return Array.from(this.steps.keys()).indexOf(currentStep.id)\n }\n\n /**\n * Get the number of completed steps for the current user in the current flow\n */\n public getNumberOfCompletedSteps(): number {\n return Array.from(this.steps.values()).filter((step) => step.isCompleted).length\n }\n\n /**\n * Get the number of available steps for the current user in the current flow. This is the number of steps that are not hidden.\n */\n public getNumberOfAvailableSteps(): number {\n return Array.from(this.steps.values()).filter((step) => !step.isHidden).length\n }\n\n public onStateChange(handler: (flow: Flow, previousFlow: Flow) => void) {\n const wrapperHandler = (flow: Flow, previousFlow: Flow) => {\n if (\n (flow.id === this.id &&\n (flow.isCompleted !== previousFlow.isCompleted ||\n flow.isStarted !== previousFlow.isStarted ||\n flow.isSkipped !== previousFlow.isSkipped ||\n flow.isVisible !== previousFlow.isVisible)) ||\n JSON.stringify(flow.steps) !== JSON.stringify(previousFlow.steps)\n ) {\n handler(flow, previousFlow)\n }\n }\n this.getGlobalState().onFlowStateChangeHandlerWrappers.set(handler, wrapperHandler)\n this.getGlobalState().onFlowStateChangeHandlers.push(wrapperHandler)\n }\n\n public removeStateChangeHandler(handler: (flow: Flow, previousFlow: Flow) => void) {\n const wrapperHandler = this.getGlobalState().onFlowStateChangeHandlerWrappers.get(handler)\n if (wrapperHandler) {\n this.getGlobalState().onFlowStateChangeHandlers =\n this.getGlobalState().onFlowStateChangeHandlers.filter((h) => h !== wrapperHandler)\n }\n }\n\n public applyVariables(variables: Record<string, any>) {\n // Replace ${variable} with the value of the variable\n const replaceVariables = (str: string) => {\n const matches = str.match(/\\${(.*?)}/g)\n if (matches) {\n matches.forEach((match) => {\n const variable = match.replace('${', '').replace('}', '')\n str = str.replace(match, variables[variable] ?? '')\n })\n }\n return str\n }\n\n this.title = replaceVariables(this.title ?? '')\n this.subtitle = replaceVariables(this.subtitle ?? '')\n this.steps.forEach((step) => {\n // Iterate over every string field in the step and replace variables\n Object.keys(step).forEach((key) => {\n if (typeof step[key] === 'string') {\n // @ts-ignore\n step[key] = replaceVariables(step[key])\n }\n })\n })\n\n this.lastUsedVariables = variables\n }\n\n private getUserFlowState(): UserFlowState {\n const userFlowStates = this.getGlobalState().userFlowStates\n return userFlowStates[this.id]\n }\n\n private async refreshUserFlowState() {\n await this.getGlobalState().refreshUserFlowStates()\n }\n}\n","import { FrigadeConfig, UserFlowState } from '../types'\nimport { clearCache, cloneFlow, isWeb, resetAllLocalStorage } from '../shared/utils'\nimport { Flow } from './flow'\nimport { FlowDataRaw, FlowStatus, FlowType, TriggerType } from './types'\nimport { frigadeGlobalState, getGlobalStateKey } from '../shared/state'\nimport { Fetchable } from '../shared/Fetchable'\n\nexport class Frigade extends Fetchable {\n private flows: Flow[] = []\n private initPromise: Promise<void>\n private hasFailed = false\n\n private visibilityChangeHandler = async () => {\n if (document.visibilityState === 'visible') {\n await this.refreshFlows()\n await this.refreshUserFlowStates()\n }\n }\n\n constructor(apiKey: string, config?: FrigadeConfig) {\n super({\n apiKey,\n ...config,\n })\n this.init(this.config)\n if (isWeb()) {\n document.addEventListener('visibilitychange', this.visibilityChangeHandler)\n }\n }\n\n destroy() {\n if (isWeb()) {\n document.removeEventListener('visibilitychange', this.visibilityChangeHandler)\n // Remove all other event listeners\n const globalStateKey = getGlobalStateKey(this.config)\n if (frigadeGlobalState[globalStateKey]) {\n frigadeGlobalState[globalStateKey].onFlowStateChangeHandlers = []\n }\n }\n }\n\n private async init(config: FrigadeConfig): Promise<void> {\n this.config = {\n ...this.config,\n ...config,\n }\n\n this.initPromise = (async () => {\n await this.refreshUserFlowStates()\n await this.refreshFlows()\n })()\n\n return this.initPromise\n }\n\n public async identify(userId: string, properties?: Record<string, any>): Promise<void> {\n this.config = { ...this.config, userId }\n await this.initIfNeeded()\n await this.fetch('/users', {\n method: 'POST',\n body: JSON.stringify({\n foreignId: this.config.userId,\n properties,\n }),\n })\n await this.refreshUserFlowStates()\n }\n\n public async group(groupId: string, properties?: Record<string, any>): Promise<void> {\n await this.initIfNeeded()\n this.config.groupId = groupId\n await this.fetch('/userGroups', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n properties,\n }),\n })\n await this.refreshUserFlowStates()\n }\n\n public async track(event: string, properties?: Record<string, any>): Promise<void> {\n await this.initIfNeeded()\n await this.fetch('/track', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n event,\n properties,\n }),\n })\n }\n\n public isReady(): boolean {\n return Boolean(this.config.__instanceId && this.config.apiKey && this.initPromise)\n }\n\n public async getFlow(flowId: string) {\n await this.initIfNeeded()\n\n return this.flows.find((flow) => flow.id == flowId)\n }\n\n public async getFlows() {\n await this.initIfNeeded()\n return this.flows\n }\n\n /**\n * Reload the current state of the flows by calling the Frigade API.\n * This will trigger all event handlers.\n */\n public async reload() {\n resetAllLocalStorage()\n clearCache()\n await this.refreshUserFlowStates()\n await this.refreshFlows()\n this.initPromise = null\n await this.init(this.config)\n // Trigger all event handlers\n this.flows.forEach((flow) => {\n this.getGlobalState().onFlowStateChangeHandlers.forEach((handler) => {\n const lastFlow = this.getGlobalState().previousFlows.get(flow.id)\n handler(flow, lastFlow)\n this.getGlobalState().previousFlows.set(flow.id, cloneFlow(flow))\n })\n })\n }\n\n public onStateChange(handler: (flow: Flow, previousFlow?: Flow) => void) {\n this.getGlobalState().onFlowStateChangeHandlers.push(handler)\n }\n\n /**\n * Returns true of Frigade has failed to call the API.\n */\n hasFailedToLoad() {\n return this.hasFailed\n }\n\n public removeStateChangeHandler(handler: (flow: Flow, previousFlow?: Flow) => void) {\n this.getGlobalState().onFlowStateChangeHandlers =\n this.getGlobalState().onFlowStateChangeHandlers.filter((h) => h !== handler)\n }\n\n private async initIfNeeded() {\n if (this.initPromise !== null) {\n return this.initPromise\n } else {\n return this.init(this.config)\n }\n }\n\n private async refreshUserFlowStates(): Promise<void> {\n const globalStateKey = getGlobalStateKey(this.config)\n\n if (!frigadeGlobalState[globalStateKey]) {\n const that = this\n\n let validator = {\n set: function (target: any, key: any, value: any) {\n if (\n target[key] &&\n target[key].flowState &&\n (JSON.stringify(target[key].flowState) !== JSON.stringify(value?.flowState) ||\n JSON.stringify(target[key].stepStates) !== JSON.stringify(value?.stepStates) ||\n JSON.stringify(target[key].shouldTrigger) !== JSON.stringify(value?.shouldTrigger))\n ) {\n that.triggerEventHandlers(target[key])\n }\n\n target[key] = value\n return true\n },\n }\n\n frigadeGlobalState[globalStateKey] = {\n refreshUserFlowStates: async () => {},\n userFlowStates: new Proxy({}, validator),\n onFlowStateChangeHandlerWrappers: new Map(),\n onStepStateChangeHandlerWrappers: new Map(),\n onFlowStateChangeHandlers: [],\n previousFlows: new Map(),\n }\n\n if (this.config.__readOnly && this.config.__flowConfigOverrides) {\n this.mockUserFlowStates(globalStateKey)\n\n return\n }\n\n frigadeGlobalState[globalStateKey].refreshUserFlowStates = async () => {\n if (this.config.__readOnly) {\n return\n }\n\n const userFlowStatesRaw = await this.fetch(\n `/userFlowStates?foreignUserId=${encodeURIComponent(this.config.userId)}${\n this.config.groupId\n ? `&foreignUserGroupId=${encodeURIComponent(this.config.groupId)}`\n : ''\n }`\n )\n if (userFlowStatesRaw && userFlowStatesRaw.data) {\n let userFlowStates = userFlowStatesRaw.data as UserFlowState[]\n userFlowStates.forEach((userFlowState) => {\n let shouldReload = false\n const before = frigadeGlobalState[globalStateKey].userFlowStates[userFlowState.flowId]\n\n // Special case: for flows that show up based on targeting logic/rules, we need to check if the flow should be triggered\n if (before && before.shouldTrigger == false && userFlowState.shouldTrigger == true) {\n shouldReload = true\n }\n frigadeGlobalState[globalStateKey].userFlowStates[userFlowState.flowId] = userFlowState\n if (shouldReload) {\n this.flows.forEach((flow) => {\n if (flow.id == userFlowState.flowId) {\n flow.reload()\n this.triggerEventHandlers(\n frigadeGlobalState[globalStateKey].userFlowStates[flow.id]\n )\n }\n })\n }\n })\n this.hasFailed = false\n } else {\n this.hasFailed = true\n }\n }\n }\n\n await frigadeGlobalState[globalStateKey].refreshUserFlowStates()\n }\n\n private async refreshFlows() {\n this.flows = []\n\n if (this.config.__flowConfigOverrides) {\n this.mockFlowConfigs()\n return\n }\n\n const flowDataRaw = await this.fetch('/flows')\n if (flowDataRaw && flowDataRaw.data) {\n let flowDatas = flowDataRaw.data as FlowDataRaw[]\n flowDatas.forEach((flowData) => {\n this.flows.push(new Flow(this.config, flowData))\n this.getGlobalState().previousFlows.set(\n flowData.slug,\n cloneFlow(this.flows[this.flows.length - 1])\n )\n })\n } else {\n this.hasFailed = true\n }\n }\n\n private mockFlowConfigs() {\n Object.keys(this.config.__flowConfigOverrides).forEach((flowId) => {\n this.flows.push(\n new Flow(this.config, {\n id: -1,\n name: '',\n description: '',\n data: this.config.__flowConfigOverrides[flowId],\n createdAt: new Date().toISOString(),\n modifiedAt: new Date().toISOString(),\n slug: flowId,\n targetingLogic: '',\n type: FlowType.CHECKLIST,\n triggerType: TriggerType.MANUAL,\n status: FlowStatus.ACTIVE,\n version: 1,\n active: true,\n })\n )\n })\n }\n\n private mockUserFlowStates(globalStateKey: string) {\n Object.keys(this.config.__flowConfigOverrides).forEach((flowId) => {\n const parsed = JSON.parse(this.config.__flowConfigOverrides[flowId])\n frigadeGlobalState[globalStateKey].userFlowStates[flowId] = {\n flowId,\n flowState: 'NOT_STARTED_FLOW',\n lastStepId: null,\n userId: this.config.userId,\n foreignUserId: this.config.userId,\n stepStates:\n parsed?.steps?.reduce((acc, step) => {\n acc[step.id] = {\n stepId: step.id,\n flowSlug: flowId,\n actionType: 'NOT_STARTED_STEP',\n createdAt: new Date().toISOString(),\n blocked: false,\n hidden: false,\n }\n return acc\n }, {}) ?? {},\n shouldTrigger: false,\n }\n })\n }\n\n private async triggerEventHandlers(previousUserFlowState: UserFlowState) {\n if (previousUserFlowState) {\n this.flows.forEach((flow) => {\n if (flow.id == previousUserFlowState.flowId) {\n this.getGlobalState().onFlowStateChangeHandlers.forEach((handler) => {\n const lastFlow = this.getGlobalState().previousFlows.get(flow.id)\n handler(flow, lastFlow)\n this.getGlobalState().previousFlows.set(flow.id, cloneFlow(flow))\n })\n }\n })\n }\n }\n}\n"],"mappings":";ojBAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,UAAAE,EAAA,YAAAC,IAAA,eAAAC,GAAAJ,ICAO,IAAMK,EAAiB,SCC9B,IAAAC,EAAkB,6BAClBC,EAA6B,gBCiBtB,IAAIC,EAAyD,CAAC,EAE9D,SAASC,EAAkBC,EAAuC,CACvE,MAAO,GAAGA,EAAe,gBAAgBA,EAAe,UAAUA,EAAe,QAAU,MACzFA,EAAe,SAAW,IAE9B,CCrBO,IAAMC,EAAN,KAAgB,CAQrB,YAAYC,EAAuB,CAPnC,KAAO,OAAwB,CAC7B,OAAQ,GACR,OAAQ,oCACR,OAAQC,EAAgB,EACxB,aAAc,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC,CACtD,EAGE,IAAMC,EAAiB,OAAO,YAAY,OAAO,QAAQF,CAAM,EAAE,OAAO,CAAC,CAACG,EAAGC,CAAC,IAAMA,GAAK,IAAI,CAAC,EAE9F,KAAK,OAAS,CACZ,GAAG,KAAK,OACR,GAAGF,CACL,CACF,CAEA,MAAa,MAAMG,EAAcC,EAA4B,CAC3D,OAAI,KAAK,OAAO,WACPC,EAAiB,EAGnBC,EAAc,GAAG,KAAK,OAAO,SAASH,IAAQ,CACnD,GAAIC,GAAW,CAAC,EAChB,GAAGG,EAAW,KAAK,OAAO,MAAM,CAClC,CAAC,CACH,CAEU,gBAAqC,CAC7C,IAAMC,EAAiBC,EAAkB,KAAK,MAAM,EACpD,GAAI,CAACC,EAAmBF,CAAc,EACpC,MAAM,IAAI,MAAM,yBAAyB,EAE3C,OAAOE,EAAmBF,CAAc,CAC1C,CACF,ECxBO,IAAMG,EAAN,cAAmBC,CAAU,CAmDlC,YAAYC,EAAuBC,EAA0B,CAC3D,MAAMD,CAAM,EAZd,KAAO,UAAqB,GAM5B,KAAQ,eACN,IAAI,IAEN,KAAQ,kBAAoB,CAAC,EAI3B,KAAK,YAAcC,EACnB,KAAK,gBAAgBA,CAAW,CAClC,CAEA,QAAS,CACP,KAAK,gBAAgB,KAAK,WAAW,CACvC,CAEQ,gBAAgBA,EAA0B,CAChD,IAAMC,EAAc,KAAK,MAAMD,EAAY,IAAI,EACzCE,EAAQD,EAAY,OAASA,EAAY,MAAQ,CAAC,EACxD,KAAK,GAAKD,EAAY,KACtB,KAAK,QAAUA,EACf,KAAK,gBAAkBC,EACvB,KAAK,MAAQ,KAAK,gBAAgB,MAClC,KAAK,SAAW,KAAK,gBAAgB,SAErC,IAAME,EAAgB,KAAK,iBAAiB,EAC5C,GAAI,CAACA,EACH,OAEF,KAAK,iBAAmBA,EAExB,KAAK,YAAcA,EAAc,WAAaC,EAC9C,KAAK,UAAYD,EAAc,WAAaE,EAC5C,KAAK,UAAYF,EAAc,WAAaG,EAC5C,IAAMC,EAAe,KAAK,aAAe,KAAK,UACxCC,EACJR,EAAY,gBAAkBG,EAAc,gBAAkB,GAChE,KAAK,UAAY,CAACI,GAAgB,CAACC,EAC/B,KAAK,YAAY,SAAW,KAC9B,KAAK,UAAY,IAEnB,IAAMC,EAAW,IAAI,IAErBP,EAAM,QAAQ,CAACQ,EAAMC,IAAU,CAC7B,IAAMC,EAAoBT,EAAc,WAAWO,EAAK,EAAE,EACpDG,EAAU,CACd,GAAGH,EACH,YAAaE,EAAkB,YAAcE,EAC7C,UAAWF,EAAkB,YAAcG,EAC3C,SAAUH,EAAkB,OAC5B,UAAWA,EAAkB,QAC7B,aAAcA,EAAkB,aAC5B,IAAI,KAAKA,EAAkB,YAAY,EACvC,OACJ,MAAOD,CACT,EAEAE,EAAQ,MAAQ,MAAOG,GAA8C,CACnE,IAAMC,EAAW,KAAK,MAAM,IAAIP,EAAK,EAAE,EAEvC,GAAI,KAAK,eAAe,EAAE,KAAOO,EAAS,IAAMA,EAAS,UACvD,OAGFA,EAAS,UAAY,GACrB,IAAMC,EAAOC,EAAM,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,CAAC,EAChED,EAAK,WAAWD,EAAS,EAAE,EAAE,WAAaF,EAC1CG,EAAK,WAAWD,EAAS,EAAE,EAAE,aAAe,IAAI,KAAK,EAAE,YAAY,EACnEC,EAAK,WAAaD,EAAS,GAE3B,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,EAAIC,EAEhD,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQD,EAAS,GACjB,KAAMD,GAAc,CAAC,EACrB,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYD,CACd,CAAC,CACH,CAAC,EAED,MAAM,KAAK,qBAAqB,EAEhC,IAAMK,EAAuB,KAAK,iBAAiB,EACnDH,EAAS,YACPG,EAAqB,WAAWH,EAAS,EAAE,EAAE,YAAcH,EAC7DG,EAAS,UAAYG,EAAqB,WAAWH,EAAS,EAAE,EAAE,YAAcF,EAChFE,EAAS,aAAe,IAAI,IAC9B,EAEAJ,EAAQ,SAAW,MAAOG,GAA8C,CACtE,IAAMC,EAAW,KAAK,MAAM,IAAIP,EAAK,EAAE,EAEvC,GAAIO,EAAS,YACX,OAIF,IAAMI,EADyB,KAAK,0BAA0B,EAClB,GAAK,KAAK,MAAM,KAE5DJ,EAAS,YAAc,GACvB,KAAK,UAAY,GACjB,IAAMC,EAAOC,EAAM,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,CAAC,EAEhED,EAAK,WAAWD,EAAS,EAAE,EAAE,WAAaH,EAC1CI,EAAK,WAAWD,EAAS,EAAE,EAAE,aAAe,IAAI,KAAK,EAAE,YAAY,EACnEC,EAAK,UAAYG,EAAajB,EAAiBC,EAE/C,IAAMiB,EAAa,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,EAAEX,EAAQ,CAAC,EAC1D,GAAIW,EAAY,CACdJ,EAAK,WAAaI,EAClBJ,EAAK,WAAWI,CAAU,EAAE,WAAaP,EACzC,IAAMQ,EAAa,IAAI,KACvBL,EAAK,WAAWI,CAAU,EAAE,aAAeC,EAAW,YAAY,EAClE,KAAK,MAAM,IAAID,CAAU,EAAE,UAAY,GACvC,KAAK,MAAM,IAAIA,CAAU,EAAE,aAAeC,EAGxCF,GACF,KAAK,gCAAgC,EAGvC,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,EAAIH,EAGhD,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQD,EAAS,GACjB,KAAMD,GAAc,CAAC,EACrB,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYF,CACd,CAAC,CACH,CAAC,EAED,MAAM,KAAK,qBAAqB,EAEhC,IAAMM,EAAuB,KAAK,iBAAiB,EACnDH,EAAS,YACPG,EAAqB,WAAWH,EAAS,EAAE,EAAE,YAAcH,EAC7DG,EAAS,UAAYG,EAAqB,WAAWH,EAAS,EAAE,EAAE,YAAcF,EAChFE,EAAS,aAAe,IAAI,IAC9B,EAEAJ,EAAQ,MAAQ,SAAY,CAC1B,IAAMI,EAAW,KAAK,MAAM,IAAIP,EAAK,EAAE,EAEvC,GAAI,CAACO,EAAS,YACZ,OAGFA,EAAS,YAAc,GACvBA,EAAS,UAAY,GACrBA,EAAS,aAAe,OACxB,IAAMC,EAAOC,EAAM,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,CAAC,EAChED,EAAK,WAAWD,EAAS,EAAE,EAAE,WAAaO,EAC1CN,EAAK,WAAWD,EAAS,EAAE,EAAE,aAAe,OAC5CC,EAAK,UAAYb,EACjB,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,EAAIa,EAEhD,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQD,EAAS,GACjB,KAAM,CAAC,EACP,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYO,CACd,CAAC,CACH,CAAC,EAED,MAAM,KAAK,qBAAqB,EAEhC,IAAMJ,EAAuB,KAAK,iBAAiB,EACnDH,EAAS,YACPG,EAAqB,WAAWH,EAAS,EAAE,EAAE,YAAcH,EAC7DG,EAAS,UAAYG,EAAqB,WAAWH,EAAS,EAAE,EAAE,YAAcF,EAChFE,EAAS,aAAe,MAC1B,EAEAJ,EAAQ,cAAiBY,GAA8D,CACrF,IAAMC,EAAkBC,GAAe,CACrC,GAAIA,EAAK,KAAO,KAAK,GACnB,OAEF,IAAMV,EAAWU,EAAK,MAAM,IAAIjB,EAAK,EAAE,EACjCkB,EAAe,KAAK,eAAe,IAAIH,CAAO,GAGlDR,EAAS,eAAgBW,GAAA,YAAAA,EAAc,cACvCX,EAAS,aAAcW,GAAA,YAAAA,EAAc,YACrCX,EAAS,YAAaW,GAAA,YAAAA,EAAc,WACpCX,EAAS,aAAcW,GAAA,YAAAA,EAAc,cAErCH,EAAQR,EAAUW,GAAgBT,EAAMF,CAAQ,CAAC,EACjD,KAAK,eAAe,IAAIQ,EAASN,EAAMF,CAAQ,CAAC,EAEpD,EACA,KAAK,eAAe,EAAE,iCAAiC,IAAIQ,EAASC,CAAc,EAClF,KAAK,eAAe,EAAE,0BAA0B,KAAKA,CAAc,CACrE,EAEAb,EAAQ,yBACNY,GACG,CACH,IAAMC,EAAiB,KAAK,eAAe,EAAE,iCAAiC,IAAID,CAAO,EACrFC,IACF,KAAK,eAAe,EAAE,0BACpB,KAAK,eAAe,EAAE,0BAA0B,OAAQG,GAAMA,IAAMH,CAAc,EAExF,EAEAjB,EAAS,IAAIC,EAAK,GAAIG,CAAO,CAC/B,CAAC,EACD,KAAK,MAAQJ,EAET,OAAO,KAAK,KAAK,iBAAiB,EAAE,OAAS,GAC/C,KAAK,eAAe,KAAK,iBAAiB,CAE9C,CAKA,MAAa,MAAMO,EAA2C,CAC5D,GAAI,KAAK,WAAa,KAAK,YACzB,OAGF,KAAK,UAAY,GACjB,IAAME,EAAOC,EAAM,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,CAAC,EAChED,EAAK,UAAYb,EACjB,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,EAAIa,EAEhD,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQ,KAAK,eAAe,EAAE,GAC9B,KAAMF,GAAc,CAAC,EACrB,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYX,CACd,CAAC,CACH,CAAC,EACD,MAAM,KAAK,qBAAqB,EAChC,KAAK,gBAAgB,KAAK,WAAW,CACvC,CAKA,MAAa,SAASW,EAA2C,CAC3D,KAAK,cAGT,KAAK,gCAAgC,EAErC,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQ,KAAK,eAAe,EAAE,GAC9B,KAAMA,GAAc,CAAC,EACrB,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYZ,CACd,CAAC,CACH,CAAC,EAED,MAAM,KAAK,qBAAqB,EAChC,KAAK,gBAAgB,KAAK,WAAW,EACvC,CAEQ,iCAAkC,CACxC,KAAK,UAAY,GACjB,KAAK,YAAc,GACnB,IAAMc,EAAOC,EAAM,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,CAAC,EAChED,EAAK,UAAYd,EACjB,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,EAAIc,EAChD,KAAK,UAAY,EACnB,CAKA,MAAa,KAAKF,EAA2C,CAC3D,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQ,KAAK,eAAe,EAAE,GAC9B,KAAMA,GAAc,CAAC,EACrB,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYV,CACd,CAAC,CACH,CAAC,EACD,MAAM,KAAK,qBAAqB,EAChC,KAAK,gBAAgB,KAAK,WAAW,CACvC,CAKA,MAAa,QAAQU,EAA2C,CAC9D,IAAMc,EAAW,KAAK,eAAe,KAAK,oBAAoB,EAAI,CAAC,EAC/DA,GACF,MAAMA,EAAS,MAAMd,CAAU,CAEnC,CAKA,MAAa,KAAKA,EAA2C,CAC3D,IAAMY,EAAe,KAAK,eAAe,KAAK,oBAAoB,EAAI,CAAC,EACnEA,GACF,MAAMA,EAAa,MAAMZ,CAAU,CAEvC,CAKA,MAAa,SAAU,CACrB,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQ,UACR,KAAM,CAAC,EACP,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYe,CACd,CAAC,CACH,CAAC,EAED,MAAM,KAAK,qBAAqB,EAChC,KAAK,gBAAgB,KAAK,WAAW,CACvC,CAMO,eAAepB,EAAqC,CACzD,OAAO,KAAK,MAAM,IAAI,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,EAAEA,CAAK,CAAC,CAC5D,CAKO,gBAA2B,CAChC,IAAIqB,EAAqB,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,EAAE,KACpDC,GAAQ,KAAK,MAAM,IAAIA,CAAG,EAAE,cAAgB,IAAS,KAAK,MAAM,IAAIA,CAAG,EAAE,WAAa,EACzF,EACA,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,EAAE,QAASA,GAAQ,CA9anD,IAAAC,EAgbQ,KAAK,MAAM,IAAID,CAAG,EAAE,WACpB,KAAK,MAAM,IAAIA,CAAG,EAAE,cACpB,KAAK,MAAM,IAAIA,CAAG,EAAE,gBACjBC,EAAA,KAAK,MAAM,IAAIF,CAAkB,IAAjC,YAAAE,EAAoC,eAAgB,IAAI,KAAK,CAAC,KAEjEF,EAAqBC,EAEzB,CAAC,EAED,IAAME,EAAgBH,GAAsB,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,EAAE,CAAC,EAC3E,OAAO,KAAK,MAAM,IAAIG,CAAa,CACrC,CAEO,qBAA8B,CACnC,IAAMC,EAAc,KAAK,eAAe,EACxC,OAAO,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,EAAE,QAAQA,EAAY,EAAE,CAC7D,CAKO,2BAAoC,CACzC,OAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,EAAE,OAAQ1B,GAASA,EAAK,WAAW,EAAE,MAC5E,CAKO,2BAAoC,CACzC,OAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,EAAE,OAAQA,GAAS,CAACA,EAAK,QAAQ,EAAE,MAC1E,CAEO,cAAce,EAAmD,CACtE,IAAMC,EAAiB,CAACC,EAAYU,IAAuB,EAEtDV,EAAK,KAAO,KAAK,KACfA,EAAK,cAAgBU,EAAa,aACjCV,EAAK,YAAcU,EAAa,WAChCV,EAAK,YAAcU,EAAa,WAChCV,EAAK,YAAcU,EAAa,YACpC,KAAK,UAAUV,EAAK,KAAK,IAAM,KAAK,UAAUU,EAAa,KAAK,IAEhEZ,EAAQE,EAAMU,CAAY,CAE9B,EACA,KAAK,eAAe,EAAE,iCAAiC,IAAIZ,EAASC,CAAc,EAClF,KAAK,eAAe,EAAE,0BAA0B,KAAKA,CAAc,CACrE,CAEO,yBAAyBD,EAAmD,CACjF,IAAMC,EAAiB,KAAK,eAAe,EAAE,iCAAiC,IAAID,CAAO,EACrFC,IACF,KAAK,eAAe,EAAE,0BACpB,KAAK,eAAe,EAAE,0BAA0B,OAAQG,GAAMA,IAAMH,CAAc,EAExF,CAEO,eAAeY,EAAgC,CAEpD,IAAMC,EAAoBC,GAAgB,CACxC,IAAMC,EAAUD,EAAI,MAAM,YAAY,EACtC,OAAIC,GACFA,EAAQ,QAASC,GAAU,CACzB,IAAMC,EAAWD,EAAM,QAAQ,KAAM,EAAE,EAAE,QAAQ,IAAK,EAAE,EACxDF,EAAMA,EAAI,QAAQE,EAAOJ,EAAUK,CAAQ,GAAK,EAAE,CACpD,CAAC,EAEIH,CACT,EAEA,KAAK,MAAQD,EAAiB,KAAK,OAAS,EAAE,EAC9C,KAAK,SAAWA,EAAiB,KAAK,UAAY,EAAE,EACpD,KAAK,MAAM,QAAS7B,GAAS,CAE3B,OAAO,KAAKA,CAAI,EAAE,QAASuB,GAAQ,CAC7B,OAAOvB,EAAKuB,CAAG,GAAM,WAEvBvB,EAAKuB,CAAG,EAAIM,EAAiB7B,EAAKuB,CAAG,CAAC,EAE1C,CAAC,CACH,CAAC,EAED,KAAK,kBAAoBK,CAC3B,CAEQ,kBAAkC,CAExC,OADuB,KAAK,eAAe,EAAE,eACvB,KAAK,EAAE,CAC/B,CAEA,MAAc,sBAAuB,CACnC,MAAM,KAAK,eAAe,EAAE,sBAAsB,CACpD,CACF,EHvgBO,IAAMM,EAAmB,mBACnBC,EAAiB,iBACjBC,EAAe,eACfC,EAAe,eACfC,EAAmB,mBACnBC,EAAiB,iBACjBC,EAAe,eAGtBC,GAAoB,wBACpBC,GAAsB,0BACtBC,EAAY,oBACZC,GAAe,SACfC,GAAmB,aAEzB,IAAMC,GAAoB,IACpBC,EAAuB,SAEtB,SAASC,EAAUC,EAAkB,CAC1C,IAAMC,EAAU,IAAIC,EAAKF,EAAK,OAAQA,EAAK,OAAO,EAClD,OAAAC,EAAQ,YAAcD,EAAK,YAC3BC,EAAQ,UAAYD,EAAK,UACzBC,EAAQ,UAAYD,EAAK,UACzBC,EAAQ,UAAYD,EAAK,UACzBC,EAAQ,MAAQD,EAAK,MACdC,CACT,CAEO,SAASE,EAASC,EAAW,CAClC,OAAO,KAAK,MAAM,KAAK,UAAUA,CAAG,CAAC,CACvC,CAEO,SAASC,EAAWC,EAAgB,CACzC,MAAO,CACL,QAAS,CACP,cAAe,UAAUA,IACzB,eAAgB,mBAChB,wBAAyBC,EACzB,yBAA0B,YAC5B,CACF,CACF,CAEA,SAASC,EAAgBC,EAAa,CACpC,OAAIC,EAAM,EACD,OAAO,aAAa,QAAQ,GAAGZ,IAAuBW,GAAK,EAE7D,IACT,CAEA,SAASE,EAAgBF,EAAaG,EAAe,CAC/CF,EAAM,GACR,OAAO,aAAa,QAAQ,GAAGZ,IAAuBW,IAAOG,CAAK,CAEtE,CAUO,SAASC,GAAa,CAC3B,OAAO,KAAKC,CAAkB,EAAE,QAASC,GAAQ,CAC3CA,EAAI,WAAWC,EAAgB,GACjC,OAAOF,EAAmBC,CAAG,CAEjC,CAAC,CACH,CAEO,SAASE,GAAuB,CACjCC,EAAM,GAER,OAAO,KAAK,OAAO,YAAY,EAAE,QAASH,GAAQ,CAC5CA,EAAI,WAAWI,CAAoB,GACrC,OAAO,aAAa,WAAWJ,CAAG,CAEtC,CAAC,CAEL,CAEA,eAAsBK,EAAcC,EAAaC,EAAc,CAC7D,IAAMC,EAAgBC,GAAoBH,EACpCI,EAAkBC,GAAsBL,EAC9C,GAAIH,EAAM,GAAKI,GAAWA,EAAQ,MAAQA,EAAQ,SAAW,OAAQ,CACnE,IAAMK,EAAWC,EAAgBL,CAAa,EACxCM,EAAeD,EAAgBH,CAAe,EACpD,GAAIE,GAAYE,GAAgBA,GAAgBP,EAAQ,KAAM,CAC5D,IAAMQ,EAAe,IAAI,KAAKH,CAAQ,EAItC,GAHY,IAAI,KAAK,EACJ,QAAQ,EAAIG,EAAa,QAAQ,EAEvCC,GACT,OAAOC,EAAiB,EAG5BC,EAAgBV,EAAe,IAAI,KAAK,EAAE,YAAY,CAAC,EACvDU,EAAgBR,EAAiBH,EAAQ,IAAI,EAC7CT,EAAW,EAGb,IAAIqB,EACJ,GAAI,CACFA,KAAW,EAAAC,SAAMd,EAAKC,CAAO,EAC7BY,EAAW,MAAMA,CACnB,OAASE,EAAP,CACA,OAAOJ,EAAiBI,CAAK,CAC/B,CAEA,GAAI,CAACF,EACH,OAAOF,EAAiB,4BAA4B,EAGtD,GAAIE,EAAS,QAAU,IACrB,OAAOF,EAAiBE,EAAS,UAAU,EAG7C,GAAI,CACF,GAAIA,EAAS,SAAW,KAAOA,EAAS,SAAW,IACjD,OAAOF,EAAiB,EAG1B,IAAMK,EAAO,MAAMH,EAAS,KAAK,EACjC,OAAIG,EAAK,MACAL,EAAiBK,EAAK,KAAK,EAE7BA,CACT,OAASC,EAAP,CACA,OAAON,EAAiBM,CAAC,CAC3B,CACF,CAEO,SAASN,EAAiBI,EAAa,CAC5C,OAAIA,GACF,QAAQ,IAAI,yBAA0BA,CAAK,EAItC,CACL,KAAM,KAAO,CAAC,EAChB,CACF,CAEO,SAASG,GAAkB,CAChC,GAAIrB,EAAM,EAAG,CACX,IAAIsB,EAAUZ,EAAgBa,CAAS,EACvC,OAAKD,IACHA,EAAU,GAAGE,QAAe,EAAAC,IAAO,IACnCV,EAAgBQ,EAAWD,CAAO,GAE7BA,EAEX,CASO,SAASI,GAAQ,CACtB,OAAO,OAAO,OAAW,GAC3B,CIpKO,IAAMC,EAAN,cAAsBC,CAAU,CAYrC,YAAYC,EAAgBC,EAAwB,CAClD,MAAM,CACJ,OAAAD,EACA,GAAGC,CACL,CAAC,EAfH,KAAQ,MAAgB,CAAC,EAEzB,KAAQ,UAAY,GAEpB,KAAQ,wBAA0B,SAAY,CACxC,SAAS,kBAAoB,YAC/B,MAAM,KAAK,aAAa,EACxB,MAAM,KAAK,sBAAsB,EAErC,EAOE,KAAK,KAAK,KAAK,MAAM,EACjBC,EAAM,GACR,SAAS,iBAAiB,mBAAoB,KAAK,uBAAuB,CAE9E,CAEA,SAAU,CACR,GAAIA,EAAM,EAAG,CACX,SAAS,oBAAoB,mBAAoB,KAAK,uBAAuB,EAE7E,IAAMC,EAAiBC,EAAkB,KAAK,MAAM,EAChDC,EAAmBF,CAAc,IACnCE,EAAmBF,CAAc,EAAE,0BAA4B,CAAC,GAGtE,CAEA,MAAc,KAAKF,EAAsC,CACvD,YAAK,OAAS,CACZ,GAAG,KAAK,OACR,GAAGA,CACL,EAEA,KAAK,aAAe,SAAY,CAC9B,MAAM,KAAK,sBAAsB,EACjC,MAAM,KAAK,aAAa,CAC1B,GAAG,EAEI,KAAK,WACd,CAEA,MAAa,SAASK,EAAgBC,EAAiD,CACrF,KAAK,OAAS,CAAE,GAAG,KAAK,OAAQ,OAAAD,CAAO,EACvC,MAAM,KAAK,aAAa,EACxB,MAAM,KAAK,MAAM,SAAU,CACzB,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,UAAW,KAAK,OAAO,OACvB,WAAAC,CACF,CAAC,CACH,CAAC,EACD,MAAM,KAAK,sBAAsB,CACnC,CAEA,MAAa,MAAMC,EAAiBD,EAAiD,CACnF,MAAM,KAAK,aAAa,EACxB,KAAK,OAAO,QAAUC,EACtB,MAAM,KAAK,MAAM,cAAe,CAC9B,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,WAAAD,CACF,CAAC,CACH,CAAC,EACD,MAAM,KAAK,sBAAsB,CACnC,CAEA,MAAa,MAAME,EAAeF,EAAiD,CACjF,MAAM,KAAK,aAAa,EACxB,MAAM,KAAK,MAAM,SAAU,CACzB,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,MAAAE,EACA,WAAAF,CACF,CAAC,CACH,CAAC,CACH,CAEO,SAAmB,CACxB,MAAO,GAAQ,KAAK,OAAO,cAAgB,KAAK,OAAO,QAAU,KAAK,YACxE,CAEA,MAAa,QAAQG,EAAgB,CACnC,aAAM,KAAK,aAAa,EAEjB,KAAK,MAAM,KAAMC,GAASA,EAAK,IAAMD,CAAM,CACpD,CAEA,MAAa,UAAW,CACtB,aAAM,KAAK,aAAa,EACjB,KAAK,KACd,CAMA,MAAa,QAAS,CACpBE,EAAqB,EACrBC,EAAW,EACX,MAAM,KAAK,sBAAsB,EACjC,MAAM,KAAK,aAAa,EACxB,KAAK,YAAc,KACnB,MAAM,KAAK,KAAK,KAAK,MAAM,EAE3B,KAAK,MAAM,QAASF,GAAS,CAC3B,KAAK,eAAe,EAAE,0BAA0B,QAASG,GAAY,CACnE,IAAMC,EAAW,KAAK,eAAe,EAAE,cAAc,IAAIJ,EAAK,EAAE,EAChEG,EAAQH,EAAMI,CAAQ,EACtB,KAAK,eAAe,EAAE,cAAc,IAAIJ,EAAK,GAAIK,EAAUL,CAAI,CAAC,CAClE,CAAC,CACH,CAAC,CACH,CAEO,cAAcG,EAAoD,CACvE,KAAK,eAAe,EAAE,0BAA0B,KAAKA,CAAO,CAC9D,CAKA,iBAAkB,CAChB,OAAO,KAAK,SACd,CAEO,yBAAyBA,EAAoD,CAClF,KAAK,eAAe,EAAE,0BACpB,KAAK,eAAe,EAAE,0BAA0B,OAAQG,GAAMA,IAAMH,CAAO,CAC/E,CAEA,MAAc,cAAe,CAC3B,OAAI,KAAK,cAAgB,KAChB,KAAK,YAEL,KAAK,KAAK,KAAK,MAAM,CAEhC,CAEA,MAAc,uBAAuC,CACnD,IAAMX,EAAiBC,EAAkB,KAAK,MAAM,EAEpD,GAAI,CAACC,EAAmBF,CAAc,EAAG,CACvC,IAAMe,EAAO,KAETC,EAAY,CACd,IAAK,SAAUC,EAAaC,EAAUC,EAAY,CAChD,OACEF,EAAOC,CAAG,GACVD,EAAOC,CAAG,EAAE,YACX,KAAK,UAAUD,EAAOC,CAAG,EAAE,SAAS,IAAM,KAAK,UAAUC,GAAA,YAAAA,EAAO,SAAS,GACxE,KAAK,UAAUF,EAAOC,CAAG,EAAE,UAAU,IAAM,KAAK,UAAUC,GAAA,YAAAA,EAAO,UAAU,GAC3E,KAAK,UAAUF,EAAOC,CAAG,EAAE,aAAa,IAAM,KAAK,UAAUC,GAAA,YAAAA,EAAO,aAAa,IAEnFJ,EAAK,qBAAqBE,EAAOC,CAAG,CAAC,EAGvCD,EAAOC,CAAG,EAAIC,EACP,EACT,CACF,EAWA,GATAjB,EAAmBF,CAAc,EAAI,CACnC,sBAAuB,SAAY,CAAC,EACpC,eAAgB,IAAI,MAAM,CAAC,EAAGgB,CAAS,EACvC,iCAAkC,IAAI,IACtC,iCAAkC,IAAI,IACtC,0BAA2B,CAAC,EAC5B,cAAe,IAAI,GACrB,EAEI,KAAK,OAAO,YAAc,KAAK,OAAO,sBAAuB,CAC/D,KAAK,mBAAmBhB,CAAc,EAEtC,OAGFE,EAAmBF,CAAc,EAAE,sBAAwB,SAAY,CACrE,GAAI,KAAK,OAAO,WACd,OAGF,IAAMoB,EAAoB,MAAM,KAAK,MACnC,iCAAiC,mBAAmB,KAAK,OAAO,MAAM,IACpE,KAAK,OAAO,QACR,uBAAuB,mBAAmB,KAAK,OAAO,OAAO,IAC7D,IAER,EACIA,GAAqBA,EAAkB,MACpBA,EAAkB,KACxB,QAASC,GAAkB,CACxC,IAAIC,EAAe,GACbC,EAASrB,EAAmBF,CAAc,EAAE,eAAeqB,EAAc,MAAM,EAGjFE,GAAUA,EAAO,eAAiB,IAASF,EAAc,eAAiB,KAC5EC,EAAe,IAEjBpB,EAAmBF,CAAc,EAAE,eAAeqB,EAAc,MAAM,EAAIA,EACtEC,GACF,KAAK,MAAM,QAASd,GAAS,CACvBA,EAAK,IAAMa,EAAc,SAC3Bb,EAAK,OAAO,EACZ,KAAK,qBACHN,EAAmBF,CAAc,EAAE,eAAeQ,EAAK,EAAE,CAC3D,EAEJ,CAAC,CAEL,CAAC,EACD,KAAK,UAAY,IAEjB,KAAK,UAAY,EAErB,EAGF,MAAMN,EAAmBF,CAAc,EAAE,sBAAsB,CACjE,CAEA,MAAc,cAAe,CAG3B,GAFA,KAAK,MAAQ,CAAC,EAEV,KAAK,OAAO,sBAAuB,CACrC,KAAK,gBAAgB,EACrB,OAGF,IAAMwB,EAAc,MAAM,KAAK,MAAM,QAAQ,EACzCA,GAAeA,EAAY,KACbA,EAAY,KAClB,QAASC,GAAa,CAC9B,KAAK,MAAM,KAAK,IAAIC,EAAK,KAAK,OAAQD,CAAQ,CAAC,EAC/C,KAAK,eAAe,EAAE,cAAc,IAClCA,EAAS,KACTZ,EAAU,KAAK,MAAM,KAAK,MAAM,OAAS,CAAC,CAAC,CAC7C,CACF,CAAC,EAED,KAAK,UAAY,EAErB,CAEQ,iBAAkB,CACxB,OAAO,KAAK,KAAK,OAAO,qBAAqB,EAAE,QAASN,GAAW,CACjE,KAAK,MAAM,KACT,IAAImB,EAAK,KAAK,OAAQ,CACpB,GAAI,GACJ,KAAM,GACN,YAAa,GACb,KAAM,KAAK,OAAO,sBAAsBnB,CAAM,EAC9C,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAY,IAAI,KAAK,EAAE,YAAY,EACnC,KAAMA,EACN,eAAgB,GAChB,iBACA,qBACA,gBACA,QAAS,EACT,OAAQ,EACV,CAAC,CACH,CACF,CAAC,CACH,CAEQ,mBAAmBP,EAAwB,CACjD,OAAO,KAAK,KAAK,OAAO,qBAAqB,EAAE,QAASO,GAAW,CA3RvE,IAAAoB,EA4RM,IAAMC,EAAS,KAAK,MAAM,KAAK,OAAO,sBAAsBrB,CAAM,CAAC,EACnEL,EAAmBF,CAAc,EAAE,eAAeO,CAAM,EAAI,CAC1D,OAAAA,EACA,UAAW,mBACX,WAAY,KACZ,OAAQ,KAAK,OAAO,OACpB,cAAe,KAAK,OAAO,OAC3B,aACEoB,EAAAC,GAAA,YAAAA,EAAQ,QAAR,YAAAD,EAAe,OAAO,CAACE,EAAKC,KAC1BD,EAAIC,EAAK,EAAE,EAAI,CACb,OAAQA,EAAK,GACb,SAAUvB,EACV,WAAY,mBACZ,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,QAAS,GACT,OAAQ,EACV,EACOsB,GACN,CAAC,KAAM,CAAC,EACb,cAAe,EACjB,CACF,CAAC,CACH,CAEA,MAAc,qBAAqBE,EAAsC,CACnEA,GACF,KAAK,MAAM,QAASvB,GAAS,CACvBA,EAAK,IAAMuB,EAAsB,QACnC,KAAK,eAAe,EAAE,0BAA0B,QAASpB,GAAY,CACnE,IAAMC,EAAW,KAAK,eAAe,EAAE,cAAc,IAAIJ,EAAK,EAAE,EAChEG,EAAQH,EAAMI,CAAQ,EACtB,KAAK,eAAe,EAAE,cAAc,IAAIJ,EAAK,GAAIK,EAAUL,CAAI,CAAC,CAClE,CAAC,CAEL,CAAC,CAEL,CACF","names":["src_exports","__export","Flow","Frigade","__toCommonJS","VERSION_NUMBER","import_cross_fetch","import_uuid","frigadeGlobalState","getGlobalStateKey","internalConfig","Fetchable","config","generateGuestId","filteredConfig","_","v","path","options","getEmptyResponse","gracefulFetch","getHeaders","globalStateKey","getGlobalStateKey","frigadeGlobalState","Flow","Fetchable","config","flowDataRaw","flowDataYml","steps","userFlowState","COMPLETED_FLOW","STARTED_FLOW","SKIPPED_FLOW","hasCompleted","targetingShouldHideFlow","newSteps","step","index","userFlowStateStep","stepObj","COMPLETED_STEP","STARTED_STEP","properties","thisStep","copy","clone","updatedUserFlowState","isLastStep","nextStepId","lastAction","NOT_STARTED_STEP","handler","wrapperHandler","flow","previousStep","h","nextStep","NOT_STARTED_FLOW","maybeCurrentStepId","key","_a","currentStepId","currentStep","previousFlow","variables","replaceVariables","str","matches","match","variable","NOT_STARTED_STEP","COMPLETED_FLOW","SKIPPED_FLOW","STARTED_FLOW","NOT_STARTED_FLOW","COMPLETED_STEP","STARTED_STEP","LAST_POST_CALL_AT","LAST_POST_CALL_DATA","GUEST_KEY","GUEST_PREFIX","GET_CACHE_PREFIX","POST_CACHE_TTL_MS","LOCAL_STORAGE_PREFIX","cloneFlow","flow","newFlow","Flow","clone","obj","getHeaders","apiKey","VERSION_NUMBER","getLocalStorage","key","isWeb","setLocalStorage","value","clearCache","frigadeGlobalState","key","GET_CACHE_PREFIX","resetAllLocalStorage","isWeb","LOCAL_STORAGE_PREFIX","gracefulFetch","url","options","lastCallAtKey","LAST_POST_CALL_AT","lastCallDataKey","LAST_POST_CALL_DATA","lastCall","getLocalStorage","lastCallData","lastCallDate","POST_CACHE_TTL_MS","getEmptyResponse","setLocalStorage","response","fetch","error","body","e","generateGuestId","guestId","GUEST_KEY","GUEST_PREFIX","uuidv4","isWeb","Frigade","Fetchable","apiKey","config","isWeb","globalStateKey","getGlobalStateKey","frigadeGlobalState","userId","properties","groupId","event","flowId","flow","resetAllLocalStorage","clearCache","handler","lastFlow","cloneFlow","h","that","validator","target","key","value","userFlowStatesRaw","userFlowState","shouldReload","before","flowDataRaw","flowData","Flow","_a","parsed","acc","step","previousUserFlowState"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/core/version.ts","../src/shared/utils.ts","../src/shared/state.ts","../src/shared/Fetchable.ts","../src/core/flow.ts","../src/core/frigade.ts"],"sourcesContent":["export { Frigade } from './core/frigade'\nexport { Flow } from './core/flow'\nexport { FlowStep } from './core/flow-step'\n\nexport * from './types'\n","export const VERSION_NUMBER = '0.2.20'\n","import { VERSION_NUMBER } from '../core/version'\nimport fetch from 'cross-fetch'\nimport { v4 as uuidv4 } from 'uuid'\nimport { Flow } from '../core/flow'\nimport { frigadeGlobalState } from './state'\n\nexport const NOT_STARTED_STEP = 'NOT_STARTED_STEP'\nexport const COMPLETED_FLOW = 'COMPLETED_FLOW'\nexport const SKIPPED_FLOW = 'SKIPPED_FLOW'\nexport const STARTED_FLOW = 'STARTED_FLOW'\nexport const NOT_STARTED_FLOW = 'NOT_STARTED_FLOW'\nexport const COMPLETED_STEP = 'COMPLETED_STEP'\nexport const STARTED_STEP = 'STARTED_STEP'\nexport type StepActionType = 'STARTED_STEP' | 'COMPLETED_STEP' | 'NOT_STARTED_STEP'\nexport type UserFlowStatus = 'NOT_STARTED_FLOW' | 'STARTED_FLOW' | 'COMPLETED_FLOW' | 'SKIPPED_FLOW'\nconst LAST_POST_CALL_AT = 'frigade-last-call-at-'\nconst LAST_POST_CALL_DATA = 'frigade-last-call-data-'\nconst GUEST_KEY = 'frigade-guest-key'\nconst GUEST_PREFIX = 'guest_'\nconst GET_CACHE_PREFIX = 'get-cache-'\nconst GET_CACHE_TTL_MS = 1000\nconst POST_CACHE_TTL_MS = 1000\nconst LOCAL_STORAGE_PREFIX = 'fr-js-'\n\nexport function cloneFlow(flow: Flow): Flow {\n const newFlow = new Flow(flow.config, flow.rawData)\n newFlow.isCompleted = flow.isCompleted\n newFlow.isStarted = flow.isStarted\n newFlow.isSkipped = flow.isSkipped\n newFlow.isVisible = flow.isVisible\n newFlow.steps = flow.steps\n return newFlow\n}\n\nexport function clone<T>(obj: T): T {\n return JSON.parse(JSON.stringify(obj))\n}\n\nexport function getHeaders(apiKey: string) {\n return {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n 'X-Frigade-SDK-Version': VERSION_NUMBER,\n 'X-Frigade-SDK-Platform': 'Javascript',\n },\n }\n}\n\nfunction getLocalStorage(key: string) {\n if (isWeb()) {\n return window.localStorage.getItem(`${LOCAL_STORAGE_PREFIX}${key}`)\n }\n return null\n}\n\nfunction setLocalStorage(key: string, value: string) {\n if (isWeb()) {\n window.localStorage.setItem(`${LOCAL_STORAGE_PREFIX}${key}`, value)\n }\n}\n\nfunction setGlobalState(key: string, value: any) {\n frigadeGlobalState[key] = value\n}\n\nfunction getGlobalState(key: string): any {\n return frigadeGlobalState[key]\n}\n\nexport function clearCache() {\n Object.keys(frigadeGlobalState).forEach((key) => {\n if (key.startsWith(GET_CACHE_PREFIX)) {\n delete frigadeGlobalState[key]\n }\n })\n}\n\nexport function resetAllLocalStorage() {\n if (isWeb()) {\n // Clear all local storage items that begin with `frigade-`\n Object.keys(window.localStorage).forEach((key) => {\n if (key.startsWith(LOCAL_STORAGE_PREFIX)) {\n window.localStorage.removeItem(key)\n }\n })\n }\n}\n\nexport async function gracefulFetch(url: string, options: any) {\n const lastCallAtKey = LAST_POST_CALL_AT + url\n const lastCallDataKey = LAST_POST_CALL_DATA + url\n if (isWeb() && options && options.body && options.method === 'POST') {\n const lastCall = getLocalStorage(lastCallAtKey)\n const lastCallData = getLocalStorage(lastCallDataKey)\n if (lastCall && lastCallData && lastCallData == options.body) {\n const lastCallDate = new Date(lastCall)\n const now = new Date()\n const diff = now.getTime() - lastCallDate.getTime()\n // Throttle consecutive POST calls to 1 second\n if (diff < POST_CACHE_TTL_MS) {\n return getEmptyResponse()\n }\n }\n setLocalStorage(lastCallAtKey, new Date().toISOString())\n setLocalStorage(lastCallDataKey, options.body)\n clearCache()\n }\n\n let response\n try {\n response = fetch(url, options)\n response = await response\n } catch (error) {\n return getEmptyResponse(error)\n }\n\n if (!response) {\n return getEmptyResponse('Received an empty response')\n }\n\n if (response.status >= 400) {\n return getEmptyResponse(response.statusText)\n }\n\n try {\n if (response.status === 204 || response.status === 201) {\n return getEmptyResponse()\n }\n\n const body = await response.json()\n if (body.error) {\n return getEmptyResponse(body.error)\n }\n return body\n } catch (e) {\n return getEmptyResponse(e)\n }\n}\n\nexport function getEmptyResponse(error?: any) {\n if (error) {\n console.log('Call to Frigade failed', error)\n }\n\n // Create empty response that contains the .json method and returns an empty object\n return {\n json: () => ({}),\n }\n}\n\nexport function generateGuestId() {\n if (isWeb()) {\n let guestId = getLocalStorage(GUEST_KEY)\n if (!guestId) {\n guestId = `${GUEST_PREFIX}${uuidv4()}`\n setLocalStorage(GUEST_KEY, guestId)\n }\n return guestId\n }\n}\n\nexport function fetcher(apiKey: string, path: string, options?: Record<any, any>) {\n return gracefulFetch(`//api.frigade.com/v1/public${path}`, {\n ...(options ?? {}),\n ...getHeaders(apiKey),\n })\n}\n\nexport function isWeb() {\n return typeof window !== 'undefined'\n}\n","import { FrigadeConfig, UserFlowState } from '../types'\nimport { Flow } from '../core/flow'\nimport { FlowStep } from '../core/flow-step'\n\nexport interface FrigadeGlobalState {\n refreshUserFlowStates: () => Promise<void>\n userFlowStates: Record<string, UserFlowState>\n onFlowStateChangeHandlerWrappers: Map<\n (flow: Flow, previousFlow: Flow) => void,\n (flow: Flow, previousFlow: Flow) => void\n >\n onStepStateChangeHandlerWrappers: Map<\n (step: FlowStep, previousStep: FlowStep) => void,\n (flow: Flow, previousFlow: Flow) => void\n >\n onFlowStateChangeHandlers: ((flow: Flow, previousFlow: Flow) => void)[]\n previousFlows: Map<string, Flow>\n}\n\nexport let frigadeGlobalState: Record<string, FrigadeGlobalState> = {}\n\nexport function getGlobalStateKey(internalConfig: FrigadeConfig): string {\n return `${internalConfig.__instanceId}-${internalConfig.apiKey}:${internalConfig.userId ?? ''}:${\n internalConfig.groupId ?? ''\n }`\n}\n","import { generateGuestId, getEmptyResponse, getHeaders, gracefulFetch } from './utils'\nimport { FrigadeConfig } from '../types'\nimport { frigadeGlobalState, FrigadeGlobalState, getGlobalStateKey } from './state'\n\nexport class Fetchable {\n public config: FrigadeConfig = {\n apiKey: '',\n apiUrl: 'https://api.frigade.com/v1/public',\n userId: generateGuestId(),\n __instanceId: Math.random().toString(36).substring(7),\n }\n\n constructor(config: FrigadeConfig) {\n const filteredConfig = Object.fromEntries(Object.entries(config).filter(([_, v]) => v != null))\n\n this.config = {\n ...this.config,\n ...filteredConfig,\n }\n }\n\n /**\n * @ignore\n */\n public async fetch(path: string, options?: Record<any, any>) {\n if (this.config.__readOnly) {\n return getEmptyResponse()\n }\n\n return gracefulFetch(`${this.config.apiUrl}${path}`, {\n ...(options ?? {}),\n ...getHeaders(this.config.apiKey),\n })\n }\n\n /**\n * @ignore\n */\n protected getGlobalState(): FrigadeGlobalState {\n const globalStateKey = getGlobalStateKey(this.config)\n if (!frigadeGlobalState[globalStateKey]) {\n throw new Error('Frigade not initialized')\n }\n return frigadeGlobalState[globalStateKey]\n }\n}\n","import { FrigadeConfig, UserFlowState } from '../types'\nimport { FlowDataRaw } from './types'\nimport {\n clone,\n COMPLETED_FLOW,\n COMPLETED_STEP,\n NOT_STARTED_FLOW,\n NOT_STARTED_STEP,\n SKIPPED_FLOW,\n STARTED_FLOW,\n STARTED_STEP,\n} from '../shared/utils'\nimport { FlowStep } from './flow-step'\nimport { Fetchable } from '../shared/Fetchable'\n\nexport class Flow extends Fetchable {\n /**\n * The Flow's ID.\n */\n public id: string\n /**\n * The raw data defined in `config.yml` as a JSON decoded object.\n * @ignore\n */\n public configYmlAsJson: any\n /**\n * Ordered map of the Steps in the Flow.\n * See [Flow Step Definition](https://docs.frigade.com/v2/sdk/js/step) for more information.\n */\n public steps: Map<string, FlowStep>\n /**\n * The user-facing title of the Flow, if defined at the top level of the YAML config.\n */\n public title?: string\n /**\n * The user-facing description of the Flow, if defined at the top level of the YAML config.\n */\n public subtitle?: string\n /**\n * The metadata of the Flow.\n * @ignore\n */\n public rawData: FlowDataRaw\n /**\n * Whether the Flow is completed or not.\n */\n public isCompleted: boolean\n /**\n * Whether the Flow is started or not.\n */\n public isStarted: boolean\n /**\n * Whether the Flow has been skipped or not.\n */\n public isSkipped: boolean\n /**\n * Whether the Flow is visible to the user based on the current user/group's state.\n */\n public isVisible: boolean = false\n /**\n * @ignore\n */\n private readonly flowDataRaw: FlowDataRaw\n /**\n * @ignore\n */\n private userFlowStateRaw?: UserFlowState\n /**\n * @ignore\n */\n private lastStepUpdate: Map<(step: FlowStep, previousStep: FlowStep) => void, FlowStep> =\n new Map()\n /**\n * @ignore\n */\n private lastUsedVariables = {}\n\n constructor(config: FrigadeConfig, flowDataRaw: FlowDataRaw) {\n super(config)\n this.flowDataRaw = flowDataRaw\n this.initFromRawData(flowDataRaw)\n }\n\n /**\n * Reload the Flow data from the server\n */\n reload() {\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * @ignore\n */\n private initFromRawData(flowDataRaw: FlowDataRaw) {\n const flowDataYml = JSON.parse(flowDataRaw.data)\n const steps = flowDataYml.steps ?? flowDataYml.data ?? []\n this.id = flowDataRaw.slug\n this.rawData = flowDataRaw\n this.configYmlAsJson = flowDataYml\n this.title = this.configYmlAsJson.title\n this.subtitle = this.configYmlAsJson.subtitle\n\n const userFlowState = this.getUserFlowState()\n if (!userFlowState) {\n return\n }\n this.userFlowStateRaw = userFlowState\n\n this.isCompleted = userFlowState.flowState == COMPLETED_FLOW\n this.isStarted = userFlowState.flowState == STARTED_FLOW\n this.isSkipped = userFlowState.flowState == SKIPPED_FLOW\n const hasCompleted = this.isCompleted || this.isSkipped\n const targetingShouldHideFlow =\n flowDataRaw.targetingLogic && userFlowState.shouldTrigger === false\n this.isVisible = !hasCompleted && !targetingShouldHideFlow\n if (this.flowDataRaw.active === false) {\n this.isVisible = false\n }\n const newSteps = new Map<string, FlowStep>()\n\n steps.forEach((step, index) => {\n const userFlowStateStep = userFlowState.stepStates[step.id]\n const stepObj = {\n ...step,\n isCompleted: userFlowStateStep.actionType == COMPLETED_STEP,\n isStarted: userFlowStateStep.actionType == STARTED_STEP,\n isHidden: userFlowStateStep.hidden,\n isBlocked: userFlowStateStep.blocked,\n lastActionAt: userFlowStateStep.lastActionAt\n ? new Date(userFlowStateStep.lastActionAt)\n : undefined,\n order: index,\n } as FlowStep\n\n stepObj.start = async (properties?: Record<string | number, any>) => {\n const thisStep = this.steps.get(step.id)\n\n if (this.getCurrentStep().id === thisStep.id && thisStep.isStarted) {\n return\n }\n\n thisStep.isStarted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.stepStates[thisStep.id].actionType = STARTED_STEP\n copy.stepStates[thisStep.id].lastActionAt = new Date().toISOString()\n copy.lastStepId = thisStep.id\n\n this.getGlobalState().userFlowStates[this.id] = copy\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: thisStep.id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: STARTED_STEP,\n }),\n })\n\n await this.refreshUserFlowState()\n\n const updatedUserFlowState = this.getUserFlowState()\n thisStep.isCompleted =\n updatedUserFlowState.stepStates[thisStep.id].actionType == COMPLETED_STEP\n thisStep.isStarted = updatedUserFlowState.stepStates[thisStep.id].actionType == STARTED_STEP\n thisStep.lastActionAt = new Date()\n }\n\n stepObj.complete = async (properties?: Record<string | number, any>) => {\n const thisStep = this.steps.get(step.id)\n\n if (thisStep.isCompleted) {\n return\n }\n\n const numberOfCompletedSteps = this.getNumberOfCompletedSteps()\n const isLastStep = numberOfCompletedSteps + 1 == this.steps.size\n\n thisStep.isCompleted = true\n this.isStarted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n\n copy.stepStates[thisStep.id].actionType = COMPLETED_STEP\n copy.stepStates[thisStep.id].lastActionAt = new Date().toISOString()\n copy.flowState = isLastStep ? COMPLETED_FLOW : STARTED_FLOW\n\n const nextStepId = Array.from(this.steps.keys())[index + 1]\n if (nextStepId) {\n copy.lastStepId = nextStepId\n copy.stepStates[nextStepId].actionType = STARTED_STEP\n const lastAction = new Date()\n copy.stepStates[nextStepId].lastActionAt = lastAction.toISOString()\n this.steps.get(nextStepId).isStarted = true\n this.steps.get(nextStepId).lastActionAt = lastAction\n }\n\n if (isLastStep) {\n this.optimisticallyMarkFlowCompleted()\n }\n\n this.getGlobalState().userFlowStates[this.id] = copy\n\n // if all steps are now completed, mark flow completed\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: thisStep.id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: COMPLETED_STEP,\n }),\n })\n\n await this.refreshUserFlowState()\n\n const updatedUserFlowState = this.getUserFlowState()\n thisStep.isCompleted =\n updatedUserFlowState.stepStates[thisStep.id].actionType == COMPLETED_STEP\n thisStep.isStarted = updatedUserFlowState.stepStates[thisStep.id].actionType == STARTED_STEP\n thisStep.lastActionAt = new Date()\n }\n\n stepObj.reset = async () => {\n const thisStep = this.steps.get(step.id)\n\n if (!thisStep.isCompleted) {\n return\n }\n\n thisStep.isCompleted = false\n thisStep.isStarted = false\n thisStep.lastActionAt = undefined\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.stepStates[thisStep.id].actionType = NOT_STARTED_STEP\n copy.stepStates[thisStep.id].lastActionAt = undefined\n copy.flowState = STARTED_FLOW\n this.getGlobalState().userFlowStates[this.id] = copy\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: thisStep.id,\n data: {},\n createdAt: new Date().toISOString(),\n actionType: NOT_STARTED_STEP,\n }),\n })\n\n await this.refreshUserFlowState()\n\n const updatedUserFlowState = this.getUserFlowState()\n thisStep.isCompleted =\n updatedUserFlowState.stepStates[thisStep.id].actionType == COMPLETED_STEP\n thisStep.isStarted = updatedUserFlowState.stepStates[thisStep.id].actionType == STARTED_STEP\n thisStep.lastActionAt = undefined\n }\n\n stepObj.onStateChange = (handler: (step: FlowStep, previousStep: FlowStep) => void) => {\n const wrapperHandler = (flow: Flow) => {\n if (flow.id !== this.id) {\n return\n }\n const thisStep = flow.steps.get(step.id)\n const previousStep = this.lastStepUpdate.get(handler)\n\n if (\n thisStep.isCompleted !== previousStep?.isCompleted ||\n thisStep.isStarted !== previousStep?.isStarted ||\n thisStep.isHidden !== previousStep?.isHidden ||\n thisStep.isBlocked !== previousStep?.isBlocked\n ) {\n handler(thisStep, previousStep ?? clone(thisStep))\n this.lastStepUpdate.set(handler, clone(thisStep))\n }\n }\n this.getGlobalState().onStepStateChangeHandlerWrappers.set(handler, wrapperHandler)\n this.getGlobalState().onFlowStateChangeHandlers.push(wrapperHandler)\n }\n\n stepObj.removeStateChangeHandler = (\n handler: (step: FlowStep, previousStep: FlowStep) => void\n ) => {\n const wrapperHandler = this.getGlobalState().onStepStateChangeHandlerWrappers.get(handler)\n if (wrapperHandler) {\n this.getGlobalState().onFlowStateChangeHandlers =\n this.getGlobalState().onFlowStateChangeHandlers.filter((h) => h !== wrapperHandler)\n }\n }\n\n newSteps.set(step.id, stepObj)\n })\n this.steps = newSteps\n // Check if empty object\n if (Object.keys(this.lastUsedVariables).length > 0) {\n this.applyVariables(this.lastUsedVariables)\n }\n }\n\n /**\n * Marks the flow started\n */\n public async start(properties?: Record<string | number, any>) {\n if (this.isStarted || this.isCompleted) {\n return\n }\n\n this.isStarted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.flowState = STARTED_FLOW\n this.getGlobalState().userFlowStates[this.id] = copy\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: this.getCurrentStep().id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: STARTED_FLOW,\n }),\n })\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * Marks the flow completed\n */\n public async complete(properties?: Record<string | number, any>) {\n if (this.isCompleted) {\n return\n }\n this.optimisticallyMarkFlowCompleted()\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: this.getCurrentStep().id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: COMPLETED_FLOW,\n }),\n })\n\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * @ignore\n */\n private optimisticallyMarkFlowCompleted() {\n this.isStarted = true\n this.isCompleted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.flowState = COMPLETED_FLOW\n this.getGlobalState().userFlowStates[this.id] = copy\n this.isVisible = false\n }\n\n /**\n * Marks the flow skipped\n */\n public async skip(properties?: Record<string | number, any>) {\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: this.getCurrentStep().id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: SKIPPED_FLOW,\n }),\n })\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * Navigates the flow to the next step if one exists. This will mark that step started, but will not complete the previous step.\n */\n public async forward(properties?: Record<string | number, any>) {\n const nextStep = this.getStepByIndex(this.getCurrentStepIndex() + 1)\n if (nextStep) {\n await nextStep.start(properties)\n }\n }\n\n /**\n * Navigates the flow to the previous step if one exists. This will mark that step started, but will not complete the previous step.\n */\n public async back(properties?: Record<string | number, any>) {\n const previousStep = this.getStepByIndex(this.getCurrentStepIndex() - 1)\n if (previousStep) {\n await previousStep.start(properties)\n }\n }\n\n /**\n * Restarts the flow/marks it not started\n */\n public async restart() {\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: 'unknown',\n data: {},\n createdAt: new Date().toISOString(),\n actionType: NOT_STARTED_FLOW,\n }),\n })\n\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * Get a step by index\n * @param index\n */\n public getStepByIndex(index: number): FlowStep | undefined {\n return this.steps.get(Array.from(this.steps.keys())[index])\n }\n\n /**\n * Gets current step\n */\n public getCurrentStep(): FlowStep {\n let maybeCurrentStepId = Array.from(this.steps.keys()).find(\n (key) => this.steps.get(key).isCompleted === false && this.steps.get(key).isHidden === false\n )\n Array.from(this.steps.keys()).forEach((key) => {\n if (\n this.steps.get(key).isStarted &&\n this.steps.get(key).lastActionAt &&\n this.steps.get(key).lastActionAt >\n (this.steps.get(maybeCurrentStepId)?.lastActionAt ?? new Date(0))\n ) {\n maybeCurrentStepId = key\n }\n })\n\n const currentStepId = maybeCurrentStepId ?? Array.from(this.steps.keys())[0]\n return this.steps.get(currentStepId)\n }\n\n /**\n * Get the index of the current step. Starts at 0\n */\n public getCurrentStepIndex(): number {\n const currentStep = this.getCurrentStep()\n return Array.from(this.steps.keys()).indexOf(currentStep.id)\n }\n\n /**\n * Get the number of completed steps for the current user in the current flow\n */\n public getNumberOfCompletedSteps(): number {\n return Array.from(this.steps.values()).filter((step) => step.isCompleted).length\n }\n\n /**\n * Get the number of available steps for the current user in the current flow. This is the number of steps that are not hidden.\n */\n public getNumberOfAvailableSteps(): number {\n return Array.from(this.steps.values()).filter((step) => !step.isHidden).length\n }\n\n /**\n * @ignore\n */\n public onStateChange(handler: (flow: Flow, previousFlow: Flow) => void) {\n const wrapperHandler = (flow: Flow, previousFlow: Flow) => {\n if (\n (flow.id === this.id &&\n (flow.isCompleted !== previousFlow.isCompleted ||\n flow.isStarted !== previousFlow.isStarted ||\n flow.isSkipped !== previousFlow.isSkipped ||\n flow.isVisible !== previousFlow.isVisible)) ||\n JSON.stringify(flow.steps) !== JSON.stringify(previousFlow.steps)\n ) {\n handler(flow, previousFlow)\n }\n }\n this.getGlobalState().onFlowStateChangeHandlerWrappers.set(handler, wrapperHandler)\n this.getGlobalState().onFlowStateChangeHandlers.push(wrapperHandler)\n }\n\n /**\n * @ignore\n */\n public removeStateChangeHandler(handler: (flow: Flow, previousFlow: Flow) => void) {\n const wrapperHandler = this.getGlobalState().onFlowStateChangeHandlerWrappers.get(handler)\n if (wrapperHandler) {\n this.getGlobalState().onFlowStateChangeHandlers =\n this.getGlobalState().onFlowStateChangeHandlers.filter((h) => h !== wrapperHandler)\n }\n }\n\n /**\n * @ignore\n */\n public applyVariables(variables: Record<string, any>) {\n // Replace ${variable} with the value of the variable\n const replaceVariables = (str: string) => {\n const matches = str.match(/\\${(.*?)}/g)\n if (matches) {\n matches.forEach((match) => {\n const variable = match.replace('${', '').replace('}', '')\n str = str.replace(match, variables[variable] ?? '')\n })\n }\n return str\n }\n\n this.title = replaceVariables(this.title ?? '')\n this.subtitle = replaceVariables(this.subtitle ?? '')\n this.steps.forEach((step) => {\n // Iterate over every string field in the step and replace variables\n Object.keys(step).forEach((key) => {\n if (typeof step[key] === 'string') {\n // @ts-ignore\n step[key] = replaceVariables(step[key])\n }\n })\n })\n\n this.lastUsedVariables = variables\n }\n\n /**\n * @ignore\n */\n private getUserFlowState(): UserFlowState {\n const userFlowStates = this.getGlobalState().userFlowStates\n return userFlowStates[this.id]\n }\n\n /**\n * @ignore\n */\n private async refreshUserFlowState() {\n await this.getGlobalState().refreshUserFlowStates()\n }\n}\n","import { FrigadeConfig, UserFlowState } from '../types'\nimport { clearCache, cloneFlow, isWeb, resetAllLocalStorage } from '../shared/utils'\nimport { Flow } from './flow'\nimport { FlowDataRaw, FlowStatus, FlowType, TriggerType } from './types'\nimport { frigadeGlobalState, getGlobalStateKey } from '../shared/state'\nimport { Fetchable } from '../shared/Fetchable'\n\nexport class Frigade extends Fetchable {\n /**\n * @ignore\n */\n private flows: Flow[] = []\n /**\n * @ignore\n */\n private initPromise: Promise<void>\n /**\n * @ignore\n */\n private hasFailed = false\n\n /**\n * @ignore\n */\n private visibilityChangeHandler = async () => {\n if (document.visibilityState === 'visible') {\n await this.refreshFlows()\n await this.refreshUserFlowStates()\n }\n }\n\n constructor(apiKey: string, config?: FrigadeConfig) {\n super({\n apiKey,\n ...config,\n })\n this.init(this.config)\n if (isWeb()) {\n document.addEventListener('visibilitychange', this.visibilityChangeHandler)\n }\n }\n\n /**\n * @ignore\n */\n destroy() {\n if (isWeb()) {\n document.removeEventListener('visibilitychange', this.visibilityChangeHandler)\n // Remove all other event listeners\n const globalStateKey = getGlobalStateKey(this.config)\n if (frigadeGlobalState[globalStateKey]) {\n frigadeGlobalState[globalStateKey].onFlowStateChangeHandlers = []\n }\n }\n }\n\n /**\n * @ignore\n */\n private async init(config: FrigadeConfig): Promise<void> {\n this.config = {\n ...this.config,\n ...config,\n }\n\n this.initPromise = (async () => {\n await this.refreshUserFlowStates()\n await this.refreshFlows()\n })()\n\n return this.initPromise\n }\n\n /**\n * Set the current user.\n * @param userId\n * @param properties\n */\n public async identify(userId: string, properties?: Record<string, any>): Promise<void> {\n this.config = { ...this.config, userId }\n await this.initIfNeeded()\n await this.fetch('/users', {\n method: 'POST',\n body: JSON.stringify({\n foreignId: this.config.userId,\n properties,\n }),\n })\n await this.refreshUserFlowStates()\n }\n\n /**\n * Set the group for the current user.\n * @param groupId\n * @param properties\n */\n public async group(groupId: string, properties?: Record<string, any>): Promise<void> {\n await this.initIfNeeded()\n this.config.groupId = groupId\n await this.fetch('/userGroups', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n properties,\n }),\n })\n await this.refreshUserFlowStates()\n }\n\n /**\n * Track an event for the current user (and group if set).\n * @param event\n * @param properties\n */\n public async track(event: string, properties?: Record<string, any>): Promise<void> {\n await this.initIfNeeded()\n if (!event) {\n console.error('Event name is required to track an event')\n return\n }\n if (this.config.userId && this.config.groupId) {\n await this.fetch('/userGroups', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n events: [\n {\n event,\n properties,\n },\n ],\n }),\n })\n } else if (this.config.userId) {\n await this.fetch('/users', {\n method: 'POST',\n body: JSON.stringify({\n foreignId: this.config.userId,\n events: [\n {\n event,\n properties,\n },\n ],\n }),\n })\n }\n }\n\n /**\n * @ignore\n */\n public isReady(): boolean {\n return Boolean(this.config.__instanceId && this.config.apiKey && this.initPromise)\n }\n\n /**\n * Get a Flow by its ID.\n * @param flowId\n */\n public async getFlow(flowId: string) {\n await this.initIfNeeded()\n\n return this.flows.find((flow) => flow.id == flowId)\n }\n\n public async getFlows() {\n await this.initIfNeeded()\n return this.flows\n }\n\n /**\n * Reload the current state of the flows by calling the Frigade API.\n * This will trigger all event handlers.\n */\n public async reload() {\n resetAllLocalStorage()\n clearCache()\n await this.refreshUserFlowStates()\n await this.refreshFlows()\n this.initPromise = null\n await this.init(this.config)\n // Trigger all event handlers\n this.flows.forEach((flow) => {\n this.getGlobalState().onFlowStateChangeHandlers.forEach((handler) => {\n const lastFlow = this.getGlobalState().previousFlows.get(flow.id)\n handler(flow, lastFlow)\n this.getGlobalState().previousFlows.set(flow.id, cloneFlow(flow))\n })\n })\n }\n\n /**\n * Event handler that captures all changes that happen to the state of the Flows.\n * @param handler\n */\n public onStateChange(handler: (flow: Flow, previousFlow?: Flow) => void) {\n this.getGlobalState().onFlowStateChangeHandlers.push(handler)\n }\n\n /**\n * Returns true if the JS SDK failed to connect to the Frigade API.\n */\n hasFailedToLoad() {\n return this.hasFailed\n }\n\n /**\n * Removes the given handler from the list of event handlers.\n * @param handler\n */\n public removeStateChangeHandler(handler: (flow: Flow, previousFlow?: Flow) => void) {\n this.getGlobalState().onFlowStateChangeHandlers =\n this.getGlobalState().onFlowStateChangeHandlers.filter((h) => h !== handler)\n }\n\n /**\n * @ignore\n */\n private async initIfNeeded() {\n if (this.initPromise !== null) {\n return this.initPromise\n } else {\n return this.init(this.config)\n }\n }\n\n /**\n * @ignore\n */\n private async refreshUserFlowStates(): Promise<void> {\n const globalStateKey = getGlobalStateKey(this.config)\n\n if (!frigadeGlobalState[globalStateKey]) {\n const that = this\n\n let validator = {\n set: function (target: any, key: any, value: any) {\n if (\n target[key] &&\n target[key].flowState &&\n (JSON.stringify(target[key].flowState) !== JSON.stringify(value?.flowState) ||\n JSON.stringify(target[key].stepStates) !== JSON.stringify(value?.stepStates) ||\n JSON.stringify(target[key].shouldTrigger) !== JSON.stringify(value?.shouldTrigger))\n ) {\n that.triggerEventHandlers(target[key])\n }\n\n target[key] = value\n return true\n },\n }\n\n frigadeGlobalState[globalStateKey] = {\n refreshUserFlowStates: async () => {},\n userFlowStates: new Proxy({}, validator),\n onFlowStateChangeHandlerWrappers: new Map(),\n onStepStateChangeHandlerWrappers: new Map(),\n onFlowStateChangeHandlers: [],\n previousFlows: new Map(),\n }\n\n if (this.config.__readOnly && this.config.__flowConfigOverrides) {\n this.mockUserFlowStates(globalStateKey)\n\n return\n }\n\n frigadeGlobalState[globalStateKey].refreshUserFlowStates = async () => {\n if (this.config.__readOnly) {\n return\n }\n\n const userFlowStatesRaw = await this.fetch(\n `/userFlowStates?foreignUserId=${encodeURIComponent(this.config.userId)}${\n this.config.groupId\n ? `&foreignUserGroupId=${encodeURIComponent(this.config.groupId)}`\n : ''\n }`\n )\n if (userFlowStatesRaw && userFlowStatesRaw.data) {\n let userFlowStates = userFlowStatesRaw.data as UserFlowState[]\n userFlowStates.forEach((userFlowState) => {\n let shouldReload = false\n const before = frigadeGlobalState[globalStateKey].userFlowStates[userFlowState.flowId]\n\n // Special case: for flows that show up based on targeting logic/rules, we need to check if the flow should be triggered\n if (before && before.shouldTrigger == false && userFlowState.shouldTrigger == true) {\n shouldReload = true\n }\n frigadeGlobalState[globalStateKey].userFlowStates[userFlowState.flowId] = userFlowState\n if (shouldReload) {\n this.flows.forEach((flow) => {\n if (flow.id == userFlowState.flowId) {\n flow.reload()\n this.triggerEventHandlers(\n frigadeGlobalState[globalStateKey].userFlowStates[flow.id]\n )\n }\n })\n }\n })\n this.hasFailed = false\n } else {\n this.hasFailed = true\n }\n }\n }\n\n await frigadeGlobalState[globalStateKey].refreshUserFlowStates()\n }\n\n /**\n * @ignore\n */\n private async refreshFlows() {\n this.flows = []\n\n if (this.config.__flowConfigOverrides) {\n this.mockFlowConfigs()\n return\n }\n\n const flowDataRaw = await this.fetch('/flows')\n if (flowDataRaw && flowDataRaw.data) {\n let flowDatas = flowDataRaw.data as FlowDataRaw[]\n flowDatas.forEach((flowData) => {\n this.flows.push(new Flow(this.config, flowData))\n this.getGlobalState().previousFlows.set(\n flowData.slug,\n cloneFlow(this.flows[this.flows.length - 1])\n )\n })\n } else {\n this.hasFailed = true\n }\n }\n\n /**\n * @ignore\n */\n private mockFlowConfigs() {\n Object.keys(this.config.__flowConfigOverrides).forEach((flowId) => {\n this.flows.push(\n new Flow(this.config, {\n id: -1,\n name: '',\n description: '',\n data: this.config.__flowConfigOverrides[flowId],\n createdAt: new Date().toISOString(),\n modifiedAt: new Date().toISOString(),\n slug: flowId,\n targetingLogic: '',\n type: FlowType.CHECKLIST,\n triggerType: TriggerType.MANUAL,\n status: FlowStatus.ACTIVE,\n version: 1,\n active: true,\n })\n )\n })\n }\n\n /**\n * @ignore\n */\n private mockUserFlowStates(globalStateKey: string) {\n Object.keys(this.config.__flowConfigOverrides).forEach((flowId) => {\n const parsed = JSON.parse(this.config.__flowConfigOverrides[flowId])\n frigadeGlobalState[globalStateKey].userFlowStates[flowId] = {\n flowId,\n flowState: 'NOT_STARTED_FLOW',\n lastStepId: null,\n userId: this.config.userId,\n foreignUserId: this.config.userId,\n stepStates:\n parsed?.steps?.reduce((acc, step) => {\n acc[step.id] = {\n stepId: step.id,\n flowSlug: flowId,\n actionType: 'NOT_STARTED_STEP',\n createdAt: new Date().toISOString(),\n blocked: false,\n hidden: false,\n }\n return acc\n }, {}) ?? {},\n shouldTrigger: false,\n }\n })\n }\n\n /**\n * @ignore\n */\n private async triggerEventHandlers(previousUserFlowState: UserFlowState) {\n if (previousUserFlowState) {\n this.flows.forEach((flow) => {\n if (flow.id == previousUserFlowState.flowId) {\n this.getGlobalState().onFlowStateChangeHandlers.forEach((handler) => {\n const lastFlow = this.getGlobalState().previousFlows.get(flow.id)\n handler(flow, lastFlow)\n this.getGlobalState().previousFlows.set(flow.id, cloneFlow(flow))\n })\n }\n })\n }\n }\n}\n"],"mappings":";ojBAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,UAAAE,EAAA,YAAAC,IAAA,eAAAC,GAAAJ,ICAO,IAAMK,EAAiB,SCC9B,IAAAC,EAAkB,6BAClBC,EAA6B,gBCiBtB,IAAIC,EAAyD,CAAC,EAE9D,SAASC,EAAkBC,EAAuC,CACvE,MAAO,GAAGA,EAAe,gBAAgBA,EAAe,UAAUA,EAAe,QAAU,MACzFA,EAAe,SAAW,IAE9B,CCrBO,IAAMC,EAAN,KAAgB,CAQrB,YAAYC,EAAuB,CAPnC,KAAO,OAAwB,CAC7B,OAAQ,GACR,OAAQ,oCACR,OAAQC,EAAgB,EACxB,aAAc,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC,CACtD,EAGE,IAAMC,EAAiB,OAAO,YAAY,OAAO,QAAQF,CAAM,EAAE,OAAO,CAAC,CAACG,EAAGC,CAAC,IAAMA,GAAK,IAAI,CAAC,EAE9F,KAAK,OAAS,CACZ,GAAG,KAAK,OACR,GAAGF,CACL,CACF,CAKA,MAAa,MAAMG,EAAcC,EAA4B,CAC3D,OAAI,KAAK,OAAO,WACPC,EAAiB,EAGnBC,EAAc,GAAG,KAAK,OAAO,SAASH,IAAQ,CACnD,GAAIC,GAAW,CAAC,EAChB,GAAGG,EAAW,KAAK,OAAO,MAAM,CAClC,CAAC,CACH,CAKU,gBAAqC,CAC7C,IAAMC,EAAiBC,EAAkB,KAAK,MAAM,EACpD,GAAI,CAACC,EAAmBF,CAAc,EACpC,MAAM,IAAI,MAAM,yBAAyB,EAE3C,OAAOE,EAAmBF,CAAc,CAC1C,CACF,EC9BO,IAAMG,EAAN,cAAmBC,CAAU,CA8DlC,YAAYC,EAAuBC,EAA0B,CAC3D,MAAMD,CAAM,EApBd,KAAO,UAAqB,GAY5B,KAAQ,eACN,IAAI,IAIN,KAAQ,kBAAoB,CAAC,EAI3B,KAAK,YAAcC,EACnB,KAAK,gBAAgBA,CAAW,CAClC,CAKA,QAAS,CACP,KAAK,gBAAgB,KAAK,WAAW,CACvC,CAKQ,gBAAgBA,EAA0B,CAChD,IAAMC,EAAc,KAAK,MAAMD,EAAY,IAAI,EACzCE,EAAQD,EAAY,OAASA,EAAY,MAAQ,CAAC,EACxD,KAAK,GAAKD,EAAY,KACtB,KAAK,QAAUA,EACf,KAAK,gBAAkBC,EACvB,KAAK,MAAQ,KAAK,gBAAgB,MAClC,KAAK,SAAW,KAAK,gBAAgB,SAErC,IAAME,EAAgB,KAAK,iBAAiB,EAC5C,GAAI,CAACA,EACH,OAEF,KAAK,iBAAmBA,EAExB,KAAK,YAAcA,EAAc,WAAaC,EAC9C,KAAK,UAAYD,EAAc,WAAaE,EAC5C,KAAK,UAAYF,EAAc,WAAaG,EAC5C,IAAMC,EAAe,KAAK,aAAe,KAAK,UACxCC,EACJR,EAAY,gBAAkBG,EAAc,gBAAkB,GAChE,KAAK,UAAY,CAACI,GAAgB,CAACC,EAC/B,KAAK,YAAY,SAAW,KAC9B,KAAK,UAAY,IAEnB,IAAMC,EAAW,IAAI,IAErBP,EAAM,QAAQ,CAACQ,EAAMC,IAAU,CAC7B,IAAMC,EAAoBT,EAAc,WAAWO,EAAK,EAAE,EACpDG,EAAU,CACd,GAAGH,EACH,YAAaE,EAAkB,YAAcE,EAC7C,UAAWF,EAAkB,YAAcG,EAC3C,SAAUH,EAAkB,OAC5B,UAAWA,EAAkB,QAC7B,aAAcA,EAAkB,aAC5B,IAAI,KAAKA,EAAkB,YAAY,EACvC,OACJ,MAAOD,CACT,EAEAE,EAAQ,MAAQ,MAAOG,GAA8C,CACnE,IAAMC,EAAW,KAAK,MAAM,IAAIP,EAAK,EAAE,EAEvC,GAAI,KAAK,eAAe,EAAE,KAAOO,EAAS,IAAMA,EAAS,UACvD,OAGFA,EAAS,UAAY,GACrB,IAAMC,EAAOC,EAAM,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,CAAC,EAChED,EAAK,WAAWD,EAAS,EAAE,EAAE,WAAaF,EAC1CG,EAAK,WAAWD,EAAS,EAAE,EAAE,aAAe,IAAI,KAAK,EAAE,YAAY,EACnEC,EAAK,WAAaD,EAAS,GAE3B,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,EAAIC,EAEhD,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQD,EAAS,GACjB,KAAMD,GAAc,CAAC,EACrB,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYD,CACd,CAAC,CACH,CAAC,EAED,MAAM,KAAK,qBAAqB,EAEhC,IAAMK,EAAuB,KAAK,iBAAiB,EACnDH,EAAS,YACPG,EAAqB,WAAWH,EAAS,EAAE,EAAE,YAAcH,EAC7DG,EAAS,UAAYG,EAAqB,WAAWH,EAAS,EAAE,EAAE,YAAcF,EAChFE,EAAS,aAAe,IAAI,IAC9B,EAEAJ,EAAQ,SAAW,MAAOG,GAA8C,CACtE,IAAMC,EAAW,KAAK,MAAM,IAAIP,EAAK,EAAE,EAEvC,GAAIO,EAAS,YACX,OAIF,IAAMI,EADyB,KAAK,0BAA0B,EAClB,GAAK,KAAK,MAAM,KAE5DJ,EAAS,YAAc,GACvB,KAAK,UAAY,GACjB,IAAMC,EAAOC,EAAM,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,CAAC,EAEhED,EAAK,WAAWD,EAAS,EAAE,EAAE,WAAaH,EAC1CI,EAAK,WAAWD,EAAS,EAAE,EAAE,aAAe,IAAI,KAAK,EAAE,YAAY,EACnEC,EAAK,UAAYG,EAAajB,EAAiBC,EAE/C,IAAMiB,EAAa,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,EAAEX,EAAQ,CAAC,EAC1D,GAAIW,EAAY,CACdJ,EAAK,WAAaI,EAClBJ,EAAK,WAAWI,CAAU,EAAE,WAAaP,EACzC,IAAMQ,EAAa,IAAI,KACvBL,EAAK,WAAWI,CAAU,EAAE,aAAeC,EAAW,YAAY,EAClE,KAAK,MAAM,IAAID,CAAU,EAAE,UAAY,GACvC,KAAK,MAAM,IAAIA,CAAU,EAAE,aAAeC,EAGxCF,GACF,KAAK,gCAAgC,EAGvC,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,EAAIH,EAGhD,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQD,EAAS,GACjB,KAAMD,GAAc,CAAC,EACrB,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYF,CACd,CAAC,CACH,CAAC,EAED,MAAM,KAAK,qBAAqB,EAEhC,IAAMM,EAAuB,KAAK,iBAAiB,EACnDH,EAAS,YACPG,EAAqB,WAAWH,EAAS,EAAE,EAAE,YAAcH,EAC7DG,EAAS,UAAYG,EAAqB,WAAWH,EAAS,EAAE,EAAE,YAAcF,EAChFE,EAAS,aAAe,IAAI,IAC9B,EAEAJ,EAAQ,MAAQ,SAAY,CAC1B,IAAMI,EAAW,KAAK,MAAM,IAAIP,EAAK,EAAE,EAEvC,GAAI,CAACO,EAAS,YACZ,OAGFA,EAAS,YAAc,GACvBA,EAAS,UAAY,GACrBA,EAAS,aAAe,OACxB,IAAMC,EAAOC,EAAM,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,CAAC,EAChED,EAAK,WAAWD,EAAS,EAAE,EAAE,WAAaO,EAC1CN,EAAK,WAAWD,EAAS,EAAE,EAAE,aAAe,OAC5CC,EAAK,UAAYb,EACjB,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,EAAIa,EAEhD,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQD,EAAS,GACjB,KAAM,CAAC,EACP,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYO,CACd,CAAC,CACH,CAAC,EAED,MAAM,KAAK,qBAAqB,EAEhC,IAAMJ,EAAuB,KAAK,iBAAiB,EACnDH,EAAS,YACPG,EAAqB,WAAWH,EAAS,EAAE,EAAE,YAAcH,EAC7DG,EAAS,UAAYG,EAAqB,WAAWH,EAAS,EAAE,EAAE,YAAcF,EAChFE,EAAS,aAAe,MAC1B,EAEAJ,EAAQ,cAAiBY,GAA8D,CACrF,IAAMC,EAAkBC,GAAe,CACrC,GAAIA,EAAK,KAAO,KAAK,GACnB,OAEF,IAAMV,EAAWU,EAAK,MAAM,IAAIjB,EAAK,EAAE,EACjCkB,EAAe,KAAK,eAAe,IAAIH,CAAO,GAGlDR,EAAS,eAAgBW,GAAA,YAAAA,EAAc,cACvCX,EAAS,aAAcW,GAAA,YAAAA,EAAc,YACrCX,EAAS,YAAaW,GAAA,YAAAA,EAAc,WACpCX,EAAS,aAAcW,GAAA,YAAAA,EAAc,cAErCH,EAAQR,EAAUW,GAAgBT,EAAMF,CAAQ,CAAC,EACjD,KAAK,eAAe,IAAIQ,EAASN,EAAMF,CAAQ,CAAC,EAEpD,EACA,KAAK,eAAe,EAAE,iCAAiC,IAAIQ,EAASC,CAAc,EAClF,KAAK,eAAe,EAAE,0BAA0B,KAAKA,CAAc,CACrE,EAEAb,EAAQ,yBACNY,GACG,CACH,IAAMC,EAAiB,KAAK,eAAe,EAAE,iCAAiC,IAAID,CAAO,EACrFC,IACF,KAAK,eAAe,EAAE,0BACpB,KAAK,eAAe,EAAE,0BAA0B,OAAQG,GAAMA,IAAMH,CAAc,EAExF,EAEAjB,EAAS,IAAIC,EAAK,GAAIG,CAAO,CAC/B,CAAC,EACD,KAAK,MAAQJ,EAET,OAAO,KAAK,KAAK,iBAAiB,EAAE,OAAS,GAC/C,KAAK,eAAe,KAAK,iBAAiB,CAE9C,CAKA,MAAa,MAAMO,EAA2C,CAC5D,GAAI,KAAK,WAAa,KAAK,YACzB,OAGF,KAAK,UAAY,GACjB,IAAME,EAAOC,EAAM,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,CAAC,EAChED,EAAK,UAAYb,EACjB,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,EAAIa,EAEhD,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQ,KAAK,eAAe,EAAE,GAC9B,KAAMF,GAAc,CAAC,EACrB,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYX,CACd,CAAC,CACH,CAAC,EACD,MAAM,KAAK,qBAAqB,EAChC,KAAK,gBAAgB,KAAK,WAAW,CACvC,CAKA,MAAa,SAASW,EAA2C,CAC3D,KAAK,cAGT,KAAK,gCAAgC,EAErC,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQ,KAAK,eAAe,EAAE,GAC9B,KAAMA,GAAc,CAAC,EACrB,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYZ,CACd,CAAC,CACH,CAAC,EAED,MAAM,KAAK,qBAAqB,EAChC,KAAK,gBAAgB,KAAK,WAAW,EACvC,CAKQ,iCAAkC,CACxC,KAAK,UAAY,GACjB,KAAK,YAAc,GACnB,IAAMc,EAAOC,EAAM,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,CAAC,EAChED,EAAK,UAAYd,EACjB,KAAK,eAAe,EAAE,eAAe,KAAK,EAAE,EAAIc,EAChD,KAAK,UAAY,EACnB,CAKA,MAAa,KAAKF,EAA2C,CAC3D,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQ,KAAK,eAAe,EAAE,GAC9B,KAAMA,GAAc,CAAC,EACrB,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYV,CACd,CAAC,CACH,CAAC,EACD,MAAM,KAAK,qBAAqB,EAChC,KAAK,gBAAgB,KAAK,WAAW,CACvC,CAKA,MAAa,QAAQU,EAA2C,CAC9D,IAAMc,EAAW,KAAK,eAAe,KAAK,oBAAoB,EAAI,CAAC,EAC/DA,GACF,MAAMA,EAAS,MAAMd,CAAU,CAEnC,CAKA,MAAa,KAAKA,EAA2C,CAC3D,IAAMY,EAAe,KAAK,eAAe,KAAK,oBAAoB,EAAI,CAAC,EACnEA,GACF,MAAMA,EAAa,MAAMZ,CAAU,CAEvC,CAKA,MAAa,SAAU,CACrB,MAAM,KAAK,MAAM,iBAAkB,CACjC,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,SAAU,KAAK,GACf,OAAQ,UACR,KAAM,CAAC,EACP,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAYe,CACd,CAAC,CACH,CAAC,EAED,MAAM,KAAK,qBAAqB,EAChC,KAAK,gBAAgB,KAAK,WAAW,CACvC,CAMO,eAAepB,EAAqC,CACzD,OAAO,KAAK,MAAM,IAAI,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,EAAEA,CAAK,CAAC,CAC5D,CAKO,gBAA2B,CAChC,IAAIqB,EAAqB,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,EAAE,KACpDC,GAAQ,KAAK,MAAM,IAAIA,CAAG,EAAE,cAAgB,IAAS,KAAK,MAAM,IAAIA,CAAG,EAAE,WAAa,EACzF,EACA,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,EAAE,QAASA,GAAQ,CAlcnD,IAAAC,EAocQ,KAAK,MAAM,IAAID,CAAG,EAAE,WACpB,KAAK,MAAM,IAAIA,CAAG,EAAE,cACpB,KAAK,MAAM,IAAIA,CAAG,EAAE,gBACjBC,EAAA,KAAK,MAAM,IAAIF,CAAkB,IAAjC,YAAAE,EAAoC,eAAgB,IAAI,KAAK,CAAC,KAEjEF,EAAqBC,EAEzB,CAAC,EAED,IAAME,EAAgBH,GAAsB,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,EAAE,CAAC,EAC3E,OAAO,KAAK,MAAM,IAAIG,CAAa,CACrC,CAKO,qBAA8B,CACnC,IAAMC,EAAc,KAAK,eAAe,EACxC,OAAO,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,EAAE,QAAQA,EAAY,EAAE,CAC7D,CAKO,2BAAoC,CACzC,OAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,EAAE,OAAQ1B,GAASA,EAAK,WAAW,EAAE,MAC5E,CAKO,2BAAoC,CACzC,OAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,EAAE,OAAQA,GAAS,CAACA,EAAK,QAAQ,EAAE,MAC1E,CAKO,cAAce,EAAmD,CACtE,IAAMC,EAAiB,CAACC,EAAYU,IAAuB,EAEtDV,EAAK,KAAO,KAAK,KACfA,EAAK,cAAgBU,EAAa,aACjCV,EAAK,YAAcU,EAAa,WAChCV,EAAK,YAAcU,EAAa,WAChCV,EAAK,YAAcU,EAAa,YACpC,KAAK,UAAUV,EAAK,KAAK,IAAM,KAAK,UAAUU,EAAa,KAAK,IAEhEZ,EAAQE,EAAMU,CAAY,CAE9B,EACA,KAAK,eAAe,EAAE,iCAAiC,IAAIZ,EAASC,CAAc,EAClF,KAAK,eAAe,EAAE,0BAA0B,KAAKA,CAAc,CACrE,CAKO,yBAAyBD,EAAmD,CACjF,IAAMC,EAAiB,KAAK,eAAe,EAAE,iCAAiC,IAAID,CAAO,EACrFC,IACF,KAAK,eAAe,EAAE,0BACpB,KAAK,eAAe,EAAE,0BAA0B,OAAQG,GAAMA,IAAMH,CAAc,EAExF,CAKO,eAAeY,EAAgC,CAEpD,IAAMC,EAAoBC,GAAgB,CACxC,IAAMC,EAAUD,EAAI,MAAM,YAAY,EACtC,OAAIC,GACFA,EAAQ,QAASC,GAAU,CACzB,IAAMC,EAAWD,EAAM,QAAQ,KAAM,EAAE,EAAE,QAAQ,IAAK,EAAE,EACxDF,EAAMA,EAAI,QAAQE,EAAOJ,EAAUK,CAAQ,GAAK,EAAE,CACpD,CAAC,EAEIH,CACT,EAEA,KAAK,MAAQD,EAAiB,KAAK,OAAS,EAAE,EAC9C,KAAK,SAAWA,EAAiB,KAAK,UAAY,EAAE,EACpD,KAAK,MAAM,QAAS7B,GAAS,CAE3B,OAAO,KAAKA,CAAI,EAAE,QAASuB,GAAQ,CAC7B,OAAOvB,EAAKuB,CAAG,GAAM,WAEvBvB,EAAKuB,CAAG,EAAIM,EAAiB7B,EAAKuB,CAAG,CAAC,EAE1C,CAAC,CACH,CAAC,EAED,KAAK,kBAAoBK,CAC3B,CAKQ,kBAAkC,CAExC,OADuB,KAAK,eAAe,EAAE,eACvB,KAAK,EAAE,CAC/B,CAKA,MAAc,sBAAuB,CACnC,MAAM,KAAK,eAAe,EAAE,sBAAsB,CACpD,CACF,EH7iBO,IAAMM,EAAmB,mBACnBC,EAAiB,iBACjBC,EAAe,eACfC,EAAe,eACfC,EAAmB,mBACnBC,EAAiB,iBACjBC,EAAe,eAGtBC,GAAoB,wBACpBC,GAAsB,0BACtBC,EAAY,oBACZC,GAAe,SACfC,GAAmB,aAEzB,IAAMC,GAAoB,IACpBC,EAAuB,SAEtB,SAASC,EAAUC,EAAkB,CAC1C,IAAMC,EAAU,IAAIC,EAAKF,EAAK,OAAQA,EAAK,OAAO,EAClD,OAAAC,EAAQ,YAAcD,EAAK,YAC3BC,EAAQ,UAAYD,EAAK,UACzBC,EAAQ,UAAYD,EAAK,UACzBC,EAAQ,UAAYD,EAAK,UACzBC,EAAQ,MAAQD,EAAK,MACdC,CACT,CAEO,SAASE,EAASC,EAAW,CAClC,OAAO,KAAK,MAAM,KAAK,UAAUA,CAAG,CAAC,CACvC,CAEO,SAASC,EAAWC,EAAgB,CACzC,MAAO,CACL,QAAS,CACP,cAAe,UAAUA,IACzB,eAAgB,mBAChB,wBAAyBC,EACzB,yBAA0B,YAC5B,CACF,CACF,CAEA,SAASC,EAAgBC,EAAa,CACpC,OAAIC,EAAM,EACD,OAAO,aAAa,QAAQ,GAAGZ,IAAuBW,GAAK,EAE7D,IACT,CAEA,SAASE,EAAgBF,EAAaG,EAAe,CAC/CF,EAAM,GACR,OAAO,aAAa,QAAQ,GAAGZ,IAAuBW,IAAOG,CAAK,CAEtE,CAUO,SAASC,GAAa,CAC3B,OAAO,KAAKC,CAAkB,EAAE,QAASC,GAAQ,CAC3CA,EAAI,WAAWC,EAAgB,GACjC,OAAOF,EAAmBC,CAAG,CAEjC,CAAC,CACH,CAEO,SAASE,GAAuB,CACjCC,EAAM,GAER,OAAO,KAAK,OAAO,YAAY,EAAE,QAASH,GAAQ,CAC5CA,EAAI,WAAWI,CAAoB,GACrC,OAAO,aAAa,WAAWJ,CAAG,CAEtC,CAAC,CAEL,CAEA,eAAsBK,EAAcC,EAAaC,EAAc,CAC7D,IAAMC,EAAgBC,GAAoBH,EACpCI,EAAkBC,GAAsBL,EAC9C,GAAIH,EAAM,GAAKI,GAAWA,EAAQ,MAAQA,EAAQ,SAAW,OAAQ,CACnE,IAAMK,EAAWC,EAAgBL,CAAa,EACxCM,EAAeD,EAAgBH,CAAe,EACpD,GAAIE,GAAYE,GAAgBA,GAAgBP,EAAQ,KAAM,CAC5D,IAAMQ,EAAe,IAAI,KAAKH,CAAQ,EAItC,GAHY,IAAI,KAAK,EACJ,QAAQ,EAAIG,EAAa,QAAQ,EAEvCC,GACT,OAAOC,EAAiB,EAG5BC,EAAgBV,EAAe,IAAI,KAAK,EAAE,YAAY,CAAC,EACvDU,EAAgBR,EAAiBH,EAAQ,IAAI,EAC7CT,EAAW,EAGb,IAAIqB,EACJ,GAAI,CACFA,KAAW,EAAAC,SAAMd,EAAKC,CAAO,EAC7BY,EAAW,MAAMA,CACnB,OAASE,EAAP,CACA,OAAOJ,EAAiBI,CAAK,CAC/B,CAEA,GAAI,CAACF,EACH,OAAOF,EAAiB,4BAA4B,EAGtD,GAAIE,EAAS,QAAU,IACrB,OAAOF,EAAiBE,EAAS,UAAU,EAG7C,GAAI,CACF,GAAIA,EAAS,SAAW,KAAOA,EAAS,SAAW,IACjD,OAAOF,EAAiB,EAG1B,IAAMK,EAAO,MAAMH,EAAS,KAAK,EACjC,OAAIG,EAAK,MACAL,EAAiBK,EAAK,KAAK,EAE7BA,CACT,OAASC,EAAP,CACA,OAAON,EAAiBM,CAAC,CAC3B,CACF,CAEO,SAASN,EAAiBI,EAAa,CAC5C,OAAIA,GACF,QAAQ,IAAI,yBAA0BA,CAAK,EAItC,CACL,KAAM,KAAO,CAAC,EAChB,CACF,CAEO,SAASG,GAAkB,CAChC,GAAIrB,EAAM,EAAG,CACX,IAAIsB,EAAUZ,EAAgBa,CAAS,EACvC,OAAKD,IACHA,EAAU,GAAGE,QAAe,EAAAC,IAAO,IACnCV,EAAgBQ,EAAWD,CAAO,GAE7BA,EAEX,CASO,SAASI,GAAQ,CACtB,OAAO,OAAO,OAAW,GAC3B,CIpKO,IAAMC,EAAN,cAAsBC,CAAU,CAwBrC,YAAYC,EAAgBC,EAAwB,CAClD,MAAM,CACJ,OAAAD,EACA,GAAGC,CACL,CAAC,EAxBH,KAAQ,MAAgB,CAAC,EAQzB,KAAQ,UAAY,GAKpB,KAAQ,wBAA0B,SAAY,CACxC,SAAS,kBAAoB,YAC/B,MAAM,KAAK,aAAa,EACxB,MAAM,KAAK,sBAAsB,EAErC,EAOE,KAAK,KAAK,KAAK,MAAM,EACjBC,EAAM,GACR,SAAS,iBAAiB,mBAAoB,KAAK,uBAAuB,CAE9E,CAKA,SAAU,CACR,GAAIA,EAAM,EAAG,CACX,SAAS,oBAAoB,mBAAoB,KAAK,uBAAuB,EAE7E,IAAMC,EAAiBC,EAAkB,KAAK,MAAM,EAChDC,EAAmBF,CAAc,IACnCE,EAAmBF,CAAc,EAAE,0BAA4B,CAAC,GAGtE,CAKA,MAAc,KAAKF,EAAsC,CACvD,YAAK,OAAS,CACZ,GAAG,KAAK,OACR,GAAGA,CACL,EAEA,KAAK,aAAe,SAAY,CAC9B,MAAM,KAAK,sBAAsB,EACjC,MAAM,KAAK,aAAa,CAC1B,GAAG,EAEI,KAAK,WACd,CAOA,MAAa,SAASK,EAAgBC,EAAiD,CACrF,KAAK,OAAS,CAAE,GAAG,KAAK,OAAQ,OAAAD,CAAO,EACvC,MAAM,KAAK,aAAa,EACxB,MAAM,KAAK,MAAM,SAAU,CACzB,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,UAAW,KAAK,OAAO,OACvB,WAAAC,CACF,CAAC,CACH,CAAC,EACD,MAAM,KAAK,sBAAsB,CACnC,CAOA,MAAa,MAAMC,EAAiBD,EAAiD,CACnF,MAAM,KAAK,aAAa,EACxB,KAAK,OAAO,QAAUC,EACtB,MAAM,KAAK,MAAM,cAAe,CAC9B,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,WAAAD,CACF,CAAC,CACH,CAAC,EACD,MAAM,KAAK,sBAAsB,CACnC,CAOA,MAAa,MAAME,EAAeF,EAAiD,CAEjF,GADA,MAAM,KAAK,aAAa,EACpB,CAACE,EAAO,CACV,QAAQ,MAAM,0CAA0C,EACxD,OAEE,KAAK,OAAO,QAAU,KAAK,OAAO,QACpC,MAAM,KAAK,MAAM,cAAe,CAC9B,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,cAAe,KAAK,OAAO,OAC3B,mBAAoB,KAAK,OAAO,QAChC,OAAQ,CACN,CACE,MAAAA,EACA,WAAAF,CACF,CACF,CACF,CAAC,CACH,CAAC,EACQ,KAAK,OAAO,QACrB,MAAM,KAAK,MAAM,SAAU,CACzB,OAAQ,OACR,KAAM,KAAK,UAAU,CACnB,UAAW,KAAK,OAAO,OACvB,OAAQ,CACN,CACE,MAAAE,EACA,WAAAF,CACF,CACF,CACF,CAAC,CACH,CAAC,CAEL,CAKO,SAAmB,CACxB,MAAO,GAAQ,KAAK,OAAO,cAAgB,KAAK,OAAO,QAAU,KAAK,YACxE,CAMA,MAAa,QAAQG,EAAgB,CACnC,aAAM,KAAK,aAAa,EAEjB,KAAK,MAAM,KAAMC,GAASA,EAAK,IAAMD,CAAM,CACpD,CAEA,MAAa,UAAW,CACtB,aAAM,KAAK,aAAa,EACjB,KAAK,KACd,CAMA,MAAa,QAAS,CACpBE,EAAqB,EACrBC,EAAW,EACX,MAAM,KAAK,sBAAsB,EACjC,MAAM,KAAK,aAAa,EACxB,KAAK,YAAc,KACnB,MAAM,KAAK,KAAK,KAAK,MAAM,EAE3B,KAAK,MAAM,QAASF,GAAS,CAC3B,KAAK,eAAe,EAAE,0BAA0B,QAASG,GAAY,CACnE,IAAMC,EAAW,KAAK,eAAe,EAAE,cAAc,IAAIJ,EAAK,EAAE,EAChEG,EAAQH,EAAMI,CAAQ,EACtB,KAAK,eAAe,EAAE,cAAc,IAAIJ,EAAK,GAAIK,EAAUL,CAAI,CAAC,CAClE,CAAC,CACH,CAAC,CACH,CAMO,cAAcG,EAAoD,CACvE,KAAK,eAAe,EAAE,0BAA0B,KAAKA,CAAO,CAC9D,CAKA,iBAAkB,CAChB,OAAO,KAAK,SACd,CAMO,yBAAyBA,EAAoD,CAClF,KAAK,eAAe,EAAE,0BACpB,KAAK,eAAe,EAAE,0BAA0B,OAAQG,GAAMA,IAAMH,CAAO,CAC/E,CAKA,MAAc,cAAe,CAC3B,OAAI,KAAK,cAAgB,KAChB,KAAK,YAEL,KAAK,KAAK,KAAK,MAAM,CAEhC,CAKA,MAAc,uBAAuC,CACnD,IAAMX,EAAiBC,EAAkB,KAAK,MAAM,EAEpD,GAAI,CAACC,EAAmBF,CAAc,EAAG,CACvC,IAAMe,EAAO,KAETC,EAAY,CACd,IAAK,SAAUC,EAAaC,EAAUC,EAAY,CAChD,OACEF,EAAOC,CAAG,GACVD,EAAOC,CAAG,EAAE,YACX,KAAK,UAAUD,EAAOC,CAAG,EAAE,SAAS,IAAM,KAAK,UAAUC,GAAA,YAAAA,EAAO,SAAS,GACxE,KAAK,UAAUF,EAAOC,CAAG,EAAE,UAAU,IAAM,KAAK,UAAUC,GAAA,YAAAA,EAAO,UAAU,GAC3E,KAAK,UAAUF,EAAOC,CAAG,EAAE,aAAa,IAAM,KAAK,UAAUC,GAAA,YAAAA,EAAO,aAAa,IAEnFJ,EAAK,qBAAqBE,EAAOC,CAAG,CAAC,EAGvCD,EAAOC,CAAG,EAAIC,EACP,EACT,CACF,EAWA,GATAjB,EAAmBF,CAAc,EAAI,CACnC,sBAAuB,SAAY,CAAC,EACpC,eAAgB,IAAI,MAAM,CAAC,EAAGgB,CAAS,EACvC,iCAAkC,IAAI,IACtC,iCAAkC,IAAI,IACtC,0BAA2B,CAAC,EAC5B,cAAe,IAAI,GACrB,EAEI,KAAK,OAAO,YAAc,KAAK,OAAO,sBAAuB,CAC/D,KAAK,mBAAmBhB,CAAc,EAEtC,OAGFE,EAAmBF,CAAc,EAAE,sBAAwB,SAAY,CACrE,GAAI,KAAK,OAAO,WACd,OAGF,IAAMoB,EAAoB,MAAM,KAAK,MACnC,iCAAiC,mBAAmB,KAAK,OAAO,MAAM,IACpE,KAAK,OAAO,QACR,uBAAuB,mBAAmB,KAAK,OAAO,OAAO,IAC7D,IAER,EACIA,GAAqBA,EAAkB,MACpBA,EAAkB,KACxB,QAASC,GAAkB,CACxC,IAAIC,EAAe,GACbC,EAASrB,EAAmBF,CAAc,EAAE,eAAeqB,EAAc,MAAM,EAGjFE,GAAUA,EAAO,eAAiB,IAASF,EAAc,eAAiB,KAC5EC,EAAe,IAEjBpB,EAAmBF,CAAc,EAAE,eAAeqB,EAAc,MAAM,EAAIA,EACtEC,GACF,KAAK,MAAM,QAASd,GAAS,CACvBA,EAAK,IAAMa,EAAc,SAC3Bb,EAAK,OAAO,EACZ,KAAK,qBACHN,EAAmBF,CAAc,EAAE,eAAeQ,EAAK,EAAE,CAC3D,EAEJ,CAAC,CAEL,CAAC,EACD,KAAK,UAAY,IAEjB,KAAK,UAAY,EAErB,EAGF,MAAMN,EAAmBF,CAAc,EAAE,sBAAsB,CACjE,CAKA,MAAc,cAAe,CAG3B,GAFA,KAAK,MAAQ,CAAC,EAEV,KAAK,OAAO,sBAAuB,CACrC,KAAK,gBAAgB,EACrB,OAGF,IAAMwB,EAAc,MAAM,KAAK,MAAM,QAAQ,EACzCA,GAAeA,EAAY,KACbA,EAAY,KAClB,QAASC,GAAa,CAC9B,KAAK,MAAM,KAAK,IAAIC,EAAK,KAAK,OAAQD,CAAQ,CAAC,EAC/C,KAAK,eAAe,EAAE,cAAc,IAClCA,EAAS,KACTZ,EAAU,KAAK,MAAM,KAAK,MAAM,OAAS,CAAC,CAAC,CAC7C,CACF,CAAC,EAED,KAAK,UAAY,EAErB,CAKQ,iBAAkB,CACxB,OAAO,KAAK,KAAK,OAAO,qBAAqB,EAAE,QAASN,GAAW,CACjE,KAAK,MAAM,KACT,IAAImB,EAAK,KAAK,OAAQ,CACpB,GAAI,GACJ,KAAM,GACN,YAAa,GACb,KAAM,KAAK,OAAO,sBAAsBnB,CAAM,EAC9C,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,WAAY,IAAI,KAAK,EAAE,YAAY,EACnC,KAAMA,EACN,eAAgB,GAChB,iBACA,qBACA,gBACA,QAAS,EACT,OAAQ,EACV,CAAC,CACH,CACF,CAAC,CACH,CAKQ,mBAAmBP,EAAwB,CACjD,OAAO,KAAK,KAAK,OAAO,qBAAqB,EAAE,QAASO,GAAW,CAjXvE,IAAAoB,EAkXM,IAAMC,EAAS,KAAK,MAAM,KAAK,OAAO,sBAAsBrB,CAAM,CAAC,EACnEL,EAAmBF,CAAc,EAAE,eAAeO,CAAM,EAAI,CAC1D,OAAAA,EACA,UAAW,mBACX,WAAY,KACZ,OAAQ,KAAK,OAAO,OACpB,cAAe,KAAK,OAAO,OAC3B,aACEoB,EAAAC,GAAA,YAAAA,EAAQ,QAAR,YAAAD,EAAe,OAAO,CAACE,EAAKC,KAC1BD,EAAIC,EAAK,EAAE,EAAI,CACb,OAAQA,EAAK,GACb,SAAUvB,EACV,WAAY,mBACZ,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,QAAS,GACT,OAAQ,EACV,EACOsB,GACN,CAAC,KAAM,CAAC,EACb,cAAe,EACjB,CACF,CAAC,CACH,CAKA,MAAc,qBAAqBE,EAAsC,CACnEA,GACF,KAAK,MAAM,QAASvB,GAAS,CACvBA,EAAK,IAAMuB,EAAsB,QACnC,KAAK,eAAe,EAAE,0BAA0B,QAASpB,GAAY,CACnE,IAAMC,EAAW,KAAK,eAAe,EAAE,cAAc,IAAIJ,EAAK,EAAE,EAChEG,EAAQH,EAAMI,CAAQ,EACtB,KAAK,eAAe,EAAE,cAAc,IAAIJ,EAAK,GAAIK,EAAUL,CAAI,CAAC,CAClE,CAAC,CAEL,CAAC,CAEL,CACF","names":["src_exports","__export","Flow","Frigade","__toCommonJS","VERSION_NUMBER","import_cross_fetch","import_uuid","frigadeGlobalState","getGlobalStateKey","internalConfig","Fetchable","config","generateGuestId","filteredConfig","_","v","path","options","getEmptyResponse","gracefulFetch","getHeaders","globalStateKey","getGlobalStateKey","frigadeGlobalState","Flow","Fetchable","config","flowDataRaw","flowDataYml","steps","userFlowState","COMPLETED_FLOW","STARTED_FLOW","SKIPPED_FLOW","hasCompleted","targetingShouldHideFlow","newSteps","step","index","userFlowStateStep","stepObj","COMPLETED_STEP","STARTED_STEP","properties","thisStep","copy","clone","updatedUserFlowState","isLastStep","nextStepId","lastAction","NOT_STARTED_STEP","handler","wrapperHandler","flow","previousStep","h","nextStep","NOT_STARTED_FLOW","maybeCurrentStepId","key","_a","currentStepId","currentStep","previousFlow","variables","replaceVariables","str","matches","match","variable","NOT_STARTED_STEP","COMPLETED_FLOW","SKIPPED_FLOW","STARTED_FLOW","NOT_STARTED_FLOW","COMPLETED_STEP","STARTED_STEP","LAST_POST_CALL_AT","LAST_POST_CALL_DATA","GUEST_KEY","GUEST_PREFIX","GET_CACHE_PREFIX","POST_CACHE_TTL_MS","LOCAL_STORAGE_PREFIX","cloneFlow","flow","newFlow","Flow","clone","obj","getHeaders","apiKey","VERSION_NUMBER","getLocalStorage","key","isWeb","setLocalStorage","value","clearCache","frigadeGlobalState","key","GET_CACHE_PREFIX","resetAllLocalStorage","isWeb","LOCAL_STORAGE_PREFIX","gracefulFetch","url","options","lastCallAtKey","LAST_POST_CALL_AT","lastCallDataKey","LAST_POST_CALL_DATA","lastCall","getLocalStorage","lastCallData","lastCallDate","POST_CACHE_TTL_MS","getEmptyResponse","setLocalStorage","response","fetch","error","body","e","generateGuestId","guestId","GUEST_KEY","GUEST_PREFIX","uuidv4","isWeb","Frigade","Fetchable","apiKey","config","isWeb","globalStateKey","getGlobalStateKey","frigadeGlobalState","userId","properties","groupId","event","flowId","flow","resetAllLocalStorage","clearCache","handler","lastFlow","cloneFlow","h","that","validator","target","key","value","userFlowStatesRaw","userFlowState","shouldReload","before","flowDataRaw","flowData","Flow","_a","parsed","acc","step","previousUserFlowState"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
interface FrigadeConfig {
|
|
2
|
+
/**
|
|
3
|
+
* Frigade API key. You can find your API key in the Frigade Dashboard under "Developer".
|
|
4
|
+
*/
|
|
2
5
|
apiKey?: string;
|
|
3
6
|
/**
|
|
4
7
|
* API url to use for all requests. Defaults to https://api.frigade.com
|
|
5
8
|
*/
|
|
6
9
|
apiUrl?: string;
|
|
7
10
|
/**
|
|
8
|
-
* User ID to use for all requests
|
|
11
|
+
* User ID to use for all requests. If not provided, a Guest ID will be generated.
|
|
9
12
|
*/
|
|
10
13
|
userId?: string;
|
|
11
14
|
/**
|
|
12
|
-
* Group ID (organization) to use for all requests
|
|
15
|
+
* Group ID (organization) to use for all requests.
|
|
13
16
|
*/
|
|
14
17
|
groupId?: string;
|
|
15
18
|
/**
|
|
@@ -23,6 +26,9 @@ interface FrigadeConfig {
|
|
|
23
26
|
* Configs will have to be provided in serialized JSON format rather than YAML.
|
|
24
27
|
*/
|
|
25
28
|
__flowConfigOverrides?: Record<string, string>;
|
|
29
|
+
/**
|
|
30
|
+
* @ignore Internal use only.
|
|
31
|
+
*/
|
|
26
32
|
__instanceId?: string;
|
|
27
33
|
}
|
|
28
34
|
interface UserFlowState {
|
|
@@ -91,19 +97,19 @@ interface FlowStep {
|
|
|
91
97
|
*/
|
|
92
98
|
id: string;
|
|
93
99
|
/**
|
|
94
|
-
* Order of the step in the
|
|
100
|
+
* Order of the step in the Flow.
|
|
95
101
|
*/
|
|
96
102
|
order: number;
|
|
97
103
|
/**
|
|
98
|
-
* Name of the step when shown in a list view
|
|
104
|
+
* Name of the step when shown in a list view.
|
|
99
105
|
*/
|
|
100
106
|
stepName?: string;
|
|
101
107
|
/**
|
|
102
|
-
* Title of the step
|
|
108
|
+
* Title of the step.
|
|
103
109
|
*/
|
|
104
110
|
title?: string;
|
|
105
111
|
/**
|
|
106
|
-
* Subtitle of the step
|
|
112
|
+
* Subtitle of the step.
|
|
107
113
|
*/
|
|
108
114
|
subtitle?: string;
|
|
109
115
|
/**
|
|
@@ -115,7 +121,7 @@ interface FlowStep {
|
|
|
115
121
|
*/
|
|
116
122
|
primaryButtonUri?: string;
|
|
117
123
|
/**
|
|
118
|
-
* Primary button URI target (either _blank or _self)
|
|
124
|
+
* Primary button URI target (either _blank or _self).
|
|
119
125
|
*/
|
|
120
126
|
primaryButtonUriTarget?: string;
|
|
121
127
|
/**
|
|
@@ -131,7 +137,7 @@ interface FlowStep {
|
|
|
131
137
|
*/
|
|
132
138
|
secondaryButtonUriTarget?: string;
|
|
133
139
|
/**
|
|
134
|
-
* Text on button if a back button is present
|
|
140
|
+
* Text on button if a back button is present.
|
|
135
141
|
*/
|
|
136
142
|
backButtonTitle?: string;
|
|
137
143
|
/**
|
|
@@ -151,64 +157,74 @@ interface FlowStep {
|
|
|
151
157
|
*/
|
|
152
158
|
autoMarkCompleted?: boolean;
|
|
153
159
|
/**
|
|
154
|
-
* Whether the step has been completed (equivalent to step status === COMPLETED_STEP)
|
|
160
|
+
* Whether the step has been completed (equivalent to step status === COMPLETED_STEP).
|
|
155
161
|
*/
|
|
156
162
|
isCompleted: boolean;
|
|
157
163
|
/**
|
|
158
|
-
* Whether the step has been completed (equivalent to step status === COMPLETED_STEP)
|
|
164
|
+
* Whether the step has been completed (equivalent to step status === COMPLETED_STEP).
|
|
159
165
|
*/
|
|
160
166
|
isStarted: boolean;
|
|
161
167
|
/**
|
|
162
|
-
* Whether the step is blocked (can't be accessed yet) based on `startCriteria
|
|
168
|
+
* Whether the step is blocked (can't be accessed yet) based on `startCriteria`.
|
|
163
169
|
*/
|
|
164
170
|
isBlocked: boolean;
|
|
165
171
|
/**
|
|
166
|
-
* Whether the step is hidden (not shown in the list view) based on `visibilityCriteria
|
|
172
|
+
* Whether the step is hidden (not shown in the list view) based on `visibilityCriteria`.
|
|
167
173
|
*/
|
|
168
174
|
isHidden: boolean;
|
|
169
175
|
/**
|
|
170
|
-
* Last state update
|
|
176
|
+
* Last state update.
|
|
171
177
|
*/
|
|
172
178
|
lastActionAt?: Date;
|
|
179
|
+
/**
|
|
180
|
+
* @ignore
|
|
181
|
+
*/
|
|
173
182
|
props?: any;
|
|
174
183
|
/**
|
|
175
|
-
* Criteria that needs to be met for the step to complete
|
|
184
|
+
* Criteria that needs to be met for the step to complete.
|
|
185
|
+
* Completion criteria uses Frigade's [Targeting Engine](https://docs.frigade.com/v2/platform/targeting) to determine if the step should be completed.
|
|
176
186
|
*/
|
|
177
187
|
completionCriteria?: string;
|
|
178
188
|
/**
|
|
179
|
-
* Criteria that needs to be met for the step to start
|
|
189
|
+
* Criteria that needs to be met for the step to start.
|
|
190
|
+
* Start criteria uses Frigade's [Targeting Engine](https://docs.frigade.com/v2/platform/targeting) to determine if the step should be started.
|
|
180
191
|
*/
|
|
181
192
|
startCriteria?: string;
|
|
182
193
|
/**
|
|
183
|
-
*
|
|
194
|
+
* Criteria that needs to be met for the step to be visible.
|
|
195
|
+
* Visibility criteria uses Frigade's [Targeting Engine](https://docs.frigade.com/v2/platform/targeting) to determine if the step should be visible.
|
|
196
|
+
*/
|
|
197
|
+
visibilityCriteria?: string;
|
|
198
|
+
/**
|
|
199
|
+
* Progress if the step is tied to another Frigade Flow through completionCriteria.
|
|
184
200
|
*/
|
|
185
201
|
progress?: number;
|
|
186
202
|
/**
|
|
187
|
-
* Whether the step is dismissible (for instance, tooltips or other non-essential steps)
|
|
203
|
+
* Whether the step is dismissible (for instance, tooltips or other non-essential steps).
|
|
188
204
|
*/
|
|
189
205
|
dismissible?: boolean;
|
|
190
206
|
/**
|
|
191
|
-
* Any other additional props defined in config.
|
|
207
|
+
* Any other additional props defined in the YAML config.
|
|
192
208
|
*/
|
|
193
209
|
[x: string | number | symbol]: unknown;
|
|
194
210
|
/**
|
|
195
|
-
* Marks the step started
|
|
211
|
+
* Marks the step started.
|
|
196
212
|
*/
|
|
197
213
|
start: (properties?: Record<string | number, any>) => Promise<void>;
|
|
198
214
|
/**
|
|
199
|
-
* Marks the step completed
|
|
215
|
+
* Marks the step completed.
|
|
200
216
|
*/
|
|
201
217
|
complete: (properties?: Record<string | number, any>) => Promise<void>;
|
|
202
218
|
/**
|
|
203
|
-
* Resets the step (useful for undoing a finished step)
|
|
219
|
+
* Resets the step (useful for undoing a finished step).
|
|
204
220
|
*/
|
|
205
221
|
reset: () => Promise<void>;
|
|
206
222
|
/**
|
|
207
|
-
* Event handler for this given step's state changes
|
|
223
|
+
* Event handler for this given step's state changes.
|
|
208
224
|
*/
|
|
209
225
|
onStateChange: (callback: (step: FlowStep, previousStep?: FlowStep) => void) => void;
|
|
210
226
|
/**
|
|
211
|
-
* Removes the given callback from the list of event handlers
|
|
227
|
+
* Removes the given callback from the list of event handlers.
|
|
212
228
|
*/
|
|
213
229
|
removeStateChangeHandler: (callback: (step: FlowStep, previousStep?: FlowStep) => void) => void;
|
|
214
230
|
}
|
|
@@ -225,57 +241,84 @@ interface FrigadeGlobalState {
|
|
|
225
241
|
declare class Fetchable {
|
|
226
242
|
config: FrigadeConfig;
|
|
227
243
|
constructor(config: FrigadeConfig);
|
|
244
|
+
/**
|
|
245
|
+
* @ignore
|
|
246
|
+
*/
|
|
228
247
|
fetch(path: string, options?: Record<any, any>): Promise<any>;
|
|
248
|
+
/**
|
|
249
|
+
* @ignore
|
|
250
|
+
*/
|
|
229
251
|
protected getGlobalState(): FrigadeGlobalState;
|
|
230
252
|
}
|
|
231
253
|
|
|
232
254
|
declare class Flow extends Fetchable {
|
|
233
255
|
/**
|
|
234
|
-
*
|
|
256
|
+
* The Flow's ID.
|
|
235
257
|
*/
|
|
236
258
|
id: string;
|
|
237
259
|
/**
|
|
238
|
-
* The raw data defined in `config.yml` as a JSON decoded object
|
|
260
|
+
* The raw data defined in `config.yml` as a JSON decoded object.
|
|
261
|
+
* @ignore
|
|
239
262
|
*/
|
|
240
263
|
configYmlAsJson: any;
|
|
241
264
|
/**
|
|
242
|
-
* Ordered map
|
|
265
|
+
* Ordered map of the Steps in the Flow.
|
|
266
|
+
* See [Flow Step Definition](https://docs.frigade.com/v2/sdk/js/step) for more information.
|
|
243
267
|
*/
|
|
244
268
|
steps: Map<string, FlowStep>;
|
|
245
269
|
/**
|
|
246
|
-
* The user-facing title of the
|
|
270
|
+
* The user-facing title of the Flow, if defined at the top level of the YAML config.
|
|
247
271
|
*/
|
|
248
272
|
title?: string;
|
|
249
273
|
/**
|
|
250
|
-
* The user-facing description of the
|
|
274
|
+
* The user-facing description of the Flow, if defined at the top level of the YAML config.
|
|
251
275
|
*/
|
|
252
276
|
subtitle?: string;
|
|
253
277
|
/**
|
|
254
|
-
* The metadata of the
|
|
278
|
+
* The metadata of the Flow.
|
|
279
|
+
* @ignore
|
|
255
280
|
*/
|
|
256
281
|
rawData: FlowDataRaw;
|
|
257
282
|
/**
|
|
258
|
-
* Whether the
|
|
283
|
+
* Whether the Flow is completed or not.
|
|
259
284
|
*/
|
|
260
285
|
isCompleted: boolean;
|
|
261
286
|
/**
|
|
262
|
-
* Whether the
|
|
287
|
+
* Whether the Flow is started or not.
|
|
263
288
|
*/
|
|
264
289
|
isStarted: boolean;
|
|
265
290
|
/**
|
|
266
|
-
* Whether the
|
|
291
|
+
* Whether the Flow has been skipped or not.
|
|
267
292
|
*/
|
|
268
293
|
isSkipped: boolean;
|
|
269
294
|
/**
|
|
270
|
-
* Whether the
|
|
295
|
+
* Whether the Flow is visible to the user based on the current user/group's state.
|
|
271
296
|
*/
|
|
272
297
|
isVisible: boolean;
|
|
298
|
+
/**
|
|
299
|
+
* @ignore
|
|
300
|
+
*/
|
|
273
301
|
private readonly flowDataRaw;
|
|
302
|
+
/**
|
|
303
|
+
* @ignore
|
|
304
|
+
*/
|
|
274
305
|
private userFlowStateRaw?;
|
|
306
|
+
/**
|
|
307
|
+
* @ignore
|
|
308
|
+
*/
|
|
275
309
|
private lastStepUpdate;
|
|
310
|
+
/**
|
|
311
|
+
* @ignore
|
|
312
|
+
*/
|
|
276
313
|
private lastUsedVariables;
|
|
277
314
|
constructor(config: FrigadeConfig, flowDataRaw: FlowDataRaw);
|
|
315
|
+
/**
|
|
316
|
+
* Reload the Flow data from the server
|
|
317
|
+
*/
|
|
278
318
|
reload(): void;
|
|
319
|
+
/**
|
|
320
|
+
* @ignore
|
|
321
|
+
*/
|
|
279
322
|
private initFromRawData;
|
|
280
323
|
/**
|
|
281
324
|
* Marks the flow started
|
|
@@ -285,6 +328,9 @@ declare class Flow extends Fetchable {
|
|
|
285
328
|
* Marks the flow completed
|
|
286
329
|
*/
|
|
287
330
|
complete(properties?: Record<string | number, any>): Promise<void>;
|
|
331
|
+
/**
|
|
332
|
+
* @ignore
|
|
333
|
+
*/
|
|
288
334
|
private optimisticallyMarkFlowCompleted;
|
|
289
335
|
/**
|
|
290
336
|
* Marks the flow skipped
|
|
@@ -311,6 +357,9 @@ declare class Flow extends Fetchable {
|
|
|
311
357
|
* Gets current step
|
|
312
358
|
*/
|
|
313
359
|
getCurrentStep(): FlowStep;
|
|
360
|
+
/**
|
|
361
|
+
* Get the index of the current step. Starts at 0
|
|
362
|
+
*/
|
|
314
363
|
getCurrentStepIndex(): number;
|
|
315
364
|
/**
|
|
316
365
|
* Get the number of completed steps for the current user in the current flow
|
|
@@ -320,25 +369,80 @@ declare class Flow extends Fetchable {
|
|
|
320
369
|
* Get the number of available steps for the current user in the current flow. This is the number of steps that are not hidden.
|
|
321
370
|
*/
|
|
322
371
|
getNumberOfAvailableSteps(): number;
|
|
372
|
+
/**
|
|
373
|
+
* @ignore
|
|
374
|
+
*/
|
|
323
375
|
onStateChange(handler: (flow: Flow, previousFlow: Flow) => void): void;
|
|
376
|
+
/**
|
|
377
|
+
* @ignore
|
|
378
|
+
*/
|
|
324
379
|
removeStateChangeHandler(handler: (flow: Flow, previousFlow: Flow) => void): void;
|
|
380
|
+
/**
|
|
381
|
+
* @ignore
|
|
382
|
+
*/
|
|
325
383
|
applyVariables(variables: Record<string, any>): void;
|
|
384
|
+
/**
|
|
385
|
+
* @ignore
|
|
386
|
+
*/
|
|
326
387
|
private getUserFlowState;
|
|
388
|
+
/**
|
|
389
|
+
* @ignore
|
|
390
|
+
*/
|
|
327
391
|
private refreshUserFlowState;
|
|
328
392
|
}
|
|
329
393
|
|
|
330
394
|
declare class Frigade extends Fetchable {
|
|
395
|
+
/**
|
|
396
|
+
* @ignore
|
|
397
|
+
*/
|
|
331
398
|
private flows;
|
|
399
|
+
/**
|
|
400
|
+
* @ignore
|
|
401
|
+
*/
|
|
332
402
|
private initPromise;
|
|
403
|
+
/**
|
|
404
|
+
* @ignore
|
|
405
|
+
*/
|
|
333
406
|
private hasFailed;
|
|
407
|
+
/**
|
|
408
|
+
* @ignore
|
|
409
|
+
*/
|
|
334
410
|
private visibilityChangeHandler;
|
|
335
411
|
constructor(apiKey: string, config?: FrigadeConfig);
|
|
412
|
+
/**
|
|
413
|
+
* @ignore
|
|
414
|
+
*/
|
|
336
415
|
destroy(): void;
|
|
416
|
+
/**
|
|
417
|
+
* @ignore
|
|
418
|
+
*/
|
|
337
419
|
private init;
|
|
420
|
+
/**
|
|
421
|
+
* Set the current user.
|
|
422
|
+
* @param userId
|
|
423
|
+
* @param properties
|
|
424
|
+
*/
|
|
338
425
|
identify(userId: string, properties?: Record<string, any>): Promise<void>;
|
|
426
|
+
/**
|
|
427
|
+
* Set the group for the current user.
|
|
428
|
+
* @param groupId
|
|
429
|
+
* @param properties
|
|
430
|
+
*/
|
|
339
431
|
group(groupId: string, properties?: Record<string, any>): Promise<void>;
|
|
432
|
+
/**
|
|
433
|
+
* Track an event for the current user (and group if set).
|
|
434
|
+
* @param event
|
|
435
|
+
* @param properties
|
|
436
|
+
*/
|
|
340
437
|
track(event: string, properties?: Record<string, any>): Promise<void>;
|
|
438
|
+
/**
|
|
439
|
+
* @ignore
|
|
440
|
+
*/
|
|
341
441
|
isReady(): boolean;
|
|
442
|
+
/**
|
|
443
|
+
* Get a Flow by its ID.
|
|
444
|
+
* @param flowId
|
|
445
|
+
*/
|
|
342
446
|
getFlow(flowId: string): Promise<Flow>;
|
|
343
447
|
getFlows(): Promise<Flow[]>;
|
|
344
448
|
/**
|
|
@@ -346,17 +450,43 @@ declare class Frigade extends Fetchable {
|
|
|
346
450
|
* This will trigger all event handlers.
|
|
347
451
|
*/
|
|
348
452
|
reload(): Promise<void>;
|
|
453
|
+
/**
|
|
454
|
+
* Event handler that captures all changes that happen to the state of the Flows.
|
|
455
|
+
* @param handler
|
|
456
|
+
*/
|
|
349
457
|
onStateChange(handler: (flow: Flow, previousFlow?: Flow) => void): void;
|
|
350
458
|
/**
|
|
351
|
-
* Returns true
|
|
459
|
+
* Returns true if the JS SDK failed to connect to the Frigade API.
|
|
352
460
|
*/
|
|
353
461
|
hasFailedToLoad(): boolean;
|
|
462
|
+
/**
|
|
463
|
+
* Removes the given handler from the list of event handlers.
|
|
464
|
+
* @param handler
|
|
465
|
+
*/
|
|
354
466
|
removeStateChangeHandler(handler: (flow: Flow, previousFlow?: Flow) => void): void;
|
|
467
|
+
/**
|
|
468
|
+
* @ignore
|
|
469
|
+
*/
|
|
355
470
|
private initIfNeeded;
|
|
471
|
+
/**
|
|
472
|
+
* @ignore
|
|
473
|
+
*/
|
|
356
474
|
private refreshUserFlowStates;
|
|
475
|
+
/**
|
|
476
|
+
* @ignore
|
|
477
|
+
*/
|
|
357
478
|
private refreshFlows;
|
|
479
|
+
/**
|
|
480
|
+
* @ignore
|
|
481
|
+
*/
|
|
358
482
|
private mockFlowConfigs;
|
|
483
|
+
/**
|
|
484
|
+
* @ignore
|
|
485
|
+
*/
|
|
359
486
|
private mockUserFlowStates;
|
|
487
|
+
/**
|
|
488
|
+
* @ignore
|
|
489
|
+
*/
|
|
360
490
|
private triggerEventHandlers;
|
|
361
491
|
}
|
|
362
492
|
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
var W="0.2.20";import j from"cross-fetch";import{v4 as Y}from"uuid";var c={};function R(o){return`${o.__instanceId}-${o.apiKey}:${o.userId??""}:${o.groupId??""}`}var A=class{constructor(n){this.config={apiKey:"",apiUrl:"https://api.frigade.com/v1/public",userId:k(),__instanceId:Math.random().toString(36).substring(7)};let t=Object.fromEntries(Object.entries(n).filter(([e,i])=>i!=null));this.config={...this.config,...t}}async fetch(n,t){return this.config.__readOnly?f():V(`${this.config.apiUrl}${n}`,{...t??{},...J(this.config.apiKey)})}getGlobalState(){let n=R(this.config);if(!c[n])throw new Error("Frigade not initialized");return c[n]}};var F=class extends A{constructor(t,e){super(t);this.isVisible=!1;this.lastStepUpdate=new Map;this.lastUsedVariables={};this.flowDataRaw=e,this.initFromRawData(e)}reload(){this.initFromRawData(this.flowDataRaw)}initFromRawData(t){let e=JSON.parse(t.data),i=e.steps??e.data??[];this.id=t.slug,this.rawData=t,this.configYmlAsJson=e,this.title=this.configYmlAsJson.title,this.subtitle=this.configYmlAsJson.subtitle;let s=this.getUserFlowState();if(!s)return;this.userFlowStateRaw=s,this.isCompleted=s.flowState==D,this.isStarted=s.flowState==E,this.isSkipped=s.flowState==P;let p=this.isCompleted||this.isSkipped,r=t.targetingLogic&&s.shouldTrigger===!1;this.isVisible=!p&&!r,this.flowDataRaw.active===!1&&(this.isVisible=!1);let y=new Map;i.forEach((S,T)=>{let C=s.stepStates[S.id],I={...S,isCompleted:C.actionType==b,isStarted:C.actionType==w,isHidden:C.hidden,isBlocked:C.blocked,lastActionAt:C.lastActionAt?new Date(C.lastActionAt):void 0,order:T};I.start=async l=>{let a=this.steps.get(S.id);if(this.getCurrentStep().id===a.id&&a.isStarted)return;a.isStarted=!0;let g=u(this.getGlobalState().userFlowStates[this.id]);g.stepStates[a.id].actionType=w,g.stepStates[a.id].lastActionAt=new Date().toISOString(),g.lastStepId=a.id,this.getGlobalState().userFlowStates[this.id]=g,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:a.id,data:l??{},createdAt:new Date().toISOString(),actionType:w})}),await this.refreshUserFlowState();let h=this.getUserFlowState();a.isCompleted=h.stepStates[a.id].actionType==b,a.isStarted=h.stepStates[a.id].actionType==w,a.lastActionAt=new Date},I.complete=async l=>{let a=this.steps.get(S.id);if(a.isCompleted)return;let h=this.getNumberOfCompletedSteps()+1==this.steps.size;a.isCompleted=!0,this.isStarted=!0;let d=u(this.getGlobalState().userFlowStates[this.id]);d.stepStates[a.id].actionType=b,d.stepStates[a.id].lastActionAt=new Date().toISOString(),d.flowState=h?D:E;let O=Array.from(this.steps.keys())[T+1];if(O){d.lastStepId=O,d.stepStates[O].actionType=w;let M=new Date;d.stepStates[O].lastActionAt=M.toISOString(),this.steps.get(O).isStarted=!0,this.steps.get(O).lastActionAt=M}h&&this.optimisticallyMarkFlowCompleted(),this.getGlobalState().userFlowStates[this.id]=d,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:a.id,data:l??{},createdAt:new Date().toISOString(),actionType:b})}),await this.refreshUserFlowState();let x=this.getUserFlowState();a.isCompleted=x.stepStates[a.id].actionType==b,a.isStarted=x.stepStates[a.id].actionType==w,a.lastActionAt=new Date},I.reset=async()=>{let l=this.steps.get(S.id);if(!l.isCompleted)return;l.isCompleted=!1,l.isStarted=!1,l.lastActionAt=void 0;let a=u(this.getGlobalState().userFlowStates[this.id]);a.stepStates[l.id].actionType=U,a.stepStates[l.id].lastActionAt=void 0,a.flowState=E,this.getGlobalState().userFlowStates[this.id]=a,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:l.id,data:{},createdAt:new Date().toISOString(),actionType:U})}),await this.refreshUserFlowState();let g=this.getUserFlowState();l.isCompleted=g.stepStates[l.id].actionType==b,l.isStarted=g.stepStates[l.id].actionType==w,l.lastActionAt=void 0},I.onStateChange=l=>{let a=g=>{if(g.id!==this.id)return;let h=g.steps.get(S.id),d=this.lastStepUpdate.get(l);(h.isCompleted!==(d==null?void 0:d.isCompleted)||h.isStarted!==(d==null?void 0:d.isStarted)||h.isHidden!==(d==null?void 0:d.isHidden)||h.isBlocked!==(d==null?void 0:d.isBlocked))&&(l(h,d??u(h)),this.lastStepUpdate.set(l,u(h)))};this.getGlobalState().onStepStateChangeHandlerWrappers.set(l,a),this.getGlobalState().onFlowStateChangeHandlers.push(a)},I.removeStateChangeHandler=l=>{let a=this.getGlobalState().onStepStateChangeHandlerWrappers.get(l);a&&(this.getGlobalState().onFlowStateChangeHandlers=this.getGlobalState().onFlowStateChangeHandlers.filter(g=>g!==a))},y.set(S.id,I)}),this.steps=y,Object.keys(this.lastUsedVariables).length>0&&this.applyVariables(this.lastUsedVariables)}async start(t){if(this.isStarted||this.isCompleted)return;this.isStarted=!0;let e=u(this.getGlobalState().userFlowStates[this.id]);e.flowState=E,this.getGlobalState().userFlowStates[this.id]=e,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:this.getCurrentStep().id,data:t??{},createdAt:new Date().toISOString(),actionType:E})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw)}async complete(t){this.isCompleted||(this.optimisticallyMarkFlowCompleted(),await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:this.getCurrentStep().id,data:t??{},createdAt:new Date().toISOString(),actionType:D})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw))}optimisticallyMarkFlowCompleted(){this.isStarted=!0,this.isCompleted=!0;let t=u(this.getGlobalState().userFlowStates[this.id]);t.flowState=D,this.getGlobalState().userFlowStates[this.id]=t,this.isVisible=!1}async skip(t){await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:this.getCurrentStep().id,data:t??{},createdAt:new Date().toISOString(),actionType:P})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw)}async forward(t){let e=this.getStepByIndex(this.getCurrentStepIndex()+1);e&&await e.start(t)}async back(t){let e=this.getStepByIndex(this.getCurrentStepIndex()-1);e&&await e.start(t)}async restart(){await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:"unknown",data:{},createdAt:new Date().toISOString(),actionType:K})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw)}getStepByIndex(t){return this.steps.get(Array.from(this.steps.keys())[t])}getCurrentStep(){let t=Array.from(this.steps.keys()).find(i=>this.steps.get(i).isCompleted===!1&&this.steps.get(i).isHidden===!1);Array.from(this.steps.keys()).forEach(i=>{var s;this.steps.get(i).isStarted&&this.steps.get(i).lastActionAt&&this.steps.get(i).lastActionAt>(((s=this.steps.get(t))==null?void 0:s.lastActionAt)??new Date(0))&&(t=i)});let e=t??Array.from(this.steps.keys())[0];return this.steps.get(e)}getCurrentStepIndex(){let t=this.getCurrentStep();return Array.from(this.steps.keys()).indexOf(t.id)}getNumberOfCompletedSteps(){return Array.from(this.steps.values()).filter(t=>t.isCompleted).length}getNumberOfAvailableSteps(){return Array.from(this.steps.values()).filter(t=>!t.isHidden).length}onStateChange(t){let e=(i,s)=>{(i.id===this.id&&(i.isCompleted!==s.isCompleted||i.isStarted!==s.isStarted||i.isSkipped!==s.isSkipped||i.isVisible!==s.isVisible)||JSON.stringify(i.steps)!==JSON.stringify(s.steps))&&t(i,s)};this.getGlobalState().onFlowStateChangeHandlerWrappers.set(t,e),this.getGlobalState().onFlowStateChangeHandlers.push(e)}removeStateChangeHandler(t){let e=this.getGlobalState().onFlowStateChangeHandlerWrappers.get(t);e&&(this.getGlobalState().onFlowStateChangeHandlers=this.getGlobalState().onFlowStateChangeHandlers.filter(i=>i!==e))}applyVariables(t){let e=i=>{let s=i.match(/\${(.*?)}/g);return s&&s.forEach(p=>{let r=p.replace("${","").replace("}","");i=i.replace(p,t[r]??"")}),i};this.title=e(this.title??""),this.subtitle=e(this.subtitle??""),this.steps.forEach(i=>{Object.keys(i).forEach(s=>{typeof i[s]=="string"&&(i[s]=e(i[s]))})}),this.lastUsedVariables=t}getUserFlowState(){return this.getGlobalState().userFlowStates[this.id]}async refreshUserFlowState(){await this.getGlobalState().refreshUserFlowStates()}};var U="NOT_STARTED_STEP",D="COMPLETED_FLOW",P="SKIPPED_FLOW",E="STARTED_FLOW",K="NOT_STARTED_FLOW",b="COMPLETED_STEP",w="STARTED_STEP",X="frigade-last-call-at-",z="frigade-last-call-data-",$="frigade-guest-key",q="guest_",Q="get-cache-";var Z=1e3,N="fr-js-";function _(o){let n=new F(o.config,o.rawData);return n.isCompleted=o.isCompleted,n.isStarted=o.isStarted,n.isSkipped=o.isSkipped,n.isVisible=o.isVisible,n.steps=o.steps,n}function u(o){return JSON.parse(JSON.stringify(o))}function J(o){return{headers:{Authorization:`Bearer ${o}`,"Content-Type":"application/json","X-Frigade-SDK-Version":W,"X-Frigade-SDK-Platform":"Javascript"}}}function v(o){return m()?window.localStorage.getItem(`${N}${o}`):null}function G(o,n){m()&&window.localStorage.setItem(`${N}${o}`,n)}function L(){Object.keys(c).forEach(o=>{o.startsWith(Q)&&delete c[o]})}function B(){m()&&Object.keys(window.localStorage).forEach(o=>{o.startsWith(N)&&window.localStorage.removeItem(o)})}async function V(o,n){let t=X+o,e=z+o;if(m()&&n&&n.body&&n.method==="POST"){let s=v(t),p=v(e);if(s&&p&&p==n.body){let r=new Date(s);if(new Date().getTime()-r.getTime()<Z)return f()}G(t,new Date().toISOString()),G(e,n.body),L()}let i;try{i=j(o,n),i=await i}catch(s){return f(s)}if(!i)return f("Received an empty response");if(i.status>=400)return f(i.statusText);try{if(i.status===204||i.status===201)return f();let s=await i.json();return s.error?f(s.error):s}catch(s){return f(s)}}function f(o){return o&&console.log("Call to Frigade failed",o),{json:()=>({})}}function k(){if(m()){let o=v($);return o||(o=`${q}${Y()}`,G($,o)),o}}function m(){return typeof window<"u"}var H=class extends A{constructor(t,e){super({apiKey:t,...e});this.flows=[];this.hasFailed=!1;this.visibilityChangeHandler=async()=>{document.visibilityState==="visible"&&(await this.refreshFlows(),await this.refreshUserFlowStates())};this.init(this.config),m()&&document.addEventListener("visibilitychange",this.visibilityChangeHandler)}destroy(){if(m()){document.removeEventListener("visibilitychange",this.visibilityChangeHandler);let t=R(this.config);c[t]&&(c[t].onFlowStateChangeHandlers=[])}}async init(t){return this.config={...this.config,...t},this.initPromise=(async()=>{await this.refreshUserFlowStates(),await this.refreshFlows()})(),this.initPromise}async identify(t,e){this.config={...this.config,userId:t},await this.initIfNeeded(),await this.fetch("/users",{method:"POST",body:JSON.stringify({foreignId:this.config.userId,properties:e})}),await this.refreshUserFlowStates()}async group(t,e){await this.initIfNeeded(),this.config.groupId=t,await this.fetch("/userGroups",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,properties:e})}),await this.refreshUserFlowStates()}async track(t,e){await this.initIfNeeded(),await this.fetch("/track",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,event:t,properties:e})})}isReady(){return!!(this.config.__instanceId&&this.config.apiKey&&this.initPromise)}async getFlow(t){return await this.initIfNeeded(),this.flows.find(e=>e.id==t)}async getFlows(){return await this.initIfNeeded(),this.flows}async reload(){B(),L(),await this.refreshUserFlowStates(),await this.refreshFlows(),this.initPromise=null,await this.init(this.config),this.flows.forEach(t=>{this.getGlobalState().onFlowStateChangeHandlers.forEach(e=>{let i=this.getGlobalState().previousFlows.get(t.id);e(t,i),this.getGlobalState().previousFlows.set(t.id,_(t))})})}onStateChange(t){this.getGlobalState().onFlowStateChangeHandlers.push(t)}hasFailedToLoad(){return this.hasFailed}removeStateChangeHandler(t){this.getGlobalState().onFlowStateChangeHandlers=this.getGlobalState().onFlowStateChangeHandlers.filter(e=>e!==t)}async initIfNeeded(){return this.initPromise!==null?this.initPromise:this.init(this.config)}async refreshUserFlowStates(){let t=R(this.config);if(!c[t]){let e=this,i={set:function(s,p,r){return s[p]&&s[p].flowState&&(JSON.stringify(s[p].flowState)!==JSON.stringify(r==null?void 0:r.flowState)||JSON.stringify(s[p].stepStates)!==JSON.stringify(r==null?void 0:r.stepStates)||JSON.stringify(s[p].shouldTrigger)!==JSON.stringify(r==null?void 0:r.shouldTrigger))&&e.triggerEventHandlers(s[p]),s[p]=r,!0}};if(c[t]={refreshUserFlowStates:async()=>{},userFlowStates:new Proxy({},i),onFlowStateChangeHandlerWrappers:new Map,onStepStateChangeHandlerWrappers:new Map,onFlowStateChangeHandlers:[],previousFlows:new Map},this.config.__readOnly&&this.config.__flowConfigOverrides){this.mockUserFlowStates(t);return}c[t].refreshUserFlowStates=async()=>{if(this.config.__readOnly)return;let s=await this.fetch(`/userFlowStates?foreignUserId=${encodeURIComponent(this.config.userId)}${this.config.groupId?`&foreignUserGroupId=${encodeURIComponent(this.config.groupId)}`:""}`);s&&s.data?(s.data.forEach(r=>{let y=!1,S=c[t].userFlowStates[r.flowId];S&&S.shouldTrigger==!1&&r.shouldTrigger==!0&&(y=!0),c[t].userFlowStates[r.flowId]=r,y&&this.flows.forEach(T=>{T.id==r.flowId&&(T.reload(),this.triggerEventHandlers(c[t].userFlowStates[T.id]))})}),this.hasFailed=!1):this.hasFailed=!0}}await c[t].refreshUserFlowStates()}async refreshFlows(){if(this.flows=[],this.config.__flowConfigOverrides){this.mockFlowConfigs();return}let t=await this.fetch("/flows");t&&t.data?t.data.forEach(i=>{this.flows.push(new F(this.config,i)),this.getGlobalState().previousFlows.set(i.slug,_(this.flows[this.flows.length-1]))}):this.hasFailed=!0}mockFlowConfigs(){Object.keys(this.config.__flowConfigOverrides).forEach(t=>{this.flows.push(new F(this.config,{id:-1,name:"",description:"",data:this.config.__flowConfigOverrides[t],createdAt:new Date().toISOString(),modifiedAt:new Date().toISOString(),slug:t,targetingLogic:"",type:"CHECKLIST",triggerType:"MANUAL",status:"ACTIVE",version:1,active:!0}))})}mockUserFlowStates(t){Object.keys(this.config.__flowConfigOverrides).forEach(e=>{var s;let i=JSON.parse(this.config.__flowConfigOverrides[e]);c[t].userFlowStates[e]={flowId:e,flowState:"NOT_STARTED_FLOW",lastStepId:null,userId:this.config.userId,foreignUserId:this.config.userId,stepStates:((s=i==null?void 0:i.steps)==null?void 0:s.reduce((p,r)=>(p[r.id]={stepId:r.id,flowSlug:e,actionType:"NOT_STARTED_STEP",createdAt:new Date().toISOString(),blocked:!1,hidden:!1},p),{}))??{},shouldTrigger:!1}})}async triggerEventHandlers(t){t&&this.flows.forEach(e=>{e.id==t.flowId&&this.getGlobalState().onFlowStateChangeHandlers.forEach(i=>{let s=this.getGlobalState().previousFlows.get(e.id);i(e,s),this.getGlobalState().previousFlows.set(e.id,_(e))})})}};export{F as Flow,H as Frigade};
|
|
2
|
+
var W="0.2.20";import j from"cross-fetch";import{v4 as Y}from"uuid";var c={};function R(o){return`${o.__instanceId}-${o.apiKey}:${o.userId??""}:${o.groupId??""}`}var E=class{constructor(n){this.config={apiKey:"",apiUrl:"https://api.frigade.com/v1/public",userId:k(),__instanceId:Math.random().toString(36).substring(7)};let t=Object.fromEntries(Object.entries(n).filter(([e,i])=>i!=null));this.config={...this.config,...t}}async fetch(n,t){return this.config.__readOnly?S():V(`${this.config.apiUrl}${n}`,{...t??{},...J(this.config.apiKey)})}getGlobalState(){let n=R(this.config);if(!c[n])throw new Error("Frigade not initialized");return c[n]}};var F=class extends E{constructor(t,e){super(t);this.isVisible=!1;this.lastStepUpdate=new Map;this.lastUsedVariables={};this.flowDataRaw=e,this.initFromRawData(e)}reload(){this.initFromRawData(this.flowDataRaw)}initFromRawData(t){let e=JSON.parse(t.data),i=e.steps??e.data??[];this.id=t.slug,this.rawData=t,this.configYmlAsJson=e,this.title=this.configYmlAsJson.title,this.subtitle=this.configYmlAsJson.subtitle;let s=this.getUserFlowState();if(!s)return;this.userFlowStateRaw=s,this.isCompleted=s.flowState==D,this.isStarted=s.flowState==A,this.isSkipped=s.flowState==P;let p=this.isCompleted||this.isSkipped,r=t.targetingLogic&&s.shouldTrigger===!1;this.isVisible=!p&&!r,this.flowDataRaw.active===!1&&(this.isVisible=!1);let y=new Map;i.forEach((f,T)=>{let C=s.stepStates[f.id],I={...f,isCompleted:C.actionType==b,isStarted:C.actionType==w,isHidden:C.hidden,isBlocked:C.blocked,lastActionAt:C.lastActionAt?new Date(C.lastActionAt):void 0,order:T};I.start=async l=>{let a=this.steps.get(f.id);if(this.getCurrentStep().id===a.id&&a.isStarted)return;a.isStarted=!0;let g=u(this.getGlobalState().userFlowStates[this.id]);g.stepStates[a.id].actionType=w,g.stepStates[a.id].lastActionAt=new Date().toISOString(),g.lastStepId=a.id,this.getGlobalState().userFlowStates[this.id]=g,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:a.id,data:l??{},createdAt:new Date().toISOString(),actionType:w})}),await this.refreshUserFlowState();let h=this.getUserFlowState();a.isCompleted=h.stepStates[a.id].actionType==b,a.isStarted=h.stepStates[a.id].actionType==w,a.lastActionAt=new Date},I.complete=async l=>{let a=this.steps.get(f.id);if(a.isCompleted)return;let h=this.getNumberOfCompletedSteps()+1==this.steps.size;a.isCompleted=!0,this.isStarted=!0;let d=u(this.getGlobalState().userFlowStates[this.id]);d.stepStates[a.id].actionType=b,d.stepStates[a.id].lastActionAt=new Date().toISOString(),d.flowState=h?D:A;let O=Array.from(this.steps.keys())[T+1];if(O){d.lastStepId=O,d.stepStates[O].actionType=w;let M=new Date;d.stepStates[O].lastActionAt=M.toISOString(),this.steps.get(O).isStarted=!0,this.steps.get(O).lastActionAt=M}h&&this.optimisticallyMarkFlowCompleted(),this.getGlobalState().userFlowStates[this.id]=d,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:a.id,data:l??{},createdAt:new Date().toISOString(),actionType:b})}),await this.refreshUserFlowState();let x=this.getUserFlowState();a.isCompleted=x.stepStates[a.id].actionType==b,a.isStarted=x.stepStates[a.id].actionType==w,a.lastActionAt=new Date},I.reset=async()=>{let l=this.steps.get(f.id);if(!l.isCompleted)return;l.isCompleted=!1,l.isStarted=!1,l.lastActionAt=void 0;let a=u(this.getGlobalState().userFlowStates[this.id]);a.stepStates[l.id].actionType=U,a.stepStates[l.id].lastActionAt=void 0,a.flowState=A,this.getGlobalState().userFlowStates[this.id]=a,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:l.id,data:{},createdAt:new Date().toISOString(),actionType:U})}),await this.refreshUserFlowState();let g=this.getUserFlowState();l.isCompleted=g.stepStates[l.id].actionType==b,l.isStarted=g.stepStates[l.id].actionType==w,l.lastActionAt=void 0},I.onStateChange=l=>{let a=g=>{if(g.id!==this.id)return;let h=g.steps.get(f.id),d=this.lastStepUpdate.get(l);(h.isCompleted!==(d==null?void 0:d.isCompleted)||h.isStarted!==(d==null?void 0:d.isStarted)||h.isHidden!==(d==null?void 0:d.isHidden)||h.isBlocked!==(d==null?void 0:d.isBlocked))&&(l(h,d??u(h)),this.lastStepUpdate.set(l,u(h)))};this.getGlobalState().onStepStateChangeHandlerWrappers.set(l,a),this.getGlobalState().onFlowStateChangeHandlers.push(a)},I.removeStateChangeHandler=l=>{let a=this.getGlobalState().onStepStateChangeHandlerWrappers.get(l);a&&(this.getGlobalState().onFlowStateChangeHandlers=this.getGlobalState().onFlowStateChangeHandlers.filter(g=>g!==a))},y.set(f.id,I)}),this.steps=y,Object.keys(this.lastUsedVariables).length>0&&this.applyVariables(this.lastUsedVariables)}async start(t){if(this.isStarted||this.isCompleted)return;this.isStarted=!0;let e=u(this.getGlobalState().userFlowStates[this.id]);e.flowState=A,this.getGlobalState().userFlowStates[this.id]=e,await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:this.getCurrentStep().id,data:t??{},createdAt:new Date().toISOString(),actionType:A})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw)}async complete(t){this.isCompleted||(this.optimisticallyMarkFlowCompleted(),await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:this.getCurrentStep().id,data:t??{},createdAt:new Date().toISOString(),actionType:D})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw))}optimisticallyMarkFlowCompleted(){this.isStarted=!0,this.isCompleted=!0;let t=u(this.getGlobalState().userFlowStates[this.id]);t.flowState=D,this.getGlobalState().userFlowStates[this.id]=t,this.isVisible=!1}async skip(t){await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:this.getCurrentStep().id,data:t??{},createdAt:new Date().toISOString(),actionType:P})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw)}async forward(t){let e=this.getStepByIndex(this.getCurrentStepIndex()+1);e&&await e.start(t)}async back(t){let e=this.getStepByIndex(this.getCurrentStepIndex()-1);e&&await e.start(t)}async restart(){await this.fetch("/flowResponses",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,flowSlug:this.id,stepId:"unknown",data:{},createdAt:new Date().toISOString(),actionType:K})}),await this.refreshUserFlowState(),this.initFromRawData(this.flowDataRaw)}getStepByIndex(t){return this.steps.get(Array.from(this.steps.keys())[t])}getCurrentStep(){let t=Array.from(this.steps.keys()).find(i=>this.steps.get(i).isCompleted===!1&&this.steps.get(i).isHidden===!1);Array.from(this.steps.keys()).forEach(i=>{var s;this.steps.get(i).isStarted&&this.steps.get(i).lastActionAt&&this.steps.get(i).lastActionAt>(((s=this.steps.get(t))==null?void 0:s.lastActionAt)??new Date(0))&&(t=i)});let e=t??Array.from(this.steps.keys())[0];return this.steps.get(e)}getCurrentStepIndex(){let t=this.getCurrentStep();return Array.from(this.steps.keys()).indexOf(t.id)}getNumberOfCompletedSteps(){return Array.from(this.steps.values()).filter(t=>t.isCompleted).length}getNumberOfAvailableSteps(){return Array.from(this.steps.values()).filter(t=>!t.isHidden).length}onStateChange(t){let e=(i,s)=>{(i.id===this.id&&(i.isCompleted!==s.isCompleted||i.isStarted!==s.isStarted||i.isSkipped!==s.isSkipped||i.isVisible!==s.isVisible)||JSON.stringify(i.steps)!==JSON.stringify(s.steps))&&t(i,s)};this.getGlobalState().onFlowStateChangeHandlerWrappers.set(t,e),this.getGlobalState().onFlowStateChangeHandlers.push(e)}removeStateChangeHandler(t){let e=this.getGlobalState().onFlowStateChangeHandlerWrappers.get(t);e&&(this.getGlobalState().onFlowStateChangeHandlers=this.getGlobalState().onFlowStateChangeHandlers.filter(i=>i!==e))}applyVariables(t){let e=i=>{let s=i.match(/\${(.*?)}/g);return s&&s.forEach(p=>{let r=p.replace("${","").replace("}","");i=i.replace(p,t[r]??"")}),i};this.title=e(this.title??""),this.subtitle=e(this.subtitle??""),this.steps.forEach(i=>{Object.keys(i).forEach(s=>{typeof i[s]=="string"&&(i[s]=e(i[s]))})}),this.lastUsedVariables=t}getUserFlowState(){return this.getGlobalState().userFlowStates[this.id]}async refreshUserFlowState(){await this.getGlobalState().refreshUserFlowStates()}};var U="NOT_STARTED_STEP",D="COMPLETED_FLOW",P="SKIPPED_FLOW",A="STARTED_FLOW",K="NOT_STARTED_FLOW",b="COMPLETED_STEP",w="STARTED_STEP",X="frigade-last-call-at-",z="frigade-last-call-data-",$="frigade-guest-key",q="guest_",Q="get-cache-";var Z=1e3,N="fr-js-";function _(o){let n=new F(o.config,o.rawData);return n.isCompleted=o.isCompleted,n.isStarted=o.isStarted,n.isSkipped=o.isSkipped,n.isVisible=o.isVisible,n.steps=o.steps,n}function u(o){return JSON.parse(JSON.stringify(o))}function J(o){return{headers:{Authorization:`Bearer ${o}`,"Content-Type":"application/json","X-Frigade-SDK-Version":W,"X-Frigade-SDK-Platform":"Javascript"}}}function v(o){return m()?window.localStorage.getItem(`${N}${o}`):null}function G(o,n){m()&&window.localStorage.setItem(`${N}${o}`,n)}function L(){Object.keys(c).forEach(o=>{o.startsWith(Q)&&delete c[o]})}function B(){m()&&Object.keys(window.localStorage).forEach(o=>{o.startsWith(N)&&window.localStorage.removeItem(o)})}async function V(o,n){let t=X+o,e=z+o;if(m()&&n&&n.body&&n.method==="POST"){let s=v(t),p=v(e);if(s&&p&&p==n.body){let r=new Date(s);if(new Date().getTime()-r.getTime()<Z)return S()}G(t,new Date().toISOString()),G(e,n.body),L()}let i;try{i=j(o,n),i=await i}catch(s){return S(s)}if(!i)return S("Received an empty response");if(i.status>=400)return S(i.statusText);try{if(i.status===204||i.status===201)return S();let s=await i.json();return s.error?S(s.error):s}catch(s){return S(s)}}function S(o){return o&&console.log("Call to Frigade failed",o),{json:()=>({})}}function k(){if(m()){let o=v($);return o||(o=`${q}${Y()}`,G($,o)),o}}function m(){return typeof window<"u"}var H=class extends E{constructor(t,e){super({apiKey:t,...e});this.flows=[];this.hasFailed=!1;this.visibilityChangeHandler=async()=>{document.visibilityState==="visible"&&(await this.refreshFlows(),await this.refreshUserFlowStates())};this.init(this.config),m()&&document.addEventListener("visibilitychange",this.visibilityChangeHandler)}destroy(){if(m()){document.removeEventListener("visibilitychange",this.visibilityChangeHandler);let t=R(this.config);c[t]&&(c[t].onFlowStateChangeHandlers=[])}}async init(t){return this.config={...this.config,...t},this.initPromise=(async()=>{await this.refreshUserFlowStates(),await this.refreshFlows()})(),this.initPromise}async identify(t,e){this.config={...this.config,userId:t},await this.initIfNeeded(),await this.fetch("/users",{method:"POST",body:JSON.stringify({foreignId:this.config.userId,properties:e})}),await this.refreshUserFlowStates()}async group(t,e){await this.initIfNeeded(),this.config.groupId=t,await this.fetch("/userGroups",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,properties:e})}),await this.refreshUserFlowStates()}async track(t,e){if(await this.initIfNeeded(),!t){console.error("Event name is required to track an event");return}this.config.userId&&this.config.groupId?await this.fetch("/userGroups",{method:"POST",body:JSON.stringify({foreignUserId:this.config.userId,foreignUserGroupId:this.config.groupId,events:[{event:t,properties:e}]})}):this.config.userId&&await this.fetch("/users",{method:"POST",body:JSON.stringify({foreignId:this.config.userId,events:[{event:t,properties:e}]})})}isReady(){return!!(this.config.__instanceId&&this.config.apiKey&&this.initPromise)}async getFlow(t){return await this.initIfNeeded(),this.flows.find(e=>e.id==t)}async getFlows(){return await this.initIfNeeded(),this.flows}async reload(){B(),L(),await this.refreshUserFlowStates(),await this.refreshFlows(),this.initPromise=null,await this.init(this.config),this.flows.forEach(t=>{this.getGlobalState().onFlowStateChangeHandlers.forEach(e=>{let i=this.getGlobalState().previousFlows.get(t.id);e(t,i),this.getGlobalState().previousFlows.set(t.id,_(t))})})}onStateChange(t){this.getGlobalState().onFlowStateChangeHandlers.push(t)}hasFailedToLoad(){return this.hasFailed}removeStateChangeHandler(t){this.getGlobalState().onFlowStateChangeHandlers=this.getGlobalState().onFlowStateChangeHandlers.filter(e=>e!==t)}async initIfNeeded(){return this.initPromise!==null?this.initPromise:this.init(this.config)}async refreshUserFlowStates(){let t=R(this.config);if(!c[t]){let e=this,i={set:function(s,p,r){return s[p]&&s[p].flowState&&(JSON.stringify(s[p].flowState)!==JSON.stringify(r==null?void 0:r.flowState)||JSON.stringify(s[p].stepStates)!==JSON.stringify(r==null?void 0:r.stepStates)||JSON.stringify(s[p].shouldTrigger)!==JSON.stringify(r==null?void 0:r.shouldTrigger))&&e.triggerEventHandlers(s[p]),s[p]=r,!0}};if(c[t]={refreshUserFlowStates:async()=>{},userFlowStates:new Proxy({},i),onFlowStateChangeHandlerWrappers:new Map,onStepStateChangeHandlerWrappers:new Map,onFlowStateChangeHandlers:[],previousFlows:new Map},this.config.__readOnly&&this.config.__flowConfigOverrides){this.mockUserFlowStates(t);return}c[t].refreshUserFlowStates=async()=>{if(this.config.__readOnly)return;let s=await this.fetch(`/userFlowStates?foreignUserId=${encodeURIComponent(this.config.userId)}${this.config.groupId?`&foreignUserGroupId=${encodeURIComponent(this.config.groupId)}`:""}`);s&&s.data?(s.data.forEach(r=>{let y=!1,f=c[t].userFlowStates[r.flowId];f&&f.shouldTrigger==!1&&r.shouldTrigger==!0&&(y=!0),c[t].userFlowStates[r.flowId]=r,y&&this.flows.forEach(T=>{T.id==r.flowId&&(T.reload(),this.triggerEventHandlers(c[t].userFlowStates[T.id]))})}),this.hasFailed=!1):this.hasFailed=!0}}await c[t].refreshUserFlowStates()}async refreshFlows(){if(this.flows=[],this.config.__flowConfigOverrides){this.mockFlowConfigs();return}let t=await this.fetch("/flows");t&&t.data?t.data.forEach(i=>{this.flows.push(new F(this.config,i)),this.getGlobalState().previousFlows.set(i.slug,_(this.flows[this.flows.length-1]))}):this.hasFailed=!0}mockFlowConfigs(){Object.keys(this.config.__flowConfigOverrides).forEach(t=>{this.flows.push(new F(this.config,{id:-1,name:"",description:"",data:this.config.__flowConfigOverrides[t],createdAt:new Date().toISOString(),modifiedAt:new Date().toISOString(),slug:t,targetingLogic:"",type:"CHECKLIST",triggerType:"MANUAL",status:"ACTIVE",version:1,active:!0}))})}mockUserFlowStates(t){Object.keys(this.config.__flowConfigOverrides).forEach(e=>{var s;let i=JSON.parse(this.config.__flowConfigOverrides[e]);c[t].userFlowStates[e]={flowId:e,flowState:"NOT_STARTED_FLOW",lastStepId:null,userId:this.config.userId,foreignUserId:this.config.userId,stepStates:((s=i==null?void 0:i.steps)==null?void 0:s.reduce((p,r)=>(p[r.id]={stepId:r.id,flowSlug:e,actionType:"NOT_STARTED_STEP",createdAt:new Date().toISOString(),blocked:!1,hidden:!1},p),{}))??{},shouldTrigger:!1}})}async triggerEventHandlers(t){t&&this.flows.forEach(e=>{e.id==t.flowId&&this.getGlobalState().onFlowStateChangeHandlers.forEach(i=>{let s=this.getGlobalState().previousFlows.get(e.id);i(e,s),this.getGlobalState().previousFlows.set(e.id,_(e))})})}};export{F as Flow,H as Frigade};
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/version.ts","../src/shared/utils.ts","../src/shared/state.ts","../src/shared/Fetchable.ts","../src/core/flow.ts","../src/core/frigade.ts"],"sourcesContent":["export const VERSION_NUMBER = '0.2.20'\n","import { VERSION_NUMBER } from '../core/version'\nimport fetch from 'cross-fetch'\nimport { v4 as uuidv4 } from 'uuid'\nimport { Flow } from '../core/flow'\nimport { frigadeGlobalState } from './state'\n\nexport const NOT_STARTED_STEP = 'NOT_STARTED_STEP'\nexport const COMPLETED_FLOW = 'COMPLETED_FLOW'\nexport const SKIPPED_FLOW = 'SKIPPED_FLOW'\nexport const STARTED_FLOW = 'STARTED_FLOW'\nexport const NOT_STARTED_FLOW = 'NOT_STARTED_FLOW'\nexport const COMPLETED_STEP = 'COMPLETED_STEP'\nexport const STARTED_STEP = 'STARTED_STEP'\nexport type StepActionType = 'STARTED_STEP' | 'COMPLETED_STEP' | 'NOT_STARTED_STEP'\nexport type UserFlowStatus = 'NOT_STARTED_FLOW' | 'STARTED_FLOW' | 'COMPLETED_FLOW' | 'SKIPPED_FLOW'\nconst LAST_POST_CALL_AT = 'frigade-last-call-at-'\nconst LAST_POST_CALL_DATA = 'frigade-last-call-data-'\nconst GUEST_KEY = 'frigade-guest-key'\nconst GUEST_PREFIX = 'guest_'\nconst GET_CACHE_PREFIX = 'get-cache-'\nconst GET_CACHE_TTL_MS = 1000\nconst POST_CACHE_TTL_MS = 1000\nconst LOCAL_STORAGE_PREFIX = 'fr-js-'\n\nexport function cloneFlow(flow: Flow): Flow {\n const newFlow = new Flow(flow.config, flow.rawData)\n newFlow.isCompleted = flow.isCompleted\n newFlow.isStarted = flow.isStarted\n newFlow.isSkipped = flow.isSkipped\n newFlow.isVisible = flow.isVisible\n newFlow.steps = flow.steps\n return newFlow\n}\n\nexport function clone<T>(obj: T): T {\n return JSON.parse(JSON.stringify(obj))\n}\n\nexport function getHeaders(apiKey: string) {\n return {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n 'X-Frigade-SDK-Version': VERSION_NUMBER,\n 'X-Frigade-SDK-Platform': 'Javascript',\n },\n }\n}\n\nfunction getLocalStorage(key: string) {\n if (isWeb()) {\n return window.localStorage.getItem(`${LOCAL_STORAGE_PREFIX}${key}`)\n }\n return null\n}\n\nfunction setLocalStorage(key: string, value: string) {\n if (isWeb()) {\n window.localStorage.setItem(`${LOCAL_STORAGE_PREFIX}${key}`, value)\n }\n}\n\nfunction setGlobalState(key: string, value: any) {\n frigadeGlobalState[key] = value\n}\n\nfunction getGlobalState(key: string): any {\n return frigadeGlobalState[key]\n}\n\nexport function clearCache() {\n Object.keys(frigadeGlobalState).forEach((key) => {\n if (key.startsWith(GET_CACHE_PREFIX)) {\n delete frigadeGlobalState[key]\n }\n })\n}\n\nexport function resetAllLocalStorage() {\n if (isWeb()) {\n // Clear all local storage items that begin with `frigade-`\n Object.keys(window.localStorage).forEach((key) => {\n if (key.startsWith(LOCAL_STORAGE_PREFIX)) {\n window.localStorage.removeItem(key)\n }\n })\n }\n}\n\nexport async function gracefulFetch(url: string, options: any) {\n const lastCallAtKey = LAST_POST_CALL_AT + url\n const lastCallDataKey = LAST_POST_CALL_DATA + url\n if (isWeb() && options && options.body && options.method === 'POST') {\n const lastCall = getLocalStorage(lastCallAtKey)\n const lastCallData = getLocalStorage(lastCallDataKey)\n if (lastCall && lastCallData && lastCallData == options.body) {\n const lastCallDate = new Date(lastCall)\n const now = new Date()\n const diff = now.getTime() - lastCallDate.getTime()\n // Throttle consecutive POST calls to 1 second\n if (diff < POST_CACHE_TTL_MS) {\n return getEmptyResponse()\n }\n }\n setLocalStorage(lastCallAtKey, new Date().toISOString())\n setLocalStorage(lastCallDataKey, options.body)\n clearCache()\n }\n\n let response\n try {\n response = fetch(url, options)\n response = await response\n } catch (error) {\n return getEmptyResponse(error)\n }\n\n if (!response) {\n return getEmptyResponse('Received an empty response')\n }\n\n if (response.status >= 400) {\n return getEmptyResponse(response.statusText)\n }\n\n try {\n if (response.status === 204 || response.status === 201) {\n return getEmptyResponse()\n }\n\n const body = await response.json()\n if (body.error) {\n return getEmptyResponse(body.error)\n }\n return body\n } catch (e) {\n return getEmptyResponse(e)\n }\n}\n\nexport function getEmptyResponse(error?: any) {\n if (error) {\n console.log('Call to Frigade failed', error)\n }\n\n // Create empty response that contains the .json method and returns an empty object\n return {\n json: () => ({}),\n }\n}\n\nexport function generateGuestId() {\n if (isWeb()) {\n let guestId = getLocalStorage(GUEST_KEY)\n if (!guestId) {\n guestId = `${GUEST_PREFIX}${uuidv4()}`\n setLocalStorage(GUEST_KEY, guestId)\n }\n return guestId\n }\n}\n\nexport function fetcher(apiKey: string, path: string, options?: Record<any, any>) {\n return gracefulFetch(`//api.frigade.com/v1/public${path}`, {\n ...(options ?? {}),\n ...getHeaders(apiKey),\n })\n}\n\nexport function isWeb() {\n return typeof window !== 'undefined'\n}\n","import { FrigadeConfig, UserFlowState } from '../types'\nimport { Flow } from '../core/flow'\nimport { FlowStep } from '../core/flow-step'\n\nexport interface FrigadeGlobalState {\n refreshUserFlowStates: () => Promise<void>\n userFlowStates: Record<string, UserFlowState>\n onFlowStateChangeHandlerWrappers: Map<\n (flow: Flow, previousFlow: Flow) => void,\n (flow: Flow, previousFlow: Flow) => void\n >\n onStepStateChangeHandlerWrappers: Map<\n (step: FlowStep, previousStep: FlowStep) => void,\n (flow: Flow, previousFlow: Flow) => void\n >\n onFlowStateChangeHandlers: ((flow: Flow, previousFlow: Flow) => void)[]\n previousFlows: Map<string, Flow>\n}\n\nexport let frigadeGlobalState: Record<string, FrigadeGlobalState> = {}\n\nexport function getGlobalStateKey(internalConfig: FrigadeConfig): string {\n return `${internalConfig.__instanceId}-${internalConfig.apiKey}:${internalConfig.userId ?? ''}:${\n internalConfig.groupId ?? ''\n }`\n}\n","import { generateGuestId, getEmptyResponse, getHeaders, gracefulFetch } from './utils'\nimport { FrigadeConfig } from '../types'\nimport { frigadeGlobalState, FrigadeGlobalState, getGlobalStateKey } from './state'\n\nexport class Fetchable {\n public config: FrigadeConfig = {\n apiKey: '',\n apiUrl: 'https://api.frigade.com/v1/public',\n userId: generateGuestId(),\n __instanceId: Math.random().toString(36).substring(7),\n }\n\n constructor(config: FrigadeConfig) {\n const filteredConfig = Object.fromEntries(Object.entries(config).filter(([_, v]) => v != null))\n\n this.config = {\n ...this.config,\n ...filteredConfig,\n }\n }\n\n public async fetch(path: string, options?: Record<any, any>) {\n if (this.config.__readOnly) {\n return getEmptyResponse()\n }\n\n return gracefulFetch(`${this.config.apiUrl}${path}`, {\n ...(options ?? {}),\n ...getHeaders(this.config.apiKey),\n })\n }\n\n protected getGlobalState(): FrigadeGlobalState {\n const globalStateKey = getGlobalStateKey(this.config)\n if (!frigadeGlobalState[globalStateKey]) {\n throw new Error('Frigade not initialized')\n }\n return frigadeGlobalState[globalStateKey]\n }\n}\n","import { FrigadeConfig, UserFlowState } from '../types'\nimport { FlowDataRaw } from './types'\nimport {\n clone,\n COMPLETED_FLOW,\n COMPLETED_STEP,\n NOT_STARTED_FLOW,\n NOT_STARTED_STEP,\n SKIPPED_FLOW,\n STARTED_FLOW,\n STARTED_STEP,\n} from '../shared/utils'\nimport { FlowStep } from './flow-step'\nimport { Fetchable } from '../shared/Fetchable'\n\nexport class Flow extends Fetchable {\n /**\n * THe Flow ID / slug of the flow\n */\n public id: string\n /**\n * The raw data defined in `config.yml` as a JSON decoded object\n */\n public configYmlAsJson: any\n /**\n * Ordered map from Step ID to step data. The `steps` array in `config.yml`\n */\n public steps: Map<string, FlowStep>\n /**\n * The user-facing title of the flow, if defined at the top level of `config.yml`\n */\n public title?: string\n /**\n * The user-facing description of the flow, if defined at the top level of `config.yml`\n */\n public subtitle?: string\n /**\n * The metadata of the flow.\n */\n public rawData: FlowDataRaw\n /**\n * Whether the flow is completed or not\n */\n public isCompleted: boolean\n /**\n * Whether the flow is started or not\n */\n public isStarted: boolean\n /**\n * Whether the flow has been skipped or not\n */\n public isSkipped: boolean\n /**\n * Whether the flow is visible to the user based on the current user/group's state\n */\n public isVisible: boolean = false\n\n private readonly flowDataRaw: FlowDataRaw\n\n private userFlowStateRaw?: UserFlowState\n\n private lastStepUpdate: Map<(step: FlowStep, previousStep: FlowStep) => void, FlowStep> =\n new Map()\n\n private lastUsedVariables = {}\n\n constructor(config: FrigadeConfig, flowDataRaw: FlowDataRaw) {\n super(config)\n this.flowDataRaw = flowDataRaw\n this.initFromRawData(flowDataRaw)\n }\n\n reload() {\n this.initFromRawData(this.flowDataRaw)\n }\n\n private initFromRawData(flowDataRaw: FlowDataRaw) {\n const flowDataYml = JSON.parse(flowDataRaw.data)\n const steps = flowDataYml.steps ?? flowDataYml.data ?? []\n this.id = flowDataRaw.slug\n this.rawData = flowDataRaw\n this.configYmlAsJson = flowDataYml\n this.title = this.configYmlAsJson.title\n this.subtitle = this.configYmlAsJson.subtitle\n\n const userFlowState = this.getUserFlowState()\n if (!userFlowState) {\n return\n }\n this.userFlowStateRaw = userFlowState\n\n this.isCompleted = userFlowState.flowState == COMPLETED_FLOW\n this.isStarted = userFlowState.flowState == STARTED_FLOW\n this.isSkipped = userFlowState.flowState == SKIPPED_FLOW\n const hasCompleted = this.isCompleted || this.isSkipped\n const targetingShouldHideFlow =\n flowDataRaw.targetingLogic && userFlowState.shouldTrigger === false\n this.isVisible = !hasCompleted && !targetingShouldHideFlow\n if (this.flowDataRaw.active === false) {\n this.isVisible = false\n }\n const newSteps = new Map<string, FlowStep>()\n\n steps.forEach((step, index) => {\n const userFlowStateStep = userFlowState.stepStates[step.id]\n const stepObj = {\n ...step,\n isCompleted: userFlowStateStep.actionType == COMPLETED_STEP,\n isStarted: userFlowStateStep.actionType == STARTED_STEP,\n isHidden: userFlowStateStep.hidden,\n isBlocked: userFlowStateStep.blocked,\n lastActionAt: userFlowStateStep.lastActionAt\n ? new Date(userFlowStateStep.lastActionAt)\n : undefined,\n order: index,\n } as FlowStep\n\n stepObj.start = async (properties?: Record<string | number, any>) => {\n const thisStep = this.steps.get(step.id)\n\n if (this.getCurrentStep().id === thisStep.id && thisStep.isStarted) {\n return\n }\n\n thisStep.isStarted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.stepStates[thisStep.id].actionType = STARTED_STEP\n copy.stepStates[thisStep.id].lastActionAt = new Date().toISOString()\n copy.lastStepId = thisStep.id\n\n this.getGlobalState().userFlowStates[this.id] = copy\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: thisStep.id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: STARTED_STEP,\n }),\n })\n\n await this.refreshUserFlowState()\n\n const updatedUserFlowState = this.getUserFlowState()\n thisStep.isCompleted =\n updatedUserFlowState.stepStates[thisStep.id].actionType == COMPLETED_STEP\n thisStep.isStarted = updatedUserFlowState.stepStates[thisStep.id].actionType == STARTED_STEP\n thisStep.lastActionAt = new Date()\n }\n\n stepObj.complete = async (properties?: Record<string | number, any>) => {\n const thisStep = this.steps.get(step.id)\n\n if (thisStep.isCompleted) {\n return\n }\n\n const numberOfCompletedSteps = this.getNumberOfCompletedSteps()\n const isLastStep = numberOfCompletedSteps + 1 == this.steps.size\n\n thisStep.isCompleted = true\n this.isStarted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n\n copy.stepStates[thisStep.id].actionType = COMPLETED_STEP\n copy.stepStates[thisStep.id].lastActionAt = new Date().toISOString()\n copy.flowState = isLastStep ? COMPLETED_FLOW : STARTED_FLOW\n\n const nextStepId = Array.from(this.steps.keys())[index + 1]\n if (nextStepId) {\n copy.lastStepId = nextStepId\n copy.stepStates[nextStepId].actionType = STARTED_STEP\n const lastAction = new Date()\n copy.stepStates[nextStepId].lastActionAt = lastAction.toISOString()\n this.steps.get(nextStepId).isStarted = true\n this.steps.get(nextStepId).lastActionAt = lastAction\n }\n\n if (isLastStep) {\n this.optimisticallyMarkFlowCompleted()\n }\n\n this.getGlobalState().userFlowStates[this.id] = copy\n\n // if all steps are now completed, mark flow completed\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: thisStep.id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: COMPLETED_STEP,\n }),\n })\n\n await this.refreshUserFlowState()\n\n const updatedUserFlowState = this.getUserFlowState()\n thisStep.isCompleted =\n updatedUserFlowState.stepStates[thisStep.id].actionType == COMPLETED_STEP\n thisStep.isStarted = updatedUserFlowState.stepStates[thisStep.id].actionType == STARTED_STEP\n thisStep.lastActionAt = new Date()\n }\n\n stepObj.reset = async () => {\n const thisStep = this.steps.get(step.id)\n\n if (!thisStep.isCompleted) {\n return\n }\n\n thisStep.isCompleted = false\n thisStep.isStarted = false\n thisStep.lastActionAt = undefined\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.stepStates[thisStep.id].actionType = NOT_STARTED_STEP\n copy.stepStates[thisStep.id].lastActionAt = undefined\n copy.flowState = STARTED_FLOW\n this.getGlobalState().userFlowStates[this.id] = copy\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: thisStep.id,\n data: {},\n createdAt: new Date().toISOString(),\n actionType: NOT_STARTED_STEP,\n }),\n })\n\n await this.refreshUserFlowState()\n\n const updatedUserFlowState = this.getUserFlowState()\n thisStep.isCompleted =\n updatedUserFlowState.stepStates[thisStep.id].actionType == COMPLETED_STEP\n thisStep.isStarted = updatedUserFlowState.stepStates[thisStep.id].actionType == STARTED_STEP\n thisStep.lastActionAt = undefined\n }\n\n stepObj.onStateChange = (handler: (step: FlowStep, previousStep: FlowStep) => void) => {\n const wrapperHandler = (flow: Flow) => {\n if (flow.id !== this.id) {\n return\n }\n const thisStep = flow.steps.get(step.id)\n const previousStep = this.lastStepUpdate.get(handler)\n\n if (\n thisStep.isCompleted !== previousStep?.isCompleted ||\n thisStep.isStarted !== previousStep?.isStarted ||\n thisStep.isHidden !== previousStep?.isHidden ||\n thisStep.isBlocked !== previousStep?.isBlocked\n ) {\n handler(thisStep, previousStep ?? clone(thisStep))\n this.lastStepUpdate.set(handler, clone(thisStep))\n }\n }\n this.getGlobalState().onStepStateChangeHandlerWrappers.set(handler, wrapperHandler)\n this.getGlobalState().onFlowStateChangeHandlers.push(wrapperHandler)\n }\n\n stepObj.removeStateChangeHandler = (\n handler: (step: FlowStep, previousStep: FlowStep) => void\n ) => {\n const wrapperHandler = this.getGlobalState().onStepStateChangeHandlerWrappers.get(handler)\n if (wrapperHandler) {\n this.getGlobalState().onFlowStateChangeHandlers =\n this.getGlobalState().onFlowStateChangeHandlers.filter((h) => h !== wrapperHandler)\n }\n }\n\n newSteps.set(step.id, stepObj)\n })\n this.steps = newSteps\n // Check if empty object\n if (Object.keys(this.lastUsedVariables).length > 0) {\n this.applyVariables(this.lastUsedVariables)\n }\n }\n\n /**\n * Marks the flow started\n */\n public async start(properties?: Record<string | number, any>) {\n if (this.isStarted || this.isCompleted) {\n return\n }\n\n this.isStarted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.flowState = STARTED_FLOW\n this.getGlobalState().userFlowStates[this.id] = copy\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: this.getCurrentStep().id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: STARTED_FLOW,\n }),\n })\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * Marks the flow completed\n */\n public async complete(properties?: Record<string | number, any>) {\n if (this.isCompleted) {\n return\n }\n this.optimisticallyMarkFlowCompleted()\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: this.getCurrentStep().id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: COMPLETED_FLOW,\n }),\n })\n\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n private optimisticallyMarkFlowCompleted() {\n this.isStarted = true\n this.isCompleted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.flowState = COMPLETED_FLOW\n this.getGlobalState().userFlowStates[this.id] = copy\n this.isVisible = false\n }\n\n /**\n * Marks the flow skipped\n */\n public async skip(properties?: Record<string | number, any>) {\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: this.getCurrentStep().id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: SKIPPED_FLOW,\n }),\n })\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * Navigates the flow to the next step if one exists. This will mark that step started, but will not complete the previous step.\n */\n public async forward(properties?: Record<string | number, any>) {\n const nextStep = this.getStepByIndex(this.getCurrentStepIndex() + 1)\n if (nextStep) {\n await nextStep.start(properties)\n }\n }\n\n /**\n * Navigates the flow to the previous step if one exists. This will mark that step started, but will not complete the previous step.\n */\n public async back(properties?: Record<string | number, any>) {\n const previousStep = this.getStepByIndex(this.getCurrentStepIndex() - 1)\n if (previousStep) {\n await previousStep.start(properties)\n }\n }\n\n /**\n * Restarts the flow/marks it not started\n */\n public async restart() {\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: 'unknown',\n data: {},\n createdAt: new Date().toISOString(),\n actionType: NOT_STARTED_FLOW,\n }),\n })\n\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * Get a step by index\n * @param index\n */\n public getStepByIndex(index: number): FlowStep | undefined {\n return this.steps.get(Array.from(this.steps.keys())[index])\n }\n\n /**\n * Gets current step\n */\n public getCurrentStep(): FlowStep {\n let maybeCurrentStepId = Array.from(this.steps.keys()).find(\n (key) => this.steps.get(key).isCompleted === false && this.steps.get(key).isHidden === false\n )\n Array.from(this.steps.keys()).forEach((key) => {\n if (\n this.steps.get(key).isStarted &&\n this.steps.get(key).lastActionAt &&\n this.steps.get(key).lastActionAt >\n (this.steps.get(maybeCurrentStepId)?.lastActionAt ?? new Date(0))\n ) {\n maybeCurrentStepId = key\n }\n })\n\n const currentStepId = maybeCurrentStepId ?? Array.from(this.steps.keys())[0]\n return this.steps.get(currentStepId)\n }\n\n public getCurrentStepIndex(): number {\n const currentStep = this.getCurrentStep()\n return Array.from(this.steps.keys()).indexOf(currentStep.id)\n }\n\n /**\n * Get the number of completed steps for the current user in the current flow\n */\n public getNumberOfCompletedSteps(): number {\n return Array.from(this.steps.values()).filter((step) => step.isCompleted).length\n }\n\n /**\n * Get the number of available steps for the current user in the current flow. This is the number of steps that are not hidden.\n */\n public getNumberOfAvailableSteps(): number {\n return Array.from(this.steps.values()).filter((step) => !step.isHidden).length\n }\n\n public onStateChange(handler: (flow: Flow, previousFlow: Flow) => void) {\n const wrapperHandler = (flow: Flow, previousFlow: Flow) => {\n if (\n (flow.id === this.id &&\n (flow.isCompleted !== previousFlow.isCompleted ||\n flow.isStarted !== previousFlow.isStarted ||\n flow.isSkipped !== previousFlow.isSkipped ||\n flow.isVisible !== previousFlow.isVisible)) ||\n JSON.stringify(flow.steps) !== JSON.stringify(previousFlow.steps)\n ) {\n handler(flow, previousFlow)\n }\n }\n this.getGlobalState().onFlowStateChangeHandlerWrappers.set(handler, wrapperHandler)\n this.getGlobalState().onFlowStateChangeHandlers.push(wrapperHandler)\n }\n\n public removeStateChangeHandler(handler: (flow: Flow, previousFlow: Flow) => void) {\n const wrapperHandler = this.getGlobalState().onFlowStateChangeHandlerWrappers.get(handler)\n if (wrapperHandler) {\n this.getGlobalState().onFlowStateChangeHandlers =\n this.getGlobalState().onFlowStateChangeHandlers.filter((h) => h !== wrapperHandler)\n }\n }\n\n public applyVariables(variables: Record<string, any>) {\n // Replace ${variable} with the value of the variable\n const replaceVariables = (str: string) => {\n const matches = str.match(/\\${(.*?)}/g)\n if (matches) {\n matches.forEach((match) => {\n const variable = match.replace('${', '').replace('}', '')\n str = str.replace(match, variables[variable] ?? '')\n })\n }\n return str\n }\n\n this.title = replaceVariables(this.title ?? '')\n this.subtitle = replaceVariables(this.subtitle ?? '')\n this.steps.forEach((step) => {\n // Iterate over every string field in the step and replace variables\n Object.keys(step).forEach((key) => {\n if (typeof step[key] === 'string') {\n // @ts-ignore\n step[key] = replaceVariables(step[key])\n }\n })\n })\n\n this.lastUsedVariables = variables\n }\n\n private getUserFlowState(): UserFlowState {\n const userFlowStates = this.getGlobalState().userFlowStates\n return userFlowStates[this.id]\n }\n\n private async refreshUserFlowState() {\n await this.getGlobalState().refreshUserFlowStates()\n }\n}\n","import { FrigadeConfig, UserFlowState } from '../types'\nimport { clearCache, cloneFlow, isWeb, resetAllLocalStorage } from '../shared/utils'\nimport { Flow } from './flow'\nimport { FlowDataRaw, FlowStatus, FlowType, TriggerType } from './types'\nimport { frigadeGlobalState, getGlobalStateKey } from '../shared/state'\nimport { Fetchable } from '../shared/Fetchable'\n\nexport class Frigade extends Fetchable {\n private flows: Flow[] = []\n private initPromise: Promise<void>\n private hasFailed = false\n\n private visibilityChangeHandler = async () => {\n if (document.visibilityState === 'visible') {\n await this.refreshFlows()\n await this.refreshUserFlowStates()\n }\n }\n\n constructor(apiKey: string, config?: FrigadeConfig) {\n super({\n apiKey,\n ...config,\n })\n this.init(this.config)\n if (isWeb()) {\n document.addEventListener('visibilitychange', this.visibilityChangeHandler)\n }\n }\n\n destroy() {\n if (isWeb()) {\n document.removeEventListener('visibilitychange', this.visibilityChangeHandler)\n // Remove all other event listeners\n const globalStateKey = getGlobalStateKey(this.config)\n if (frigadeGlobalState[globalStateKey]) {\n frigadeGlobalState[globalStateKey].onFlowStateChangeHandlers = []\n }\n }\n }\n\n private async init(config: FrigadeConfig): Promise<void> {\n this.config = {\n ...this.config,\n ...config,\n }\n\n this.initPromise = (async () => {\n await this.refreshUserFlowStates()\n await this.refreshFlows()\n })()\n\n return this.initPromise\n }\n\n public async identify(userId: string, properties?: Record<string, any>): Promise<void> {\n this.config = { ...this.config, userId }\n await this.initIfNeeded()\n await this.fetch('/users', {\n method: 'POST',\n body: JSON.stringify({\n foreignId: this.config.userId,\n properties,\n }),\n })\n await this.refreshUserFlowStates()\n }\n\n public async group(groupId: string, properties?: Record<string, any>): Promise<void> {\n await this.initIfNeeded()\n this.config.groupId = groupId\n await this.fetch('/userGroups', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n properties,\n }),\n })\n await this.refreshUserFlowStates()\n }\n\n public async track(event: string, properties?: Record<string, any>): Promise<void> {\n await this.initIfNeeded()\n await this.fetch('/track', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n event,\n properties,\n }),\n })\n }\n\n public isReady(): boolean {\n return Boolean(this.config.__instanceId && this.config.apiKey && this.initPromise)\n }\n\n public async getFlow(flowId: string) {\n await this.initIfNeeded()\n\n return this.flows.find((flow) => flow.id == flowId)\n }\n\n public async getFlows() {\n await this.initIfNeeded()\n return this.flows\n }\n\n /**\n * Reload the current state of the flows by calling the Frigade API.\n * This will trigger all event handlers.\n */\n public async reload() {\n resetAllLocalStorage()\n clearCache()\n await this.refreshUserFlowStates()\n await this.refreshFlows()\n this.initPromise = null\n await this.init(this.config)\n // Trigger all event handlers\n this.flows.forEach((flow) => {\n this.getGlobalState().onFlowStateChangeHandlers.forEach((handler) => {\n const lastFlow = this.getGlobalState().previousFlows.get(flow.id)\n handler(flow, lastFlow)\n this.getGlobalState().previousFlows.set(flow.id, cloneFlow(flow))\n })\n })\n }\n\n public onStateChange(handler: (flow: Flow, previousFlow?: Flow) => void) {\n this.getGlobalState().onFlowStateChangeHandlers.push(handler)\n }\n\n /**\n * Returns true of Frigade has failed to call the API.\n */\n hasFailedToLoad() {\n return this.hasFailed\n }\n\n public removeStateChangeHandler(handler: (flow: Flow, previousFlow?: Flow) => void) {\n this.getGlobalState().onFlowStateChangeHandlers =\n this.getGlobalState().onFlowStateChangeHandlers.filter((h) => h !== handler)\n }\n\n private async initIfNeeded() {\n if (this.initPromise !== null) {\n return this.initPromise\n } else {\n return this.init(this.config)\n }\n }\n\n private async refreshUserFlowStates(): Promise<void> {\n const globalStateKey = getGlobalStateKey(this.config)\n\n if (!frigadeGlobalState[globalStateKey]) {\n const that = this\n\n let validator = {\n set: function (target: any, key: any, value: any) {\n if (\n target[key] &&\n target[key].flowState &&\n (JSON.stringify(target[key].flowState) !== JSON.stringify(value?.flowState) ||\n JSON.stringify(target[key].stepStates) !== JSON.stringify(value?.stepStates) ||\n JSON.stringify(target[key].shouldTrigger) !== JSON.stringify(value?.shouldTrigger))\n ) {\n that.triggerEventHandlers(target[key])\n }\n\n target[key] = value\n return true\n },\n }\n\n frigadeGlobalState[globalStateKey] = {\n refreshUserFlowStates: async () => {},\n userFlowStates: new Proxy({}, validator),\n onFlowStateChangeHandlerWrappers: new Map(),\n onStepStateChangeHandlerWrappers: new Map(),\n onFlowStateChangeHandlers: [],\n previousFlows: new Map(),\n }\n\n if (this.config.__readOnly && this.config.__flowConfigOverrides) {\n this.mockUserFlowStates(globalStateKey)\n\n return\n }\n\n frigadeGlobalState[globalStateKey].refreshUserFlowStates = async () => {\n if (this.config.__readOnly) {\n return\n }\n\n const userFlowStatesRaw = await this.fetch(\n `/userFlowStates?foreignUserId=${encodeURIComponent(this.config.userId)}${\n this.config.groupId\n ? `&foreignUserGroupId=${encodeURIComponent(this.config.groupId)}`\n : ''\n }`\n )\n if (userFlowStatesRaw && userFlowStatesRaw.data) {\n let userFlowStates = userFlowStatesRaw.data as UserFlowState[]\n userFlowStates.forEach((userFlowState) => {\n let shouldReload = false\n const before = frigadeGlobalState[globalStateKey].userFlowStates[userFlowState.flowId]\n\n // Special case: for flows that show up based on targeting logic/rules, we need to check if the flow should be triggered\n if (before && before.shouldTrigger == false && userFlowState.shouldTrigger == true) {\n shouldReload = true\n }\n frigadeGlobalState[globalStateKey].userFlowStates[userFlowState.flowId] = userFlowState\n if (shouldReload) {\n this.flows.forEach((flow) => {\n if (flow.id == userFlowState.flowId) {\n flow.reload()\n this.triggerEventHandlers(\n frigadeGlobalState[globalStateKey].userFlowStates[flow.id]\n )\n }\n })\n }\n })\n this.hasFailed = false\n } else {\n this.hasFailed = true\n }\n }\n }\n\n await frigadeGlobalState[globalStateKey].refreshUserFlowStates()\n }\n\n private async refreshFlows() {\n this.flows = []\n\n if (this.config.__flowConfigOverrides) {\n this.mockFlowConfigs()\n return\n }\n\n const flowDataRaw = await this.fetch('/flows')\n if (flowDataRaw && flowDataRaw.data) {\n let flowDatas = flowDataRaw.data as FlowDataRaw[]\n flowDatas.forEach((flowData) => {\n this.flows.push(new Flow(this.config, flowData))\n this.getGlobalState().previousFlows.set(\n flowData.slug,\n cloneFlow(this.flows[this.flows.length - 1])\n )\n })\n } else {\n this.hasFailed = true\n }\n }\n\n private mockFlowConfigs() {\n Object.keys(this.config.__flowConfigOverrides).forEach((flowId) => {\n this.flows.push(\n new Flow(this.config, {\n id: -1,\n name: '',\n description: '',\n data: this.config.__flowConfigOverrides[flowId],\n createdAt: new Date().toISOString(),\n modifiedAt: new Date().toISOString(),\n slug: flowId,\n targetingLogic: '',\n type: FlowType.CHECKLIST,\n triggerType: TriggerType.MANUAL,\n status: FlowStatus.ACTIVE,\n version: 1,\n active: true,\n })\n )\n })\n }\n\n private mockUserFlowStates(globalStateKey: string) {\n Object.keys(this.config.__flowConfigOverrides).forEach((flowId) => {\n const parsed = JSON.parse(this.config.__flowConfigOverrides[flowId])\n frigadeGlobalState[globalStateKey].userFlowStates[flowId] = {\n flowId,\n flowState: 'NOT_STARTED_FLOW',\n lastStepId: null,\n userId: this.config.userId,\n foreignUserId: this.config.userId,\n stepStates:\n parsed?.steps?.reduce((acc, step) => {\n acc[step.id] = {\n stepId: step.id,\n flowSlug: flowId,\n actionType: 'NOT_STARTED_STEP',\n createdAt: new Date().toISOString(),\n blocked: false,\n hidden: false,\n }\n return acc\n }, {}) ?? {},\n shouldTrigger: false,\n }\n })\n }\n\n private async triggerEventHandlers(previousUserFlowState: UserFlowState) {\n if (previousUserFlowState) {\n this.flows.forEach((flow) => {\n if (flow.id == previousUserFlowState.flowId) {\n this.getGlobalState().onFlowStateChangeHandlers.forEach((handler) => {\n const lastFlow = this.getGlobalState().previousFlows.get(flow.id)\n handler(flow, lastFlow)\n this.getGlobalState().previousFlows.set(flow.id, cloneFlow(flow))\n })\n }\n })\n }\n }\n}\n"],"mappings":"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","names":["VERSION_NUMBER","fetch","uuidv4","frigadeGlobalState","getGlobalStateKey","internalConfig","Fetchable","config","generateGuestId","filteredConfig","_","v","path","options","getEmptyResponse","gracefulFetch","getHeaders","globalStateKey","getGlobalStateKey","frigadeGlobalState","Flow","Fetchable","config","flowDataRaw","flowDataYml","steps","userFlowState","COMPLETED_FLOW","STARTED_FLOW","SKIPPED_FLOW","hasCompleted","targetingShouldHideFlow","newSteps","step","index","userFlowStateStep","stepObj","COMPLETED_STEP","STARTED_STEP","properties","thisStep","copy","clone","updatedUserFlowState","isLastStep","nextStepId","lastAction","NOT_STARTED_STEP","handler","wrapperHandler","flow","previousStep","h","nextStep","NOT_STARTED_FLOW","maybeCurrentStepId","key","_a","currentStepId","currentStep","previousFlow","variables","replaceVariables","str","matches","match","variable","NOT_STARTED_STEP","COMPLETED_FLOW","SKIPPED_FLOW","STARTED_FLOW","NOT_STARTED_FLOW","COMPLETED_STEP","STARTED_STEP","LAST_POST_CALL_AT","LAST_POST_CALL_DATA","GUEST_KEY","GUEST_PREFIX","GET_CACHE_PREFIX","POST_CACHE_TTL_MS","LOCAL_STORAGE_PREFIX","cloneFlow","flow","newFlow","Flow","clone","obj","getHeaders","apiKey","VERSION_NUMBER","getLocalStorage","key","isWeb","setLocalStorage","value","clearCache","frigadeGlobalState","key","GET_CACHE_PREFIX","resetAllLocalStorage","isWeb","LOCAL_STORAGE_PREFIX","gracefulFetch","url","options","lastCallAtKey","LAST_POST_CALL_AT","lastCallDataKey","LAST_POST_CALL_DATA","lastCall","getLocalStorage","lastCallData","lastCallDate","POST_CACHE_TTL_MS","getEmptyResponse","setLocalStorage","response","fetch","error","body","e","generateGuestId","guestId","GUEST_KEY","GUEST_PREFIX","uuidv4","isWeb","Frigade","Fetchable","apiKey","config","isWeb","globalStateKey","getGlobalStateKey","frigadeGlobalState","userId","properties","groupId","event","flowId","flow","resetAllLocalStorage","clearCache","handler","lastFlow","cloneFlow","h","that","validator","target","key","value","userFlowStatesRaw","userFlowState","shouldReload","before","flowDataRaw","flowData","Flow","_a","parsed","acc","step","previousUserFlowState"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/version.ts","../src/shared/utils.ts","../src/shared/state.ts","../src/shared/Fetchable.ts","../src/core/flow.ts","../src/core/frigade.ts"],"sourcesContent":["export const VERSION_NUMBER = '0.2.20'\n","import { VERSION_NUMBER } from '../core/version'\nimport fetch from 'cross-fetch'\nimport { v4 as uuidv4 } from 'uuid'\nimport { Flow } from '../core/flow'\nimport { frigadeGlobalState } from './state'\n\nexport const NOT_STARTED_STEP = 'NOT_STARTED_STEP'\nexport const COMPLETED_FLOW = 'COMPLETED_FLOW'\nexport const SKIPPED_FLOW = 'SKIPPED_FLOW'\nexport const STARTED_FLOW = 'STARTED_FLOW'\nexport const NOT_STARTED_FLOW = 'NOT_STARTED_FLOW'\nexport const COMPLETED_STEP = 'COMPLETED_STEP'\nexport const STARTED_STEP = 'STARTED_STEP'\nexport type StepActionType = 'STARTED_STEP' | 'COMPLETED_STEP' | 'NOT_STARTED_STEP'\nexport type UserFlowStatus = 'NOT_STARTED_FLOW' | 'STARTED_FLOW' | 'COMPLETED_FLOW' | 'SKIPPED_FLOW'\nconst LAST_POST_CALL_AT = 'frigade-last-call-at-'\nconst LAST_POST_CALL_DATA = 'frigade-last-call-data-'\nconst GUEST_KEY = 'frigade-guest-key'\nconst GUEST_PREFIX = 'guest_'\nconst GET_CACHE_PREFIX = 'get-cache-'\nconst GET_CACHE_TTL_MS = 1000\nconst POST_CACHE_TTL_MS = 1000\nconst LOCAL_STORAGE_PREFIX = 'fr-js-'\n\nexport function cloneFlow(flow: Flow): Flow {\n const newFlow = new Flow(flow.config, flow.rawData)\n newFlow.isCompleted = flow.isCompleted\n newFlow.isStarted = flow.isStarted\n newFlow.isSkipped = flow.isSkipped\n newFlow.isVisible = flow.isVisible\n newFlow.steps = flow.steps\n return newFlow\n}\n\nexport function clone<T>(obj: T): T {\n return JSON.parse(JSON.stringify(obj))\n}\n\nexport function getHeaders(apiKey: string) {\n return {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n 'X-Frigade-SDK-Version': VERSION_NUMBER,\n 'X-Frigade-SDK-Platform': 'Javascript',\n },\n }\n}\n\nfunction getLocalStorage(key: string) {\n if (isWeb()) {\n return window.localStorage.getItem(`${LOCAL_STORAGE_PREFIX}${key}`)\n }\n return null\n}\n\nfunction setLocalStorage(key: string, value: string) {\n if (isWeb()) {\n window.localStorage.setItem(`${LOCAL_STORAGE_PREFIX}${key}`, value)\n }\n}\n\nfunction setGlobalState(key: string, value: any) {\n frigadeGlobalState[key] = value\n}\n\nfunction getGlobalState(key: string): any {\n return frigadeGlobalState[key]\n}\n\nexport function clearCache() {\n Object.keys(frigadeGlobalState).forEach((key) => {\n if (key.startsWith(GET_CACHE_PREFIX)) {\n delete frigadeGlobalState[key]\n }\n })\n}\n\nexport function resetAllLocalStorage() {\n if (isWeb()) {\n // Clear all local storage items that begin with `frigade-`\n Object.keys(window.localStorage).forEach((key) => {\n if (key.startsWith(LOCAL_STORAGE_PREFIX)) {\n window.localStorage.removeItem(key)\n }\n })\n }\n}\n\nexport async function gracefulFetch(url: string, options: any) {\n const lastCallAtKey = LAST_POST_CALL_AT + url\n const lastCallDataKey = LAST_POST_CALL_DATA + url\n if (isWeb() && options && options.body && options.method === 'POST') {\n const lastCall = getLocalStorage(lastCallAtKey)\n const lastCallData = getLocalStorage(lastCallDataKey)\n if (lastCall && lastCallData && lastCallData == options.body) {\n const lastCallDate = new Date(lastCall)\n const now = new Date()\n const diff = now.getTime() - lastCallDate.getTime()\n // Throttle consecutive POST calls to 1 second\n if (diff < POST_CACHE_TTL_MS) {\n return getEmptyResponse()\n }\n }\n setLocalStorage(lastCallAtKey, new Date().toISOString())\n setLocalStorage(lastCallDataKey, options.body)\n clearCache()\n }\n\n let response\n try {\n response = fetch(url, options)\n response = await response\n } catch (error) {\n return getEmptyResponse(error)\n }\n\n if (!response) {\n return getEmptyResponse('Received an empty response')\n }\n\n if (response.status >= 400) {\n return getEmptyResponse(response.statusText)\n }\n\n try {\n if (response.status === 204 || response.status === 201) {\n return getEmptyResponse()\n }\n\n const body = await response.json()\n if (body.error) {\n return getEmptyResponse(body.error)\n }\n return body\n } catch (e) {\n return getEmptyResponse(e)\n }\n}\n\nexport function getEmptyResponse(error?: any) {\n if (error) {\n console.log('Call to Frigade failed', error)\n }\n\n // Create empty response that contains the .json method and returns an empty object\n return {\n json: () => ({}),\n }\n}\n\nexport function generateGuestId() {\n if (isWeb()) {\n let guestId = getLocalStorage(GUEST_KEY)\n if (!guestId) {\n guestId = `${GUEST_PREFIX}${uuidv4()}`\n setLocalStorage(GUEST_KEY, guestId)\n }\n return guestId\n }\n}\n\nexport function fetcher(apiKey: string, path: string, options?: Record<any, any>) {\n return gracefulFetch(`//api.frigade.com/v1/public${path}`, {\n ...(options ?? {}),\n ...getHeaders(apiKey),\n })\n}\n\nexport function isWeb() {\n return typeof window !== 'undefined'\n}\n","import { FrigadeConfig, UserFlowState } from '../types'\nimport { Flow } from '../core/flow'\nimport { FlowStep } from '../core/flow-step'\n\nexport interface FrigadeGlobalState {\n refreshUserFlowStates: () => Promise<void>\n userFlowStates: Record<string, UserFlowState>\n onFlowStateChangeHandlerWrappers: Map<\n (flow: Flow, previousFlow: Flow) => void,\n (flow: Flow, previousFlow: Flow) => void\n >\n onStepStateChangeHandlerWrappers: Map<\n (step: FlowStep, previousStep: FlowStep) => void,\n (flow: Flow, previousFlow: Flow) => void\n >\n onFlowStateChangeHandlers: ((flow: Flow, previousFlow: Flow) => void)[]\n previousFlows: Map<string, Flow>\n}\n\nexport let frigadeGlobalState: Record<string, FrigadeGlobalState> = {}\n\nexport function getGlobalStateKey(internalConfig: FrigadeConfig): string {\n return `${internalConfig.__instanceId}-${internalConfig.apiKey}:${internalConfig.userId ?? ''}:${\n internalConfig.groupId ?? ''\n }`\n}\n","import { generateGuestId, getEmptyResponse, getHeaders, gracefulFetch } from './utils'\nimport { FrigadeConfig } from '../types'\nimport { frigadeGlobalState, FrigadeGlobalState, getGlobalStateKey } from './state'\n\nexport class Fetchable {\n public config: FrigadeConfig = {\n apiKey: '',\n apiUrl: 'https://api.frigade.com/v1/public',\n userId: generateGuestId(),\n __instanceId: Math.random().toString(36).substring(7),\n }\n\n constructor(config: FrigadeConfig) {\n const filteredConfig = Object.fromEntries(Object.entries(config).filter(([_, v]) => v != null))\n\n this.config = {\n ...this.config,\n ...filteredConfig,\n }\n }\n\n /**\n * @ignore\n */\n public async fetch(path: string, options?: Record<any, any>) {\n if (this.config.__readOnly) {\n return getEmptyResponse()\n }\n\n return gracefulFetch(`${this.config.apiUrl}${path}`, {\n ...(options ?? {}),\n ...getHeaders(this.config.apiKey),\n })\n }\n\n /**\n * @ignore\n */\n protected getGlobalState(): FrigadeGlobalState {\n const globalStateKey = getGlobalStateKey(this.config)\n if (!frigadeGlobalState[globalStateKey]) {\n throw new Error('Frigade not initialized')\n }\n return frigadeGlobalState[globalStateKey]\n }\n}\n","import { FrigadeConfig, UserFlowState } from '../types'\nimport { FlowDataRaw } from './types'\nimport {\n clone,\n COMPLETED_FLOW,\n COMPLETED_STEP,\n NOT_STARTED_FLOW,\n NOT_STARTED_STEP,\n SKIPPED_FLOW,\n STARTED_FLOW,\n STARTED_STEP,\n} from '../shared/utils'\nimport { FlowStep } from './flow-step'\nimport { Fetchable } from '../shared/Fetchable'\n\nexport class Flow extends Fetchable {\n /**\n * The Flow's ID.\n */\n public id: string\n /**\n * The raw data defined in `config.yml` as a JSON decoded object.\n * @ignore\n */\n public configYmlAsJson: any\n /**\n * Ordered map of the Steps in the Flow.\n * See [Flow Step Definition](https://docs.frigade.com/v2/sdk/js/step) for more information.\n */\n public steps: Map<string, FlowStep>\n /**\n * The user-facing title of the Flow, if defined at the top level of the YAML config.\n */\n public title?: string\n /**\n * The user-facing description of the Flow, if defined at the top level of the YAML config.\n */\n public subtitle?: string\n /**\n * The metadata of the Flow.\n * @ignore\n */\n public rawData: FlowDataRaw\n /**\n * Whether the Flow is completed or not.\n */\n public isCompleted: boolean\n /**\n * Whether the Flow is started or not.\n */\n public isStarted: boolean\n /**\n * Whether the Flow has been skipped or not.\n */\n public isSkipped: boolean\n /**\n * Whether the Flow is visible to the user based on the current user/group's state.\n */\n public isVisible: boolean = false\n /**\n * @ignore\n */\n private readonly flowDataRaw: FlowDataRaw\n /**\n * @ignore\n */\n private userFlowStateRaw?: UserFlowState\n /**\n * @ignore\n */\n private lastStepUpdate: Map<(step: FlowStep, previousStep: FlowStep) => void, FlowStep> =\n new Map()\n /**\n * @ignore\n */\n private lastUsedVariables = {}\n\n constructor(config: FrigadeConfig, flowDataRaw: FlowDataRaw) {\n super(config)\n this.flowDataRaw = flowDataRaw\n this.initFromRawData(flowDataRaw)\n }\n\n /**\n * Reload the Flow data from the server\n */\n reload() {\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * @ignore\n */\n private initFromRawData(flowDataRaw: FlowDataRaw) {\n const flowDataYml = JSON.parse(flowDataRaw.data)\n const steps = flowDataYml.steps ?? flowDataYml.data ?? []\n this.id = flowDataRaw.slug\n this.rawData = flowDataRaw\n this.configYmlAsJson = flowDataYml\n this.title = this.configYmlAsJson.title\n this.subtitle = this.configYmlAsJson.subtitle\n\n const userFlowState = this.getUserFlowState()\n if (!userFlowState) {\n return\n }\n this.userFlowStateRaw = userFlowState\n\n this.isCompleted = userFlowState.flowState == COMPLETED_FLOW\n this.isStarted = userFlowState.flowState == STARTED_FLOW\n this.isSkipped = userFlowState.flowState == SKIPPED_FLOW\n const hasCompleted = this.isCompleted || this.isSkipped\n const targetingShouldHideFlow =\n flowDataRaw.targetingLogic && userFlowState.shouldTrigger === false\n this.isVisible = !hasCompleted && !targetingShouldHideFlow\n if (this.flowDataRaw.active === false) {\n this.isVisible = false\n }\n const newSteps = new Map<string, FlowStep>()\n\n steps.forEach((step, index) => {\n const userFlowStateStep = userFlowState.stepStates[step.id]\n const stepObj = {\n ...step,\n isCompleted: userFlowStateStep.actionType == COMPLETED_STEP,\n isStarted: userFlowStateStep.actionType == STARTED_STEP,\n isHidden: userFlowStateStep.hidden,\n isBlocked: userFlowStateStep.blocked,\n lastActionAt: userFlowStateStep.lastActionAt\n ? new Date(userFlowStateStep.lastActionAt)\n : undefined,\n order: index,\n } as FlowStep\n\n stepObj.start = async (properties?: Record<string | number, any>) => {\n const thisStep = this.steps.get(step.id)\n\n if (this.getCurrentStep().id === thisStep.id && thisStep.isStarted) {\n return\n }\n\n thisStep.isStarted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.stepStates[thisStep.id].actionType = STARTED_STEP\n copy.stepStates[thisStep.id].lastActionAt = new Date().toISOString()\n copy.lastStepId = thisStep.id\n\n this.getGlobalState().userFlowStates[this.id] = copy\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: thisStep.id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: STARTED_STEP,\n }),\n })\n\n await this.refreshUserFlowState()\n\n const updatedUserFlowState = this.getUserFlowState()\n thisStep.isCompleted =\n updatedUserFlowState.stepStates[thisStep.id].actionType == COMPLETED_STEP\n thisStep.isStarted = updatedUserFlowState.stepStates[thisStep.id].actionType == STARTED_STEP\n thisStep.lastActionAt = new Date()\n }\n\n stepObj.complete = async (properties?: Record<string | number, any>) => {\n const thisStep = this.steps.get(step.id)\n\n if (thisStep.isCompleted) {\n return\n }\n\n const numberOfCompletedSteps = this.getNumberOfCompletedSteps()\n const isLastStep = numberOfCompletedSteps + 1 == this.steps.size\n\n thisStep.isCompleted = true\n this.isStarted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n\n copy.stepStates[thisStep.id].actionType = COMPLETED_STEP\n copy.stepStates[thisStep.id].lastActionAt = new Date().toISOString()\n copy.flowState = isLastStep ? COMPLETED_FLOW : STARTED_FLOW\n\n const nextStepId = Array.from(this.steps.keys())[index + 1]\n if (nextStepId) {\n copy.lastStepId = nextStepId\n copy.stepStates[nextStepId].actionType = STARTED_STEP\n const lastAction = new Date()\n copy.stepStates[nextStepId].lastActionAt = lastAction.toISOString()\n this.steps.get(nextStepId).isStarted = true\n this.steps.get(nextStepId).lastActionAt = lastAction\n }\n\n if (isLastStep) {\n this.optimisticallyMarkFlowCompleted()\n }\n\n this.getGlobalState().userFlowStates[this.id] = copy\n\n // if all steps are now completed, mark flow completed\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: thisStep.id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: COMPLETED_STEP,\n }),\n })\n\n await this.refreshUserFlowState()\n\n const updatedUserFlowState = this.getUserFlowState()\n thisStep.isCompleted =\n updatedUserFlowState.stepStates[thisStep.id].actionType == COMPLETED_STEP\n thisStep.isStarted = updatedUserFlowState.stepStates[thisStep.id].actionType == STARTED_STEP\n thisStep.lastActionAt = new Date()\n }\n\n stepObj.reset = async () => {\n const thisStep = this.steps.get(step.id)\n\n if (!thisStep.isCompleted) {\n return\n }\n\n thisStep.isCompleted = false\n thisStep.isStarted = false\n thisStep.lastActionAt = undefined\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.stepStates[thisStep.id].actionType = NOT_STARTED_STEP\n copy.stepStates[thisStep.id].lastActionAt = undefined\n copy.flowState = STARTED_FLOW\n this.getGlobalState().userFlowStates[this.id] = copy\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: thisStep.id,\n data: {},\n createdAt: new Date().toISOString(),\n actionType: NOT_STARTED_STEP,\n }),\n })\n\n await this.refreshUserFlowState()\n\n const updatedUserFlowState = this.getUserFlowState()\n thisStep.isCompleted =\n updatedUserFlowState.stepStates[thisStep.id].actionType == COMPLETED_STEP\n thisStep.isStarted = updatedUserFlowState.stepStates[thisStep.id].actionType == STARTED_STEP\n thisStep.lastActionAt = undefined\n }\n\n stepObj.onStateChange = (handler: (step: FlowStep, previousStep: FlowStep) => void) => {\n const wrapperHandler = (flow: Flow) => {\n if (flow.id !== this.id) {\n return\n }\n const thisStep = flow.steps.get(step.id)\n const previousStep = this.lastStepUpdate.get(handler)\n\n if (\n thisStep.isCompleted !== previousStep?.isCompleted ||\n thisStep.isStarted !== previousStep?.isStarted ||\n thisStep.isHidden !== previousStep?.isHidden ||\n thisStep.isBlocked !== previousStep?.isBlocked\n ) {\n handler(thisStep, previousStep ?? clone(thisStep))\n this.lastStepUpdate.set(handler, clone(thisStep))\n }\n }\n this.getGlobalState().onStepStateChangeHandlerWrappers.set(handler, wrapperHandler)\n this.getGlobalState().onFlowStateChangeHandlers.push(wrapperHandler)\n }\n\n stepObj.removeStateChangeHandler = (\n handler: (step: FlowStep, previousStep: FlowStep) => void\n ) => {\n const wrapperHandler = this.getGlobalState().onStepStateChangeHandlerWrappers.get(handler)\n if (wrapperHandler) {\n this.getGlobalState().onFlowStateChangeHandlers =\n this.getGlobalState().onFlowStateChangeHandlers.filter((h) => h !== wrapperHandler)\n }\n }\n\n newSteps.set(step.id, stepObj)\n })\n this.steps = newSteps\n // Check if empty object\n if (Object.keys(this.lastUsedVariables).length > 0) {\n this.applyVariables(this.lastUsedVariables)\n }\n }\n\n /**\n * Marks the flow started\n */\n public async start(properties?: Record<string | number, any>) {\n if (this.isStarted || this.isCompleted) {\n return\n }\n\n this.isStarted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.flowState = STARTED_FLOW\n this.getGlobalState().userFlowStates[this.id] = copy\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: this.getCurrentStep().id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: STARTED_FLOW,\n }),\n })\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * Marks the flow completed\n */\n public async complete(properties?: Record<string | number, any>) {\n if (this.isCompleted) {\n return\n }\n this.optimisticallyMarkFlowCompleted()\n\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: this.getCurrentStep().id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: COMPLETED_FLOW,\n }),\n })\n\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * @ignore\n */\n private optimisticallyMarkFlowCompleted() {\n this.isStarted = true\n this.isCompleted = true\n const copy = clone(this.getGlobalState().userFlowStates[this.id])\n copy.flowState = COMPLETED_FLOW\n this.getGlobalState().userFlowStates[this.id] = copy\n this.isVisible = false\n }\n\n /**\n * Marks the flow skipped\n */\n public async skip(properties?: Record<string | number, any>) {\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: this.getCurrentStep().id,\n data: properties ?? {},\n createdAt: new Date().toISOString(),\n actionType: SKIPPED_FLOW,\n }),\n })\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * Navigates the flow to the next step if one exists. This will mark that step started, but will not complete the previous step.\n */\n public async forward(properties?: Record<string | number, any>) {\n const nextStep = this.getStepByIndex(this.getCurrentStepIndex() + 1)\n if (nextStep) {\n await nextStep.start(properties)\n }\n }\n\n /**\n * Navigates the flow to the previous step if one exists. This will mark that step started, but will not complete the previous step.\n */\n public async back(properties?: Record<string | number, any>) {\n const previousStep = this.getStepByIndex(this.getCurrentStepIndex() - 1)\n if (previousStep) {\n await previousStep.start(properties)\n }\n }\n\n /**\n * Restarts the flow/marks it not started\n */\n public async restart() {\n await this.fetch('/flowResponses', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n flowSlug: this.id,\n stepId: 'unknown',\n data: {},\n createdAt: new Date().toISOString(),\n actionType: NOT_STARTED_FLOW,\n }),\n })\n\n await this.refreshUserFlowState()\n this.initFromRawData(this.flowDataRaw)\n }\n\n /**\n * Get a step by index\n * @param index\n */\n public getStepByIndex(index: number): FlowStep | undefined {\n return this.steps.get(Array.from(this.steps.keys())[index])\n }\n\n /**\n * Gets current step\n */\n public getCurrentStep(): FlowStep {\n let maybeCurrentStepId = Array.from(this.steps.keys()).find(\n (key) => this.steps.get(key).isCompleted === false && this.steps.get(key).isHidden === false\n )\n Array.from(this.steps.keys()).forEach((key) => {\n if (\n this.steps.get(key).isStarted &&\n this.steps.get(key).lastActionAt &&\n this.steps.get(key).lastActionAt >\n (this.steps.get(maybeCurrentStepId)?.lastActionAt ?? new Date(0))\n ) {\n maybeCurrentStepId = key\n }\n })\n\n const currentStepId = maybeCurrentStepId ?? Array.from(this.steps.keys())[0]\n return this.steps.get(currentStepId)\n }\n\n /**\n * Get the index of the current step. Starts at 0\n */\n public getCurrentStepIndex(): number {\n const currentStep = this.getCurrentStep()\n return Array.from(this.steps.keys()).indexOf(currentStep.id)\n }\n\n /**\n * Get the number of completed steps for the current user in the current flow\n */\n public getNumberOfCompletedSteps(): number {\n return Array.from(this.steps.values()).filter((step) => step.isCompleted).length\n }\n\n /**\n * Get the number of available steps for the current user in the current flow. This is the number of steps that are not hidden.\n */\n public getNumberOfAvailableSteps(): number {\n return Array.from(this.steps.values()).filter((step) => !step.isHidden).length\n }\n\n /**\n * @ignore\n */\n public onStateChange(handler: (flow: Flow, previousFlow: Flow) => void) {\n const wrapperHandler = (flow: Flow, previousFlow: Flow) => {\n if (\n (flow.id === this.id &&\n (flow.isCompleted !== previousFlow.isCompleted ||\n flow.isStarted !== previousFlow.isStarted ||\n flow.isSkipped !== previousFlow.isSkipped ||\n flow.isVisible !== previousFlow.isVisible)) ||\n JSON.stringify(flow.steps) !== JSON.stringify(previousFlow.steps)\n ) {\n handler(flow, previousFlow)\n }\n }\n this.getGlobalState().onFlowStateChangeHandlerWrappers.set(handler, wrapperHandler)\n this.getGlobalState().onFlowStateChangeHandlers.push(wrapperHandler)\n }\n\n /**\n * @ignore\n */\n public removeStateChangeHandler(handler: (flow: Flow, previousFlow: Flow) => void) {\n const wrapperHandler = this.getGlobalState().onFlowStateChangeHandlerWrappers.get(handler)\n if (wrapperHandler) {\n this.getGlobalState().onFlowStateChangeHandlers =\n this.getGlobalState().onFlowStateChangeHandlers.filter((h) => h !== wrapperHandler)\n }\n }\n\n /**\n * @ignore\n */\n public applyVariables(variables: Record<string, any>) {\n // Replace ${variable} with the value of the variable\n const replaceVariables = (str: string) => {\n const matches = str.match(/\\${(.*?)}/g)\n if (matches) {\n matches.forEach((match) => {\n const variable = match.replace('${', '').replace('}', '')\n str = str.replace(match, variables[variable] ?? '')\n })\n }\n return str\n }\n\n this.title = replaceVariables(this.title ?? '')\n this.subtitle = replaceVariables(this.subtitle ?? '')\n this.steps.forEach((step) => {\n // Iterate over every string field in the step and replace variables\n Object.keys(step).forEach((key) => {\n if (typeof step[key] === 'string') {\n // @ts-ignore\n step[key] = replaceVariables(step[key])\n }\n })\n })\n\n this.lastUsedVariables = variables\n }\n\n /**\n * @ignore\n */\n private getUserFlowState(): UserFlowState {\n const userFlowStates = this.getGlobalState().userFlowStates\n return userFlowStates[this.id]\n }\n\n /**\n * @ignore\n */\n private async refreshUserFlowState() {\n await this.getGlobalState().refreshUserFlowStates()\n }\n}\n","import { FrigadeConfig, UserFlowState } from '../types'\nimport { clearCache, cloneFlow, isWeb, resetAllLocalStorage } from '../shared/utils'\nimport { Flow } from './flow'\nimport { FlowDataRaw, FlowStatus, FlowType, TriggerType } from './types'\nimport { frigadeGlobalState, getGlobalStateKey } from '../shared/state'\nimport { Fetchable } from '../shared/Fetchable'\n\nexport class Frigade extends Fetchable {\n /**\n * @ignore\n */\n private flows: Flow[] = []\n /**\n * @ignore\n */\n private initPromise: Promise<void>\n /**\n * @ignore\n */\n private hasFailed = false\n\n /**\n * @ignore\n */\n private visibilityChangeHandler = async () => {\n if (document.visibilityState === 'visible') {\n await this.refreshFlows()\n await this.refreshUserFlowStates()\n }\n }\n\n constructor(apiKey: string, config?: FrigadeConfig) {\n super({\n apiKey,\n ...config,\n })\n this.init(this.config)\n if (isWeb()) {\n document.addEventListener('visibilitychange', this.visibilityChangeHandler)\n }\n }\n\n /**\n * @ignore\n */\n destroy() {\n if (isWeb()) {\n document.removeEventListener('visibilitychange', this.visibilityChangeHandler)\n // Remove all other event listeners\n const globalStateKey = getGlobalStateKey(this.config)\n if (frigadeGlobalState[globalStateKey]) {\n frigadeGlobalState[globalStateKey].onFlowStateChangeHandlers = []\n }\n }\n }\n\n /**\n * @ignore\n */\n private async init(config: FrigadeConfig): Promise<void> {\n this.config = {\n ...this.config,\n ...config,\n }\n\n this.initPromise = (async () => {\n await this.refreshUserFlowStates()\n await this.refreshFlows()\n })()\n\n return this.initPromise\n }\n\n /**\n * Set the current user.\n * @param userId\n * @param properties\n */\n public async identify(userId: string, properties?: Record<string, any>): Promise<void> {\n this.config = { ...this.config, userId }\n await this.initIfNeeded()\n await this.fetch('/users', {\n method: 'POST',\n body: JSON.stringify({\n foreignId: this.config.userId,\n properties,\n }),\n })\n await this.refreshUserFlowStates()\n }\n\n /**\n * Set the group for the current user.\n * @param groupId\n * @param properties\n */\n public async group(groupId: string, properties?: Record<string, any>): Promise<void> {\n await this.initIfNeeded()\n this.config.groupId = groupId\n await this.fetch('/userGroups', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n properties,\n }),\n })\n await this.refreshUserFlowStates()\n }\n\n /**\n * Track an event for the current user (and group if set).\n * @param event\n * @param properties\n */\n public async track(event: string, properties?: Record<string, any>): Promise<void> {\n await this.initIfNeeded()\n if (!event) {\n console.error('Event name is required to track an event')\n return\n }\n if (this.config.userId && this.config.groupId) {\n await this.fetch('/userGroups', {\n method: 'POST',\n body: JSON.stringify({\n foreignUserId: this.config.userId,\n foreignUserGroupId: this.config.groupId,\n events: [\n {\n event,\n properties,\n },\n ],\n }),\n })\n } else if (this.config.userId) {\n await this.fetch('/users', {\n method: 'POST',\n body: JSON.stringify({\n foreignId: this.config.userId,\n events: [\n {\n event,\n properties,\n },\n ],\n }),\n })\n }\n }\n\n /**\n * @ignore\n */\n public isReady(): boolean {\n return Boolean(this.config.__instanceId && this.config.apiKey && this.initPromise)\n }\n\n /**\n * Get a Flow by its ID.\n * @param flowId\n */\n public async getFlow(flowId: string) {\n await this.initIfNeeded()\n\n return this.flows.find((flow) => flow.id == flowId)\n }\n\n public async getFlows() {\n await this.initIfNeeded()\n return this.flows\n }\n\n /**\n * Reload the current state of the flows by calling the Frigade API.\n * This will trigger all event handlers.\n */\n public async reload() {\n resetAllLocalStorage()\n clearCache()\n await this.refreshUserFlowStates()\n await this.refreshFlows()\n this.initPromise = null\n await this.init(this.config)\n // Trigger all event handlers\n this.flows.forEach((flow) => {\n this.getGlobalState().onFlowStateChangeHandlers.forEach((handler) => {\n const lastFlow = this.getGlobalState().previousFlows.get(flow.id)\n handler(flow, lastFlow)\n this.getGlobalState().previousFlows.set(flow.id, cloneFlow(flow))\n })\n })\n }\n\n /**\n * Event handler that captures all changes that happen to the state of the Flows.\n * @param handler\n */\n public onStateChange(handler: (flow: Flow, previousFlow?: Flow) => void) {\n this.getGlobalState().onFlowStateChangeHandlers.push(handler)\n }\n\n /**\n * Returns true if the JS SDK failed to connect to the Frigade API.\n */\n hasFailedToLoad() {\n return this.hasFailed\n }\n\n /**\n * Removes the given handler from the list of event handlers.\n * @param handler\n */\n public removeStateChangeHandler(handler: (flow: Flow, previousFlow?: Flow) => void) {\n this.getGlobalState().onFlowStateChangeHandlers =\n this.getGlobalState().onFlowStateChangeHandlers.filter((h) => h !== handler)\n }\n\n /**\n * @ignore\n */\n private async initIfNeeded() {\n if (this.initPromise !== null) {\n return this.initPromise\n } else {\n return this.init(this.config)\n }\n }\n\n /**\n * @ignore\n */\n private async refreshUserFlowStates(): Promise<void> {\n const globalStateKey = getGlobalStateKey(this.config)\n\n if (!frigadeGlobalState[globalStateKey]) {\n const that = this\n\n let validator = {\n set: function (target: any, key: any, value: any) {\n if (\n target[key] &&\n target[key].flowState &&\n (JSON.stringify(target[key].flowState) !== JSON.stringify(value?.flowState) ||\n JSON.stringify(target[key].stepStates) !== JSON.stringify(value?.stepStates) ||\n JSON.stringify(target[key].shouldTrigger) !== JSON.stringify(value?.shouldTrigger))\n ) {\n that.triggerEventHandlers(target[key])\n }\n\n target[key] = value\n return true\n },\n }\n\n frigadeGlobalState[globalStateKey] = {\n refreshUserFlowStates: async () => {},\n userFlowStates: new Proxy({}, validator),\n onFlowStateChangeHandlerWrappers: new Map(),\n onStepStateChangeHandlerWrappers: new Map(),\n onFlowStateChangeHandlers: [],\n previousFlows: new Map(),\n }\n\n if (this.config.__readOnly && this.config.__flowConfigOverrides) {\n this.mockUserFlowStates(globalStateKey)\n\n return\n }\n\n frigadeGlobalState[globalStateKey].refreshUserFlowStates = async () => {\n if (this.config.__readOnly) {\n return\n }\n\n const userFlowStatesRaw = await this.fetch(\n `/userFlowStates?foreignUserId=${encodeURIComponent(this.config.userId)}${\n this.config.groupId\n ? `&foreignUserGroupId=${encodeURIComponent(this.config.groupId)}`\n : ''\n }`\n )\n if (userFlowStatesRaw && userFlowStatesRaw.data) {\n let userFlowStates = userFlowStatesRaw.data as UserFlowState[]\n userFlowStates.forEach((userFlowState) => {\n let shouldReload = false\n const before = frigadeGlobalState[globalStateKey].userFlowStates[userFlowState.flowId]\n\n // Special case: for flows that show up based on targeting logic/rules, we need to check if the flow should be triggered\n if (before && before.shouldTrigger == false && userFlowState.shouldTrigger == true) {\n shouldReload = true\n }\n frigadeGlobalState[globalStateKey].userFlowStates[userFlowState.flowId] = userFlowState\n if (shouldReload) {\n this.flows.forEach((flow) => {\n if (flow.id == userFlowState.flowId) {\n flow.reload()\n this.triggerEventHandlers(\n frigadeGlobalState[globalStateKey].userFlowStates[flow.id]\n )\n }\n })\n }\n })\n this.hasFailed = false\n } else {\n this.hasFailed = true\n }\n }\n }\n\n await frigadeGlobalState[globalStateKey].refreshUserFlowStates()\n }\n\n /**\n * @ignore\n */\n private async refreshFlows() {\n this.flows = []\n\n if (this.config.__flowConfigOverrides) {\n this.mockFlowConfigs()\n return\n }\n\n const flowDataRaw = await this.fetch('/flows')\n if (flowDataRaw && flowDataRaw.data) {\n let flowDatas = flowDataRaw.data as FlowDataRaw[]\n flowDatas.forEach((flowData) => {\n this.flows.push(new Flow(this.config, flowData))\n this.getGlobalState().previousFlows.set(\n flowData.slug,\n cloneFlow(this.flows[this.flows.length - 1])\n )\n })\n } else {\n this.hasFailed = true\n }\n }\n\n /**\n * @ignore\n */\n private mockFlowConfigs() {\n Object.keys(this.config.__flowConfigOverrides).forEach((flowId) => {\n this.flows.push(\n new Flow(this.config, {\n id: -1,\n name: '',\n description: '',\n data: this.config.__flowConfigOverrides[flowId],\n createdAt: new Date().toISOString(),\n modifiedAt: new Date().toISOString(),\n slug: flowId,\n targetingLogic: '',\n type: FlowType.CHECKLIST,\n triggerType: TriggerType.MANUAL,\n status: FlowStatus.ACTIVE,\n version: 1,\n active: true,\n })\n )\n })\n }\n\n /**\n * @ignore\n */\n private mockUserFlowStates(globalStateKey: string) {\n Object.keys(this.config.__flowConfigOverrides).forEach((flowId) => {\n const parsed = JSON.parse(this.config.__flowConfigOverrides[flowId])\n frigadeGlobalState[globalStateKey].userFlowStates[flowId] = {\n flowId,\n flowState: 'NOT_STARTED_FLOW',\n lastStepId: null,\n userId: this.config.userId,\n foreignUserId: this.config.userId,\n stepStates:\n parsed?.steps?.reduce((acc, step) => {\n acc[step.id] = {\n stepId: step.id,\n flowSlug: flowId,\n actionType: 'NOT_STARTED_STEP',\n createdAt: new Date().toISOString(),\n blocked: false,\n hidden: false,\n }\n return acc\n }, {}) ?? {},\n shouldTrigger: false,\n }\n })\n }\n\n /**\n * @ignore\n */\n private async triggerEventHandlers(previousUserFlowState: UserFlowState) {\n if (previousUserFlowState) {\n this.flows.forEach((flow) => {\n if (flow.id == previousUserFlowState.flowId) {\n this.getGlobalState().onFlowStateChangeHandlers.forEach((handler) => {\n const lastFlow = this.getGlobalState().previousFlows.get(flow.id)\n handler(flow, lastFlow)\n this.getGlobalState().previousFlows.set(flow.id, cloneFlow(flow))\n })\n }\n })\n }\n }\n}\n"],"mappings":"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","names":["VERSION_NUMBER","fetch","uuidv4","frigadeGlobalState","getGlobalStateKey","internalConfig","Fetchable","config","generateGuestId","filteredConfig","_","v","path","options","getEmptyResponse","gracefulFetch","getHeaders","globalStateKey","getGlobalStateKey","frigadeGlobalState","Flow","Fetchable","config","flowDataRaw","flowDataYml","steps","userFlowState","COMPLETED_FLOW","STARTED_FLOW","SKIPPED_FLOW","hasCompleted","targetingShouldHideFlow","newSteps","step","index","userFlowStateStep","stepObj","COMPLETED_STEP","STARTED_STEP","properties","thisStep","copy","clone","updatedUserFlowState","isLastStep","nextStepId","lastAction","NOT_STARTED_STEP","handler","wrapperHandler","flow","previousStep","h","nextStep","NOT_STARTED_FLOW","maybeCurrentStepId","key","_a","currentStepId","currentStep","previousFlow","variables","replaceVariables","str","matches","match","variable","NOT_STARTED_STEP","COMPLETED_FLOW","SKIPPED_FLOW","STARTED_FLOW","NOT_STARTED_FLOW","COMPLETED_STEP","STARTED_STEP","LAST_POST_CALL_AT","LAST_POST_CALL_DATA","GUEST_KEY","GUEST_PREFIX","GET_CACHE_PREFIX","POST_CACHE_TTL_MS","LOCAL_STORAGE_PREFIX","cloneFlow","flow","newFlow","Flow","clone","obj","getHeaders","apiKey","VERSION_NUMBER","getLocalStorage","key","isWeb","setLocalStorage","value","clearCache","frigadeGlobalState","key","GET_CACHE_PREFIX","resetAllLocalStorage","isWeb","LOCAL_STORAGE_PREFIX","gracefulFetch","url","options","lastCallAtKey","LAST_POST_CALL_AT","lastCallDataKey","LAST_POST_CALL_DATA","lastCall","getLocalStorage","lastCallData","lastCallDate","POST_CACHE_TTL_MS","getEmptyResponse","setLocalStorage","response","fetch","error","body","e","generateGuestId","guestId","GUEST_KEY","GUEST_PREFIX","uuidv4","isWeb","Frigade","Fetchable","apiKey","config","isWeb","globalStateKey","getGlobalStateKey","frigadeGlobalState","userId","properties","groupId","event","flowId","flow","resetAllLocalStorage","clearCache","handler","lastFlow","cloneFlow","h","that","validator","target","key","value","userFlowStatesRaw","userFlowState","shouldReload","before","flowDataRaw","flowData","Flow","_a","parsed","acc","step","previousUserFlowState"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frigade/js",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.22",
|
|
4
4
|
"description": "The official Javascript SDK for Frigade.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,9 +18,8 @@
|
|
|
18
18
|
"dev": "tsup --watch",
|
|
19
19
|
"test": "jest",
|
|
20
20
|
"lint": "eslint --fix --ext .ts,.tsx .",
|
|
21
|
-
"build": "
|
|
22
|
-
"local-release": "tsup"
|
|
23
|
-
"copy-version-number": "node ./scripts/copy-version-number.js"
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"local-release": "tsup"
|
|
24
23
|
},
|
|
25
24
|
"repository": {
|
|
26
25
|
"type": "git",
|
|
@@ -54,8 +53,8 @@
|
|
|
54
53
|
"rimraf": "^5.0.0",
|
|
55
54
|
"ts-jest": "^29.1.0",
|
|
56
55
|
"tsup": "^6.7.0",
|
|
57
|
-
"typedoc": "^0.
|
|
58
|
-
"typedoc-plugin-markdown": "^3.
|
|
56
|
+
"typedoc": "^0.25.8",
|
|
57
|
+
"typedoc-plugin-markdown": "^3.17.1",
|
|
59
58
|
"typescript": "^4.9.4"
|
|
60
59
|
},
|
|
61
60
|
"author": "Frigade Inc.",
|