@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 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
@@ -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":"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","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":"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","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 flow.
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
- * Progress if the step is tied to another Frigade Flow through completionCriteria
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.yml
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
- * THe Flow ID / slug of the flow
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 from Step ID to step data. The `steps` array in `config.yml`
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 flow, if defined at the top level of `config.yml`
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 flow, if defined at the top level of `config.yml`
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 flow.
278
+ * The metadata of the Flow.
279
+ * @ignore
255
280
  */
256
281
  rawData: FlowDataRaw;
257
282
  /**
258
- * Whether the flow is completed or not
283
+ * Whether the Flow is completed or not.
259
284
  */
260
285
  isCompleted: boolean;
261
286
  /**
262
- * Whether the flow is started or not
287
+ * Whether the Flow is started or not.
263
288
  */
264
289
  isStarted: boolean;
265
290
  /**
266
- * Whether the flow has been skipped or not
291
+ * Whether the Flow has been skipped or not.
267
292
  */
268
293
  isSkipped: boolean;
269
294
  /**
270
- * Whether the flow is visible to the user based on the current user/group's state
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 of Frigade has failed to call the API.
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.20",
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": "yarn copy-version-number && tsup",
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.24.8",
58
- "typedoc-plugin-markdown": "^3.15.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.",