@schematichq/schematic-js 1.2.17 → 1.2.18

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.
@@ -1,3 +1,3 @@
1
- "use strict";(()=>{var re=Object.create;var Q=Object.defineProperty;var ie=Object.getOwnPropertyDescriptor;var se=Object.getOwnPropertyNames;var ae=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var ce=(s,e)=>()=>(e||s((e={exports:{}}).exports,e),e.exports);var le=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of se(e))!oe.call(s,n)&&n!==t&&Q(s,n,{get:()=>e[n],enumerable:!(r=ie(e,n))||r.enumerable});return s};var ue=(s,e,t)=>(t=s!=null?re(ae(s)):{},le(e||!s||!s.__esModule?Q(t,"default",{value:s,enumerable:!0}):t,s));var G=ce(z=>{(function(s){var e=(function(t){var r=typeof globalThis<"u"&&globalThis||typeof s<"u"&&s||typeof global<"u"&&global||{},n={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 c(i){return i&&DataView.prototype.isPrototypeOf(i)}if(n.arrayBuffer)var o=["[object Int8Array]","[object Uint8Array]","[object Uint8ClampedArray]","[object Int16Array]","[object Uint16Array]","[object Int32Array]","[object Uint32Array]","[object Float32Array]","[object Float64Array]"],l=ArrayBuffer.isView||function(i){return i&&o.indexOf(Object.prototype.toString.call(i))>-1};function f(i){if(typeof i!="string"&&(i=String(i)),/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(i)||i==="")throw new TypeError('Invalid character in header field name: "'+i+'"');return i.toLowerCase()}function h(i){return typeof i!="string"&&(i=String(i)),i}function v(i){var a={next:function(){var u=i.shift();return{done:u===void 0,value:u}}};return n.iterable&&(a[Symbol.iterator]=function(){return a}),a}function g(i){this.map={},i instanceof g?i.forEach(function(a,u){this.append(u,a)},this):Array.isArray(i)?i.forEach(function(a){if(a.length!=2)throw new TypeError("Headers constructor: expected name/value pair to be length 2, found"+a.length);this.append(a[0],a[1])},this):i&&Object.getOwnPropertyNames(i).forEach(function(a){this.append(a,i[a])},this)}g.prototype.append=function(i,a){i=f(i),a=h(a);var u=this.map[i];this.map[i]=u?u+", "+a:a},g.prototype.delete=function(i){delete this.map[f(i)]},g.prototype.get=function(i){return i=f(i),this.has(i)?this.map[i]:null},g.prototype.has=function(i){return this.map.hasOwnProperty(f(i))},g.prototype.set=function(i,a){this.map[f(i)]=h(a)},g.prototype.forEach=function(i,a){for(var u in this.map)this.map.hasOwnProperty(u)&&i.call(a,this.map[u],u,this)},g.prototype.keys=function(){var i=[];return this.forEach(function(a,u){i.push(u)}),v(i)},g.prototype.values=function(){var i=[];return this.forEach(function(a){i.push(a)}),v(i)},g.prototype.entries=function(){var i=[];return this.forEach(function(a,u){i.push([u,a])}),v(i)},n.iterable&&(g.prototype[Symbol.iterator]=g.prototype.entries);function k(i){if(!i._noBody){if(i.bodyUsed)return Promise.reject(new TypeError("Already read"));i.bodyUsed=!0}}function F(i){return new Promise(function(a,u){i.onload=function(){a(i.result)},i.onerror=function(){u(i.error)}})}function T(i){var a=new FileReader,u=F(a);return a.readAsArrayBuffer(i),u}function W(i){var a=new FileReader,u=F(a),p=/charset=([A-Za-z0-9_-]+)/.exec(i.type),y=p?p[1]:"utf-8";return a.readAsText(i,y),u}function Y(i){for(var a=new Uint8Array(i),u=new Array(a.length),p=0;p<a.length;p++)u[p]=String.fromCharCode(a[p]);return u.join("")}function V(i){if(i.slice)return i.slice(0);var a=new Uint8Array(i.byteLength);return a.set(new Uint8Array(i)),a.buffer}function J(){return this.bodyUsed=!1,this._initBody=function(i){this.bodyUsed=this.bodyUsed,this._bodyInit=i,i?typeof i=="string"?this._bodyText=i:n.blob&&Blob.prototype.isPrototypeOf(i)?this._bodyBlob=i:n.formData&&FormData.prototype.isPrototypeOf(i)?this._bodyFormData=i:n.searchParams&&URLSearchParams.prototype.isPrototypeOf(i)?this._bodyText=i.toString():n.arrayBuffer&&n.blob&&c(i)?(this._bodyArrayBuffer=V(i.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer])):n.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(i)||l(i))?this._bodyArrayBuffer=V(i):this._bodyText=i=Object.prototype.toString.call(i):(this._noBody=!0,this._bodyText=""),this.headers.get("content-type")||(typeof i=="string"?this.headers.set("content-type","text/plain;charset=UTF-8"):this._bodyBlob&&this._bodyBlob.type?this.headers.set("content-type",this._bodyBlob.type):n.searchParams&&URLSearchParams.prototype.isPrototypeOf(i)&&this.headers.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"))},n.blob&&(this.blob=function(){var i=k(this);if(i)return i;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 i=k(this);return i||(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(n.blob)return this.blob().then(T);throw new Error("could not read as ArrayBuffer")}},this.text=function(){var i=k(this);if(i)return i;if(this._bodyBlob)return W(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(Y(this._bodyArrayBuffer));if(this._bodyFormData)throw new Error("could not read FormData body as text");return Promise.resolve(this._bodyText)},n.formData&&(this.formData=function(){return this.text().then(ee)}),this.json=function(){return this.text().then(JSON.parse)},this}var Z=["CONNECT","DELETE","GET","HEAD","OPTIONS","PATCH","POST","PUT","TRACE"];function j(i){var a=i.toUpperCase();return Z.indexOf(a)>-1?a:i}function R(i,a){if(!(this instanceof R))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');a=a||{};var u=a.body;if(i instanceof R){if(i.bodyUsed)throw new TypeError("Already read");this.url=i.url,this.credentials=i.credentials,a.headers||(this.headers=new g(i.headers)),this.method=i.method,this.mode=i.mode,this.signal=i.signal,!u&&i._bodyInit!=null&&(u=i._bodyInit,i.bodyUsed=!0)}else this.url=String(i);if(this.credentials=a.credentials||this.credentials||"same-origin",(a.headers||!this.headers)&&(this.headers=new g(a.headers)),this.method=j(a.method||this.method||"GET"),this.mode=a.mode||this.mode||null,this.signal=a.signal||this.signal||(function(){if("AbortController"in r){var d=new AbortController;return d.signal}})(),this.referrer=null,(this.method==="GET"||this.method==="HEAD")&&u)throw new TypeError("Body not allowed for GET or HEAD requests");if(this._initBody(u),(this.method==="GET"||this.method==="HEAD")&&(a.cache==="no-store"||a.cache==="no-cache")){var p=/([?&])_=[^&]*/;if(p.test(this.url))this.url=this.url.replace(p,"$1_="+new Date().getTime());else{var y=/\?/;this.url+=(y.test(this.url)?"&":"?")+"_="+new Date().getTime()}}}R.prototype.clone=function(){return new R(this,{body:this._bodyInit})};function ee(i){var a=new FormData;return i.trim().split("&").forEach(function(u){if(u){var p=u.split("="),y=p.shift().replace(/\+/g," "),d=p.join("=").replace(/\+/g," ");a.append(decodeURIComponent(y),decodeURIComponent(d))}}),a}function te(i){var a=new g,u=i.replace(/\r?\n[\t ]+/g," ");return u.split("\r").map(function(p){return p.indexOf(`
2
- `)===0?p.substr(1,p.length):p}).forEach(function(p){var y=p.split(":"),d=y.shift().trim();if(d){var D=y.join(":").trim();try{a.append(d,D)}catch(U){console.warn("Response "+U.message)}}}),a}J.call(R.prototype);function E(i,a){if(!(this instanceof E))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');if(a||(a={}),this.type="default",this.status=a.status===void 0?200:a.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=a.statusText===void 0?"":""+a.statusText,this.headers=new g(a.headers),this.url=a.url||"",this._initBody(i)}J.call(E.prototype),E.prototype.clone=function(){return new E(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new g(this.headers),url:this.url})},E.error=function(){var i=new E(null,{status:200,statusText:""});return i.ok=!1,i.status=0,i.type="error",i};var ne=[301,302,303,307,308];E.redirect=function(i,a){if(ne.indexOf(a)===-1)throw new RangeError("Invalid status code");return new E(null,{status:a,headers:{location:i}})},t.DOMException=r.DOMException;try{new t.DOMException}catch{t.DOMException=function(a,u){this.message=a,this.name=u;var p=Error(a);this.stack=p.stack},t.DOMException.prototype=Object.create(Error.prototype),t.DOMException.prototype.constructor=t.DOMException}function O(i,a){return new Promise(function(u,p){var y=new R(i,a);if(y.signal&&y.signal.aborted)return p(new t.DOMException("Aborted","AbortError"));var d=new XMLHttpRequest;function D(){d.abort()}d.onload=function(){var m={statusText:d.statusText,headers:te(d.getAllResponseHeaders()||"")};y.url.indexOf("file://")===0&&(d.status<200||d.status>599)?m.status=200:m.status=d.status,m.url="responseURL"in d?d.responseURL:m.headers.get("X-Request-URL");var S="response"in d?d.response:d.responseText;setTimeout(function(){u(new E(S,m))},0)},d.onerror=function(){setTimeout(function(){p(new TypeError("Network request failed"))},0)},d.ontimeout=function(){setTimeout(function(){p(new TypeError("Network request timed out"))},0)},d.onabort=function(){setTimeout(function(){p(new t.DOMException("Aborted","AbortError"))},0)};function U(m){try{return m===""&&r.location.href?r.location.href:m}catch{return m}}if(d.open(y.method,U(y.url),!0),y.credentials==="include"?d.withCredentials=!0:y.credentials==="omit"&&(d.withCredentials=!1),"responseType"in d&&(n.blob?d.responseType="blob":n.arrayBuffer&&(d.responseType="arraybuffer")),a&&typeof a.headers=="object"&&!(a.headers instanceof g||r.Headers&&a.headers instanceof r.Headers)){var q=[];Object.getOwnPropertyNames(a.headers).forEach(function(m){q.push(f(m)),d.setRequestHeader(m,h(a.headers[m]))}),y.headers.forEach(function(m,S){q.indexOf(S)===-1&&d.setRequestHeader(S,m)})}else y.headers.forEach(function(m,S){d.setRequestHeader(S,m)});y.signal&&(y.signal.addEventListener("abort",D),d.onreadystatechange=function(){d.readyState===4&&y.signal.removeEventListener("abort",D)}),d.send(typeof y._bodyInit>"u"?null:y._bodyInit)})}return O.polyfill=!0,r.fetch||(r.fetch=O,r.Headers=g,r.Request=R,r.Response=E),t.Headers=g,t.Request=R,t.Response=E,t.fetch=O,t})({})})(typeof self<"u"?self:z)});var b=[];for(let s=0;s<256;++s)b.push((s+256).toString(16).slice(1));function H(s,e=0){return(b[s[e+0]]+b[s[e+1]]+b[s[e+2]]+b[s[e+3]]+"-"+b[s[e+4]]+b[s[e+5]]+"-"+b[s[e+6]]+b[s[e+7]]+"-"+b[s[e+8]]+b[s[e+9]]+"-"+b[s[e+10]]+b[s[e+11]]+b[s[e+12]]+b[s[e+13]]+b[s[e+14]]+b[s[e+15]]).toLowerCase()}var I,de=new Uint8Array(16);function A(){if(!I){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");I=crypto.getRandomValues.bind(crypto)}return I(de)}var fe=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),P={randomUUID:fe};function he(s,e,t){s=s||{};let r=s.random??s.rng?.()??A();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 n=0;n<16;++n)e[t+n]=r[n];return e}return H(r)}function ge(s,e,t){return P.randomUUID&&!e&&!s?P.randomUUID():he(s,e,t)}var C=ge;var it=ue(G());function x(s){return pe(s,!1)}function pe(s,e){return s==null?s:{companyId:s.company_id==null?void 0:s.company_id,error:s.error==null?void 0:s.error,featureAllocation:s.feature_allocation==null?void 0:s.feature_allocation,featureUsage:s.feature_usage==null?void 0:s.feature_usage,featureUsageEvent:s.feature_usage_event==null?void 0:s.feature_usage_event,featureUsagePeriod:s.feature_usage_period==null?void 0:s.feature_usage_period,featureUsageResetAt:s.feature_usage_reset_at==null?void 0:new Date(s.feature_usage_reset_at),flag:s.flag,flagId:s.flag_id==null?void 0:s.flag_id,reason:s.reason,ruleId:s.rule_id==null?void 0:s.rule_id,ruleType:s.rule_type==null?void 0:s.rule_type,userId:s.user_id==null?void 0:s.user_id,value:s.value}}function N(s){return ye(s,!1)}function ye(s,e=!1){return s==null?s:{company_id:s.companyId,error:s.error,flag_id:s.flagId,flag_key:s.flagKey,reason:s.reason,req_company:s.reqCompany,req_user:s.reqUser,rule_id:s.ruleId,user_id:s.userId,value:s.value}}function L(s){return be(s,!1)}function be(s,e){return s==null?s:{data:x(s.data),params:s.params}}function X(s){return ve(s,!1)}function ve(s,e){return s==null?s:{flags:s.flags.map(x)}}function B(s){return ke(s,!1)}function ke(s,e){return s==null?s:{data:X(s.data),params:s.params}}var M=s=>{let{companyId:e,error:t,featureAllocation:r,featureUsage:n,featureUsageEvent:c,featureUsagePeriod:o,featureUsageResetAt:l,flag:f,flagId:h,reason:v,ruleId:g,ruleType:k,userId:F,value:T}=x(s);return{featureUsageExceeded:!T&&(k=="company_override_usage_exceeded"||k=="plan_entitlement_usage_exceeded"),companyId:e??void 0,error:t??void 0,featureAllocation:r??void 0,featureUsage:n??void 0,featureUsageEvent:c===null?void 0:c,featureUsagePeriod:o??void 0,featureUsageResetAt:l??void 0,flag:f,flagId:h??void 0,reason:v,ruleId:g??void 0,ruleType:k??void 0,userId:F??void 0,value:T}};function w(s){let e=Object.keys(s).reduce((t,r)=>{let c=Object.keys(s[r]||{}).sort().reduce((o,l)=>(o[l]=s[r][l],o),{});return t[r]=c,t},{});return JSON.stringify(e)}var $="1.2.17";var K="schematicId";var _=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;storage;useWebSocket=!1;checks={};featureUsageEventMap={};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={};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 r=new URLSearchParams(window.location.search),n=r.get("schematic_debug");n!==null&&(n===""||n==="true"||n==="1")&&(this.debugEnabled=!0);let c=r.get("schematic_offline");c!==null&&(c===""||c==="true"||c==="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@${$}`,...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,r="Fallback value used",n){if(t!==void 0)return{flag:e,value:t,reason:r,error:n};if(e in this.flagCheckDefaults){let c=this.flagCheckDefaults[e];return{...c,flag:e,reason:n!==void 0?r:c.reason,error:n}}return e in this.flagValueDefaults?{flag:e,value:this.flagValueDefaults[e],reason:r,error:n}:{flag:e,value:!1,reason:r,error:n}}async checkFlag(e){let{fallback:t,key:r}=e,n=e.context||this.context,c=w(n);if(this.debug(`checkFlag: ${r}`,{context:n,fallback:t}),this.isOffline()){let o=this.resolveFallbackCheckFlagReturn(r,t,"Offline mode - using initialization defaults");return this.debug(`checkFlag offline result: ${r}`,{value:o.value,offlineMode:!0}),o.value}if(!this.useWebSocket){let o=`${this.apiUrl}/flags/${r}/check`;return fetch(o,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:JSON.stringify(n)}).then(l=>{if(!l.ok)throw new Error("Network response was not ok");return l.json()}).then(l=>{let f=L(l);this.debug(`checkFlag result: ${r}`,f);let h=M(f.data);return typeof h.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(h),this.submitFlagCheckEvent(r,h,n),h.value}).catch(l=>{console.warn("There was a problem with the fetch operation:",l);let f=this.resolveFallbackCheckFlagReturn(r,t,"API request failed",l instanceof Error?l.message:String(l));return this.submitFlagCheckEvent(r,f,n),f.value})}try{let o=this.checks[c];if(this.conn!==null&&typeof o<"u"&&typeof o[r]<"u")return this.debug(`checkFlag cached result: ${r}`,o[r]),o[r].value;if(this.isOffline())return this.resolveFallbackValue(r,t);try{await this.setContext(n)}catch(v){console.warn("WebSocket connection failed, using fallback value:",v);let g=this.resolveFallbackCheckFlagReturn(r,t,"WebSocket connection failed",v instanceof Error?v.message:String(v));return this.submitFlagCheckEvent(r,g,n),g.value}let f=(this.checks[c]??{})[r],h=f?.value??this.resolveFallbackValue(r,t);return this.debug(`checkFlag WebSocket result: ${r}`,typeof f<"u"?f:{value:h,fallbackUsed:!0}),typeof f<"u"&&this.submitFlagCheckEvent(r,f,n),h}catch(o){console.error("Unexpected error in checkFlag:",o);let l=this.resolveFallbackCheckFlagReturn(r,t,"Unexpected error in flag check",o instanceof Error?o.message:String(o));return this.submitFlagCheckEvent(r,l,n),l.value}}debug(e,...t){this.debugEnabled&&console.log(`[Schematic] ${e}`,...t)}createPersistentMessageHandler(e){return t=>{let r=JSON.parse(t.data);this.debug("WebSocket persistent message received:",r),w(e)in this.checks||(this.checks[w(e)]={}),(r.flags??[]).forEach(n=>{let c=M(n),o=w(e);this.checks[o]===void 0&&(this.checks[o]={}),this.checks[o][c.flag]=c,this.debug("WebSocket flag update:",{flag:c.flag,value:c.value,flagCheck:c}),typeof c.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(c),((this.flagCheckListeners[n.flag]?.size??0)>0||(this.flagValueListeners[n.flag]?.size??0)>0)&&this.submitFlagCheckEvent(c.flag,c,e),this.debug(`About to notify listeners for flag ${n.flag}`,{flag:n.flag,value:c.value}),this.notifyFlagCheckListeners(n.flag,c),this.notifyFlagValueListeners(n.flag,c.value),this.debug(`Finished notifying listeners for flag ${n.flag}`,{flag:n.flag,value:c.value})}),this.flushContextDependentEventQueue(),this.setIsPending(!1)}}isOffline(){return this.offlineEnabled}submitFlagCheckEvent(e,t,r){let n={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:",n),this.handleEvent("flag_check",N(n))}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(n=>{if(!n.ok)throw new Error("Network response was not ok");return n.json()}).then(n=>{let c=B(n);return this.debug("checkFlags result:",c),(c?.data?.flags??[]).reduce((o,l)=>(o[l.flag]=l.value,o),{})}).catch(n=>(console.warn("There was a problem with the fetch operation:",n),{}))};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();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(r=>setTimeout(r,10));if(this.conn!==null){let r=await this.conn;await this.wsSendMessage(r,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 r=await this.conn;this.isConnecting=!1,await this.wsSendMessage(r,e);return}catch(r){throw this.isConnecting=!1,r}}let t=await this.conn;await this.wsSendMessage(t,e)}catch(t){throw console.warn("Failed to establish WebSocket connection:",t),t}};track=e=>{let{company:t,user:r,event:n,traits:c,quantity:o=1}=e;if(!this.hasContext(t,r)){this.debug(`track: queuing event "${n}" until context is available`);let f={api_key:this.apiKey,body:{company:t,event:n,traits:c??{},user:r,quantity:o},sent_at:new Date().toISOString(),tracker_event_id:C(),tracker_user_id:this.getAnonymousId(),type:"track"};return this.contextDependentEventQueue.push(f),Promise.resolve()}let l={company:t??this.context.company,event:n,traits:c??{},user:r??this.context.user,quantity:o};return this.debug("track:",l),n in this.featureUsageEventMap&&this.optimisticallyUpdateFeatureUsage(n,o),this.handleEvent("track",l)};optimisticallyUpdateFeatureUsage=(e,t=1)=>{let r=this.featureUsageEventMap[e];r!=null&&(this.debug(`Optimistically updating feature usage for event: ${e}`,{quantity:t}),Object.entries(r).forEach(([n,c])=>{if(c===void 0)return;let o={...c};if(typeof o.featureUsage=="number"){if(o.featureUsage+=t,typeof o.featureAllocation=="number"){let f=o.featureUsageExceeded===!0,h=o.featureUsage>=o.featureAllocation;h!==f&&(o.featureUsageExceeded=h,h&&(o.value=!1),this.debug(`Usage limit status changed for flag: ${n}`,{was:f?"exceeded":"within limits",now:h?"exceeded":"within limits",featureUsage:o.featureUsage,featureAllocation:o.featureAllocation,value:o.value}))}this.featureUsageEventMap[e]!==void 0&&(this.featureUsageEventMap[e][n]=o);let l=w(this.context);this.checks[l]!==void 0&&this.checks[l]!==null&&(this.checks[l][n]=o),this.notifyFlagCheckListeners(n,o),this.notifyFlagValueListeners(n,o.value)}}))};hasContext=(e,t)=>{let r=e!=null&&Object.keys(e).length>0||t!=null&&Object.keys(t).length>0,n=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||n};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},n={...e,body:r,sent_at:new Date().toISOString()};this.sendEvent(n)}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 n of this.eventQueue)n.next_retry_at===void 0||n.next_retry_at<=e?t.push(n):r.push(n);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 n of t)try{await this.sendEvent(n),this.debug("Queued event sent successfully:",n.type)}catch(c){this.debug("Failed to send queued event:",c)}};getAnonymousId=()=>{if(!this.storage)return C();let e=this.storage.getItem(K);if(typeof e<"u")return e;let t=C();return this.storage.setItem(K,t),t};handleEvent=(e,t)=>{let r={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(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 n=await fetch(t,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8"},body:r});if(!n.ok)throw new Error(`HTTP ${n.status}: ${n.statusText}`);this.debug("event sent:",{status:n.status,statusText:n.statusText})}catch(n){let c=(e.retry_count??0)+1;if(c<=this.maxEventRetries){this.debug(`Event failed to send (attempt ${c}/${this.maxEventRetries}), queueing for retry:`,n);let o=this.eventRetryInitialDelay*Math.pow(2,c-1),l=Math.min(o,this.eventRetryMaxDelay),f=Date.now()+l,h={...e,retry_count:c,next_retry_at:f};this.eventQueue.length<this.maxEventQueueSize?(this.eventQueue.push(h),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(h)),this.startRetryTimer()}else this.debug(`Event failed permanently after ${this.maxEventRetries} attempts, dropping:`,n)}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 n=await this.conn;this.currentWebSocket===n&&(this.currentWebSocket=null),(n.readyState===WebSocket.OPEN||n.readyState===WebSocket.CONNECTING)&&n.close()}catch(n){this.debug(`${r}: error closing existing connection:`,n)}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 n=await this.conn;this.isConnecting=!1,await this.wsSendMessage(n,this.context,!0),this.debug(`${r}: reconnection successful`)}catch(n){this.isConnecting=!1,this.debug(`${r}: reconnection failed:`,n)}}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,n=t+r;return this.debug(`Reconnect delay calculated: ${n.toFixed(0)}ms (attempt ${this.wsReconnectAttempts+1}/${this.webSocketMaxReconnectAttempts})`),n};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(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 n=await this.wsConnectOnce();return this.wsReconnectAttempts=0,n}catch(n){if(e=n instanceof Error?n:new Error(String(n)),!(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 o=this.webSocketInitialRetryDelay*Math.pow(2,r),l=Math.min(o,this.webSocketMaxRetryDelay),f=l*.2*Math.random(),h=l+f;this.debug(`WebSocket connection timeout (attempt ${r+1}/${t}), retrying in ${h.toFixed(0)}ms`),await new Promise(v=>setTimeout(v,h))}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 n=new WebSocket(r),c=Math.random().toString(36).substring(7);this.debug(`Creating WebSocket connection ${c} to ${r}`);let o=null,l=!1;o=setTimeout(()=>{l||(l=!0,this.debug(`WebSocket connection timeout after ${this.webSocketConnectionTimeout}ms`),n.close(),t(new Error("WebSocket connection timeout")))},this.webSocketConnectionTimeout),n.onopen=()=>{l||(l=!0,o!==null&&clearTimeout(o),this.wsIntentionalDisconnect=!1,this.debug(`WebSocket connection ${c} opened successfully`),e(n))},n.onerror=f=>{if(l)return;l=!0,o!==null&&clearTimeout(o),this.debug(`WebSocket connection ${c} error:`,f);let h=new Error("WebSocket connection failed during handshake");t(h)},n.onclose=()=>{o!==null&&clearTimeout(o),this.debug(`WebSocket connection ${c} closed`),this.conn=null,this.currentWebSocket===n&&(this.currentWebSocket=null,this.isConnecting=!1),!l&&!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((n,c)=>{if(!r&&w(t)==w(this.context))return this.debug("WebSocket context unchanged, skipping update"),n(this.setIsPending(!1));this.debug(r?"WebSocket force sending context (reconnection):":"WebSocket context updated:",t),this.context=t;let o=()=>{let l=!1,f=this.createPersistentMessageHandler(t),h=k=>{f(k),l||(l=!0,n())};e.addEventListener("message",h),e.addEventListener("close",k=>{l||(l=!0,k.code===4001?c(new Error(`Authentication failed: ${k.reason!==""?k.reason:"Invalid API key"}`)):c(new Error("WebSocket connection closed unexpectedly")))}),this.currentWebSocket=e;let v=this.additionalHeaders["X-Schematic-Client-Version"]??`schematic-js@${$}`,g={apiKey:this.apiKey,clientVersion:v,data:t};this.debug("WebSocket sending message:",g),e.send(JSON.stringify(g))};e.readyState===WebSocket.OPEN?(this.debug("WebSocket already open, sending message"),o()):e.readyState===WebSocket.CONNECTING?(this.debug("WebSocket connecting, waiting for open to send message"),e.addEventListener("open",o)):(this.debug("WebSocket is closed, cannot send message"),c("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.isPendingListeners.forEach(t=>Ee(t,e))};getFlagCheck=e=>{let t=w(this.context),n=(this.checks[t]??{})[e];if(n!==void 0)return n;if(e in this.flagCheckDefaults||e in this.flagValueDefaults)return this.resolveFallbackCheckFlagReturn(e,void 0,"Default value used")};getFlagValue=e=>{let t=w(this.context),n=(this.checks[t]??{})[e];if(n?.value!==void 0)return n.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)});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(n=>we(n,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((n,c)=>{this.debug(`Calling listener ${c} for flag ${e}`,{flagKey:e,value:t}),Re(n,t),this.debug(`Listener ${c} for flag ${e} completed`,{flagKey:e,value:t})})}},Ee=(s,e)=>{s.length>0?s(e):s()},we=(s,e)=>{s.length>0?s(e):s()},Re=(s,e)=>{s.length>0?s(e):s()};window.Schematic=_;})();
1
+ "use strict";(()=>{var se=Object.create;var Q=Object.defineProperty;var ae=Object.getOwnPropertyDescriptor;var oe=Object.getOwnPropertyNames;var le=Object.getPrototypeOf,ce=Object.prototype.hasOwnProperty;var ue=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports);var de=(n,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of oe(e))!ce.call(n,r)&&r!==t&&Q(n,r,{get:()=>e[r],enumerable:!(i=ae(e,r))||i.enumerable});return n};var fe=(n,e,t)=>(t=n!=null?se(le(n)):{},de(e||!n||!n.__esModule?Q(t,"default",{value:n,enumerable:!0}):t,n));var G=ue(z=>{(function(n){var e=(function(t){var i=typeof globalThis<"u"&&globalThis||typeof n<"u"&&n||typeof global<"u"&&global||{},r={searchParams:"URLSearchParams"in i,iterable:"Symbol"in i&&"iterator"in Symbol,blob:"FileReader"in i&&"Blob"in i&&(function(){try{return new Blob,!0}catch{return!1}})(),formData:"FormData"in i,arrayBuffer:"ArrayBuffer"in i};function l(s){return s&&DataView.prototype.isPrototypeOf(s)}if(r.arrayBuffer)var o=["[object Int8Array]","[object Uint8Array]","[object Uint8ClampedArray]","[object Int16Array]","[object Uint16Array]","[object Int32Array]","[object Uint32Array]","[object Float32Array]","[object Float64Array]"],c=ArrayBuffer.isView||function(s){return s&&o.indexOf(Object.prototype.toString.call(s))>-1};function f(s){if(typeof s!="string"&&(s=String(s)),/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(s)||s==="")throw new TypeError('Invalid character in header field name: "'+s+'"');return s.toLowerCase()}function h(s){return typeof s!="string"&&(s=String(s)),s}function k(s){var a={next:function(){var u=s.shift();return{done:u===void 0,value:u}}};return r.iterable&&(a[Symbol.iterator]=function(){return a}),a}function g(s){this.map={},s instanceof g?s.forEach(function(a,u){this.append(u,a)},this):Array.isArray(s)?s.forEach(function(a){if(a.length!=2)throw new TypeError("Headers constructor: expected name/value pair to be length 2, found"+a.length);this.append(a[0],a[1])},this):s&&Object.getOwnPropertyNames(s).forEach(function(a){this.append(a,s[a])},this)}g.prototype.append=function(s,a){s=f(s),a=h(a);var u=this.map[s];this.map[s]=u?u+", "+a:a},g.prototype.delete=function(s){delete this.map[f(s)]},g.prototype.get=function(s){return s=f(s),this.has(s)?this.map[s]:null},g.prototype.has=function(s){return this.map.hasOwnProperty(f(s))},g.prototype.set=function(s,a){this.map[f(s)]=h(a)},g.prototype.forEach=function(s,a){for(var u in this.map)this.map.hasOwnProperty(u)&&s.call(a,this.map[u],u,this)},g.prototype.keys=function(){var s=[];return this.forEach(function(a,u){s.push(u)}),k(s)},g.prototype.values=function(){var s=[];return this.forEach(function(a){s.push(a)}),k(s)},g.prototype.entries=function(){var s=[];return this.forEach(function(a,u){s.push([u,a])}),k(s)},r.iterable&&(g.prototype[Symbol.iterator]=g.prototype.entries);function v(s){if(!s._noBody){if(s.bodyUsed)return Promise.reject(new TypeError("Already read"));s.bodyUsed=!0}}function C(s){return new Promise(function(a,u){s.onload=function(){a(s.result)},s.onerror=function(){u(s.error)}})}function T(s){var a=new FileReader,u=C(a);return a.readAsArrayBuffer(s),u}function $(s){var a=new FileReader,u=C(a),p=/charset=([A-Za-z0-9_-]+)/.exec(s.type),m=p?p[1]:"utf-8";return a.readAsText(s,m),u}function j(s){for(var a=new Uint8Array(s),u=new Array(a.length),p=0;p<a.length;p++)u[p]=String.fromCharCode(a[p]);return u.join("")}function W(s){if(s.slice)return s.slice(0);var a=new Uint8Array(s.byteLength);return a.set(new Uint8Array(s)),a.buffer}function J(){return this.bodyUsed=!1,this._initBody=function(s){this.bodyUsed=this.bodyUsed,this._bodyInit=s,s?typeof s=="string"?this._bodyText=s:r.blob&&Blob.prototype.isPrototypeOf(s)?this._bodyBlob=s:r.formData&&FormData.prototype.isPrototypeOf(s)?this._bodyFormData=s:r.searchParams&&URLSearchParams.prototype.isPrototypeOf(s)?this._bodyText=s.toString():r.arrayBuffer&&r.blob&&l(s)?(this._bodyArrayBuffer=W(s.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer])):r.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(s)||c(s))?this._bodyArrayBuffer=W(s):this._bodyText=s=Object.prototype.toString.call(s):(this._noBody=!0,this._bodyText=""),this.headers.get("content-type")||(typeof s=="string"?this.headers.set("content-type","text/plain;charset=UTF-8"):this._bodyBlob&&this._bodyBlob.type?this.headers.set("content-type",this._bodyBlob.type):r.searchParams&&URLSearchParams.prototype.isPrototypeOf(s)&&this.headers.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"))},r.blob&&(this.blob=function(){var s=v(this);if(s)return s;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 s=v(this);return s||(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(r.blob)return this.blob().then(T);throw new Error("could not read as ArrayBuffer")}},this.text=function(){var s=v(this);if(s)return s;if(this._bodyBlob)return $(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(j(this._bodyArrayBuffer));if(this._bodyFormData)throw new Error("could not read FormData body as text");return Promise.resolve(this._bodyText)},r.formData&&(this.formData=function(){return this.text().then(ne)}),this.json=function(){return this.text().then(JSON.parse)},this}var ee=["CONNECT","DELETE","GET","HEAD","OPTIONS","PATCH","POST","PUT","TRACE"];function te(s){var a=s.toUpperCase();return ee.indexOf(a)>-1?a:s}function R(s,a){if(!(this instanceof R))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');a=a||{};var u=a.body;if(s instanceof R){if(s.bodyUsed)throw new TypeError("Already read");this.url=s.url,this.credentials=s.credentials,a.headers||(this.headers=new g(s.headers)),this.method=s.method,this.mode=s.mode,this.signal=s.signal,!u&&s._bodyInit!=null&&(u=s._bodyInit,s.bodyUsed=!0)}else this.url=String(s);if(this.credentials=a.credentials||this.credentials||"same-origin",(a.headers||!this.headers)&&(this.headers=new g(a.headers)),this.method=te(a.method||this.method||"GET"),this.mode=a.mode||this.mode||null,this.signal=a.signal||this.signal||(function(){if("AbortController"in i){var d=new AbortController;return d.signal}})(),this.referrer=null,(this.method==="GET"||this.method==="HEAD")&&u)throw new TypeError("Body not allowed for GET or HEAD requests");if(this._initBody(u),(this.method==="GET"||this.method==="HEAD")&&(a.cache==="no-store"||a.cache==="no-cache")){var p=/([?&])_=[^&]*/;if(p.test(this.url))this.url=this.url.replace(p,"$1_="+new Date().getTime());else{var m=/\?/;this.url+=(m.test(this.url)?"&":"?")+"_="+new Date().getTime()}}}R.prototype.clone=function(){return new R(this,{body:this._bodyInit})};function ne(s){var a=new FormData;return s.trim().split("&").forEach(function(u){if(u){var p=u.split("="),m=p.shift().replace(/\+/g," "),d=p.join("=").replace(/\+/g," ");a.append(decodeURIComponent(m),decodeURIComponent(d))}}),a}function re(s){var a=new g,u=s.replace(/\r?\n[\t ]+/g," ");return u.split("\r").map(function(p){return p.indexOf(`
2
+ `)===0?p.substr(1,p.length):p}).forEach(function(p){var m=p.split(":"),d=m.shift().trim();if(d){var _=m.join(":").trim();try{a.append(d,_)}catch(I){console.warn("Response "+I.message)}}}),a}J.call(R.prototype);function E(s,a){if(!(this instanceof E))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');if(a||(a={}),this.type="default",this.status=a.status===void 0?200:a.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=a.statusText===void 0?"":""+a.statusText,this.headers=new g(a.headers),this.url=a.url||"",this._initBody(s)}J.call(E.prototype),E.prototype.clone=function(){return new E(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new g(this.headers),url:this.url})},E.error=function(){var s=new E(null,{status:200,statusText:""});return s.ok=!1,s.status=0,s.type="error",s};var ie=[301,302,303,307,308];E.redirect=function(s,a){if(ie.indexOf(a)===-1)throw new RangeError("Invalid status code");return new E(null,{status:a,headers:{location:s}})},t.DOMException=i.DOMException;try{new t.DOMException}catch{t.DOMException=function(a,u){this.message=a,this.name=u;var p=Error(a);this.stack=p.stack},t.DOMException.prototype=Object.create(Error.prototype),t.DOMException.prototype.constructor=t.DOMException}function O(s,a){return new Promise(function(u,p){var m=new R(s,a);if(m.signal&&m.signal.aborted)return p(new t.DOMException("Aborted","AbortError"));var d=new XMLHttpRequest;function _(){d.abort()}d.onload=function(){var y={statusText:d.statusText,headers:re(d.getAllResponseHeaders()||"")};m.url.indexOf("file://")===0&&(d.status<200||d.status>599)?y.status=200:y.status=d.status,y.url="responseURL"in d?d.responseURL:y.headers.get("X-Request-URL");var F="response"in d?d.response:d.responseText;setTimeout(function(){u(new E(F,y))},0)},d.onerror=function(){setTimeout(function(){p(new TypeError("Network request failed"))},0)},d.ontimeout=function(){setTimeout(function(){p(new TypeError("Network request timed out"))},0)},d.onabort=function(){setTimeout(function(){p(new t.DOMException("Aborted","AbortError"))},0)};function I(y){try{return y===""&&i.location.href?i.location.href:y}catch{return y}}if(d.open(m.method,I(m.url),!0),m.credentials==="include"?d.withCredentials=!0:m.credentials==="omit"&&(d.withCredentials=!1),"responseType"in d&&(r.blob?d.responseType="blob":r.arrayBuffer&&(d.responseType="arraybuffer")),a&&typeof a.headers=="object"&&!(a.headers instanceof g||i.Headers&&a.headers instanceof i.Headers)){var q=[];Object.getOwnPropertyNames(a.headers).forEach(function(y){q.push(f(y)),d.setRequestHeader(y,h(a.headers[y]))}),m.headers.forEach(function(y,F){q.indexOf(F)===-1&&d.setRequestHeader(F,y)})}else m.headers.forEach(function(y,F){d.setRequestHeader(F,y)});m.signal&&(m.signal.addEventListener("abort",_),d.onreadystatechange=function(){d.readyState===4&&m.signal.removeEventListener("abort",_)}),d.send(typeof m._bodyInit>"u"?null:m._bodyInit)})}return O.polyfill=!0,i.fetch||(i.fetch=O,i.Headers=g,i.Request=R,i.Response=E),t.Headers=g,t.Request=R,t.Response=E,t.fetch=O,t})({})})(typeof self<"u"?self:z)});var b=[];for(let n=0;n<256;++n)b.push((n+256).toString(16).slice(1));function H(n,e=0){return(b[n[e+0]]+b[n[e+1]]+b[n[e+2]]+b[n[e+3]]+"-"+b[n[e+4]]+b[n[e+5]]+"-"+b[n[e+6]]+b[n[e+7]]+"-"+b[n[e+8]]+b[n[e+9]]+"-"+b[n[e+10]]+b[n[e+11]]+b[n[e+12]]+b[n[e+13]]+b[n[e+14]]+b[n[e+15]]).toLowerCase()}var U,he=new Uint8Array(16);function A(){if(!U){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");U=crypto.getRandomValues.bind(crypto)}return U(he)}var ge=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),P={randomUUID:ge};function pe(n,e,t){n=n||{};let i=n.random??n.rng?.()??A();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 H(i)}function me(n,e,t){return P.randomUUID&&!e&&!n?P.randomUUID():pe(n,e,t)}var S=me;var bt=fe(G());function X(n){return ye(n,!1)}function ye(n,e){return n}function K(n){return be(n,!1)}function be(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:X(n.value_type)}}function x(n){return ke(n,!1)}function ke(n,e){return n==null?n:{companyId:n.company_id==null?void 0:n.company_id,entitlement:n.entitlement==null?void 0:K(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 N(n){return ve(n,!1)}function ve(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}}function L(n){return we(n,!1)}function we(n,e){return n==null?n:{data:x(n.data),params:n.params}}function Y(n){return Re(n,!1)}function Re(n,e){return n==null?n:{flags:n.flags.map(x)}}function B(n){return Fe(n,!1)}function Fe(n,e){return n==null?n:{data:Y(n.data),params:n.params}}var M=n=>{let{companyId:e,error:t,featureAllocation:i,featureUsage:r,featureUsageEvent:l,featureUsagePeriod:o,featureUsageResetAt:c,flag:f,flagId:h,reason:k,ruleId:g,ruleType:v,userId:C,value:T}=x(n);return{featureUsageExceeded:!T&&(v=="company_override_usage_exceeded"||v=="plan_entitlement_usage_exceeded"),companyId:e??void 0,error:t??void 0,featureAllocation:i??void 0,featureUsage:r??void 0,featureUsageEvent:l===null?void 0:l,featureUsagePeriod:o??void 0,featureUsageResetAt:c??void 0,flag:f,flagId:h??void 0,reason:k,ruleId:g??void 0,ruleType:v??void 0,userId:C??void 0,value:T}};function w(n){let e=Object.keys(n).reduce((t,i)=>{let l=Object.keys(n[i]||{}).sort().reduce((o,c)=>(o[c]=n[i][c],o),{});return t[i]=l,t},{});return JSON.stringify(e)}var V="1.2.18";var Z="schematicId";var D=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;storage;useWebSocket=!1;checks={};featureUsageEventMap={};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={};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@${V}`,...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=w(r);if(this.debug(`checkFlag: ${i}`,{context:r,fallback:t}),this.isOffline()){let o=this.resolveFallbackCheckFlagReturn(i,t,"Offline mode - using initialization defaults");return this.debug(`checkFlag offline result: ${i}`,{value:o.value,offlineMode:!0}),o.value}if(!this.useWebSocket){let o=`${this.apiUrl}/flags/${i}/check`;return fetch(o,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:JSON.stringify(r)}).then(c=>{if(!c.ok)throw new Error("Network response was not ok");return c.json()}).then(c=>{let f=L(c);this.debug(`checkFlag result: ${i}`,f);let h=M(f.data);return typeof h.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(h),this.submitFlagCheckEvent(i,h,r),h.value}).catch(c=>{console.warn("There was a problem with the fetch operation:",c);let f=this.resolveFallbackCheckFlagReturn(i,t,"API request failed",c instanceof Error?c.message:String(c));return this.submitFlagCheckEvent(i,f,r),f.value})}try{let o=this.checks[l];if(this.conn!==null&&typeof o<"u"&&typeof o[i]<"u")return this.debug(`checkFlag cached result: ${i}`,o[i]),o[i].value;if(this.isOffline())return this.resolveFallbackValue(i,t);try{await this.setContext(r)}catch(k){console.warn("WebSocket connection failed, using fallback value:",k);let g=this.resolveFallbackCheckFlagReturn(i,t,"WebSocket connection failed",k instanceof Error?k.message:String(k));return this.submitFlagCheckEvent(i,g,r),g.value}let f=(this.checks[l]??{})[i],h=f?.value??this.resolveFallbackValue(i,t);if(this.debug(`checkFlag WebSocket result: ${i}`,typeof f<"u"?f:{value:h,fallbackUsed:!0}),typeof f<"u")this.submitFlagCheckEvent(i,f,r);else{let k=this.resolveFallbackCheckFlagReturn(i,t,"No flag values available");this.submitFlagCheckEvent(i,k,r)}return h}catch(o){console.error("Unexpected error in checkFlag:",o);let c=this.resolveFallbackCheckFlagReturn(i,t,"Unexpected error in flag check",o instanceof Error?o.message:String(o));return this.submitFlagCheckEvent(i,c,r),c.value}}debug(e,...t){this.debugEnabled&&console.log(`[Schematic] ${e}`,...t)}createPersistentMessageHandler(e){return t=>{let i=JSON.parse(t.data);this.debug("WebSocket persistent message received:",i),w(e)in this.checks||(this.checks[w(e)]={}),(i.flags??[]).forEach(r=>{let l=M(r),o=w(e);this.checks[o]===void 0&&(this.checks[o]={}),this.checks[o][l.flag]=l,this.debug("WebSocket flag update:",{flag:l.flag,value:l.value,flagCheck: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(`About to notify listeners for flag ${r.flag}`,{flag:r.flag,value:l.value}),this.notifyFlagCheckListeners(r.flag,l),this.notifyFlagValueListeners(r.flag,l.value),this.debug(`Finished notifying listeners for flag ${r.flag}`,{flag:r.flag,value:l.value})}),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",N(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=B(r);return this.debug("checkFlags result:",l),(l?.data?.flags??[]).reduce((o,c)=>(o[c.flag]=c.value,o),{})}).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();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:o=1}=e;if(!this.hasContext(t,i)){this.debug(`track: queuing event "${r}" until context is available`);let f={api_key:this.apiKey,body:{company:t,event:r,traits:l??{},user:i,quantity:o},sent_at:new Date().toISOString(),tracker_event_id:S(),tracker_user_id:this.getAnonymousId(),type:"track"};return this.contextDependentEventQueue.push(f),Promise.resolve()}let c={company:t??this.context.company,event:r,traits:l??{},user:i??this.context.user,quantity:o};return this.debug("track:",c),r in this.featureUsageEventMap&&this.optimisticallyUpdateFeatureUsage(r,o),this.handleEvent("track",c)};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 o={...l};if(typeof o.featureUsage=="number"){if(o.featureUsage+=t,typeof o.featureAllocation=="number"){let f=o.featureUsageExceeded===!0,h=o.featureUsage>=o.featureAllocation;h!==f&&(o.featureUsageExceeded=h,h&&(o.value=!1),this.debug(`Usage limit status changed for flag: ${r}`,{was:f?"exceeded":"within limits",now:h?"exceeded":"within limits",featureUsage:o.featureUsage,featureAllocation:o.featureAllocation,value:o.value}))}this.featureUsageEventMap[e]!==void 0&&(this.featureUsageEventMap[e][r]=o);let c=w(this.context);this.checks[c]!==void 0&&this.checks[c]!==null&&(this.checks[c][r]=o),this.notifyFlagCheckListeners(r,o),this.notifyFlagValueListeners(r,o.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 S();let e=this.storage.getItem(Z);if(typeof e<"u")return e;let t=S();return this.storage.setItem(Z,t),t};handleEvent=(e,t)=>{let i={api_key:this.apiKey,body:t,sent_at:new Date().toISOString(),tracker_event_id:S(),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 o=this.eventRetryInitialDelay*Math.pow(2,l-1),c=Math.min(o,this.eventRetryMaxDelay),f=Date.now()+c,h={...e,retry_count:l,next_retry_at:f};this.eventQueue.length<this.maxEventQueueSize?(this.eventQueue.push(h),this.debug(`Event queued for retry in ${c}ms (${this.eventQueue.length}/${this.maxEventQueueSize})`)):(this.debug(`Event queue full (${this.maxEventQueueSize}), dropping oldest event`),this.eventQueue.shift(),this.eventQueue.push(h)),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 o=this.webSocketInitialRetryDelay*Math.pow(2,i),c=Math.min(o,this.webSocketMaxRetryDelay),f=c*.2*Math.random(),h=c+f;this.debug(`WebSocket connection timeout (attempt ${i+1}/${t}), retrying in ${h.toFixed(0)}ms`),await new Promise(k=>setTimeout(k,h))}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 o=null,c=!1;o=setTimeout(()=>{c||(c=!0,this.debug(`WebSocket connection timeout after ${this.webSocketConnectionTimeout}ms`),r.close(),t(new Error("WebSocket connection timeout")))},this.webSocketConnectionTimeout),r.onopen=()=>{c||(c=!0,o!==null&&clearTimeout(o),this.wsIntentionalDisconnect=!1,this.debug(`WebSocket connection ${l} opened successfully`),e(r))},r.onerror=f=>{if(c)return;c=!0,o!==null&&clearTimeout(o),this.debug(`WebSocket connection ${l} error:`,f);let h=new Error("WebSocket connection failed during handshake");t(h)},r.onclose=()=>{o!==null&&clearTimeout(o),this.debug(`WebSocket connection ${l} closed`),this.conn=null,this.currentWebSocket===r&&(this.currentWebSocket=null,this.isConnecting=!1),!c&&!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&&w(t)==w(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 o=()=>{let c=!1,f=this.createPersistentMessageHandler(t),h=v=>{f(v),c||(c=!0,r())};e.addEventListener("message",h),e.addEventListener("close",v=>{c||(c=!0,v.code===4001?l(new Error(`Authentication failed: ${v.reason!==""?v.reason:"Invalid API key"}`)):l(new Error("WebSocket connection closed unexpectedly")))}),this.currentWebSocket=e;let k=this.additionalHeaders["X-Schematic-Client-Version"]??`schematic-js@${V}`,g={apiKey:this.apiKey,clientVersion:k,data:t};this.debug("WebSocket sending message:",g),e.send(JSON.stringify(g))};e.readyState===WebSocket.OPEN?(this.debug("WebSocket already open, sending message"),o()):e.readyState===WebSocket.CONNECTING?(this.debug("WebSocket connecting, waiting for open to send message"),e.addEventListener("open",o)):(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.isPendingListeners.forEach(t=>Se(t,e))};getFlagCheck=e=>{let t=w(this.context),r=(this.checks[t]??{})[e];if(r!==void 0)return r;if(e in this.flagCheckDefaults||e in this.flagValueDefaults)return this.resolveFallbackCheckFlagReturn(e,void 0,"Default value used")};getFlagValue=e=>{let t=w(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)});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=>xe(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}),Ce(r,t),this.debug(`Listener ${l} for flag ${e} completed`,{flagKey:e,value:t})})}},Se=(n,e)=>{n.length>0?n(e):n()},xe=(n,e)=>{n.length>0?n(e):n()},Ce=(n,e)=>{n.length>0?n(e):n()};window.Schematic=D;})();
3
3
  /* @preserve */
@@ -637,6 +637,40 @@ var v4_default = v4;
637
637
  // src/index.ts
638
638
  var import_polyfill = __toESM(require_browser_polyfill());
639
639
 
640
+ // src/types/api/models/EntitlementValueType.ts
641
+ function EntitlementValueTypeFromJSON(json) {
642
+ return EntitlementValueTypeFromJSONTyped(json, false);
643
+ }
644
+ function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
645
+ return json;
646
+ }
647
+
648
+ // src/types/api/models/FeatureEntitlement.ts
649
+ function FeatureEntitlementFromJSON(json) {
650
+ return FeatureEntitlementFromJSONTyped(json, false);
651
+ }
652
+ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
653
+ if (json == null) {
654
+ return json;
655
+ }
656
+ return {
657
+ allocation: json["allocation"] == null ? void 0 : json["allocation"],
658
+ creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
659
+ creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
660
+ creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
661
+ creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
662
+ eventName: json["event_name"] == null ? void 0 : json["event_name"],
663
+ featureId: json["feature_id"],
664
+ featureKey: json["feature_key"],
665
+ metricPeriod: json["metric_period"] == null ? void 0 : json["metric_period"],
666
+ metricResetAt: json["metric_reset_at"] == null ? void 0 : new Date(json["metric_reset_at"]),
667
+ monthReset: json["month_reset"] == null ? void 0 : json["month_reset"],
668
+ softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
669
+ usage: json["usage"] == null ? void 0 : json["usage"],
670
+ valueType: EntitlementValueTypeFromJSON(json["value_type"])
671
+ };
672
+ }
673
+
640
674
  // src/types/api/models/CheckFlagResponseData.ts
641
675
  function CheckFlagResponseDataFromJSON(json) {
642
676
  return CheckFlagResponseDataFromJSONTyped(json, false);
@@ -647,6 +681,7 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
647
681
  }
648
682
  return {
649
683
  companyId: json["company_id"] == null ? void 0 : json["company_id"],
684
+ entitlement: json["entitlement"] == null ? void 0 : FeatureEntitlementFromJSON(json["entitlement"]),
650
685
  error: json["error"] == null ? void 0 : json["error"],
651
686
  featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
652
687
  featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
@@ -800,7 +835,7 @@ function contextString(context) {
800
835
  }
801
836
 
802
837
  // src/version.ts
803
- var version = "1.2.17";
838
+ var version = "1.2.18";
804
839
 
805
840
  // src/index.ts
806
841
  var anonymousIdKey = "schematicId";
@@ -1107,6 +1142,13 @@ var Schematic = class {
1107
1142
  );
1108
1143
  if (typeof flagCheck !== "undefined") {
1109
1144
  this.submitFlagCheckEvent(key, flagCheck, context);
1145
+ } else {
1146
+ const fallbackResult = this.resolveFallbackCheckFlagReturn(
1147
+ key,
1148
+ fallback,
1149
+ "No flag values available"
1150
+ );
1151
+ this.submitFlagCheckEvent(key, fallbackResult, context);
1110
1152
  }
1111
1153
  return result;
1112
1154
  } catch (error) {
@@ -1311,7 +1353,10 @@ var Schematic = class {
1311
1353
  await this.wsSendMessage(socket, context);
1312
1354
  } catch (error) {
1313
1355
  console.warn("Failed to establish WebSocket connection:", error);
1314
- throw error;
1356
+ this.context = context;
1357
+ this.flushContextDependentEventQueue();
1358
+ this.setIsPending(false);
1359
+ this.attemptReconnect();
1315
1360
  }
1316
1361
  };
1317
1362
  /**
@@ -20,17 +20,6 @@ declare interface CheckFlagResponse {
20
20
  params: object;
21
21
  }
22
22
 
23
- /**
24
- * Schematic API
25
- * Schematic API
26
- *
27
- * The version of the OpenAPI document: 0.1
28
- *
29
- *
30
- * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
31
- * https://openapi-generator.tech
32
- * Do not edit the class manually.
33
- */
34
23
  /**
35
24
  *
36
25
  * @export
@@ -43,6 +32,12 @@ export declare interface CheckFlagResponseData {
43
32
  * @memberof CheckFlagResponseData
44
33
  */
45
34
  companyId?: string | null;
35
+ /**
36
+ * If a feature entitlement rule was matched, its entitlement details
37
+ * @type {FeatureEntitlement}
38
+ * @memberof CheckFlagResponseData
39
+ */
40
+ entitlement?: FeatureEntitlement;
46
41
  /**
47
42
  * If an error occurred while checking the flag, the error message
48
43
  * @type {string}
@@ -50,33 +45,38 @@ export declare interface CheckFlagResponseData {
50
45
  */
51
46
  error?: string | null;
52
47
  /**
53
- * If a numeric feature entitlement rule was matched, its allocation
48
+ * Deprecated: Use Entitlement.Allocation instead.
54
49
  * @type {number}
55
50
  * @memberof CheckFlagResponseData
51
+ * @deprecated
56
52
  */
57
53
  featureAllocation?: number | null;
58
54
  /**
59
- * If a numeric feature entitlement rule was matched, the company's usage
55
+ * Deprecated: Use Entitlement.Usage instead.
60
56
  * @type {number}
61
57
  * @memberof CheckFlagResponseData
58
+ * @deprecated
62
59
  */
63
60
  featureUsage?: number | null;
64
61
  /**
65
- * If an event-based numeric feature entitlement rule was matched, the event used to track its usage
62
+ * Deprecated: Use Entitlement.EventName instead.
66
63
  * @type {string}
67
64
  * @memberof CheckFlagResponseData
65
+ * @deprecated
68
66
  */
69
67
  featureUsageEvent?: string | null;
70
68
  /**
71
- * For event-based feature entitlement rules, the period over which usage is tracked (current_month, current_day, current_week, all_time)
69
+ * Deprecated: Use Entitlement.MetricPeriod instead.
72
70
  * @type {string}
73
71
  * @memberof CheckFlagResponseData
72
+ * @deprecated
74
73
  */
75
74
  featureUsagePeriod?: string | null;
76
75
  /**
77
- * For event-based feature entitlement rules, when the usage period will reset
76
+ * Deprecated: Use Entitlement.MetricResetAt instead.
78
77
  * @type {Date}
79
78
  * @memberof CheckFlagResponseData
79
+ * @deprecated
80
80
  */
81
81
  featureUsageResetAt?: Date | null;
82
82
  /**
@@ -206,6 +206,21 @@ export declare type CheckOptions = {
206
206
 
207
207
  export declare type EmptyListenerFn = () => void;
208
208
 
209
+ /**
210
+ *
211
+ * @export
212
+ */
213
+ declare const EntitlementValueType: {
214
+ readonly Boolean: "boolean";
215
+ readonly Credit: "credit";
216
+ readonly Numeric: "numeric";
217
+ readonly Trait: "trait";
218
+ readonly Unknown: "unknown";
219
+ readonly Unlimited: "unlimited";
220
+ };
221
+
222
+ declare type EntitlementValueType = (typeof EntitlementValueType)[keyof typeof EntitlementValueType];
223
+
209
224
  declare type Event_2 = {
210
225
  api_key: string;
211
226
  body: EventBody;
@@ -324,6 +339,120 @@ export declare type EventBodyTrack = SchematicContext & {
324
339
 
325
340
  export declare type EventType = "identify" | "track" | "flag_check";
326
341
 
342
+ /**
343
+ *
344
+ * @export
345
+ * @interface FeatureEntitlement
346
+ */
347
+ declare interface FeatureEntitlement {
348
+ /**
349
+ * If the company has a numeric entitlement for this feature, the allocated amount
350
+ * @type {number}
351
+ * @memberof FeatureEntitlement
352
+ */
353
+ allocation?: number | null;
354
+ /**
355
+ * If the company has a credit-based entitlement for this feature, the ID of the credit
356
+ * @type {string}
357
+ * @memberof FeatureEntitlement
358
+ */
359
+ creditId?: string | null;
360
+ /**
361
+ * If the company has a credit-based entitlement for this feature, the remaining credit amount
362
+ * @type {number}
363
+ * @memberof FeatureEntitlement
364
+ */
365
+ creditRemaining?: number | null;
366
+ /**
367
+ * If the company has a credit-based entitlement for this feature, the total credit amount
368
+ * @type {number}
369
+ * @memberof FeatureEntitlement
370
+ */
371
+ creditTotal?: number | null;
372
+ /**
373
+ * If the company has a credit-based entitlement for this feature, the amount of credit used
374
+ * @type {number}
375
+ * @memberof FeatureEntitlement
376
+ */
377
+ creditUsed?: number | null;
378
+ /**
379
+ * If the feature is event-based, the name of the event tracked for usage
380
+ * @type {string}
381
+ * @memberof FeatureEntitlement
382
+ */
383
+ eventName?: string | null;
384
+ /**
385
+ * The ID of the feature
386
+ * @type {string}
387
+ * @memberof FeatureEntitlement
388
+ */
389
+ featureId: string;
390
+ /**
391
+ * The key of the flag associated with the feature
392
+ * @type {string}
393
+ * @memberof FeatureEntitlement
394
+ */
395
+ featureKey: string;
396
+ /**
397
+ * For event-based feature entitlements, the period over which usage is tracked
398
+ * @type {string}
399
+ * @memberof FeatureEntitlement
400
+ */
401
+ metricPeriod?: FeatureEntitlementMetricPeriodEnum | null;
402
+ /**
403
+ * For event-based feature entitlements, when the usage period will reset
404
+ * @type {Date}
405
+ * @memberof FeatureEntitlement
406
+ */
407
+ metricResetAt?: Date | null;
408
+ /**
409
+ * For event-based feature entitlements that have a monthly period, whether that monthly reset is based on the calendar month or a billing cycle
410
+ * @type {string}
411
+ * @memberof FeatureEntitlement
412
+ */
413
+ monthReset?: FeatureEntitlementMonthResetEnum | null;
414
+ /**
415
+ * For usage-based pricing, the soft limit for overage charges or the next tier boundary
416
+ * @type {number}
417
+ * @memberof FeatureEntitlement
418
+ */
419
+ softLimit?: number | null;
420
+ /**
421
+ * If the company has a numeric entitlement for this feature, the current usage amount
422
+ * @type {number}
423
+ * @memberof FeatureEntitlement
424
+ */
425
+ usage?: number | null;
426
+ /**
427
+ * The type of the entitlement value
428
+ * @type {EntitlementValueType}
429
+ * @memberof FeatureEntitlement
430
+ */
431
+ valueType: EntitlementValueType;
432
+ }
433
+
434
+ /**
435
+ * @export
436
+ */
437
+ declare const FeatureEntitlementMetricPeriodEnum: {
438
+ readonly AllTime: "all_time";
439
+ readonly CurrentDay: "current_day";
440
+ readonly CurrentMonth: "current_month";
441
+ readonly CurrentWeek: "current_week";
442
+ };
443
+
444
+ declare type FeatureEntitlementMetricPeriodEnum = (typeof FeatureEntitlementMetricPeriodEnum)[keyof typeof FeatureEntitlementMetricPeriodEnum];
445
+
446
+ /**
447
+ * @export
448
+ */
449
+ declare const FeatureEntitlementMonthResetEnum: {
450
+ readonly FirstOfMonth: "first_of_month";
451
+ readonly BillingCycle: "billing_cycle";
452
+ };
453
+
454
+ declare type FeatureEntitlementMonthResetEnum = (typeof FeatureEntitlementMonthResetEnum)[keyof typeof FeatureEntitlementMonthResetEnum];
455
+
327
456
  export declare type FlagCheckListenerFn = CheckFlagReturnListenerFn | EmptyListenerFn;
328
457
 
329
458
  export declare type FlagValueListenerFn = BooleanListenerFn | EmptyListenerFn;
@@ -618,6 +618,40 @@ var v4_default = v4;
618
618
  // src/index.ts
619
619
  var import_polyfill = __toESM(require_browser_polyfill());
620
620
 
621
+ // src/types/api/models/EntitlementValueType.ts
622
+ function EntitlementValueTypeFromJSON(json) {
623
+ return EntitlementValueTypeFromJSONTyped(json, false);
624
+ }
625
+ function EntitlementValueTypeFromJSONTyped(json, ignoreDiscriminator) {
626
+ return json;
627
+ }
628
+
629
+ // src/types/api/models/FeatureEntitlement.ts
630
+ function FeatureEntitlementFromJSON(json) {
631
+ return FeatureEntitlementFromJSONTyped(json, false);
632
+ }
633
+ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
634
+ if (json == null) {
635
+ return json;
636
+ }
637
+ return {
638
+ allocation: json["allocation"] == null ? void 0 : json["allocation"],
639
+ creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
640
+ creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
641
+ creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
642
+ creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
643
+ eventName: json["event_name"] == null ? void 0 : json["event_name"],
644
+ featureId: json["feature_id"],
645
+ featureKey: json["feature_key"],
646
+ metricPeriod: json["metric_period"] == null ? void 0 : json["metric_period"],
647
+ metricResetAt: json["metric_reset_at"] == null ? void 0 : new Date(json["metric_reset_at"]),
648
+ monthReset: json["month_reset"] == null ? void 0 : json["month_reset"],
649
+ softLimit: json["soft_limit"] == null ? void 0 : json["soft_limit"],
650
+ usage: json["usage"] == null ? void 0 : json["usage"],
651
+ valueType: EntitlementValueTypeFromJSON(json["value_type"])
652
+ };
653
+ }
654
+
621
655
  // src/types/api/models/CheckFlagResponseData.ts
622
656
  function CheckFlagResponseDataFromJSON(json) {
623
657
  return CheckFlagResponseDataFromJSONTyped(json, false);
@@ -628,6 +662,7 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
628
662
  }
629
663
  return {
630
664
  companyId: json["company_id"] == null ? void 0 : json["company_id"],
665
+ entitlement: json["entitlement"] == null ? void 0 : FeatureEntitlementFromJSON(json["entitlement"]),
631
666
  error: json["error"] == null ? void 0 : json["error"],
632
667
  featureAllocation: json["feature_allocation"] == null ? void 0 : json["feature_allocation"],
633
668
  featureUsage: json["feature_usage"] == null ? void 0 : json["feature_usage"],
@@ -781,7 +816,7 @@ function contextString(context) {
781
816
  }
782
817
 
783
818
  // src/version.ts
784
- var version = "1.2.17";
819
+ var version = "1.2.18";
785
820
 
786
821
  // src/index.ts
787
822
  var anonymousIdKey = "schematicId";
@@ -1088,6 +1123,13 @@ var Schematic = class {
1088
1123
  );
1089
1124
  if (typeof flagCheck !== "undefined") {
1090
1125
  this.submitFlagCheckEvent(key, flagCheck, context);
1126
+ } else {
1127
+ const fallbackResult = this.resolveFallbackCheckFlagReturn(
1128
+ key,
1129
+ fallback,
1130
+ "No flag values available"
1131
+ );
1132
+ this.submitFlagCheckEvent(key, fallbackResult, context);
1091
1133
  }
1092
1134
  return result;
1093
1135
  } catch (error) {
@@ -1292,7 +1334,10 @@ var Schematic = class {
1292
1334
  await this.wsSendMessage(socket, context);
1293
1335
  } catch (error) {
1294
1336
  console.warn("Failed to establish WebSocket connection:", error);
1295
- throw error;
1337
+ this.context = context;
1338
+ this.flushContextDependentEventQueue();
1339
+ this.setIsPending(false);
1340
+ this.attemptReconnect();
1296
1341
  }
1297
1342
  };
1298
1343
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schematichq/schematic-js",
3
- "version": "1.2.17",
3
+ "version": "1.2.18",
4
4
  "main": "dist/schematic.cjs.js",
5
5
  "module": "dist/schematic.esm.js",
6
6
  "types": "dist/schematic.d.ts",
@@ -25,7 +25,7 @@
25
25
  "clean": "rm -rf dist",
26
26
  "format": "prettier --write src/*.ts",
27
27
  "lint": "eslint src --report-unused-disable-directives --fix",
28
- "openapi": "rm -rf src/types/api/ && npx openapi-generator-cli generate -c openapi-config.yaml --global-property models=\"EventBody:EventBodyFlagCheck:EventBodyIdentify:EventBodyIdentifyCompany:EventBodyTrack:CheckFlagResponse:CheckFlagResponseData:CheckFlagsResponse:CheckFlagsResponseData\",supportingFiles=runtime.ts && prettier --write \"src/types/api/**/*.{ts,tsx}\"",
28
+ "openapi": "rm -rf src/types/api/ && npx openapi-generator-cli generate -c openapi-config.yaml --global-property models=\"EventBody:EventBodyFlagCheck:EventBodyIdentify:EventBodyIdentifyCompany:EventBodyTrack:CheckFlagResponse:CheckFlagResponseData:CheckFlagsResponse:CheckFlagsResponseData:FeatureEntitlement:EntitlementValueType\",supportingFiles=runtime.ts && prettier --write \"src/types/api/**/*.{ts,tsx}\"",
29
29
  "prepare": "husky",
30
30
  "test": "vitest run",
31
31
  "test:reactnative": "vitest run --config vitest.config.reactnative.ts",
@@ -38,19 +38,19 @@
38
38
  },
39
39
  "devDependencies": {
40
40
  "@eslint/js": "^10.0.1",
41
- "@microsoft/api-extractor": "^7.56.3",
42
- "@openapitools/openapi-generator-cli": "^2.28.3",
41
+ "@microsoft/api-extractor": "^7.57.6",
42
+ "@openapitools/openapi-generator-cli": "^2.30.0",
43
43
  "@vitest/browser": "^4.0.18",
44
44
  "esbuild": "^0.27.3",
45
- "eslint": "^9.39.2",
46
- "globals": "^17.3.0",
47
- "happy-dom": "^20.6.1",
45
+ "eslint": "^10.0.2",
46
+ "globals": "^17.4.0",
47
+ "happy-dom": "^20.7.0",
48
48
  "husky": "^9.1.7",
49
- "jsdom": "^28.0.0",
49
+ "jsdom": "^28.1.0",
50
50
  "mock-socket": "^9.3.1",
51
51
  "prettier": "^3.8.1",
52
52
  "typescript": "^5.9.3",
53
- "typescript-eslint": "^8.55.0",
53
+ "typescript-eslint": "^8.56.1",
54
54
  "vitest": "^4.0.18"
55
55
  },
56
56
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"