@schematichq/schematic-js 1.4.0 → 1.5.0
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/README.md +17 -0
- package/dist/schematic.browser.js +2 -2
- package/dist/schematic.cjs.js +649 -29
- package/dist/schematic.d.ts +160 -22
- package/dist/schematic.esm.js +649 -29
- package/package.json +15 -16
package/README.md
CHANGED
|
@@ -86,6 +86,23 @@ await schematic.checkFlag("some-flag-key");
|
|
|
86
86
|
schematic.cleanup();
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
+
### Credit balances
|
|
90
|
+
|
|
91
|
+
In websocket mode, the client also tracks the company's credit balances, keyed by credit ID, updating in real time as balances change:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// Read the balance for a single credit, or all balances for the current context
|
|
95
|
+
const balance = schematic.getCreditBalance("credit-id");
|
|
96
|
+
const balances = schematic.getCreditBalances();
|
|
97
|
+
|
|
98
|
+
// Subscribe to balance changes
|
|
99
|
+
const unsubscribe = schematic.addCreditBalanceListener((balances) => {
|
|
100
|
+
console.log(balances["credit-id"]?.settled);
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`settled` is the spendable balance and the number to display to end users.
|
|
105
|
+
|
|
89
106
|
## Fallback Behavior
|
|
90
107
|
|
|
91
108
|
The SDK includes built-in fallback behavior you can use to ensure your application continues to function even when unable to reach Schematic (e.g., during service disruptions or network issues).
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";(()=>{var
|
|
2
|
-
`)===0?m.substr(1,m.length):m}).forEach(function(m){var g=m.split(":"),c=g.shift().trim();if(c){var G=g.join(":").trim();try{o.append(c,G)}catch(X){console.warn("Response "+X.message)}}}),o}J.call(_.prototype);function S(a,o){if(!(this instanceof S))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');if(o||(o={}),this.type="default",this.status=o.status===void 0?200:o.status,this.status<200||this.status>599)throw new RangeError("Failed to construct 'Response': The status provided (0) is outside the range [200, 599].");this.ok=this.status>=200&&this.status<300,this.statusText=o.statusText===void 0?"":""+o.statusText,this.headers=new y(o.headers),this.url=o.url||"",this._initBody(a)}J.call(S.prototype),S.prototype.clone=function(){return new S(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new y(this.headers),url:this.url})},S.error=function(){var a=new S(null,{status:200,statusText:""});return a.ok=!1,a.status=0,a.type="error",a};var Me=[301,302,303,307,308];S.redirect=function(a,o){if(Me.indexOf(o)===-1)throw new RangeError("Invalid status code");return new S(null,{status:o,headers:{location:a}})},t.DOMException=i.DOMException;try{new t.DOMException}catch{t.DOMException=function(o,d){this.message=o,this.name=d;var m=Error(o);this.stack=m.stack},t.DOMException.prototype=Object.create(Error.prototype),t.DOMException.prototype.constructor=t.DOMException}function K(a,o){return new Promise(function(d,m){var g=new _(a,o);if(g.signal&&g.signal.aborted)return m(new t.DOMException("Aborted","AbortError"));var c=new XMLHttpRequest;function G(){c.abort()}c.onload=function(){var h={statusText:c.statusText,headers:Le(c.getAllResponseHeaders()||"")};g.url.indexOf("file://")===0&&(c.status<200||c.status>599)?h.status=200:h.status=c.status,h.url="responseURL"in c?c.responseURL:h.headers.get("X-Request-URL");var b="response"in c?c.response:c.responseText;setTimeout(function(){d(new S(b,h))},0)},c.onerror=function(){setTimeout(function(){m(new TypeError("Network request failed"))},0)},c.ontimeout=function(){setTimeout(function(){m(new TypeError("Network request timed out"))},0)},c.onabort=function(){setTimeout(function(){m(new t.DOMException("Aborted","AbortError"))},0)};function X(h){try{return h===""&&i.location.href?i.location.href:h}catch{return h}}if(c.open(g.method,X(g.url),!0),g.credentials==="include"?c.withCredentials=!0:g.credentials==="omit"&&(c.withCredentials=!1),"responseType"in c&&(r.blob?c.responseType="blob":r.arrayBuffer&&(c.responseType="arraybuffer")),o&&typeof o.headers=="object"&&!(o.headers instanceof y||i.Headers&&o.headers instanceof i.Headers)){var le=[];Object.getOwnPropertyNames(o.headers).forEach(function(h){le.push(u(h)),c.setRequestHeader(h,f(o.headers[h]))}),g.headers.forEach(function(h,b){le.indexOf(b)===-1&&c.setRequestHeader(b,h)})}else g.headers.forEach(function(h,b){c.setRequestHeader(b,h)});g.signal&&(g.signal.addEventListener("abort",G),c.onreadystatechange=function(){c.readyState===4&&g.signal.removeEventListener("abort",G)}),c.send(typeof g._bodyInit>"u"?null:g._bodyInit)})}return K.polyfill=!0,i.fetch||(i.fetch=K,i.Headers=y,i.Request=_,i.Response=S),t.Headers=y,t.Request=_,t.Response=S,t.fetch=K,t})({})})(typeof self<"u"?self:ce)});var D=[];for(let n=0;n<256;++n)D.push((n+256).toString(16).slice(1));function de(n,e=0){return(D[n[e+0]]+D[n[e+1]]+D[n[e+2]]+D[n[e+3]]+"-"+D[n[e+4]]+D[n[e+5]]+"-"+D[n[e+6]]+D[n[e+7]]+"-"+D[n[e+8]]+D[n[e+9]]+"-"+D[n[e+10]]+D[n[e+11]]+D[n[e+12]]+D[n[e+13]]+D[n[e+14]]+D[n[e+15]]).toLowerCase()}var Y,Xe=new Uint8Array(16);function Z(){if(!Y){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");Y=crypto.getRandomValues.bind(crypto)}return Y(Xe)}var Ye=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),j={randomUUID:Ye};function Ze(n,e,t){n=n||{};let i=n.random??n.rng?.()??Z();if(i.length<16)throw new Error("Random bytes length must be >= 16");if(i[6]=i[6]&15|64,i[8]=i[8]&63|128,e){if(t=t||0,t<0||t+16>e.length)throw new RangeError(`UUID byte range ${t}:${t+15} is out of buffer bounds`);for(let r=0;r<16;++r)e[t+r]=i[r];return e}return de(i)}function je(n,e,t){return j.randomUUID&&!e&&!n?j.randomUUID():Ze(n,e,t)}var C=je;var Cm=Ke(ue());function ne(n){return Rt(n,!1)}function Rt(n,e){return n}function Pe(n){return _t(n,!1)}function _t(n,e){return n==null?n:{allocation:n.allocation==null?void 0:n.allocation,creditId:n.credit_id==null?void 0:n.credit_id,creditRemaining:n.credit_remaining==null?void 0:n.credit_remaining,creditTotal:n.credit_total==null?void 0:n.credit_total,creditUsed:n.credit_used==null?void 0:n.credit_used,eventName:n.event_name==null?void 0:n.event_name,featureId:n.feature_id,featureKey:n.feature_key,metricPeriod:n.metric_period==null?void 0:n.metric_period,metricResetAt:n.metric_reset_at==null?void 0:new Date(n.metric_reset_at),monthReset:n.month_reset==null?void 0:n.month_reset,softLimit:n.soft_limit==null?void 0:n.soft_limit,usage:n.usage==null?void 0:n.usage,valueType:ne(n.value_type)}}function N(n){return St(n,!1)}function St(n,e){return n==null?n:{companyId:n.company_id==null?void 0:n.company_id,entitlement:n.entitlement==null?void 0:Pe(n.entitlement),error:n.error==null?void 0:n.error,featureAllocation:n.feature_allocation==null?void 0:n.feature_allocation,featureUsage:n.feature_usage==null?void 0:n.feature_usage,featureUsageEvent:n.feature_usage_event==null?void 0:n.feature_usage_event,featureUsagePeriod:n.feature_usage_period==null?void 0:n.feature_usage_period,featureUsageResetAt:n.feature_usage_reset_at==null?void 0:new Date(n.feature_usage_reset_at),flag:n.flag,flagId:n.flag_id==null?void 0:n.flag_id,reason:n.reason,ruleId:n.rule_id==null?void 0:n.rule_id,ruleType:n.rule_type==null?void 0:n.rule_type,userId:n.user_id==null?void 0:n.user_id,value:n.value}}function re(n){return bt(n,!1)}function bt(n,e){return n==null?n:{data:N(n.data),params:n.params}}function _e(n){return Ct(n,!1)}function Ct(n,e){return n}function I(n){return xt(n,!1)}function xt(n,e){return n==null?n:{id:n.id,name:n.name,trialEndDate:n.trial_end_date==null?void 0:new Date(n.trial_end_date),trialStatus:n.trial_status==null?void 0:_e(n.trial_status)}}function ie(n){return Bt(n,!1)}function Bt(n,e){return n==null?n:{flags:n.flags.map(N),plan:n.plan==null?void 0:I(n.plan)}}function ae(n){return Ft(n,!1)}function Ft(n,e){return n==null?n:{data:ie(n.data),params:n.params}}function L(n){return Jt(n,!1)}function Jt(n,e=!1){return n==null?n:{company_id:n.companyId,error:n.error,flag_id:n.flagId,flag_key:n.flagKey,reason:n.reason,req_company:n.reqCompany,req_user:n.reqUser,rule_id:n.ruleId,user_id:n.userId,value:n.value}}var oe=n=>{let{companyId:e,entitlement:t,error:i,featureAllocation:r,featureUsage:l,featureUsageEvent:s,featureUsagePeriod:p,featureUsageResetAt:u,flag:f,flagId:T,reason:y,ruleId:P,ruleType:O,userId:A,value:w}=N(n),Q=!w&&(O=="company_override_usage_exceeded"||O=="plan_entitlement_usage_exceeded"),F=t?.allocation??r,J=t?.usage??l,V=t?.eventName??s,U=t?.metricPeriod??p,_=t?.metricResetAt??u;return{featureUsageExceeded:Q,companyId:e??void 0,creditRemaining:t?.creditRemaining==null?void 0:t.creditRemaining,error:i??void 0,featureAllocation:F??void 0,featureUsage:J??void 0,featureUsageEvent:V??void 0,featureUsagePeriod:U??void 0,featureUsageResetAt:_??void 0,flag:f,flagId:T??void 0,reason:y,ruleId:P??void 0,ruleType:O??void 0,softLimit:t?.softLimit==null?void 0:t.softLimit,userId:A??void 0,value:w}},Ve=n=>{let{id:e,name:t,trialEndDate:i,trialStatus:r}=I(n);return{id:e,name:t,trialEndDate:i??void 0,trialStatus:r??void 0}};function R(n){let e=Object.keys(n).reduce((t,i)=>{let l=Object.keys(n[i]||{}).sort().reduce((s,p)=>(s[p]=n[i][p],s),{});return t[i]=l,t},{});return JSON.stringify(e)}var se="1.4.0";var Ue="schematicId";var H=class{additionalHeaders={};apiKey;apiUrl="https://api.schematichq.com";conn=null;context={};debugEnabled=!1;offlineEnabled=!1;eventQueue;contextDependentEventQueue;eventUrl="https://c.schematichq.com";flagCheckListeners={};flagValueListeners={};isPending=!0;isPendingListeners=new Set;planListeners=new Set;storage;useWebSocket=!1;checks={};featureUsageEventMap={};planChecks={};webSocketUrl="wss://api.schematichq.com";webSocketConnectionTimeout=1e4;webSocketReconnect=!0;webSocketMaxReconnectAttempts=7;webSocketMaxConnectionAttempts=3;webSocketInitialRetryDelay=1e3;webSocketMaxRetryDelay=3e4;wsReconnectAttempts=0;wsReconnectTimer=null;wsIntentionalDisconnect=!1;currentWebSocket=null;isConnecting=!1;maxEventQueueSize=100;maxEventRetries=5;eventRetryInitialDelay=1e3;eventRetryMaxDelay=3e4;retryTimer=null;flagValueDefaults={};flagCheckDefaults={};fallbackCheckCache={};constructor(e,t){if(this.apiKey=e,this.eventQueue=[],this.contextDependentEventQueue=[],this.useWebSocket=t?.useWebSocket??!1,this.debugEnabled=t?.debug??!1,this.offlineEnabled=t?.offline??!1,typeof window<"u"&&typeof window.location<"u"){let i=new URLSearchParams(window.location.search),r=i.get("schematic_debug");r!==null&&(r===""||r==="true"||r==="1")&&(this.debugEnabled=!0);let l=i.get("schematic_offline");l!==null&&(l===""||l==="true"||l==="1")&&(this.offlineEnabled=!0,this.debugEnabled=!0)}if(this.offlineEnabled&&t?.debug!==!1&&(this.debugEnabled=!0),this.offlineEnabled&&this.setIsPending(!1),this.additionalHeaders={"X-Schematic-Client-Version":`schematic-js@${se}`,...t?.additionalHeaders??{}},t?.storage)this.storage=t.storage;else try{typeof localStorage<"u"&&(this.storage=localStorage)}catch{}t?.apiUrl!==void 0&&(this.apiUrl=t.apiUrl),t?.eventUrl!==void 0&&(this.eventUrl=t.eventUrl),t?.webSocketUrl!==void 0&&(this.webSocketUrl=t.webSocketUrl),t?.webSocketConnectionTimeout!==void 0&&(this.webSocketConnectionTimeout=t.webSocketConnectionTimeout),t?.webSocketReconnect!==void 0&&(this.webSocketReconnect=t.webSocketReconnect),t?.webSocketMaxReconnectAttempts!==void 0&&(this.webSocketMaxReconnectAttempts=t.webSocketMaxReconnectAttempts),t?.webSocketInitialRetryDelay!==void 0&&(this.webSocketInitialRetryDelay=t.webSocketInitialRetryDelay),t?.webSocketMaxRetryDelay!==void 0&&(this.webSocketMaxRetryDelay=t.webSocketMaxRetryDelay),t?.maxEventQueueSize!==void 0&&(this.maxEventQueueSize=t.maxEventQueueSize),t?.maxEventRetries!==void 0&&(this.maxEventRetries=t.maxEventRetries),t?.eventRetryInitialDelay!==void 0&&(this.eventRetryInitialDelay=t.eventRetryInitialDelay),t?.eventRetryMaxDelay!==void 0&&(this.eventRetryMaxDelay=t.eventRetryMaxDelay),t?.flagValueDefaults!==void 0&&(this.flagValueDefaults=t.flagValueDefaults),t?.flagCheckDefaults!==void 0&&(this.flagCheckDefaults=t.flagCheckDefaults),typeof window<"u"&&window?.addEventListener&&(window.addEventListener("beforeunload",()=>{this.flushEventQueue(),this.flushContextDependentEventQueue()}),this.useWebSocket&&(window.addEventListener("offline",()=>{this.debug("Browser went offline, closing WebSocket connection"),this.handleNetworkOffline()}),window.addEventListener("online",()=>{this.debug("Browser came online, attempting to reconnect WebSocket"),this.handleNetworkOnline()}))),this.offlineEnabled?this.debug("Initialized with offline mode enabled - no network requests will be made"):this.debugEnabled&&this.debug("Initialized with debug mode enabled")}resolveFallbackValue(e,t){return t!==void 0?t:e in this.flagCheckDefaults?this.flagCheckDefaults[e].value:e in this.flagValueDefaults?this.flagValueDefaults[e]:!1}resolveFallbackCheckFlagReturn(e,t,i="Fallback value used",r){if(t!==void 0)return{flag:e,value:t,reason:i,error:r};if(e in this.flagCheckDefaults){let l=this.flagCheckDefaults[e];return{...l,flag:e,reason:r!==void 0?i:l.reason,error:r}}return e in this.flagValueDefaults?{flag:e,value:this.flagValueDefaults[e],reason:i,error:r}:{flag:e,value:!1,reason:i,error:r}}async checkFlag(e){let{fallback:t,key:i}=e,r=e.context||this.context,l=R(r);if(this.debug(`checkFlag: ${i}`,{context:r,fallback:t}),this.isOffline()){let s=this.resolveFallbackCheckFlagReturn(i,t,"Offline mode - using initialization defaults");return this.debug(`checkFlag offline result: ${i}`,{value:s.value,offlineMode:!0}),s.value}if(!this.useWebSocket){let s=`${this.apiUrl}/flags/${i}/check`;return fetch(s,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:JSON.stringify(r)}).then(p=>{if(!p.ok)throw new Error("Network response was not ok");return p.json()}).then(p=>{let u=re(p);this.debug(`checkFlag result: ${i}`,u);let f=oe(u.data);return typeof f.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(f),this.submitFlagCheckEvent(i,f,r),f.value}).catch(p=>{console.warn("There was a problem with the fetch operation:",p);let u=this.resolveFallbackCheckFlagReturn(i,t,"API request failed",p instanceof Error?p.message:String(p));return this.submitFlagCheckEvent(i,u,r),u.value})}try{let s=this.checks[l];if(this.conn!==null&&typeof s<"u"&&typeof s[i]<"u")return this.debug(`checkFlag cached result: ${i}`,s[i]),s[i].value;if(this.isOffline())return this.resolveFallbackValue(i,t);try{await this.setContext(r)}catch(T){console.warn("WebSocket connection failed, using fallback value:",T);let y=this.resolveFallbackCheckFlagReturn(i,t,"WebSocket connection failed",T instanceof Error?T.message:String(T));return this.submitFlagCheckEvent(i,y,r),y.value}let u=(this.checks[l]??{})[i],f=u?.value??this.resolveFallbackValue(i,t);if(this.debug(`checkFlag WebSocket result: ${i}`,typeof u<"u"?u:{value:f,fallbackUsed:!0}),typeof u<"u")this.submitFlagCheckEvent(i,u,r);else{let T=this.resolveFallbackCheckFlagReturn(i,t,"No flag values available");this.submitFlagCheckEvent(i,T,r)}return f}catch(s){console.error("Unexpected error in checkFlag:",s);let p=this.resolveFallbackCheckFlagReturn(i,t,"Unexpected error in flag check",s instanceof Error?s.message:String(s));return this.submitFlagCheckEvent(i,p,r),p.value}}debug(e,...t){this.debugEnabled&&console.log(`[Schematic] ${e}`,...t)}createPersistentMessageHandler(e){return t=>{let i=JSON.parse(t.data);if(this.debug("WebSocket persistent message received:",i),R(e)in this.checks||(this.checks[R(e)]={}),(i.flags??[]).forEach(r=>{let l=oe(r),s=R(e);this.checks[s]===void 0&&(this.checks[s]={}),this.checks[s][l.flag]=l,typeof l.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(l),((this.flagCheckListeners[r.flag]?.size??0)>0||(this.flagValueListeners[r.flag]?.size??0)>0)&&this.submitFlagCheckEvent(l.flag,l,e),this.debug(`WebSocket flag update received. Notifying listeners for ${r.flag}`,{flag:r.flag,value:l.value,flagCheck:l}),this.notifyFlagCheckListeners(r.flag,l),this.notifyFlagValueListeners(r.flag,l.value)}),i.plan!==void 0&&i.plan!==null){let r=Ve(i.plan),l=R(e);this.planChecks[l]=r,this.debug("WebSocket plan update received. Notifying listeners",{plan:r}),this.notifyPlanListeners(r)}this.flushContextDependentEventQueue(),this.setIsPending(!1)}}isOffline(){return this.offlineEnabled}submitFlagCheckEvent(e,t,i){let r={flagKey:e,value:t.value,reason:t.reason,flagId:t.flagId,ruleId:t.ruleId,companyId:t.companyId,userId:t.userId,error:t.error,reqCompany:i.company,reqUser:i.user};return this.debug("submitting flag check event:",r),this.handleEvent("flag_check",L(r))}checkFlags=async e=>{if(e=e||this.context,this.debug("checkFlags",{context:e}),this.isOffline())return this.debug("checkFlags offline result: returning empty object"),{};let t=`${this.apiUrl}/flags/check`,i=JSON.stringify(e);return fetch(t,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:i}).then(r=>{if(!r.ok)throw new Error("Network response was not ok");return r.json()}).then(r=>{let l=ae(r);return this.debug("checkFlags result:",l),(l?.data?.flags??[]).reduce((s,p)=>(s[p.flag]=p.value,s),{})}).catch(r=>(console.warn("There was a problem with the fetch operation:",r),{}))};identify=e=>(this.debug("identify:",e),this.setContext({company:e.company?.keys,user:e.keys}).catch(t=>{console.warn("Error setting context:",t)}),this.handleEvent("identify",e));setContext=async e=>{if(this.isOffline()||!this.useWebSocket)return this.context=e,this.flushContextDependentEventQueue(),this.setIsPending(!1),Promise.resolve();if(!(R(e)===R(this.context)&&this.conn!==null&&!this.isPending))try{if(this.setIsPending(!0),!this.conn){if(this.isConnecting){for(this.debug("Connection already in progress, waiting for it to complete");this.isConnecting&&this.conn===null;)await new Promise(i=>setTimeout(i,10));if(this.conn!==null){let i=await this.conn;await this.wsSendMessage(i,e);return}}this.wsReconnectTimer!==null&&(this.debug("Cancelling scheduled reconnection, connecting immediately"),clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.isConnecting=!0;try{this.conn=this.wsConnect();let i=await this.conn;this.isConnecting=!1,await this.wsSendMessage(i,e);return}catch(i){throw this.isConnecting=!1,i}}let t=await this.conn;await this.wsSendMessage(t,e)}catch(t){console.warn("Failed to establish WebSocket connection:",t),this.context=e,this.flushContextDependentEventQueue(),this.setIsPending(!1),this.attemptReconnect()}};track=e=>{let{company:t,user:i,event:r,traits:l,quantity:s=1}=e;if(!this.hasContext(t,i)){this.debug(`track: queuing event "${r}" until context is available`);let u={api_key:this.apiKey,body:{company:t,event:r,traits:l??{},user:i,quantity:s},sent_at:new Date().toISOString(),tracker_event_id:C(),tracker_user_id:this.getAnonymousId(),type:"track"};return this.contextDependentEventQueue.push(u),Promise.resolve()}let p={company:t??this.context.company,event:r,traits:l??{},user:i??this.context.user,quantity:s};return this.debug("track:",p),r in this.featureUsageEventMap&&this.optimisticallyUpdateFeatureUsage(r,s),this.handleEvent("track",p)};optimisticallyUpdateFeatureUsage=(e,t=1)=>{let i=this.featureUsageEventMap[e];i!=null&&(this.debug(`Optimistically updating feature usage for event: ${e}`,{quantity:t}),Object.entries(i).forEach(([r,l])=>{if(l===void 0)return;let s={...l};if(typeof s.featureUsage=="number"){if(s.featureUsage+=t,typeof s.featureAllocation=="number"){let u=s.featureUsageExceeded===!0,f=s.featureUsage>=s.featureAllocation;f!==u&&(s.featureUsageExceeded=f,f&&(s.value=!1),this.debug(`Usage limit status changed for flag: ${r}`,{was:u?"exceeded":"within limits",now:f?"exceeded":"within limits",featureUsage:s.featureUsage,featureAllocation:s.featureAllocation,value:s.value}))}this.featureUsageEventMap[e]!==void 0&&(this.featureUsageEventMap[e][r]=s);let p=R(this.context);this.checks[p]!==void 0&&this.checks[p]!==null&&(this.checks[p][r]=s),this.notifyFlagCheckListeners(r,s),this.notifyFlagValueListeners(r,s.value)}}))};hasContext=(e,t)=>{let i=e!=null&&Object.keys(e).length>0||t!=null&&Object.keys(t).length>0,r=this.context.company!==void 0&&this.context.company!==null&&Object.keys(this.context.company).length>0||this.context.user!==void 0&&this.context.user!==null&&Object.keys(this.context.user).length>0;return i||r};flushContextDependentEventQueue=()=>{for(this.debug(`flushing ${this.contextDependentEventQueue.length} context-dependent events`);this.contextDependentEventQueue.length>0;){let e=this.contextDependentEventQueue.shift();if(e)if(e.type==="track"&&typeof e.body=="object"&&e.body!==null){let t=e.body,i={...t,company:t.company??this.context.company,user:t.user??this.context.user},r={...e,body:i,sent_at:new Date().toISOString()};this.sendEvent(r)}else this.sendEvent(e)}};startRetryTimer=()=>{this.retryTimer===null&&(this.retryTimer=setInterval(()=>{this.flushEventQueue().catch(e=>{this.debug("Error in retry timer flush:",e)}),this.eventQueue.length===0&&this.stopRetryTimer()},5e3),this.debug("Started retry timer"))};stopRetryTimer=()=>{this.retryTimer!==null&&(clearInterval(this.retryTimer),this.retryTimer=null,this.debug("Stopped retry timer"))};flushEventQueue=async()=>{if(this.eventQueue.length===0)return;let e=Date.now(),t=[],i=[];for(let r of this.eventQueue)r.next_retry_at===void 0||r.next_retry_at<=e?t.push(r):i.push(r);if(t.length===0){this.debug(`No events ready for retry yet (${i.length} still in backoff)`);return}this.debug(`Flushing event queue: ${t.length} ready, ${i.length} waiting`),this.eventQueue=i;for(let r of t)try{await this.sendEvent(r),this.debug("Queued event sent successfully:",r.type)}catch(l){this.debug("Failed to send queued event:",l)}};getAnonymousId=()=>{if(!this.storage)return C();let e=this.storage.getItem(Ue);if(typeof e<"u")return e;let t=C();return this.storage.setItem(Ue,t),t};handleEvent=(e,t)=>{let i={api_key:this.apiKey,body:t,sent_at:new Date().toISOString(),tracker_event_id:C(),tracker_user_id:this.getAnonymousId(),type:e};return typeof document<"u"&&document?.hidden?this.storeEvent(i):this.sendEvent(i)};sendEvent=async e=>{let t=`${this.eventUrl}/e`,i=JSON.stringify(e);if(this.debug("sending event:",{url:t,event:e}),this.isOffline())return this.debug("event not sent (offline mode):",{event:e}),Promise.resolve();try{let r=await fetch(t,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8"},body:i});if(!r.ok)throw new Error(`HTTP ${r.status}: ${r.statusText}`);this.debug("event sent:",{status:r.status,statusText:r.statusText})}catch(r){let l=(e.retry_count??0)+1;if(l<=this.maxEventRetries){this.debug(`Event failed to send (attempt ${l}/${this.maxEventRetries}), queueing for retry:`,r);let s=this.eventRetryInitialDelay*Math.pow(2,l-1),p=Math.min(s,this.eventRetryMaxDelay),u=Date.now()+p,f={...e,retry_count:l,next_retry_at:u};this.eventQueue.length<this.maxEventQueueSize?(this.eventQueue.push(f),this.debug(`Event queued for retry in ${p}ms (${this.eventQueue.length}/${this.maxEventQueueSize})`)):(this.debug(`Event queue full (${this.maxEventQueueSize}), dropping oldest event`),this.eventQueue.shift(),this.eventQueue.push(f)),this.startRetryTimer()}else this.debug(`Event failed permanently after ${this.maxEventRetries} attempts, dropping:`,r)}return Promise.resolve()};storeEvent=e=>(this.eventQueue.push(e),Promise.resolve());forceReconnect=async()=>this.reconnect({force:!0});reconnectIfNeeded=async()=>this.reconnect({force:!1});reconnect=async e=>{let{force:t}=e,i=t?"forceReconnect":"reconnectIfNeeded";if(this.isOffline())return this.debug(`${i}: skipped (offline mode)`),Promise.resolve();if(!t&&this.conn!==null)try{if((await this.conn).readyState===WebSocket.OPEN)return this.debug(`${i}: connection is healthy, skipping`),Promise.resolve()}catch{}if(this.debug(`${i}: ${t?"forcing immediate reconnection":"reconnecting"}`),this.wsIntentionalDisconnect=!1,this.wsReconnectTimer!==null&&(this.debug(`${i}: cancelling pending reconnection timer`),clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.wsReconnectAttempts=0,this.conn!==null){this.debug(`${i}: closing existing connection`);try{let r=await this.conn;this.currentWebSocket===r&&(this.currentWebSocket=null),(r.readyState===WebSocket.OPEN||r.readyState===WebSocket.CONNECTING)&&r.close()}catch(r){this.debug(`${i}: error closing existing connection:`,r)}this.conn=null,this.isConnecting=!1}if(this.context.company!==void 0||this.context.user!==void 0){this.debug(`${i}: reconnecting with existing context`);try{this.isConnecting=!0,this.conn=this.wsConnect();let r=await this.conn;this.isConnecting=!1,await this.wsSendMessage(r,this.context,!0),this.debug(`${i}: reconnection successful`)}catch(r){this.isConnecting=!1,this.debug(`${i}: reconnection failed:`,r)}}else this.debug(`${i}: no context set, skipping reconnection`);return Promise.resolve()};cleanup=async()=>{if(this.isOffline())return this.debug("cleanup: skipped (offline mode)"),Promise.resolve();if(this.wsIntentionalDisconnect=!0,this.wsReconnectTimer!==null&&(clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.stopRetryTimer(),this.conn)try{let e=await this.conn;this.currentWebSocket===e&&(this.debug("Cleaning up current websocket tracking"),this.currentWebSocket=null),e.close()}catch(e){console.warn("Error during cleanup:",e)}finally{this.conn=null,this.currentWebSocket=null,this.isConnecting=!1}};calculateReconnectDelay=()=>{let e=this.webSocketInitialRetryDelay*Math.pow(2,this.wsReconnectAttempts),t=Math.min(e,this.webSocketMaxRetryDelay),i=Math.random()*t*.5,r=t+i;return this.debug(`Reconnect delay calculated: ${r.toFixed(0)}ms (attempt ${this.wsReconnectAttempts+1}/${this.webSocketMaxReconnectAttempts})`),r};handleNetworkOffline=async()=>{if(this.conn!==null){try{let e=await this.conn;(e.readyState===WebSocket.OPEN||e.readyState===WebSocket.CONNECTING)&&e.close()}catch(e){this.debug("Error closing connection on offline:",e)}this.conn=null}this.wsReconnectTimer!==null&&(clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null)};handleNetworkOnline=()=>{this.debug("Network online, attempting reconnection and flushing queued events"),this.wsReconnectAttempts=0,this.wsReconnectTimer!==null&&(clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.flushEventQueue().catch(e=>{this.debug("Error flushing event queue on network online:",e)}),this.attemptReconnect()};attemptReconnect=()=>{if(this.wsReconnectAttempts>=this.webSocketMaxReconnectAttempts){this.debug(`Maximum reconnection attempts (${this.webSocketMaxReconnectAttempts}) reached, giving up`);return}if(this.wsReconnectTimer!==null){this.debug("Reconnection attempt already scheduled, ignoring duplicate request");return}let e=this.calculateReconnectDelay();this.debug(`Scheduling reconnection attempt ${this.wsReconnectAttempts+1}/${this.webSocketMaxReconnectAttempts} in ${e.toFixed(0)}ms`),this.wsReconnectTimer=setTimeout(async()=>{this.wsReconnectTimer=null,this.wsReconnectAttempts++,this.debug(`Attempting to reconnect (attempt ${this.wsReconnectAttempts}/${this.webSocketMaxReconnectAttempts})`);try{if(this.conn!==null){this.debug("Cleaning up existing connection before reconnection");try{let t=await this.conn;this.currentWebSocket===t&&(this.debug("Existing websocket is current, will be replaced"),this.currentWebSocket=null),(t.readyState===WebSocket.OPEN||t.readyState===WebSocket.CONNECTING)&&t.close()}catch(t){this.debug("Error cleaning up existing connection:",t)}this.conn=null,this.currentWebSocket=null,this.isConnecting=!1}this.isConnecting=!0;try{this.conn=this.wsConnect();let t=await this.conn;this.isConnecting=!1,this.debug("Reconnection context check:",{hasCompany:this.context.company!==void 0,hasUser:this.context.user!==void 0,context:this.context}),this.context.company!==void 0||this.context.user!==void 0?(this.debug("Reconnected, force re-sending context"),await this.wsSendMessage(t,this.context,!0)):(this.debug("No context to re-send after reconnection - websocket ready for new context"),this.debug("Setting up tracking for reconnected websocket (no context to send)"),this.currentWebSocket=t),this.flushEventQueue().catch(i=>{this.debug("Error flushing event queue after websocket reconnection:",i)}),this.debug("Reconnection successful")}catch(t){throw this.isConnecting=!1,t}}catch(t){this.debug("Reconnection attempt failed:",t)}},e)};wsConnect=async()=>{if(this.isOffline())throw this.debug("wsConnect: skipped (offline mode)"),new Error("WebSocket connection skipped in offline mode");let e=null,t=this.webSocketMaxConnectionAttempts;for(let i=0;i<t;i++)try{let r=await this.wsConnectOnce();return this.wsReconnectAttempts=0,r}catch(r){if(e=r instanceof Error?r:new Error(String(r)),!(e.message==="WebSocket connection timeout"))throw this.debug("WebSocket connection failed with non-timeout error, not retrying:",e.message),e;if(i<t-1){let s=this.webSocketInitialRetryDelay*Math.pow(2,i),p=Math.min(s,this.webSocketMaxRetryDelay),u=p*.2*Math.random(),f=p+u;this.debug(`WebSocket connection timeout (attempt ${i+1}/${t}), retrying in ${f.toFixed(0)}ms`),await new Promise(T=>setTimeout(T,f))}else this.debug(`WebSocket connection timeout (attempt ${i+1}/${t}), no more retries`)}throw e??new Error("WebSocket connection failed")};wsConnectOnce=()=>new Promise((e,t)=>{let i=`${this.webSocketUrl}/flags/bootstrap?apiKey=${this.apiKey}`;this.debug("connecting to WebSocket:",i);let r=new WebSocket(i),l=Math.random().toString(36).substring(7);this.debug(`Creating WebSocket connection ${l} to ${i}`);let s=null,p=!1;s=setTimeout(()=>{p||(p=!0,this.debug(`WebSocket connection timeout after ${this.webSocketConnectionTimeout}ms`),r.close(),t(new Error("WebSocket connection timeout")))},this.webSocketConnectionTimeout),r.onopen=()=>{p||(p=!0,s!==null&&clearTimeout(s),this.wsIntentionalDisconnect=!1,this.debug(`WebSocket connection ${l} opened successfully`),e(r))},r.onerror=u=>{if(p)return;p=!0,s!==null&&clearTimeout(s),this.debug(`WebSocket connection ${l} error:`,u);let f=new Error("WebSocket connection failed during handshake");t(f)},r.onclose=()=>{s!==null&&clearTimeout(s),this.debug(`WebSocket connection ${l} closed`),this.conn=null,this.currentWebSocket===r&&(this.currentWebSocket=null,this.isConnecting=!1),!p&&!this.wsIntentionalDisconnect&&this.webSocketReconnect&&this.attemptReconnect()}});wsSendMessage=(e,t,i=!1)=>this.isOffline()?(this.debug("wsSendMessage: skipped (offline mode)"),this.setIsPending(!1),Promise.resolve()):new Promise((r,l)=>{if(!i&&R(t)==R(this.context))return this.debug("WebSocket context unchanged, skipping update"),r(this.setIsPending(!1));this.debug(i?"WebSocket force sending context (reconnection):":"WebSocket context updated:",t),this.context=t;let s=()=>{let p=!1,u=this.createPersistentMessageHandler(t),f=P=>{u(P),p||(p=!0,r())};e.addEventListener("message",f),e.addEventListener("close",P=>{p||(p=!0,P.code===4001?l(new Error(`Authentication failed: ${P.reason!==""?P.reason:"Invalid API key"}`)):l(new Error("WebSocket connection closed unexpectedly")))}),this.currentWebSocket=e;let T=this.additionalHeaders["X-Schematic-Client-Version"]??`schematic-js@${se}`,y={apiKey:this.apiKey,clientVersion:T,data:t};this.debug("WebSocket sending message:",y),e.send(JSON.stringify(y))};e.readyState===WebSocket.OPEN?(this.debug("WebSocket already open, sending message"),s()):e.readyState===WebSocket.CONNECTING?(this.debug("WebSocket connecting, waiting for open to send message"),e.addEventListener("open",s)):(this.debug("WebSocket is closed, cannot send message"),l("WebSocket is not open or connecting"))});getIsPending=()=>this.isPending;addIsPendingListener=e=>(this.isPendingListeners.add(e),()=>{this.isPendingListeners.delete(e)});setIsPending=e=>{this.isPending!==e&&(this.isPending=e,this.isPendingListeners.forEach(t=>Qt(t,e)))};getPlan=()=>{let e=R(this.context);return this.planChecks[e]};getFlagCheck=e=>{let t=R(this.context),r=(this.checks[t]??{})[e];if(r!==void 0)return r;if(e in this.flagCheckDefaults||e in this.flagValueDefaults)return e in this.fallbackCheckCache||(this.fallbackCheckCache[e]=this.resolveFallbackCheckFlagReturn(e,void 0,"Default value used")),this.fallbackCheckCache[e]};getFlagValue=e=>{let t=R(this.context),r=(this.checks[t]??{})[e];if(r?.value!==void 0)return r.value;if(e in this.flagCheckDefaults||e in this.flagValueDefaults)return this.resolveFallbackValue(e)};addFlagValueListener=(e,t)=>(e in this.flagValueListeners||(this.flagValueListeners[e]=new Set),this.flagValueListeners[e].add(t),()=>{this.flagValueListeners[e].delete(t)});addFlagCheckListener=(e,t)=>(e in this.flagCheckListeners||(this.flagCheckListeners[e]=new Set),this.flagCheckListeners[e].add(t),()=>{this.flagCheckListeners[e].delete(t)});addPlanListener=e=>(this.planListeners.add(e),()=>{this.planListeners.delete(e)});notifyFlagCheckListeners=(e,t)=>{let i=this.flagCheckListeners?.[e]??[];i.size>0&&this.debug(`Notifying ${i.size} flag check listeners for ${e}`,t),typeof t.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(t),i.forEach(r=>Kt(r,t))};updateFeatureUsageEventMap=e=>{if(typeof e.featureUsageEvent!="string")return;let t=e.featureUsageEvent;(this.featureUsageEventMap[t]===void 0||this.featureUsageEventMap[t]===null)&&(this.featureUsageEventMap[t]={}),this.featureUsageEventMap[t]!==void 0&&(this.featureUsageEventMap[t][e.flag]=e),this.debug(`Updated featureUsageEventMap for event: ${t}, flag: ${e.flag}`,e)};notifyFlagValueListeners=(e,t)=>{let i=this.flagValueListeners?.[e]??[];i.size>0&&this.debug(`Notifying ${i.size} flag value listeners for ${e}`,{value:t}),i.forEach((r,l)=>{this.debug(`Calling listener ${l} for flag ${e}`,{flagKey:e,value:t}),Xt(r,t),this.debug(`Listener ${l} for flag ${e} completed`,{flagKey:e,value:t})})};notifyPlanListeners=e=>{let t=this.planListeners??[];t.size>0&&this.debug(`Notifying ${t.size} plan listeners`,{value:e}),t.forEach((i,r)=>{this.debug(`Calling listener ${r} for plan`,{value:e}),Yt(i,e),this.debug(`Listener ${r} for plan completed`,{value:e})})}},Qt=(n,e)=>{n.length>0?n(e):n()},Kt=(n,e)=>{n.length>0?n(e):n()},Xt=(n,e)=>{n.length>0?n(e):n()},Yt=(n,e)=>{n.length>0?n(e):n()};window.Schematic=H;})();
|
|
1
|
+
"use strict";(()=>{var lt=Object.create;var Pe=Object.defineProperty;var st=Object.getOwnPropertyDescriptor;var dt=Object.getOwnPropertyNames;var pt=Object.getPrototypeOf,ct=Object.prototype.hasOwnProperty;var ut=(n,e)=>()=>{try{return e||n((e={exports:{}}).exports,e),e.exports}catch(t){throw e=0,t}};var ft=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of dt(e))!ct.call(n,i)&&i!==t&&Pe(n,i,{get:()=>e[i],enumerable:!(r=st(e,i))||r.enumerable});return n};var yt=(n,e,t)=>(t=n!=null?lt(pt(n)):{},ft(e||!n||!n.__esModule?Pe(t,"default",{value:n,enumerable:!0}):t,n));var _e=ut(Re=>{(function(n){var e=(function(t){var r=typeof globalThis<"u"&&globalThis||typeof n<"u"&&n||typeof global<"u"&&global||{},i={searchParams:"URLSearchParams"in r,iterable:"Symbol"in r&&"iterator"in Symbol,blob:"FileReader"in r&&"Blob"in r&&(function(){try{return new Blob,!0}catch{return!1}})(),formData:"FormData"in r,arrayBuffer:"ArrayBuffer"in r};function o(a){return a&&DataView.prototype.isPrototypeOf(a)}if(i.arrayBuffer)var d=["[object Int8Array]","[object Uint8Array]","[object Uint8ClampedArray]","[object Int16Array]","[object Uint16Array]","[object Int32Array]","[object Uint32Array]","[object Float32Array]","[object Float64Array]"],l=ArrayBuffer.isView||function(a){return a&&d.indexOf(Object.prototype.toString.call(a))>-1};function p(a){if(typeof a!="string"&&(a=String(a)),/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(a)||a==="")throw new TypeError('Invalid character in header field name: "'+a+'"');return a.toLowerCase()}function c(a){return typeof a!="string"&&(a=String(a)),a}function y(a){var s={next:function(){var f=a.shift();return{done:f===void 0,value:f}}};return i.iterable&&(s[Symbol.iterator]=function(){return s}),s}function u(a){this.map={},a instanceof u?a.forEach(function(s,f){this.append(f,s)},this):Array.isArray(a)?a.forEach(function(s){if(s.length!=2)throw new TypeError("Headers constructor: expected name/value pair to be length 2, found"+s.length);this.append(s[0],s[1])},this):a&&Object.getOwnPropertyNames(a).forEach(function(s){this.append(s,a[s])},this)}u.prototype.append=function(a,s){a=p(a),s=c(s);var f=this.map[a];this.map[a]=f?f+", "+s:s},u.prototype.delete=function(a){delete this.map[p(a)]},u.prototype.get=function(a){return a=p(a),this.has(a)?this.map[a]:null},u.prototype.has=function(a){return this.map.hasOwnProperty(p(a))},u.prototype.set=function(a,s){this.map[p(a)]=c(s)},u.prototype.forEach=function(a,s){for(var f in this.map)this.map.hasOwnProperty(f)&&a.call(s,this.map[f],f,this)},u.prototype.keys=function(){var a=[];return this.forEach(function(s,f){a.push(f)}),y(a)},u.prototype.values=function(){var a=[];return this.forEach(function(s){a.push(s)}),y(a)},u.prototype.entries=function(){var a=[];return this.forEach(function(s,f){a.push([f,s])}),y(a)},i.iterable&&(u.prototype[Symbol.iterator]=u.prototype.entries);function R(a){if(!a._noBody){if(a.bodyUsed)return Promise.reject(new TypeError("Already read"));a.bodyUsed=!0}}function _(a){return new Promise(function(s,f){a.onload=function(){s(a.result)},a.onerror=function(){f(a.error)}})}function M(a){var s=new FileReader,f=_(s);return s.readAsArrayBuffer(a),f}function U(a){var s=new FileReader,f=_(s),g=/charset=([A-Za-z0-9_-]+)/.exec(a.type),T=g?g[1]:"utf-8";return s.readAsText(a,T),f}function ee(a){for(var s=new Uint8Array(a),f=new Array(s.length),g=0;g<s.length;g++)f[g]=String.fromCharCode(s[g]);return f.join("")}function I(a){if(a.slice)return a.slice(0);var s=new Uint8Array(a.byteLength);return s.set(new Uint8Array(a)),s.buffer}function A(){return this.bodyUsed=!1,this._initBody=function(a){this.bodyUsed=this.bodyUsed,this._bodyInit=a,a?typeof a=="string"?this._bodyText=a:i.blob&&Blob.prototype.isPrototypeOf(a)?this._bodyBlob=a:i.formData&&FormData.prototype.isPrototypeOf(a)?this._bodyFormData=a:i.searchParams&&URLSearchParams.prototype.isPrototypeOf(a)?this._bodyText=a.toString():i.arrayBuffer&&i.blob&&o(a)?(this._bodyArrayBuffer=I(a.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer])):i.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(a)||l(a))?this._bodyArrayBuffer=I(a):this._bodyText=a=Object.prototype.toString.call(a):(this._noBody=!0,this._bodyText=""),this.headers.get("content-type")||(typeof a=="string"?this.headers.set("content-type","text/plain;charset=UTF-8"):this._bodyBlob&&this._bodyBlob.type?this.headers.set("content-type",this._bodyBlob.type):i.searchParams&&URLSearchParams.prototype.isPrototypeOf(a)&&this.headers.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"))},i.blob&&(this.blob=function(){var a=R(this);if(a)return a;if(this._bodyBlob)return Promise.resolve(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(new Blob([this._bodyArrayBuffer]));if(this._bodyFormData)throw new Error("could not read FormData body as blob");return Promise.resolve(new Blob([this._bodyText]))}),this.arrayBuffer=function(){if(this._bodyArrayBuffer){var a=R(this);return a||(ArrayBuffer.isView(this._bodyArrayBuffer)?Promise.resolve(this._bodyArrayBuffer.buffer.slice(this._bodyArrayBuffer.byteOffset,this._bodyArrayBuffer.byteOffset+this._bodyArrayBuffer.byteLength)):Promise.resolve(this._bodyArrayBuffer))}else{if(i.blob)return this.blob().then(M);throw new Error("could not read as ArrayBuffer")}},this.text=function(){var a=R(this);if(a)return a;if(this._bodyBlob)return U(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(ee(this._bodyArrayBuffer));if(this._bodyFormData)throw new Error("could not read FormData body as text");return Promise.resolve(this._bodyText)},i.formData&&(this.formData=function(){return this.text().then(it)}),this.json=function(){return this.text().then(JSON.parse)},this}var v=["CONNECT","DELETE","GET","HEAD","OPTIONS","PATCH","POST","PUT","TRACE"];function L(a){var s=a.toUpperCase();return v.indexOf(s)>-1?s:a}function C(a,s){if(!(this instanceof C))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');s=s||{};var f=s.body;if(a instanceof C){if(a.bodyUsed)throw new TypeError("Already read");this.url=a.url,this.credentials=a.credentials,s.headers||(this.headers=new u(a.headers)),this.method=a.method,this.mode=a.mode,this.signal=a.signal,!f&&a._bodyInit!=null&&(f=a._bodyInit,a.bodyUsed=!0)}else this.url=String(a);if(this.credentials=s.credentials||this.credentials||"same-origin",(s.headers||!this.headers)&&(this.headers=new u(s.headers)),this.method=L(s.method||this.method||"GET"),this.mode=s.mode||this.mode||null,this.signal=s.signal||this.signal||(function(){if("AbortController"in r){var m=new AbortController;return m.signal}})(),this.referrer=null,(this.method==="GET"||this.method==="HEAD")&&f)throw new TypeError("Body not allowed for GET or HEAD requests");if(this._initBody(f),(this.method==="GET"||this.method==="HEAD")&&(s.cache==="no-store"||s.cache==="no-cache")){var g=/([?&])_=[^&]*/;if(g.test(this.url))this.url=this.url.replace(g,"$1_="+new Date().getTime());else{var T=/\?/;this.url+=(T.test(this.url)?"&":"?")+"_="+new Date().getTime()}}}C.prototype.clone=function(){return new C(this,{body:this._bodyInit})};function it(a){var s=new FormData;return a.trim().split("&").forEach(function(f){if(f){var g=f.split("="),T=g.shift().replace(/\+/g," "),m=g.join("=").replace(/\+/g," ");s.append(decodeURIComponent(T),decodeURIComponent(m))}}),s}function at(a){var s=new u,f=a.replace(/\r?\n[\t ]+/g," ");return f.split("\r").map(function(g){return g.indexOf(`
|
|
2
|
+
`)===0?g.substr(1,g.length):g}).forEach(function(g){var T=g.split(":"),m=T.shift().trim();if(m){var G=T.join(":").trim();try{s.append(m,G)}catch(ne){console.warn("Response "+ne.message)}}}),s}A.call(C.prototype);function D(a,s){if(!(this instanceof D))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');if(s||(s={}),this.type="default",this.status=s.status===void 0?200:s.status,this.status<200||this.status>599)throw new RangeError("Failed to construct 'Response': The status provided (0) is outside the range [200, 599].");this.ok=this.status>=200&&this.status<300,this.statusText=s.statusText===void 0?"":""+s.statusText,this.headers=new u(s.headers),this.url=s.url||"",this._initBody(a)}A.call(D.prototype),D.prototype.clone=function(){return new D(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new u(this.headers),url:this.url})},D.error=function(){var a=new D(null,{status:200,statusText:""});return a.ok=!1,a.status=0,a.type="error",a};var ot=[301,302,303,307,308];D.redirect=function(a,s){if(ot.indexOf(s)===-1)throw new RangeError("Invalid status code");return new D(null,{status:s,headers:{location:a}})},t.DOMException=r.DOMException;try{new t.DOMException}catch{t.DOMException=function(s,f){this.message=s,this.name=f;var g=Error(s);this.stack=g.stack},t.DOMException.prototype=Object.create(Error.prototype),t.DOMException.prototype.constructor=t.DOMException}function te(a,s){return new Promise(function(f,g){var T=new C(a,s);if(T.signal&&T.signal.aborted)return g(new t.DOMException("Aborted","AbortError"));var m=new XMLHttpRequest;function G(){m.abort()}m.onload=function(){var P={statusText:m.statusText,headers:at(m.getAllResponseHeaders()||"")};T.url.indexOf("file://")===0&&(m.status<200||m.status>599)?P.status=200:P.status=m.status,P.url="responseURL"in m?m.responseURL:P.headers.get("X-Request-URL");var x="response"in m?m.response:m.responseText;setTimeout(function(){f(new D(x,P))},0)},m.onerror=function(){setTimeout(function(){g(new TypeError("Network request failed"))},0)},m.ontimeout=function(){setTimeout(function(){g(new TypeError("Network request timed out"))},0)},m.onabort=function(){setTimeout(function(){g(new t.DOMException("Aborted","AbortError"))},0)};function ne(P){try{return P===""&&r.location.href?r.location.href:P}catch{return P}}if(m.open(T.method,ne(T.url),!0),T.credentials==="include"?m.withCredentials=!0:T.credentials==="omit"&&(m.withCredentials=!1),"responseType"in m&&(i.blob?m.responseType="blob":i.arrayBuffer&&(m.responseType="arraybuffer")),s&&typeof s.headers=="object"&&!(s.headers instanceof u||r.Headers&&s.headers instanceof r.Headers)){var he=[];Object.getOwnPropertyNames(s.headers).forEach(function(P){he.push(p(P)),m.setRequestHeader(P,c(s.headers[P]))}),T.headers.forEach(function(P,x){he.indexOf(x)===-1&&m.setRequestHeader(x,P)})}else T.headers.forEach(function(P,x){m.setRequestHeader(x,P)});T.signal&&(T.signal.addEventListener("abort",G),m.onreadystatechange=function(){m.readyState===4&&T.signal.removeEventListener("abort",G)}),m.send(typeof T._bodyInit>"u"?null:T._bodyInit)})}return te.polyfill=!0,r.fetch||(r.fetch=te,r.Headers=u,r.Request=C,r.Response=D),t.Headers=u,t.Request=C,t.Response=D,t.fetch=te,t})({})})(typeof self<"u"?self:Re)});var S=[];for(let n=0;n<256;++n)S.push((n+256).toString(16).slice(1));function Se(n,e=0){return(S[n[e+0]]+S[n[e+1]]+S[n[e+2]]+S[n[e+3]]+"-"+S[n[e+4]]+S[n[e+5]]+"-"+S[n[e+6]]+S[n[e+7]]+"-"+S[n[e+8]]+S[n[e+9]]+"-"+S[n[e+10]]+S[n[e+11]]+S[n[e+12]]+S[n[e+13]]+S[n[e+14]]+S[n[e+15]]).toLowerCase()}var mt=new Uint8Array(16);function re(){return crypto.getRandomValues(mt)}function gt(n,e,t){return!e&&!n&&crypto.randomUUID?crypto.randomUUID():Tt(n,e,t)}function Tt(n,e,t){n=n||{};let r=n.random??n.rng?.()??re();if(r.length<16)throw new Error("Random bytes length must be >= 16");if(r[6]=r[6]&15|64,r[8]=r[8]&63|128,e){if(t=t||0,t<0||t+16>e.length)throw new RangeError(`UUID byte range ${t}:${t+15} is out of buffer bounds`);for(let i=0;i<16;++i)e[t+i]=r[i];return e}return Se(r)}var N=gt;var ch=yt(_e());function se(n){return Mt(n,!1)}function Mt(n,e){return n}function w(n){return Ut(n,!1)}function Ut(n,e){return n}function B(n){return vt(n,!1)}function vt(n,e){return n}function Ne(n){return Gt(n,!1)}function Gt(n,e){return n==null?n:{allocation:n.allocation==null?void 0:n.allocation,consumptionRate:n.consumption_rate==null?void 0:n.consumption_rate,creditId:n.credit_id==null?void 0:n.credit_id,creditRemaining:n.credit_remaining==null?void 0:n.credit_remaining,creditReserved:n.credit_reserved==null?void 0:n.credit_reserved,creditSettled:n.credit_settled==null?void 0:n.credit_settled,creditTotal:n.credit_total==null?void 0:n.credit_total,creditUsed:n.credit_used==null?void 0:n.credit_used,eventName:n.event_name==null?void 0:n.event_name,eventSubtype:n.event_subtype==null?void 0:n.event_subtype,featureId:n.feature_id,featureKey:n.feature_key,metricPeriod:n.metric_period==null?void 0:B(n.metric_period),metricResetAt:n.metric_reset_at==null?void 0:new Date(n.metric_reset_at),monthReset:n.month_reset==null?void 0:w(n.month_reset),softLimit:n.soft_limit==null?void 0:n.soft_limit,usage:n.usage==null?void 0:n.usage,valueType:se(n.value_type)}}function W(n){return qt(n,!1)}function qt(n,e){return n}function E(n){return Wt(n,!1)}function Wt(n,e){return n==null?n:{companyId:n.company_id==null?void 0:n.company_id,entitlement:n.entitlement==null?void 0:Ne(n.entitlement),error:n.error==null?void 0:n.error,featureAllocation:n.feature_allocation==null?void 0:n.feature_allocation,featureUsage:n.feature_usage==null?void 0:n.feature_usage,featureUsageEvent:n.feature_usage_event==null?void 0:n.feature_usage_event,featureUsagePeriod:n.feature_usage_period==null?void 0:B(n.feature_usage_period),featureUsageResetAt:n.feature_usage_reset_at==null?void 0:new Date(n.feature_usage_reset_at),flag:n.flag,flagId:n.flag_id==null?void 0:n.flag_id,reason:n.reason,ruleId:n.rule_id==null?void 0:n.rule_id,ruleType:n.rule_type==null?void 0:W(n.rule_type),userId:n.user_id==null?void 0:n.user_id,value:n.value}}function pe(n){return Ht(n,!1)}function Ht(n,e){return n==null?n:{data:E(n.data),params:n.params}}var Qt="https://api.schematichq.com".replace(/\/+$/,""),ce=class{constructor(e={}){this.configuration=e}configuration;set config(e){this.configuration=e}get basePath(){return this.configuration.basePath!=null?this.configuration.basePath:Qt}get fetchApi(){return this.configuration.fetchApi}get middleware(){return this.configuration.middleware||[]}get queryParamsStringify(){return this.configuration.queryParamsStringify||Ee}get username(){return this.configuration.username}get password(){return this.configuration.password}get apiKey(){let e=this.configuration.apiKey;if(e)return typeof e=="function"?e:()=>e}get accessToken(){let e=this.configuration.accessToken;if(e)return typeof e=="function"?e:async()=>e}get headers(){return this.configuration.headers}get credentials(){return this.configuration.credentials}},zt=new ce,Je=class n{constructor(e=zt){this.configuration=e;this.middleware=e.middleware}configuration;static jsonRegex=new RegExp("^(:?application/json|[^;/ ]+/[^;/ ]+[+]json)[ ]*(:?;.*)?$","i");middleware;withMiddleware(...e){let t=this.clone();return t.middleware=t.middleware.concat(...e),t}withPreMiddleware(...e){let t=e.map(r=>({pre:r}));return this.withMiddleware(...t)}withPostMiddleware(...e){let t=e.map(r=>({post:r}));return this.withMiddleware(...t)}isJsonMime(e){return e?n.jsonRegex.test(e):!1}async request(e,t){let{url:r,init:i}=await this.createFetchParams(e,t),o=await this.fetchApi(r,i);if(o&&o.status>=200&&o.status<300)return o;throw new ue(o,"Response returned an error code")}async createFetchParams(e,t){let r=this.configuration.basePath+e.path;e.query!==void 0&&Object.keys(e.query).length!==0&&(r+="?"+this.configuration.queryParamsStringify(e.query));let i=Object.assign({},this.configuration.headers,e.headers);Object.keys(i).forEach(y=>i[y]===void 0?delete i[y]:{});let o=typeof t=="function"?t:async()=>t,d={method:e.method,headers:i,body:e.body,credentials:this.configuration.credentials},l={...d,...await o({init:d,context:e})},p;Xt(l.body)||l.body instanceof URLSearchParams||Kt(l.body)?p=l.body:this.isJsonMime(i["Content-Type"])?p=JSON.stringify(l.body):p=l.body;let c={...l,body:p};return{url:r,init:c}}fetchApi=async(e,t)=>{let r={url:e,init:t};for(let o of this.middleware)o.pre&&(r=await o.pre({fetch:this.fetchApi,...r})||r);let i;try{i=await(this.configuration.fetchApi||fetch)(r.url,r.init)}catch(o){for(let d of this.middleware)d.onError&&(i=await d.onError({fetch:this.fetchApi,url:r.url,init:r.init,error:o,response:i?i.clone():void 0})||i);if(i===void 0)throw o instanceof Error?new fe(o,"The request failed and the interceptors did not return an alternative response"):o}for(let o of this.middleware)o.post&&(i=await o.post({fetch:this.fetchApi,url:r.url,init:r.init,response:i.clone()})||i);return i};clone(){let e=this.constructor,t=new e(this.configuration);return t.middleware=this.middleware.slice(),t}};function Kt(n){return typeof Blob<"u"&&n instanceof Blob}function Xt(n){return typeof FormData<"u"&&n instanceof FormData}var ue=class extends Error{constructor(t,r){super(r);this.response=t}response;name="ResponseError"},fe=class extends Error{constructor(t,r){super(r);this.cause=t}cause;name="FetchError"};function Ee(n,e=""){return Object.keys(n).map(t=>ke(t,n[t],e)).filter(t=>t.length>0).join("&")}function ke(n,e,t=""){let r=t+(t.length?`[${n}]`:n);if(e instanceof Array){let i=e.map(o=>encodeURIComponent(String(o))).join(`&${encodeURIComponent(r)}=`);return`${encodeURIComponent(r)}=${i}`}if(e instanceof Set){let i=Array.from(e);return ke(n,i,t)}return e instanceof Date?`${encodeURIComponent(r)}=${encodeURIComponent(e.toISOString())}`:e instanceof Object?Ee(e,r):`${encodeURIComponent(r)}=${encodeURIComponent(String(e))}`}function Ie(n,e){return Object.keys(n).reduce((t,r)=>({...t,[r]:e(n[r])}),{})}function $(n){return Yt(n,!1)}function Yt(n,e){return n==null?n:{remaining:n.remaining,reserved:n.reserved,settled:n.settled}}function Ae(n){return Zt(n,!1)}function Zt(n,e){return n}function V(n){return jt(n,!1)}function jt(n,e){return n==null?n:{id:n.id,name:n.name,trialEndDate:n.trial_end_date==null?void 0:new Date(n.trial_end_date),trialStatus:n.trial_status==null?void 0:Ae(n.trial_status)}}function ye(n){return en(n,!1)}function en(n,e){return n==null?n:{creditBalances:n.credit_balances==null?void 0:Ie(n.credit_balances,$),flags:n.flags.map(E),plan:n.plan==null?void 0:V(n.plan)}}function me(n){return nn(n,!1)}function nn(n,e){return n==null?n:{data:ye(n.data),params:n.params}}function H(n){return rn(n,!1)}function rn(n,e=!1){return n==null?n:{company_id:n.companyId,error:n.error,flag_id:n.flagId,flag_key:n.flagKey,reason:n.reason,req_company:n.reqCompany,req_user:n.reqUser,rule_id:n.ruleId,user_id:n.userId,value:n.value}}var ge=n=>{let{companyId:e,entitlement:t,error:r,featureAllocation:i,featureUsage:o,featureUsageEvent:d,featureUsagePeriod:l,featureUsageResetAt:p,flag:c,flagId:y,reason:u,ruleId:R,ruleType:_,userId:M,value:U}=E(n),ee=!U&&(_=="company_override_usage_exceeded"||_=="plan_entitlement_usage_exceeded"),I=t?.allocation??i,A=t?.usage??o,v=t?.eventName??d,L=t?.metricPeriod??l,C=t?.metricResetAt??p;return{featureUsageExceeded:ee,companyId:e??void 0,creditId:t?.creditId==null?void 0:t.creditId,creditRemaining:t?.creditRemaining==null?void 0:t.creditRemaining,creditReserved:t?.creditReserved==null?void 0:t.creditReserved,creditSettled:t?.creditSettled==null?void 0:t.creditSettled,error:r??void 0,featureAllocation:I??void 0,featureUsage:A??void 0,featureUsageEvent:v??void 0,featureUsagePeriod:L??void 0,featureUsageResetAt:C??void 0,flag:c,flagId:y??void 0,reason:u,ruleId:R??void 0,ruleType:_??void 0,softLimit:t?.softLimit==null?void 0:t.softLimit,userId:M??void 0,value:U}},et=n=>{let{id:e,name:t,trialEndDate:r,trialStatus:i}=V(n);return{id:e,name:t,trialEndDate:r??void 0,trialStatus:i??void 0}},tt=n=>{if(n==null||typeof n!="object")return{};let e={};for(let[t,r]of Object.entries(n)){if(r==null||typeof r!="object")continue;let{remaining:i,reserved:o,settled:d}=$(r);typeof i!="number"||typeof o!="number"||typeof d!="number"||(e[t]={remaining:i,reserved:o,settled:d})}return e};var k="bb56e75d";function h(n){let e=Object.keys(n).reduce((t,r)=>{let o=Object.keys(n[r]||{}).sort().reduce((d,l)=>(d[l]=n[r][l],d),{});return t[r]=o,t},{});return JSON.stringify(e)}var Te="1.5.0";var nt="schematicId",bn="schematicCache",rt=10,On=10080*60*1e3,xn=Object.freeze({});var j=class{additionalHeaders={};apiKey;apiUrl="https://api.schematichq.com";conn=null;context={};debugEnabled=!1;offlineEnabled=!1;eventQueue;contextDependentEventQueue;eventUrl="https://c.schematichq.com";flagCheckListeners={};flagValueListeners={};isPending=!0;isPendingListeners=new Set;planListeners=new Set;creditBalanceListeners=new Set;storage;persistFlagState=!0;flagStateCacheKey;flagStateCacheMaxAgeMs=On;cachedFlagState=null;useWebSocket=!1;checks={};featureUsageEventMap={};planChecks={};creditBalances={};webSocketUrl="wss://api.schematichq.com";webSocketConnectionTimeout=1e4;webSocketReconnect=!0;webSocketMaxReconnectAttempts=7;webSocketMaxConnectionAttempts=3;webSocketInitialRetryDelay=1e3;webSocketMaxRetryDelay=3e4;wsReconnectAttempts=0;wsReconnectTimer=null;wsIntentionalDisconnect=!1;currentWebSocket=null;isConnecting=!1;maxEventQueueSize=100;maxEventRetries=5;eventRetryInitialDelay=1e3;eventRetryMaxDelay=3e4;retryTimer=null;flagValueDefaults={};flagCheckDefaults={};fallbackCheckCache={};constructor(e,t){if(this.apiKey=e,this.flagStateCacheKey=`${bn}:${e}`,this.eventQueue=[],this.contextDependentEventQueue=[],this.useWebSocket=t?.useWebSocket??!1,this.debugEnabled=t?.debug??!1,this.offlineEnabled=t?.offline??!1,this.persistFlagState=t?.persistFlagState??!0,typeof t?.flagStateCacheMaxAgeMs=="number"&&t.flagStateCacheMaxAgeMs>0&&(this.flagStateCacheMaxAgeMs=t.flagStateCacheMaxAgeMs),typeof window<"u"&&typeof window.location<"u"){let r=new URLSearchParams(window.location.search),i=r.get("schematic_debug");i!==null&&(i===""||i==="true"||i==="1")&&(this.debugEnabled=!0);let o=r.get("schematic_offline");o!==null&&(o===""||o==="true"||o==="1")&&(this.offlineEnabled=!0,this.debugEnabled=!0)}if(this.offlineEnabled&&t?.debug!==!1&&(this.debugEnabled=!0),this.offlineEnabled&&this.setIsPending(!1),this.additionalHeaders={"X-Schematic-Client-Version":`schematic-js@${Te}`,...t?.additionalHeaders??{}},t?.storage)this.storage=t.storage;else try{typeof localStorage<"u"&&(this.storage=localStorage)}catch{}this.hydrateFlagStateFromCache(),t?.apiUrl!==void 0&&(this.apiUrl=t.apiUrl),t?.eventUrl!==void 0&&(this.eventUrl=t.eventUrl),t?.webSocketUrl!==void 0&&(this.webSocketUrl=t.webSocketUrl),t?.webSocketConnectionTimeout!==void 0&&(this.webSocketConnectionTimeout=t.webSocketConnectionTimeout),t?.webSocketReconnect!==void 0&&(this.webSocketReconnect=t.webSocketReconnect),t?.webSocketMaxReconnectAttempts!==void 0&&(this.webSocketMaxReconnectAttempts=t.webSocketMaxReconnectAttempts),t?.webSocketInitialRetryDelay!==void 0&&(this.webSocketInitialRetryDelay=t.webSocketInitialRetryDelay),t?.webSocketMaxRetryDelay!==void 0&&(this.webSocketMaxRetryDelay=t.webSocketMaxRetryDelay),t?.maxEventQueueSize!==void 0&&(this.maxEventQueueSize=t.maxEventQueueSize),t?.maxEventRetries!==void 0&&(this.maxEventRetries=t.maxEventRetries),t?.eventRetryInitialDelay!==void 0&&(this.eventRetryInitialDelay=t.eventRetryInitialDelay),t?.eventRetryMaxDelay!==void 0&&(this.eventRetryMaxDelay=t.eventRetryMaxDelay),t?.flagValueDefaults!==void 0&&(this.flagValueDefaults=t.flagValueDefaults),t?.flagCheckDefaults!==void 0&&(this.flagCheckDefaults=t.flagCheckDefaults),typeof window<"u"&&window?.addEventListener&&(window.addEventListener("beforeunload",()=>{this.flushEventQueue(),this.flushContextDependentEventQueue()}),this.useWebSocket&&(window.addEventListener("offline",()=>{this.debug("Browser went offline, closing WebSocket connection"),this.handleNetworkOffline()}),window.addEventListener("online",()=>{this.debug("Browser came online, attempting to reconnect WebSocket"),this.handleNetworkOnline()}))),this.offlineEnabled?this.debug("Initialized with offline mode enabled - no network requests will be made"):this.debugEnabled&&this.debug("Initialized with debug mode enabled")}resolveFallbackValue(e,t){return t!==void 0?t:e in this.flagCheckDefaults?this.flagCheckDefaults[e].value:e in this.flagValueDefaults?this.flagValueDefaults[e]:!1}resolveFallbackCheckFlagReturn(e,t,r="Fallback value used",i){if(t!==void 0)return{flag:e,value:t,reason:r,error:i};if(e in this.flagCheckDefaults){let o=this.flagCheckDefaults[e];return{...o,flag:e,reason:i!==void 0?r:o.reason,error:i}}return e in this.flagValueDefaults?{flag:e,value:this.flagValueDefaults[e],reason:r,error:i}:{flag:e,value:!1,reason:r,error:i}}async checkFlag(e){let{fallback:t,key:r}=e,i=e.context||this.context,o=h(i);if(this.debug(`checkFlag: ${r}`,{context:i,fallback:t}),this.isOffline()){let d=this.resolveFallbackCheckFlagReturn(r,t,"Offline mode - using initialization defaults");return this.debug(`checkFlag offline result: ${r}`,{value:d.value,offlineMode:!0}),d.value}if(!this.useWebSocket){let d=`${this.apiUrl}/flags/${r}/check`;return fetch(d,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:JSON.stringify(i)}).then(l=>{if(!l.ok)throw new Error("Network response was not ok");return l.json()}).then(l=>{let p=pe(l);this.debug(`checkFlag result: ${r}`,p);let c=ge(p.data);return typeof c.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(c),this.submitFlagCheckEvent(r,c,i),c.value}).catch(l=>{console.warn("There was a problem with the fetch operation:",l);let p=this.resolveFallbackCheckFlagReturn(r,t,"API request failed",l instanceof Error?l.message:String(l));return this.submitFlagCheckEvent(r,p,i),p.value})}try{let d=this.checks[o];if(this.conn!==null&&typeof d<"u"&&typeof d[r]<"u")return this.debug(`checkFlag cached result: ${r}`,d[r]),d[r].value;if(this.isOffline())return this.resolveFallbackValue(r,t);try{await this.setContext(i)}catch(y){console.warn("WebSocket connection failed, using fallback value:",y);let u=this.resolveFallbackCheckFlagReturn(r,t,"WebSocket connection failed",y instanceof Error?y.message:String(y));return this.submitFlagCheckEvent(r,u,i),u.value}let p=(this.checks[o]??{})[r],c=p?.value??this.resolveFallbackValue(r,t);if(this.debug(`checkFlag WebSocket result: ${r}`,typeof p<"u"?p:{value:c,fallbackUsed:!0}),typeof p<"u")this.submitFlagCheckEvent(r,p,i);else{let y=this.resolveFallbackCheckFlagReturn(r,t,"No flag values available");this.submitFlagCheckEvent(r,y,i)}return c}catch(d){console.error("Unexpected error in checkFlag:",d);let l=this.resolveFallbackCheckFlagReturn(r,t,"Unexpected error in flag check",d instanceof Error?d.message:String(d));return this.submitFlagCheckEvent(r,l,i),l.value}}debug(e,...t){this.debugEnabled&&console.log(`[Schematic] ${e}`,...t)}createPersistentMessageHandler(e){return t=>{let r=JSON.parse(t.data);if(this.debug("WebSocket persistent message received:",r),h(e)in this.checks||(this.checks[h(e)]={}),(r.flags??[]).forEach(i=>{let o=ge(i),d=h(e);this.checks[d]===void 0&&(this.checks[d]={}),this.checks[d][o.flag]=o,typeof o.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(o),((this.flagCheckListeners[i.flag]?.size??0)>0||(this.flagValueListeners[i.flag]?.size??0)>0)&&this.submitFlagCheckEvent(o.flag,o,e),this.debug(`WebSocket flag update received. Notifying listeners for ${i.flag}`,{flag:i.flag,value:o.value,flagCheck:o}),this.notifyFlagCheckListeners(i.flag,o),this.notifyFlagValueListeners(i.flag,o.value)}),r.plan!==void 0&&r.plan!==null){let i=et(r.plan),o=h(e);this.planChecks[o]=i,this.debug("WebSocket plan update received. Notifying listeners",{plan:i}),this.notifyPlanListeners(i)}if(r.credit_balances!==void 0&&r.credit_balances!==null){let i=h(e),o=tt(r.credit_balances),d=this.creditBalances[i]??{},l=!1,p={...d};for(let[c,y]of Object.entries(o)){let u=d[c];(u===void 0||u.remaining!==y.remaining||u.reserved!==y.reserved||u.settled!==y.settled)&&(p[c]=y,l=!0)}l&&(this.creditBalances[i]=p,this.debug("WebSocket credit balance update received. Notifying listeners",{creditBalances:p}),this.notifyCreditBalanceListeners(p))}this.persistContextToCache(h(e)),this.flushContextDependentEventQueue(),this.setIsPending(!1)}}isOffline(){return this.offlineEnabled}submitFlagCheckEvent(e,t,r){let i={flagKey:e,value:t.value,reason:t.reason,flagId:t.flagId,ruleId:t.ruleId,companyId:t.companyId,userId:t.userId,error:t.error,reqCompany:r.company,reqUser:r.user};return this.debug("submitting flag check event:",i),this.handleEvent("flag_check",H(i))}checkFlags=async e=>{if(e=e||this.context,this.debug("checkFlags",{context:e}),this.isOffline())return this.debug("checkFlags offline result: returning empty object"),{};let t=`${this.apiUrl}/flags/check`,r=JSON.stringify(e);return fetch(t,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:r}).then(i=>{if(!i.ok)throw new Error("Network response was not ok");return i.json()}).then(i=>{let o=me(i);return this.debug("checkFlags result:",o),(o?.data?.flags??[]).reduce((d,l)=>(d[l.flag]=l.value,d),{})}).catch(i=>(console.warn("There was a problem with the fetch operation:",i),{}))};identify=e=>(this.debug("identify:",e),this.setContext({company:e.company?.keys,user:e.keys}).catch(t=>{console.warn("Error setting context:",t)}),this.handleEvent("identify",e));setContext=async e=>{if(this.isOffline()||!this.useWebSocket)return this.context=e,this.flushContextDependentEventQueue(),this.setIsPending(!1),Promise.resolve();if(!(h(e)===h(this.context)&&this.conn!==null&&!this.isPending))try{let t=h(e),r=this.hasCachedValuesForContext(t);if(r){this.debug("setContext: cache hit for context, pre-resolving from cached values"),this.context=e,this.flushContextDependentEventQueue(),this.setIsPending(!1);let o=this.checks[t]??{};for(let[p,c]of Object.entries(o))c!==void 0&&(this.notifyFlagCheckListeners(p,c),this.notifyFlagValueListeners(p,c.value));let d=this.planChecks[t];d!==void 0&&this.notifyPlanListeners(d);let l=this.creditBalances[t];l!==void 0&&this.notifyCreditBalanceListeners(l)}else this.setIsPending(!0);if(!this.conn){if(this.isConnecting){for(this.debug("Connection already in progress, waiting for it to complete");this.isConnecting&&this.conn===null;)await new Promise(o=>setTimeout(o,10));if(this.conn!==null){let o=await this.conn;await this.wsSendMessage(o,e,r);return}}this.wsReconnectTimer!==null&&(this.debug("Cancelling scheduled reconnection, connecting immediately"),clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.isConnecting=!0;try{this.conn=this.wsConnect();let o=await this.conn;this.isConnecting=!1,await this.wsSendMessage(o,e,r);return}catch(o){throw this.isConnecting=!1,o}}let i=await this.conn;await this.wsSendMessage(i,e,r)}catch(t){console.warn("Failed to establish WebSocket connection:",t),this.context=e,this.flushContextDependentEventQueue(),this.setIsPending(!1),this.attemptReconnect()}};track=e=>{let{company:t,user:r,event:i,traits:o,quantity:d=1}=e;if(!this.hasContext(t,r)){this.debug(`track: queuing event "${i}" until context is available`);let p={api_key:this.apiKey,body:{company:t,event:i,traits:o??{},user:r,quantity:d},sent_at:new Date().toISOString(),tracker_event_id:N(),tracker_user_id:this.getAnonymousId(),type:"track"};return this.contextDependentEventQueue.push(p),Promise.resolve()}let l={company:t??this.context.company,event:i,traits:o??{},user:r??this.context.user,quantity:d};return this.debug("track:",l),i in this.featureUsageEventMap&&this.optimisticallyUpdateFeatureUsage(i,d),this.handleEvent("track",l)};optimisticallyUpdateFeatureUsage=(e,t=1)=>{let r=this.featureUsageEventMap[e];if(r==null)return;this.debug(`Optimistically updating feature usage for event: ${e}`,{quantity:t});let i=!1;Object.entries(r).forEach(([o,d])=>{if(d===void 0)return;let l={...d};if(typeof l.featureUsage=="number"){if(i=!0,l.featureUsage+=t,typeof l.featureAllocation=="number"){let c=l.featureUsageExceeded===!0,y=l.featureUsage>=l.featureAllocation;y!==c&&(l.featureUsageExceeded=y,y&&(l.value=!1),this.debug(`Usage limit status changed for flag: ${o}`,{was:c?"exceeded":"within limits",now:y?"exceeded":"within limits",featureUsage:l.featureUsage,featureAllocation:l.featureAllocation,value:l.value}))}this.featureUsageEventMap[e]!==void 0&&(this.featureUsageEventMap[e][o]=l);let p=h(this.context);this.checks[p]!==void 0&&this.checks[p]!==null&&(this.checks[p][o]=l),this.notifyFlagCheckListeners(o,l),this.notifyFlagValueListeners(o,l.value)}}),i&&this.persistContextToCache(h(this.context))};hasContext=(e,t)=>{let r=e!=null&&Object.keys(e).length>0||t!=null&&Object.keys(t).length>0,i=this.context.company!==void 0&&this.context.company!==null&&Object.keys(this.context.company).length>0||this.context.user!==void 0&&this.context.user!==null&&Object.keys(this.context.user).length>0;return r||i};flushContextDependentEventQueue=()=>{for(this.debug(`flushing ${this.contextDependentEventQueue.length} context-dependent events`);this.contextDependentEventQueue.length>0;){let e=this.contextDependentEventQueue.shift();if(e)if(e.type==="track"&&typeof e.body=="object"&&e.body!==null){let t=e.body,r={...t,company:t.company??this.context.company,user:t.user??this.context.user},i={...e,body:r,sent_at:new Date().toISOString()};this.sendEvent(i)}else this.sendEvent(e)}};startRetryTimer=()=>{this.retryTimer===null&&(this.retryTimer=setInterval(()=>{this.flushEventQueue().catch(e=>{this.debug("Error in retry timer flush:",e)}),this.eventQueue.length===0&&this.stopRetryTimer()},5e3),this.debug("Started retry timer"))};stopRetryTimer=()=>{this.retryTimer!==null&&(clearInterval(this.retryTimer),this.retryTimer=null,this.debug("Stopped retry timer"))};flushEventQueue=async()=>{if(this.eventQueue.length===0)return;let e=Date.now(),t=[],r=[];for(let i of this.eventQueue)i.next_retry_at===void 0||i.next_retry_at<=e?t.push(i):r.push(i);if(t.length===0){this.debug(`No events ready for retry yet (${r.length} still in backoff)`);return}this.debug(`Flushing event queue: ${t.length} ready, ${r.length} waiting`),this.eventQueue=r;for(let i of t)try{await this.sendEvent(i),this.debug("Queued event sent successfully:",i.type)}catch(o){this.debug("Failed to send queued event:",o)}};getAnonymousId=()=>{if(!this.storage)return N();let e=this.storage.getItem(nt);if(typeof e<"u")return e;let t=N();return this.storage.setItem(nt,t),t};hasCachedValuesForContext=e=>{let t=this.checks[e];if(t!==void 0&&Object.keys(t).length>0||this.planChecks[e]!==void 0)return!0;let r=this.creditBalances[e];return r!==void 0&&Object.keys(r).length>0};readFlagStateCache=()=>{if(!this.persistFlagState||this.storage===void 0)return null;let e;try{e=this.storage.getItem(this.flagStateCacheKey)}catch(r){return this.debug("Failed to read flag state cache:",r),null}if(e==null)return null;let t;try{t=typeof e=="string"?JSON.parse(e):e}catch(r){return this.debug("Flag state cache is not valid JSON, ignoring:",r),null}return t===null||typeof t!="object"||t.version!==k||typeof t.contexts!="object"||t.contexts===null?(this.debug(`Flag state cache invalid or version mismatch (expected ${k}), ignoring`,{parsedType:typeof t,version:t?.version}),null):t};reviveCachedCheck=e=>{if(e===null||typeof e!="object")return null;let t=e;if(typeof t.flag!="string"||typeof t.value!="boolean"||typeof t.reason!="string")return null;let r={...t};if(typeof r.featureUsageResetAt=="string"){let i=new Date(r.featureUsageResetAt);r.featureUsageResetAt=isNaN(i.getTime())?void 0:i}return r};reviveCachedPlan=e=>{if(e===null||typeof e!="object")return null;let t=e;if(typeof t.id!="string"||typeof t.name!="string")return null;let r={...t};if(typeof r.trialEndDate=="string"){let i=new Date(r.trialEndDate);r.trialEndDate=isNaN(i.getTime())?void 0:i}return r};reviveCachedCreditBalances=e=>{if(e===null||typeof e!="object")return null;let t={};for(let[r,i]of Object.entries(e)){if(i===null||typeof i!="object")continue;let o=i;typeof o.remaining!="number"||typeof o.reserved!="number"||typeof o.settled!="number"||(t[r]={remaining:o.remaining,reserved:o.reserved,settled:o.settled})}return Object.keys(t).length>0?t:null};hydrateFlagStateFromCache=()=>{let e=this.readFlagStateCache();if(e===null)return;let t=Date.now()-this.flagStateCacheMaxAgeMs,r={},i=0,o=0;for(let[d,l]of Object.entries(e.contexts)){if(l===null||typeof l!="object"||typeof l.updatedAt!="number")continue;if(l.updatedAt<t){o+=1;continue}let p={};if(l.checks!==null&&typeof l.checks=="object"){for(let[u,R]of Object.entries(l.checks)){let _=this.reviveCachedCheck(R);_===null||_.flag!==u||(p[u]=_,typeof _.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(_))}Object.keys(p).length>0&&(this.checks[d]=p)}let c;if(l.plan!==void 0&&l.plan!==null){let u=this.reviveCachedPlan(l.plan);u!==null&&(c=u,this.planChecks[d]=u)}let y;if(l.creditBalances!==void 0&&l.creditBalances!==null){let u=this.reviveCachedCreditBalances(l.creditBalances);u!==null&&(y=u,this.creditBalances[d]=u)}r[d]={checks:p,plan:c,creditBalances:y,updatedAt:l.updatedAt},i+=1}this.cachedFlagState={version:k,contexts:r},this.debug(`Hydrated flag state cache: ${i} loaded, ${o} expired`)};persistContextToCache=e=>{let t=this.checks[e],r=this.planChecks[e],i=this.creditBalances[e];if(t===void 0&&r===void 0&&i===void 0)return;this.cachedFlagState===null&&(this.cachedFlagState=(this.persistFlagState?this.readFlagStateCache():null)??{version:k,contexts:{}});let o={};if(t!==void 0)for(let[l,p]of Object.entries(t))p!==void 0&&(o[l]=p);this.cachedFlagState.contexts[e]={checks:o,plan:r,creditBalances:i,updatedAt:Date.now()};let d=Object.entries(this.cachedFlagState.contexts);if(d.length>rt){d.sort((c,y)=>y[1].updatedAt-c[1].updatedAt);let l=d.slice(0,rt),p=new Set(l.map(([c])=>c));for(let c of Object.keys(this.checks))p.has(c)||delete this.checks[c];for(let c of Object.keys(this.planChecks))p.has(c)||delete this.planChecks[c];for(let c of Object.keys(this.creditBalances))p.has(c)||delete this.creditBalances[c];this.cachedFlagState={version:k,contexts:Object.fromEntries(l)}}if(!(!this.persistFlagState||this.storage===void 0))try{this.storage.setItem(this.flagStateCacheKey,JSON.stringify(this.cachedFlagState))}catch(l){this.debug("Failed to write flag state cache:",l)}};handleEvent=(e,t)=>{let r={api_key:this.apiKey,body:t,sent_at:new Date().toISOString(),tracker_event_id:N(),tracker_user_id:this.getAnonymousId(),type:e};return typeof document<"u"&&document?.hidden?this.storeEvent(r):this.sendEvent(r)};sendEvent=async e=>{let t=`${this.eventUrl}/e`,r=JSON.stringify(e);if(this.debug("sending event:",{url:t,event:e}),this.isOffline())return this.debug("event not sent (offline mode):",{event:e}),Promise.resolve();try{let i=await fetch(t,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8"},body:r});if(!i.ok)throw new Error(`HTTP ${i.status}: ${i.statusText}`);this.debug("event sent:",{status:i.status,statusText:i.statusText})}catch(i){let o=(e.retry_count??0)+1;if(o<=this.maxEventRetries){this.debug(`Event failed to send (attempt ${o}/${this.maxEventRetries}), queueing for retry:`,i);let d=this.eventRetryInitialDelay*Math.pow(2,o-1),l=Math.min(d,this.eventRetryMaxDelay),p=Date.now()+l,c={...e,retry_count:o,next_retry_at:p};this.eventQueue.length<this.maxEventQueueSize?(this.eventQueue.push(c),this.debug(`Event queued for retry in ${l}ms (${this.eventQueue.length}/${this.maxEventQueueSize})`)):(this.debug(`Event queue full (${this.maxEventQueueSize}), dropping oldest event`),this.eventQueue.shift(),this.eventQueue.push(c)),this.startRetryTimer()}else this.debug(`Event failed permanently after ${this.maxEventRetries} attempts, dropping:`,i)}return Promise.resolve()};storeEvent=e=>(this.eventQueue.push(e),Promise.resolve());forceReconnect=async()=>this.reconnect({force:!0});reconnectIfNeeded=async()=>this.reconnect({force:!1});reconnect=async e=>{let{force:t}=e,r=t?"forceReconnect":"reconnectIfNeeded";if(this.isOffline())return this.debug(`${r}: skipped (offline mode)`),Promise.resolve();if(!t&&this.conn!==null)try{if((await this.conn).readyState===WebSocket.OPEN)return this.debug(`${r}: connection is healthy, skipping`),Promise.resolve()}catch{}if(this.debug(`${r}: ${t?"forcing immediate reconnection":"reconnecting"}`),this.wsIntentionalDisconnect=!1,this.wsReconnectTimer!==null&&(this.debug(`${r}: cancelling pending reconnection timer`),clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.wsReconnectAttempts=0,this.conn!==null){this.debug(`${r}: closing existing connection`);try{let i=await this.conn;this.currentWebSocket===i&&(this.currentWebSocket=null),(i.readyState===WebSocket.OPEN||i.readyState===WebSocket.CONNECTING)&&i.close()}catch(i){this.debug(`${r}: error closing existing connection:`,i)}this.conn=null,this.isConnecting=!1}if(this.context.company!==void 0||this.context.user!==void 0){this.debug(`${r}: reconnecting with existing context`);try{this.isConnecting=!0,this.conn=this.wsConnect();let i=await this.conn;this.isConnecting=!1,await this.wsSendMessage(i,this.context,!0),this.debug(`${r}: reconnection successful`)}catch(i){this.isConnecting=!1,this.debug(`${r}: reconnection failed:`,i)}}else this.debug(`${r}: no context set, skipping reconnection`);return Promise.resolve()};cleanup=async()=>{if(this.isOffline())return this.debug("cleanup: skipped (offline mode)"),Promise.resolve();if(this.wsIntentionalDisconnect=!0,this.wsReconnectTimer!==null&&(clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.stopRetryTimer(),this.conn)try{let e=await this.conn;this.currentWebSocket===e&&(this.debug("Cleaning up current websocket tracking"),this.currentWebSocket=null),e.close()}catch(e){console.warn("Error during cleanup:",e)}finally{this.conn=null,this.currentWebSocket=null,this.isConnecting=!1}};calculateReconnectDelay=()=>{let e=this.webSocketInitialRetryDelay*Math.pow(2,this.wsReconnectAttempts),t=Math.min(e,this.webSocketMaxRetryDelay),r=Math.random()*t*.5,i=t+r;return this.debug(`Reconnect delay calculated: ${i.toFixed(0)}ms (attempt ${this.wsReconnectAttempts+1}/${this.webSocketMaxReconnectAttempts})`),i};handleNetworkOffline=async()=>{if(this.conn!==null){try{let e=await this.conn;this.currentWebSocket===e&&(this.currentWebSocket=null),(e.readyState===WebSocket.OPEN||e.readyState===WebSocket.CONNECTING)&&e.close()}catch(e){this.debug("Error closing connection on offline:",e)}this.conn=null}this.wsReconnectTimer!==null&&(clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null)};handleNetworkOnline=()=>{this.debug("Network online, attempting reconnection and flushing queued events"),this.wsReconnectAttempts=0,this.wsReconnectTimer!==null&&(clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.flushEventQueue().catch(e=>{this.debug("Error flushing event queue on network online:",e)}),this.attemptReconnect()};attemptReconnect=()=>{if(this.wsReconnectAttempts>=this.webSocketMaxReconnectAttempts){this.debug(`Maximum reconnection attempts (${this.webSocketMaxReconnectAttempts}) reached, giving up`);return}if(this.wsReconnectTimer!==null){this.debug("Reconnection attempt already scheduled, ignoring duplicate request");return}let e=this.calculateReconnectDelay();this.debug(`Scheduling reconnection attempt ${this.wsReconnectAttempts+1}/${this.webSocketMaxReconnectAttempts} in ${e.toFixed(0)}ms`),this.wsReconnectTimer=setTimeout(async()=>{this.wsReconnectTimer=null,this.wsReconnectAttempts++,this.debug(`Attempting to reconnect (attempt ${this.wsReconnectAttempts}/${this.webSocketMaxReconnectAttempts})`);try{if(this.conn!==null){this.debug("Cleaning up existing connection before reconnection");try{let t=await this.conn;this.currentWebSocket===t&&(this.debug("Existing websocket is current, will be replaced"),this.currentWebSocket=null),(t.readyState===WebSocket.OPEN||t.readyState===WebSocket.CONNECTING)&&t.close()}catch(t){this.debug("Error cleaning up existing connection:",t)}this.conn=null,this.currentWebSocket=null,this.isConnecting=!1}this.isConnecting=!0;try{this.conn=this.wsConnect();let t=await this.conn;this.isConnecting=!1,this.debug("Reconnection context check:",{hasCompany:this.context.company!==void 0,hasUser:this.context.user!==void 0,context:this.context}),this.context.company!==void 0||this.context.user!==void 0?(this.debug("Reconnected, force re-sending context"),await this.wsSendMessage(t,this.context,!0)):(this.debug("No context to re-send after reconnection - websocket ready for new context"),this.debug("Setting up tracking for reconnected websocket (no context to send)"),this.currentWebSocket=t),this.flushEventQueue().catch(r=>{this.debug("Error flushing event queue after websocket reconnection:",r)}),this.debug("Reconnection successful")}catch(t){throw this.isConnecting=!1,t}}catch(t){this.debug("Reconnection attempt failed:",t)}},e)};wsConnect=async()=>{if(this.isOffline())throw this.debug("wsConnect: skipped (offline mode)"),new Error("WebSocket connection skipped in offline mode");let e=null,t=this.webSocketMaxConnectionAttempts;for(let r=0;r<t;r++)try{let i=await this.wsConnectOnce();return this.wsReconnectAttempts=0,i}catch(i){if(e=i instanceof Error?i:new Error(String(i)),!(e.message==="WebSocket connection timeout"))throw this.debug("WebSocket connection failed with non-timeout error, not retrying:",e.message),e;if(r<t-1){let d=this.webSocketInitialRetryDelay*Math.pow(2,r),l=Math.min(d,this.webSocketMaxRetryDelay),p=l*.2*Math.random(),c=l+p;this.debug(`WebSocket connection timeout (attempt ${r+1}/${t}), retrying in ${c.toFixed(0)}ms`),await new Promise(y=>setTimeout(y,c))}else this.debug(`WebSocket connection timeout (attempt ${r+1}/${t}), no more retries`)}throw e??new Error("WebSocket connection failed")};wsConnectOnce=()=>new Promise((e,t)=>{let r=`${this.webSocketUrl}/flags/bootstrap?apiKey=${this.apiKey}`;this.debug("connecting to WebSocket:",r);let i=new WebSocket(r),o=Math.random().toString(36).substring(7);this.debug(`Creating WebSocket connection ${o} to ${r}`);let d=null,l=!1,p=!1;d=setTimeout(()=>{l||(l=!0,this.debug(`WebSocket connection timeout after ${this.webSocketConnectionTimeout}ms`),i.close(),t(new Error("WebSocket connection timeout")))},this.webSocketConnectionTimeout),i.onopen=()=>{l||(l=!0,p=!0,d!==null&&clearTimeout(d),this.wsIntentionalDisconnect=!1,this.debug(`WebSocket connection ${o} opened successfully`),e(i))},i.onerror=c=>{if(l)return;l=!0,d!==null&&clearTimeout(d),this.debug(`WebSocket connection ${o} error:`,c);let y=new Error("WebSocket connection failed during handshake");t(y)},i.onclose=()=>{d!==null&&clearTimeout(d),this.debug(`WebSocket connection ${o} closed`),this.conn=null;let c=this.currentWebSocket===i;this.currentWebSocket===i&&(this.currentWebSocket=null,this.isConnecting=!1),c&&p&&!this.wsIntentionalDisconnect&&this.webSocketReconnect&&this.attemptReconnect()}});wsSendMessage=(e,t,r=!1)=>this.isOffline()?(this.debug("wsSendMessage: skipped (offline mode)"),this.setIsPending(!1),Promise.resolve()):new Promise((i,o)=>{if(!r&&h(t)==h(this.context))return this.debug("WebSocket context unchanged, skipping update"),i(this.setIsPending(!1));this.debug(r?"WebSocket force sending context (reconnection):":"WebSocket context updated:",t),this.context=t;let d=()=>{let l=!1,p=this.createPersistentMessageHandler(t),c=R=>{p(R),l||(l=!0,i())};e.addEventListener("message",c),e.addEventListener("close",R=>{l||(l=!0,R.code===4001?o(new Error(`Authentication failed: ${R.reason!==""?R.reason:"Invalid API key"}`)):o(new Error("WebSocket connection closed unexpectedly")))}),this.currentWebSocket=e;let y=this.additionalHeaders["X-Schematic-Client-Version"]??`schematic-js@${Te}`,u={apiKey:this.apiKey,clientVersion:y,data:t};this.debug("WebSocket sending message:",u),e.send(JSON.stringify(u))};e.readyState===WebSocket.OPEN?(this.debug("WebSocket already open, sending message"),d()):e.readyState===WebSocket.CONNECTING?(this.debug("WebSocket connecting, waiting for open to send message"),e.addEventListener("open",d)):(this.debug("WebSocket is closed, cannot send message"),o("WebSocket is not open or connecting"))});getIsPending=()=>this.isPending;addIsPendingListener=e=>(this.isPendingListeners.add(e),()=>{this.isPendingListeners.delete(e)});setIsPending=e=>{this.isPending!==e&&(this.isPending=e,this.isPendingListeners.forEach(t=>Bn(t,e)))};getPlan=()=>{let e=h(this.context);return this.planChecks[e]};getCreditBalances=()=>{let e=h(this.context);return this.creditBalances[e]??xn};getCreditBalance=e=>{let t=h(this.context);return this.creditBalances[t]?.[e]};getFlagCheck=e=>{let t=h(this.context),i=(this.checks[t]??{})[e];if(i!==void 0)return i;if(e in this.flagCheckDefaults||e in this.flagValueDefaults)return e in this.fallbackCheckCache||(this.fallbackCheckCache[e]=this.resolveFallbackCheckFlagReturn(e,void 0,"Default value used")),this.fallbackCheckCache[e]};getFlagValue=e=>{let t=h(this.context),i=(this.checks[t]??{})[e];if(i?.value!==void 0)return i.value;if(e in this.flagCheckDefaults||e in this.flagValueDefaults)return this.resolveFallbackValue(e)};addFlagValueListener=(e,t)=>(e in this.flagValueListeners||(this.flagValueListeners[e]=new Set),this.flagValueListeners[e].add(t),()=>{this.flagValueListeners[e].delete(t)});addFlagCheckListener=(e,t)=>(e in this.flagCheckListeners||(this.flagCheckListeners[e]=new Set),this.flagCheckListeners[e].add(t),()=>{this.flagCheckListeners[e].delete(t)});addPlanListener=e=>(this.planListeners.add(e),()=>{this.planListeners.delete(e)});addCreditBalanceListener=e=>(this.creditBalanceListeners.add(e),()=>{this.creditBalanceListeners.delete(e)});notifyFlagCheckListeners=(e,t)=>{let r=this.flagCheckListeners?.[e]??[];r.size>0&&this.debug(`Notifying ${r.size} flag check listeners for ${e}`,t),typeof t.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(t),r.forEach(i=>Nn(i,t))};updateFeatureUsageEventMap=e=>{if(typeof e.featureUsageEvent!="string")return;let t=e.featureUsageEvent;(this.featureUsageEventMap[t]===void 0||this.featureUsageEventMap[t]===null)&&(this.featureUsageEventMap[t]={}),this.featureUsageEventMap[t]!==void 0&&(this.featureUsageEventMap[t][e.flag]=e),this.debug(`Updated featureUsageEventMap for event: ${t}, flag: ${e.flag}`,e)};notifyFlagValueListeners=(e,t)=>{let r=this.flagValueListeners?.[e]??[];r.size>0&&this.debug(`Notifying ${r.size} flag value listeners for ${e}`,{value:t}),r.forEach((i,o)=>{this.debug(`Calling listener ${o} for flag ${e}`,{flagKey:e,value:t}),Fn(i,t),this.debug(`Listener ${o} for flag ${e} completed`,{flagKey:e,value:t})})};notifyPlanListeners=e=>{let t=this.planListeners??[];t.size>0&&this.debug(`Notifying ${t.size} plan listeners`,{value:e}),t.forEach((r,i)=>{this.debug(`Calling listener ${i} for plan`,{value:e}),Jn(r,e),this.debug(`Listener ${i} for plan completed`,{value:e})})};notifyCreditBalanceListeners=e=>{let t=this.creditBalanceListeners??[];t.size>0&&this.debug(`Notifying ${t.size} credit balance listeners`,{value:e}),t.forEach(r=>En(r,e))}},Bn=(n,e)=>{n.length>0?n(e):n()},Nn=(n,e)=>{n.length>0?n(e):n()},Fn=(n,e)=>{n.length>0?n(e):n()},Jn=(n,e)=>{n.length>0?n(e):n()},En=(n,e)=>{n.length>0?n(e):n()};window.Schematic=j;})();
|
|
3
3
|
/* @preserve */
|