@schematichq/schematic-js 1.2.21 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/dist/schematic.browser.js +2 -2
- package/dist/schematic.cjs.js +118 -37
- package/dist/schematic.d.ts +70 -0
- package/dist/schematic.esm.js +118 -37
- package/package.json +15 -10
package/LICENSE
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";(()=>{var
|
|
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 w(s,a){if(!(this instanceof w))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(w.prototype),w.prototype.clone=function(){return new w(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new g(this.headers),url:this.url})},w.error=function(){var s=new w(null,{status:200,statusText:""});return s.ok=!1,s.status=0,s.type="error",s};var ie=[301,302,303,307,308];w.redirect=function(s,a){if(ie.indexOf(a)===-1)throw new RangeError("Invalid status code");return new w(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 w(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=w),t.Headers=g,t.Request=R,t.Response=w,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 C(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:C(n.data),params:n.params}}function Y(n){return Re(n,!1)}function Re(n,e){return n==null?n:{flags:n.flags.map(C)}}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:c,featureUsagePeriod:o,featureUsageResetAt:l,flag:f,flagId:h,reason:k,ruleId:g,ruleType:v,userId:x,value:T}=C(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:c===null?void 0:c,featureUsagePeriod:o??void 0,featureUsageResetAt:l??void 0,flag:f,flagId:h??void 0,reason:k,ruleId:g??void 0,ruleType:v??void 0,userId:x??void 0,value:T}};function E(n){let e=Object.keys(n).reduce((t,i)=>{let c=Object.keys(n[i]||{}).sort().reduce((o,l)=>(o[l]=n[i][l],o),{});return t[i]=c,t},{});return JSON.stringify(e)}var V="1.2.21";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={};fallbackCheckCache={};constructor(e,t){if(this.apiKey=e,this.eventQueue=[],this.contextDependentEventQueue=[],this.useWebSocket=t?.useWebSocket??!1,this.debugEnabled=t?.debug??!1,this.offlineEnabled=t?.offline??!1,typeof window<"u"&&typeof window.location<"u"){let i=new URLSearchParams(window.location.search),r=i.get("schematic_debug");r!==null&&(r===""||r==="true"||r==="1")&&(this.debugEnabled=!0);let c=i.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@${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 c=this.flagCheckDefaults[e];return{...c,flag:e,reason:r!==void 0?i:c.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,c=E(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(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: ${i}`,f);let h=M(f.data);return typeof h.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(h),this.submitFlagCheckEvent(i,h,r),h.value}).catch(l=>{console.warn("There was a problem with the fetch operation:",l);let f=this.resolveFallbackCheckFlagReturn(i,t,"API request failed",l instanceof Error?l.message:String(l));return this.submitFlagCheckEvent(i,f,r),f.value})}try{let o=this.checks[c];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[c]??{})[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 l=this.resolveFallbackCheckFlagReturn(i,t,"Unexpected error in flag check",o instanceof Error?o.message:String(o));return this.submitFlagCheckEvent(i,l,r),l.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),E(e)in this.checks||(this.checks[E(e)]={}),(i.flags??[]).forEach(r=>{let c=M(r),o=E(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[r.flag]?.size??0)>0||(this.flagValueListeners[r.flag]?.size??0)>0)&&this.submitFlagCheckEvent(c.flag,c,e),this.debug(`About to notify listeners for flag ${r.flag}`,{flag:r.flag,value:c.value}),this.notifyFlagCheckListeners(r.flag,c),this.notifyFlagValueListeners(r.flag,c.value),this.debug(`Finished notifying listeners for flag ${r.flag}`,{flag:r.flag,value:c.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 c=B(r);return this.debug("checkFlags result:",c),(c?.data?.flags??[]).reduce((o,l)=>(o[l.flag]=l.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();if(!(E(e)===E(this.context)&&this.conn!==null&&!this.isPending))try{if(this.setIsPending(!0),!this.conn){if(this.isConnecting){for(this.debug("Connection already in progress, waiting for it to complete");this.isConnecting&&this.conn===null;)await new Promise(i=>setTimeout(i,10));if(this.conn!==null){let i=await this.conn;await this.wsSendMessage(i,e);return}}this.wsReconnectTimer!==null&&(this.debug("Cancelling scheduled reconnection, connecting immediately"),clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.isConnecting=!0;try{this.conn=this.wsConnect();let i=await this.conn;this.isConnecting=!1,await this.wsSendMessage(i,e);return}catch(i){throw this.isConnecting=!1,i}}let t=await this.conn;await this.wsSendMessage(t,e)}catch(t){console.warn("Failed to establish WebSocket connection:",t),this.context=e,this.flushContextDependentEventQueue(),this.setIsPending(!1),this.attemptReconnect()}};track=e=>{let{company:t,user:i,event:r,traits:c,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:c??{},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 l={company:t??this.context.company,event:r,traits:c??{},user:i??this.context.user,quantity:o};return this.debug("track:",l),r in this.featureUsageEventMap&&this.optimisticallyUpdateFeatureUsage(r,o),this.handleEvent("track",l)};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,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: ${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 l=E(this.context);this.checks[l]!==void 0&&this.checks[l]!==null&&(this.checks[l][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(c){this.debug("Failed to send queued event:",c)}};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 c=(e.retry_count??0)+1;if(c<=this.maxEventRetries){this.debug(`Event failed to send (attempt ${c}/${this.maxEventRetries}), queueing for retry:`,r);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:`,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),l=Math.min(o,this.webSocketMaxRetryDelay),f=l*.2*Math.random(),h=l+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),c=Math.random().toString(36).substring(7);this.debug(`Creating WebSocket connection ${c} to ${i}`);let o=null,l=!1;o=setTimeout(()=>{l||(l=!0,this.debug(`WebSocket connection timeout after ${this.webSocketConnectionTimeout}ms`),r.close(),t(new Error("WebSocket connection timeout")))},this.webSocketConnectionTimeout),r.onopen=()=>{l||(l=!0,o!==null&&clearTimeout(o),this.wsIntentionalDisconnect=!1,this.debug(`WebSocket connection ${c} opened successfully`),e(r))},r.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)},r.onclose=()=>{o!==null&&clearTimeout(o),this.debug(`WebSocket connection ${c} closed`),this.conn=null,this.currentWebSocket===r&&(this.currentWebSocket=null,this.isConnecting=!1),!l&&!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,c)=>{if(!i&&E(t)==E(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 l=!1,f=this.createPersistentMessageHandler(t),h=v=>{f(v),l||(l=!0,r())};e.addEventListener("message",h),e.addEventListener("close",v=>{l||(l=!0,v.code===4001?c(new Error(`Authentication failed: ${v.reason!==""?v.reason:"Invalid API key"}`)):c(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"),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.isPending=e,this.isPendingListeners.forEach(t=>Se(t,e)))};getFlagCheck=e=>{let t=E(this.context),r=(this.checks[t]??{})[e];if(r!==void 0)return r;if(e in this.flagCheckDefaults||e in this.flagValueDefaults)return e in this.fallbackCheckCache||(this.fallbackCheckCache[e]=this.resolveFallbackCheckFlagReturn(e,void 0,"Default value used")),this.fallbackCheckCache[e]};getFlagValue=e=>{let t=E(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=>Ce(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,c)=>{this.debug(`Calling listener ${c} for flag ${e}`,{flagKey:e,value:t}),xe(r,t),this.debug(`Listener ${c} for flag ${e} completed`,{flagKey:e,value:t})})}},Se=(n,e)=>{n.length>0?n(e):n()},Ce=(n,e)=>{n.length>0?n(e):n()},xe=(n,e)=>{n.length>0?n(e):n()};window.Schematic=D;})();
|
|
1
|
+
"use strict";(()=>{var ve=Object.create;var ie=Object.defineProperty;var qe=Object.getOwnPropertyDescriptor;var We=Object.getOwnPropertyNames;var $e=Object.getPrototypeOf,ze=Object.prototype.hasOwnProperty;var He=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports);var Qe=(n,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of We(e))!ze.call(n,r)&&r!==t&&ie(n,r,{get:()=>e[r],enumerable:!(i=qe(e,r))||i.enumerable});return n};var Ke=(n,e,t)=>(t=n!=null?ve($e(n)):{},Qe(e||!n||!n.__esModule?ie(t,"default",{value:n,enumerable:!0}):t,n));var se=He(oe=>{(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(a){return a&&DataView.prototype.isPrototypeOf(a)}if(r.arrayBuffer)var s=["[object Int8Array]","[object Uint8Array]","[object Uint8ClampedArray]","[object Int16Array]","[object Uint16Array]","[object Int32Array]","[object Uint32Array]","[object Float32Array]","[object Float64Array]"],p=ArrayBuffer.isView||function(a){return a&&s.indexOf(Object.prototype.toString.call(a))>-1};function u(a){if(typeof a!="string"&&(a=String(a)),/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(a)||a==="")throw new TypeError('Invalid character in header field name: "'+a+'"');return a.toLowerCase()}function f(a){return typeof a!="string"&&(a=String(a)),a}function P(a){var o={next:function(){var d=a.shift();return{done:d===void 0,value:d}}};return r.iterable&&(o[Symbol.iterator]=function(){return o}),o}function y(a){this.map={},a instanceof y?a.forEach(function(o,d){this.append(d,o)},this):Array.isArray(a)?a.forEach(function(o){if(o.length!=2)throw new TypeError("Headers constructor: expected name/value pair to be length 2, found"+o.length);this.append(o[0],o[1])},this):a&&Object.getOwnPropertyNames(a).forEach(function(o){this.append(o,a[o])},this)}y.prototype.append=function(a,o){a=u(a),o=f(o);var d=this.map[a];this.map[a]=d?d+", "+o:o},y.prototype.delete=function(a){delete this.map[u(a)]},y.prototype.get=function(a){return a=u(a),this.has(a)?this.map[a]:null},y.prototype.has=function(a){return this.map.hasOwnProperty(u(a))},y.prototype.set=function(a,o){this.map[u(a)]=f(o)},y.prototype.forEach=function(a,o){for(var d in this.map)this.map.hasOwnProperty(d)&&a.call(o,this.map[d],d,this)},y.prototype.keys=function(){var a=[];return this.forEach(function(o,d){a.push(d)}),P(a)},y.prototype.values=function(){var a=[];return this.forEach(function(o){a.push(o)}),P(a)},y.prototype.entries=function(){var a=[];return this.forEach(function(o,d){a.push([d,o])}),P(a)},r.iterable&&(y.prototype[Symbol.iterator]=y.prototype.entries);function D(a){if(!a._noBody){if(a.bodyUsed)return Promise.reject(new TypeError("Already read"));a.bodyUsed=!0}}function N(a){return new Promise(function(o,d){a.onload=function(){o(a.result)},a.onerror=function(){d(a.error)}})}function E(a){var o=new FileReader,d=N(o);return o.readAsArrayBuffer(a),d}function ee(a){var o=new FileReader,d=N(o),m=/charset=([A-Za-z0-9_-]+)/.exec(a.type),g=m?m[1]:"utf-8";return o.readAsText(a,g),d}function we(a){for(var o=new Uint8Array(a),d=new Array(o.length),m=0;m<o.length;m++)d[m]=String.fromCharCode(o[m]);return d.join("")}function te(a){if(a.slice)return a.slice(0);var o=new Uint8Array(a.byteLength);return o.set(new Uint8Array(a)),o.buffer}function ne(){return this.bodyUsed=!1,this._initBody=function(a){this.bodyUsed=this.bodyUsed,this._bodyInit=a,a?typeof a=="string"?this._bodyText=a:r.blob&&Blob.prototype.isPrototypeOf(a)?this._bodyBlob=a:r.formData&&FormData.prototype.isPrototypeOf(a)?this._bodyFormData=a:r.searchParams&&URLSearchParams.prototype.isPrototypeOf(a)?this._bodyText=a.toString():r.arrayBuffer&&r.blob&&l(a)?(this._bodyArrayBuffer=te(a.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer])):r.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(a)||p(a))?this._bodyArrayBuffer=te(a):this._bodyText=a=Object.prototype.toString.call(a):(this._noBody=!0,this._bodyText=""),this.headers.get("content-type")||(typeof a=="string"?this.headers.set("content-type","text/plain;charset=UTF-8"):this._bodyBlob&&this._bodyBlob.type?this.headers.set("content-type",this._bodyBlob.type):r.searchParams&&URLSearchParams.prototype.isPrototypeOf(a)&&this.headers.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"))},r.blob&&(this.blob=function(){var a=D(this);if(a)return a;if(this._bodyBlob)return Promise.resolve(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(new Blob([this._bodyArrayBuffer]));if(this._bodyFormData)throw new Error("could not read FormData body as blob");return Promise.resolve(new Blob([this._bodyText]))}),this.arrayBuffer=function(){if(this._bodyArrayBuffer){var a=D(this);return a||(ArrayBuffer.isView(this._bodyArrayBuffer)?Promise.resolve(this._bodyArrayBuffer.buffer.slice(this._bodyArrayBuffer.byteOffset,this._bodyArrayBuffer.byteOffset+this._bodyArrayBuffer.byteLength)):Promise.resolve(this._bodyArrayBuffer))}else{if(r.blob)return this.blob().then(E);throw new Error("could not read as ArrayBuffer")}},this.text=function(){var a=D(this);if(a)return a;if(this._bodyBlob)return ee(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(we(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(Ge)}),this.json=function(){return this.text().then(JSON.parse)},this}var Ve=["CONNECT","DELETE","GET","HEAD","OPTIONS","PATCH","POST","PUT","TRACE"];function Ue(a){var o=a.toUpperCase();return Ve.indexOf(o)>-1?o:a}function _(a,o){if(!(this instanceof _))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');o=o||{};var d=o.body;if(a instanceof _){if(a.bodyUsed)throw new TypeError("Already read");this.url=a.url,this.credentials=a.credentials,o.headers||(this.headers=new y(a.headers)),this.method=a.method,this.mode=a.mode,this.signal=a.signal,!d&&a._bodyInit!=null&&(d=a._bodyInit,a.bodyUsed=!0)}else this.url=String(a);if(this.credentials=o.credentials||this.credentials||"same-origin",(o.headers||!this.headers)&&(this.headers=new y(o.headers)),this.method=Ue(o.method||this.method||"GET"),this.mode=o.mode||this.mode||null,this.signal=o.signal||this.signal||(function(){if("AbortController"in i){var c=new AbortController;return c.signal}})(),this.referrer=null,(this.method==="GET"||this.method==="HEAD")&&d)throw new TypeError("Body not allowed for GET or HEAD requests");if(this._initBody(d),(this.method==="GET"||this.method==="HEAD")&&(o.cache==="no-store"||o.cache==="no-cache")){var m=/([?&])_=[^&]*/;if(m.test(this.url))this.url=this.url.replace(m,"$1_="+new Date().getTime());else{var g=/\?/;this.url+=(g.test(this.url)?"&":"?")+"_="+new Date().getTime()}}}_.prototype.clone=function(){return new _(this,{body:this._bodyInit})};function Ge(a){var o=new FormData;return a.trim().split("&").forEach(function(d){if(d){var m=d.split("="),g=m.shift().replace(/\+/g," "),c=m.join("=").replace(/\+/g," ");o.append(decodeURIComponent(g),decodeURIComponent(c))}}),o}function Le(a){var o=new y,d=a.replace(/\r?\n[\t ]+/g," ");return d.split("\r").map(function(m){return m.indexOf(`
|
|
2
|
+
`)===0?m.substr(1,m.length):m}).forEach(function(m){var g=m.split(":"),c=g.shift().trim();if(c){var J=g.join(":").trim();try{o.append(c,J)}catch(v){console.warn("Response "+v.message)}}}),o}ne.call(_.prototype);function R(a,o){if(!(this instanceof R))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');if(o||(o={}),this.type="default",this.status=o.status===void 0?200:o.status,this.status<200||this.status>599)throw new RangeError("Failed to construct 'Response': The status provided (0) is outside the range [200, 599].");this.ok=this.status>=200&&this.status<300,this.statusText=o.statusText===void 0?"":""+o.statusText,this.headers=new y(o.headers),this.url=o.url||"",this._initBody(a)}ne.call(R.prototype),R.prototype.clone=function(){return new R(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new y(this.headers),url:this.url})},R.error=function(){var a=new R(null,{status:200,statusText:""});return a.ok=!1,a.status=0,a.type="error",a};var Me=[301,302,303,307,308];R.redirect=function(a,o){if(Me.indexOf(o)===-1)throw new RangeError("Invalid status code");return new R(null,{status:o,headers:{location:a}})},t.DOMException=i.DOMException;try{new t.DOMException}catch{t.DOMException=function(o,d){this.message=o,this.name=d;var m=Error(o);this.stack=m.stack},t.DOMException.prototype=Object.create(Error.prototype),t.DOMException.prototype.constructor=t.DOMException}function M(a,o){return new Promise(function(d,m){var g=new _(a,o);if(g.signal&&g.signal.aborted)return m(new t.DOMException("Aborted","AbortError"));var c=new XMLHttpRequest;function J(){c.abort()}c.onload=function(){var T={statusText:c.statusText,headers:Le(c.getAllResponseHeaders()||"")};g.url.indexOf("file://")===0&&(c.status<200||c.status>599)?T.status=200:T.status=c.status,T.url="responseURL"in c?c.responseURL:T.headers.get("X-Request-URL");var O="response"in c?c.response:c.responseText;setTimeout(function(){d(new R(O,T))},0)},c.onerror=function(){setTimeout(function(){m(new TypeError("Network request failed"))},0)},c.ontimeout=function(){setTimeout(function(){m(new TypeError("Network request timed out"))},0)},c.onabort=function(){setTimeout(function(){m(new t.DOMException("Aborted","AbortError"))},0)};function v(T){try{return T===""&&i.location.href?i.location.href:T}catch{return T}}if(c.open(g.method,v(g.url),!0),g.credentials==="include"?c.withCredentials=!0:g.credentials==="omit"&&(c.withCredentials=!1),"responseType"in c&&(r.blob?c.responseType="blob":r.arrayBuffer&&(c.responseType="arraybuffer")),o&&typeof o.headers=="object"&&!(o.headers instanceof y||i.Headers&&o.headers instanceof i.Headers)){var re=[];Object.getOwnPropertyNames(o.headers).forEach(function(T){re.push(u(T)),c.setRequestHeader(T,f(o.headers[T]))}),g.headers.forEach(function(T,O){re.indexOf(O)===-1&&c.setRequestHeader(O,T)})}else g.headers.forEach(function(T,O){c.setRequestHeader(O,T)});g.signal&&(g.signal.addEventListener("abort",J),c.onreadystatechange=function(){c.readyState===4&&g.signal.removeEventListener("abort",J)}),c.send(typeof g._bodyInit>"u"?null:g._bodyInit)})}return M.polyfill=!0,i.fetch||(i.fetch=M,i.Headers=y,i.Request=_,i.Response=R),t.Headers=y,t.Request=_,t.Response=R,t.fetch=M,t})({})})(typeof self<"u"?self:oe)});var h=[];for(let n=0;n<256;++n)h.push((n+256).toString(16).slice(1));function ae(n,e=0){return(h[n[e+0]]+h[n[e+1]]+h[n[e+2]]+h[n[e+3]]+"-"+h[n[e+4]]+h[n[e+5]]+"-"+h[n[e+6]]+h[n[e+7]]+"-"+h[n[e+8]]+h[n[e+9]]+"-"+h[n[e+10]]+h[n[e+11]]+h[n[e+12]]+h[n[e+13]]+h[n[e+14]]+h[n[e+15]]).toLowerCase()}var q,Xe=new Uint8Array(16);function W(){if(!q){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");q=crypto.getRandomValues.bind(crypto)}return q(Xe)}var Ye=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),$={randomUUID:Ye};function Ze(n,e,t){n=n||{};let i=n.random??n.rng?.()??W();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 ae(i)}function je(n,e,t){return $.randomUUID&&!e&&!n?$.randomUUID():Ze(n,e,t)}var C=je;var Tm=Ke(se());function Q(n){return Dt(n,!1)}function Dt(n,e){return n}function ge(n){return Rt(n,!1)}function Rt(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:Q(n.value_type)}}function B(n){return _t(n,!1)}function _t(n,e){return n==null?n:{companyId:n.company_id==null?void 0:n.company_id,entitlement:n.entitlement==null?void 0:ge(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 K(n){return Ct(n,!1)}function Ct(n,e){return n==null?n:{data:B(n.data),params:n.params}}function Te(n){return bt(n,!1)}function bt(n,e){return n}function F(n){return xt(n,!1)}function xt(n,e){return n==null?n:{id:n.id,name:n.name,trialEndDate:n.trial_end_date==null?void 0:new Date(n.trial_end_date),trialStatus:n.trial_status==null?void 0:Te(n.trial_status)}}function X(n){return Bt(n,!1)}function Bt(n,e){return n==null?n:{flags:n.flags.map(B),plan:n.plan==null?void 0:F(n.plan)}}function Y(n){return Ft(n,!1)}function Ft(n,e){return n==null?n:{data:X(n.data),params:n.params}}function I(n){return Et(n,!1)}function Et(n,e=!1){return n==null?n:{company_id:n.companyId,error:n.error,flag_id:n.flagId,flag_key:n.flagKey,reason:n.reason,req_company:n.reqCompany,req_user:n.reqUser,rule_id:n.ruleId,user_id:n.userId,value:n.value}}var Z=n=>{let{companyId:e,error:t,featureAllocation:i,featureUsage:r,featureUsageEvent:l,featureUsagePeriod:s,featureUsageResetAt:p,flag:u,flagId:f,reason:P,ruleId:y,ruleType:D,userId:N,value:E}=B(n);return{featureUsageExceeded:!E&&(D=="company_override_usage_exceeded"||D=="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:s??void 0,featureUsageResetAt:p??void 0,flag:u,flagId:f??void 0,reason:P,ruleId:y??void 0,ruleType:D??void 0,userId:N??void 0,value:E}},Ae=n=>{let{id:e,name:t,trialEndDate:i,trialStatus:r}=F(n);return{id:e,name:t,trialEndDate:i??void 0,trialStatus:r??void 0}};function S(n){let e=Object.keys(n).reduce((t,i)=>{let l=Object.keys(n[i]||{}).sort().reduce((s,p)=>(s[p]=n[i][p],s),{});return t[i]=l,t},{});return JSON.stringify(e)}var j="1.3.1";var Ie="schematicId";var L=class{additionalHeaders={};apiKey;apiUrl="https://api.schematichq.com";conn=null;context={};debugEnabled=!1;offlineEnabled=!1;eventQueue;contextDependentEventQueue;eventUrl="https://c.schematichq.com";flagCheckListeners={};flagValueListeners={};isPending=!0;isPendingListeners=new Set;planListeners=new Set;storage;useWebSocket=!1;checks={};featureUsageEventMap={};planChecks={};webSocketUrl="wss://api.schematichq.com";webSocketConnectionTimeout=1e4;webSocketReconnect=!0;webSocketMaxReconnectAttempts=7;webSocketMaxConnectionAttempts=3;webSocketInitialRetryDelay=1e3;webSocketMaxRetryDelay=3e4;wsReconnectAttempts=0;wsReconnectTimer=null;wsIntentionalDisconnect=!1;currentWebSocket=null;isConnecting=!1;maxEventQueueSize=100;maxEventRetries=5;eventRetryInitialDelay=1e3;eventRetryMaxDelay=3e4;retryTimer=null;flagValueDefaults={};flagCheckDefaults={};fallbackCheckCache={};constructor(e,t){if(this.apiKey=e,this.eventQueue=[],this.contextDependentEventQueue=[],this.useWebSocket=t?.useWebSocket??!1,this.debugEnabled=t?.debug??!1,this.offlineEnabled=t?.offline??!1,typeof window<"u"&&typeof window.location<"u"){let i=new URLSearchParams(window.location.search),r=i.get("schematic_debug");r!==null&&(r===""||r==="true"||r==="1")&&(this.debugEnabled=!0);let l=i.get("schematic_offline");l!==null&&(l===""||l==="true"||l==="1")&&(this.offlineEnabled=!0,this.debugEnabled=!0)}if(this.offlineEnabled&&t?.debug!==!1&&(this.debugEnabled=!0),this.offlineEnabled&&this.setIsPending(!1),this.additionalHeaders={"X-Schematic-Client-Version":`schematic-js@${j}`,...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=S(r);if(this.debug(`checkFlag: ${i}`,{context:r,fallback:t}),this.isOffline()){let s=this.resolveFallbackCheckFlagReturn(i,t,"Offline mode - using initialization defaults");return this.debug(`checkFlag offline result: ${i}`,{value:s.value,offlineMode:!0}),s.value}if(!this.useWebSocket){let s=`${this.apiUrl}/flags/${i}/check`;return fetch(s,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:JSON.stringify(r)}).then(p=>{if(!p.ok)throw new Error("Network response was not ok");return p.json()}).then(p=>{let u=K(p);this.debug(`checkFlag result: ${i}`,u);let f=Z(u.data);return typeof f.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(f),this.submitFlagCheckEvent(i,f,r),f.value}).catch(p=>{console.warn("There was a problem with the fetch operation:",p);let u=this.resolveFallbackCheckFlagReturn(i,t,"API request failed",p instanceof Error?p.message:String(p));return this.submitFlagCheckEvent(i,u,r),u.value})}try{let s=this.checks[l];if(this.conn!==null&&typeof s<"u"&&typeof s[i]<"u")return this.debug(`checkFlag cached result: ${i}`,s[i]),s[i].value;if(this.isOffline())return this.resolveFallbackValue(i,t);try{await this.setContext(r)}catch(P){console.warn("WebSocket connection failed, using fallback value:",P);let y=this.resolveFallbackCheckFlagReturn(i,t,"WebSocket connection failed",P instanceof Error?P.message:String(P));return this.submitFlagCheckEvent(i,y,r),y.value}let u=(this.checks[l]??{})[i],f=u?.value??this.resolveFallbackValue(i,t);if(this.debug(`checkFlag WebSocket result: ${i}`,typeof u<"u"?u:{value:f,fallbackUsed:!0}),typeof u<"u")this.submitFlagCheckEvent(i,u,r);else{let P=this.resolveFallbackCheckFlagReturn(i,t,"No flag values available");this.submitFlagCheckEvent(i,P,r)}return f}catch(s){console.error("Unexpected error in checkFlag:",s);let p=this.resolveFallbackCheckFlagReturn(i,t,"Unexpected error in flag check",s instanceof Error?s.message:String(s));return this.submitFlagCheckEvent(i,p,r),p.value}}debug(e,...t){this.debugEnabled&&console.log(`[Schematic] ${e}`,...t)}createPersistentMessageHandler(e){return t=>{let i=JSON.parse(t.data);if(this.debug("WebSocket persistent message received:",i),S(e)in this.checks||(this.checks[S(e)]={}),(i.flags??[]).forEach(r=>{let l=Z(r),s=S(e);this.checks[s]===void 0&&(this.checks[s]={}),this.checks[s][l.flag]=l,typeof l.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(l),((this.flagCheckListeners[r.flag]?.size??0)>0||(this.flagValueListeners[r.flag]?.size??0)>0)&&this.submitFlagCheckEvent(l.flag,l,e),this.debug(`WebSocket flag update received. Notifying listeners for ${r.flag}`,{flag:r.flag,value:l.value,flagCheck:l}),this.notifyFlagCheckListeners(r.flag,l),this.notifyFlagValueListeners(r.flag,l.value)}),i.plan!==void 0&&i.plan!==null){let r=Ae(i.plan),l=S(e);this.planChecks[l]=r,this.debug("WebSocket plan update received. Notifying listeners",{plan:r}),this.notifyPlanListeners(r)}this.flushContextDependentEventQueue(),this.setIsPending(!1)}}isOffline(){return this.offlineEnabled}submitFlagCheckEvent(e,t,i){let r={flagKey:e,value:t.value,reason:t.reason,flagId:t.flagId,ruleId:t.ruleId,companyId:t.companyId,userId:t.userId,error:t.error,reqCompany:i.company,reqUser:i.user};return this.debug("submitting flag check event:",r),this.handleEvent("flag_check",I(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=Y(r);return this.debug("checkFlags result:",l),(l?.data?.flags??[]).reduce((s,p)=>(s[p.flag]=p.value,s),{})}).catch(r=>(console.warn("There was a problem with the fetch operation:",r),{}))};identify=e=>(this.debug("identify:",e),this.setContext({company:e.company?.keys,user:e.keys}).catch(t=>{console.warn("Error setting context:",t)}),this.handleEvent("identify",e));setContext=async e=>{if(this.isOffline()||!this.useWebSocket)return this.context=e,this.flushContextDependentEventQueue(),this.setIsPending(!1),Promise.resolve();if(!(S(e)===S(this.context)&&this.conn!==null&&!this.isPending))try{if(this.setIsPending(!0),!this.conn){if(this.isConnecting){for(this.debug("Connection already in progress, waiting for it to complete");this.isConnecting&&this.conn===null;)await new Promise(i=>setTimeout(i,10));if(this.conn!==null){let i=await this.conn;await this.wsSendMessage(i,e);return}}this.wsReconnectTimer!==null&&(this.debug("Cancelling scheduled reconnection, connecting immediately"),clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.isConnecting=!0;try{this.conn=this.wsConnect();let i=await this.conn;this.isConnecting=!1,await this.wsSendMessage(i,e);return}catch(i){throw this.isConnecting=!1,i}}let t=await this.conn;await this.wsSendMessage(t,e)}catch(t){console.warn("Failed to establish WebSocket connection:",t),this.context=e,this.flushContextDependentEventQueue(),this.setIsPending(!1),this.attemptReconnect()}};track=e=>{let{company:t,user:i,event:r,traits:l,quantity:s=1}=e;if(!this.hasContext(t,i)){this.debug(`track: queuing event "${r}" until context is available`);let u={api_key:this.apiKey,body:{company:t,event:r,traits:l??{},user:i,quantity:s},sent_at:new Date().toISOString(),tracker_event_id:C(),tracker_user_id:this.getAnonymousId(),type:"track"};return this.contextDependentEventQueue.push(u),Promise.resolve()}let p={company:t??this.context.company,event:r,traits:l??{},user:i??this.context.user,quantity:s};return this.debug("track:",p),r in this.featureUsageEventMap&&this.optimisticallyUpdateFeatureUsage(r,s),this.handleEvent("track",p)};optimisticallyUpdateFeatureUsage=(e,t=1)=>{let i=this.featureUsageEventMap[e];i!=null&&(this.debug(`Optimistically updating feature usage for event: ${e}`,{quantity:t}),Object.entries(i).forEach(([r,l])=>{if(l===void 0)return;let s={...l};if(typeof s.featureUsage=="number"){if(s.featureUsage+=t,typeof s.featureAllocation=="number"){let u=s.featureUsageExceeded===!0,f=s.featureUsage>=s.featureAllocation;f!==u&&(s.featureUsageExceeded=f,f&&(s.value=!1),this.debug(`Usage limit status changed for flag: ${r}`,{was:u?"exceeded":"within limits",now:f?"exceeded":"within limits",featureUsage:s.featureUsage,featureAllocation:s.featureAllocation,value:s.value}))}this.featureUsageEventMap[e]!==void 0&&(this.featureUsageEventMap[e][r]=s);let p=S(this.context);this.checks[p]!==void 0&&this.checks[p]!==null&&(this.checks[p][r]=s),this.notifyFlagCheckListeners(r,s),this.notifyFlagValueListeners(r,s.value)}}))};hasContext=(e,t)=>{let i=e!=null&&Object.keys(e).length>0||t!=null&&Object.keys(t).length>0,r=this.context.company!==void 0&&this.context.company!==null&&Object.keys(this.context.company).length>0||this.context.user!==void 0&&this.context.user!==null&&Object.keys(this.context.user).length>0;return i||r};flushContextDependentEventQueue=()=>{for(this.debug(`flushing ${this.contextDependentEventQueue.length} context-dependent events`);this.contextDependentEventQueue.length>0;){let e=this.contextDependentEventQueue.shift();if(e)if(e.type==="track"&&typeof e.body=="object"&&e.body!==null){let t=e.body,i={...t,company:t.company??this.context.company,user:t.user??this.context.user},r={...e,body:i,sent_at:new Date().toISOString()};this.sendEvent(r)}else this.sendEvent(e)}};startRetryTimer=()=>{this.retryTimer===null&&(this.retryTimer=setInterval(()=>{this.flushEventQueue().catch(e=>{this.debug("Error in retry timer flush:",e)}),this.eventQueue.length===0&&this.stopRetryTimer()},5e3),this.debug("Started retry timer"))};stopRetryTimer=()=>{this.retryTimer!==null&&(clearInterval(this.retryTimer),this.retryTimer=null,this.debug("Stopped retry timer"))};flushEventQueue=async()=>{if(this.eventQueue.length===0)return;let e=Date.now(),t=[],i=[];for(let r of this.eventQueue)r.next_retry_at===void 0||r.next_retry_at<=e?t.push(r):i.push(r);if(t.length===0){this.debug(`No events ready for retry yet (${i.length} still in backoff)`);return}this.debug(`Flushing event queue: ${t.length} ready, ${i.length} waiting`),this.eventQueue=i;for(let r of t)try{await this.sendEvent(r),this.debug("Queued event sent successfully:",r.type)}catch(l){this.debug("Failed to send queued event:",l)}};getAnonymousId=()=>{if(!this.storage)return C();let e=this.storage.getItem(Ie);if(typeof e<"u")return e;let t=C();return this.storage.setItem(Ie,t),t};handleEvent=(e,t)=>{let i={api_key:this.apiKey,body:t,sent_at:new Date().toISOString(),tracker_event_id:C(),tracker_user_id:this.getAnonymousId(),type:e};return typeof document<"u"&&document?.hidden?this.storeEvent(i):this.sendEvent(i)};sendEvent=async e=>{let t=`${this.eventUrl}/e`,i=JSON.stringify(e);if(this.debug("sending event:",{url:t,event:e}),this.isOffline())return this.debug("event not sent (offline mode):",{event:e}),Promise.resolve();try{let r=await fetch(t,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8"},body:i});if(!r.ok)throw new Error(`HTTP ${r.status}: ${r.statusText}`);this.debug("event sent:",{status:r.status,statusText:r.statusText})}catch(r){let l=(e.retry_count??0)+1;if(l<=this.maxEventRetries){this.debug(`Event failed to send (attempt ${l}/${this.maxEventRetries}), queueing for retry:`,r);let s=this.eventRetryInitialDelay*Math.pow(2,l-1),p=Math.min(s,this.eventRetryMaxDelay),u=Date.now()+p,f={...e,retry_count:l,next_retry_at:u};this.eventQueue.length<this.maxEventQueueSize?(this.eventQueue.push(f),this.debug(`Event queued for retry in ${p}ms (${this.eventQueue.length}/${this.maxEventQueueSize})`)):(this.debug(`Event queue full (${this.maxEventQueueSize}), dropping oldest event`),this.eventQueue.shift(),this.eventQueue.push(f)),this.startRetryTimer()}else this.debug(`Event failed permanently after ${this.maxEventRetries} attempts, dropping:`,r)}return Promise.resolve()};storeEvent=e=>(this.eventQueue.push(e),Promise.resolve());forceReconnect=async()=>this.reconnect({force:!0});reconnectIfNeeded=async()=>this.reconnect({force:!1});reconnect=async e=>{let{force:t}=e,i=t?"forceReconnect":"reconnectIfNeeded";if(this.isOffline())return this.debug(`${i}: skipped (offline mode)`),Promise.resolve();if(!t&&this.conn!==null)try{if((await this.conn).readyState===WebSocket.OPEN)return this.debug(`${i}: connection is healthy, skipping`),Promise.resolve()}catch{}if(this.debug(`${i}: ${t?"forcing immediate reconnection":"reconnecting"}`),this.wsIntentionalDisconnect=!1,this.wsReconnectTimer!==null&&(this.debug(`${i}: cancelling pending reconnection timer`),clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.wsReconnectAttempts=0,this.conn!==null){this.debug(`${i}: closing existing connection`);try{let r=await this.conn;this.currentWebSocket===r&&(this.currentWebSocket=null),(r.readyState===WebSocket.OPEN||r.readyState===WebSocket.CONNECTING)&&r.close()}catch(r){this.debug(`${i}: error closing existing connection:`,r)}this.conn=null,this.isConnecting=!1}if(this.context.company!==void 0||this.context.user!==void 0){this.debug(`${i}: reconnecting with existing context`);try{this.isConnecting=!0,this.conn=this.wsConnect();let r=await this.conn;this.isConnecting=!1,await this.wsSendMessage(r,this.context,!0),this.debug(`${i}: reconnection successful`)}catch(r){this.isConnecting=!1,this.debug(`${i}: reconnection failed:`,r)}}else this.debug(`${i}: no context set, skipping reconnection`);return Promise.resolve()};cleanup=async()=>{if(this.isOffline())return this.debug("cleanup: skipped (offline mode)"),Promise.resolve();if(this.wsIntentionalDisconnect=!0,this.wsReconnectTimer!==null&&(clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.stopRetryTimer(),this.conn)try{let e=await this.conn;this.currentWebSocket===e&&(this.debug("Cleaning up current websocket tracking"),this.currentWebSocket=null),e.close()}catch(e){console.warn("Error during cleanup:",e)}finally{this.conn=null,this.currentWebSocket=null,this.isConnecting=!1}};calculateReconnectDelay=()=>{let e=this.webSocketInitialRetryDelay*Math.pow(2,this.wsReconnectAttempts),t=Math.min(e,this.webSocketMaxRetryDelay),i=Math.random()*t*.5,r=t+i;return this.debug(`Reconnect delay calculated: ${r.toFixed(0)}ms (attempt ${this.wsReconnectAttempts+1}/${this.webSocketMaxReconnectAttempts})`),r};handleNetworkOffline=async()=>{if(this.conn!==null){try{let e=await this.conn;(e.readyState===WebSocket.OPEN||e.readyState===WebSocket.CONNECTING)&&e.close()}catch(e){this.debug("Error closing connection on offline:",e)}this.conn=null}this.wsReconnectTimer!==null&&(clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null)};handleNetworkOnline=()=>{this.debug("Network online, attempting reconnection and flushing queued events"),this.wsReconnectAttempts=0,this.wsReconnectTimer!==null&&(clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.flushEventQueue().catch(e=>{this.debug("Error flushing event queue on network online:",e)}),this.attemptReconnect()};attemptReconnect=()=>{if(this.wsReconnectAttempts>=this.webSocketMaxReconnectAttempts){this.debug(`Maximum reconnection attempts (${this.webSocketMaxReconnectAttempts}) reached, giving up`);return}if(this.wsReconnectTimer!==null){this.debug("Reconnection attempt already scheduled, ignoring duplicate request");return}let e=this.calculateReconnectDelay();this.debug(`Scheduling reconnection attempt ${this.wsReconnectAttempts+1}/${this.webSocketMaxReconnectAttempts} in ${e.toFixed(0)}ms`),this.wsReconnectTimer=setTimeout(async()=>{this.wsReconnectTimer=null,this.wsReconnectAttempts++,this.debug(`Attempting to reconnect (attempt ${this.wsReconnectAttempts}/${this.webSocketMaxReconnectAttempts})`);try{if(this.conn!==null){this.debug("Cleaning up existing connection before reconnection");try{let t=await this.conn;this.currentWebSocket===t&&(this.debug("Existing websocket is current, will be replaced"),this.currentWebSocket=null),(t.readyState===WebSocket.OPEN||t.readyState===WebSocket.CONNECTING)&&t.close()}catch(t){this.debug("Error cleaning up existing connection:",t)}this.conn=null,this.currentWebSocket=null,this.isConnecting=!1}this.isConnecting=!0;try{this.conn=this.wsConnect();let t=await this.conn;this.isConnecting=!1,this.debug("Reconnection context check:",{hasCompany:this.context.company!==void 0,hasUser:this.context.user!==void 0,context:this.context}),this.context.company!==void 0||this.context.user!==void 0?(this.debug("Reconnected, force re-sending context"),await this.wsSendMessage(t,this.context,!0)):(this.debug("No context to re-send after reconnection - websocket ready for new context"),this.debug("Setting up tracking for reconnected websocket (no context to send)"),this.currentWebSocket=t),this.flushEventQueue().catch(i=>{this.debug("Error flushing event queue after websocket reconnection:",i)}),this.debug("Reconnection successful")}catch(t){throw this.isConnecting=!1,t}}catch(t){this.debug("Reconnection attempt failed:",t)}},e)};wsConnect=async()=>{if(this.isOffline())throw this.debug("wsConnect: skipped (offline mode)"),new Error("WebSocket connection skipped in offline mode");let e=null,t=this.webSocketMaxConnectionAttempts;for(let i=0;i<t;i++)try{let r=await this.wsConnectOnce();return this.wsReconnectAttempts=0,r}catch(r){if(e=r instanceof Error?r:new Error(String(r)),!(e.message==="WebSocket connection timeout"))throw this.debug("WebSocket connection failed with non-timeout error, not retrying:",e.message),e;if(i<t-1){let s=this.webSocketInitialRetryDelay*Math.pow(2,i),p=Math.min(s,this.webSocketMaxRetryDelay),u=p*.2*Math.random(),f=p+u;this.debug(`WebSocket connection timeout (attempt ${i+1}/${t}), retrying in ${f.toFixed(0)}ms`),await new Promise(P=>setTimeout(P,f))}else this.debug(`WebSocket connection timeout (attempt ${i+1}/${t}), no more retries`)}throw e??new Error("WebSocket connection failed")};wsConnectOnce=()=>new Promise((e,t)=>{let i=`${this.webSocketUrl}/flags/bootstrap?apiKey=${this.apiKey}`;this.debug("connecting to WebSocket:",i);let r=new WebSocket(i),l=Math.random().toString(36).substring(7);this.debug(`Creating WebSocket connection ${l} to ${i}`);let s=null,p=!1;s=setTimeout(()=>{p||(p=!0,this.debug(`WebSocket connection timeout after ${this.webSocketConnectionTimeout}ms`),r.close(),t(new Error("WebSocket connection timeout")))},this.webSocketConnectionTimeout),r.onopen=()=>{p||(p=!0,s!==null&&clearTimeout(s),this.wsIntentionalDisconnect=!1,this.debug(`WebSocket connection ${l} opened successfully`),e(r))},r.onerror=u=>{if(p)return;p=!0,s!==null&&clearTimeout(s),this.debug(`WebSocket connection ${l} error:`,u);let f=new Error("WebSocket connection failed during handshake");t(f)},r.onclose=()=>{s!==null&&clearTimeout(s),this.debug(`WebSocket connection ${l} closed`),this.conn=null,this.currentWebSocket===r&&(this.currentWebSocket=null,this.isConnecting=!1),!p&&!this.wsIntentionalDisconnect&&this.webSocketReconnect&&this.attemptReconnect()}});wsSendMessage=(e,t,i=!1)=>this.isOffline()?(this.debug("wsSendMessage: skipped (offline mode)"),this.setIsPending(!1),Promise.resolve()):new Promise((r,l)=>{if(!i&&S(t)==S(this.context))return this.debug("WebSocket context unchanged, skipping update"),r(this.setIsPending(!1));this.debug(i?"WebSocket force sending context (reconnection):":"WebSocket context updated:",t),this.context=t;let s=()=>{let p=!1,u=this.createPersistentMessageHandler(t),f=D=>{u(D),p||(p=!0,r())};e.addEventListener("message",f),e.addEventListener("close",D=>{p||(p=!0,D.code===4001?l(new Error(`Authentication failed: ${D.reason!==""?D.reason:"Invalid API key"}`)):l(new Error("WebSocket connection closed unexpectedly")))}),this.currentWebSocket=e;let P=this.additionalHeaders["X-Schematic-Client-Version"]??`schematic-js@${j}`,y={apiKey:this.apiKey,clientVersion:P,data:t};this.debug("WebSocket sending message:",y),e.send(JSON.stringify(y))};e.readyState===WebSocket.OPEN?(this.debug("WebSocket already open, sending message"),s()):e.readyState===WebSocket.CONNECTING?(this.debug("WebSocket connecting, waiting for open to send message"),e.addEventListener("open",s)):(this.debug("WebSocket is closed, cannot send message"),l("WebSocket is not open or connecting"))});getIsPending=()=>this.isPending;addIsPendingListener=e=>(this.isPendingListeners.add(e),()=>{this.isPendingListeners.delete(e)});setIsPending=e=>{this.isPending!==e&&(this.isPending=e,this.isPendingListeners.forEach(t=>Qt(t,e)))};getPlan=()=>{let e=S(this.context);return this.planChecks[e]};getFlagCheck=e=>{let t=S(this.context),r=(this.checks[t]??{})[e];if(r!==void 0)return r;if(e in this.flagCheckDefaults||e in this.flagValueDefaults)return e in this.fallbackCheckCache||(this.fallbackCheckCache[e]=this.resolveFallbackCheckFlagReturn(e,void 0,"Default value used")),this.fallbackCheckCache[e]};getFlagValue=e=>{let t=S(this.context),r=(this.checks[t]??{})[e];if(r?.value!==void 0)return r.value;if(e in this.flagCheckDefaults||e in this.flagValueDefaults)return this.resolveFallbackValue(e)};addFlagValueListener=(e,t)=>(e in this.flagValueListeners||(this.flagValueListeners[e]=new Set),this.flagValueListeners[e].add(t),()=>{this.flagValueListeners[e].delete(t)});addFlagCheckListener=(e,t)=>(e in this.flagCheckListeners||(this.flagCheckListeners[e]=new Set),this.flagCheckListeners[e].add(t),()=>{this.flagCheckListeners[e].delete(t)});addPlanListener=e=>(this.planListeners.add(e),()=>{this.planListeners.delete(e)});notifyFlagCheckListeners=(e,t)=>{let i=this.flagCheckListeners?.[e]??[];i.size>0&&this.debug(`Notifying ${i.size} flag check listeners for ${e}`,t),typeof t.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(t),i.forEach(r=>Kt(r,t))};updateFeatureUsageEventMap=e=>{if(typeof e.featureUsageEvent!="string")return;let t=e.featureUsageEvent;(this.featureUsageEventMap[t]===void 0||this.featureUsageEventMap[t]===null)&&(this.featureUsageEventMap[t]={}),this.featureUsageEventMap[t]!==void 0&&(this.featureUsageEventMap[t][e.flag]=e),this.debug(`Updated featureUsageEventMap for event: ${t}, flag: ${e.flag}`,e)};notifyFlagValueListeners=(e,t)=>{let i=this.flagValueListeners?.[e]??[];i.size>0&&this.debug(`Notifying ${i.size} flag value listeners for ${e}`,{value:t}),i.forEach((r,l)=>{this.debug(`Calling listener ${l} for flag ${e}`,{flagKey:e,value:t}),Xt(r,t),this.debug(`Listener ${l} for flag ${e} completed`,{flagKey:e,value:t})})};notifyPlanListeners=e=>{let t=this.planListeners??[];t.size>0&&this.debug(`Notifying ${t.size} plan listeners`,{value:e}),t.forEach((i,r)=>{this.debug(`Calling listener ${r} for plan`,{value:e}),Yt(i,e),this.debug(`Listener ${r} for plan completed`,{value:e})})}},Qt=(n,e)=>{n.length>0?n(e):n()},Kt=(n,e)=>{n.length>0?n(e):n()},Xt=(n,e)=>{n.length>0?n(e):n()},Yt=(n,e)=>{n.length>0?n(e):n()};window.Schematic=L;})();
|
|
3
3
|
/* @preserve */
|
package/dist/schematic.cjs.js
CHANGED
|
@@ -572,9 +572,12 @@ __export(index_exports, {
|
|
|
572
572
|
CheckFlagResponseFromJSON: () => CheckFlagResponseFromJSON,
|
|
573
573
|
CheckFlagReturnFromJSON: () => CheckFlagReturnFromJSON,
|
|
574
574
|
CheckFlagsResponseFromJSON: () => CheckFlagsResponseFromJSON,
|
|
575
|
+
CheckPlanReturnFromJSON: () => CheckPlanReturnFromJSON,
|
|
576
|
+
DatastreamCompanyPlanFromJSON: () => DatastreamCompanyPlanFromJSON,
|
|
575
577
|
EventBodyFlagCheckToJSON: () => EventBodyFlagCheckToJSON,
|
|
576
578
|
RuleType: () => RuleType,
|
|
577
579
|
Schematic: () => Schematic,
|
|
580
|
+
TrialStatus: () => TrialStatus,
|
|
578
581
|
UsagePeriod: () => UsagePeriod
|
|
579
582
|
});
|
|
580
583
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -698,28 +701,6 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
698
701
|
};
|
|
699
702
|
}
|
|
700
703
|
|
|
701
|
-
// src/types/api/models/EventBodyFlagCheck.ts
|
|
702
|
-
function EventBodyFlagCheckToJSON(json) {
|
|
703
|
-
return EventBodyFlagCheckToJSONTyped(json, false);
|
|
704
|
-
}
|
|
705
|
-
function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
|
|
706
|
-
if (value == null) {
|
|
707
|
-
return value;
|
|
708
|
-
}
|
|
709
|
-
return {
|
|
710
|
-
company_id: value["companyId"],
|
|
711
|
-
error: value["error"],
|
|
712
|
-
flag_id: value["flagId"],
|
|
713
|
-
flag_key: value["flagKey"],
|
|
714
|
-
reason: value["reason"],
|
|
715
|
-
req_company: value["reqCompany"],
|
|
716
|
-
req_user: value["reqUser"],
|
|
717
|
-
rule_id: value["ruleId"],
|
|
718
|
-
user_id: value["userId"],
|
|
719
|
-
value: value["value"]
|
|
720
|
-
};
|
|
721
|
-
}
|
|
722
|
-
|
|
723
704
|
// src/types/api/models/CheckFlagResponse.ts
|
|
724
705
|
function CheckFlagResponseFromJSON(json) {
|
|
725
706
|
return CheckFlagResponseFromJSONTyped(json, false);
|
|
@@ -734,6 +715,35 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
734
715
|
};
|
|
735
716
|
}
|
|
736
717
|
|
|
718
|
+
// src/types/api/models/TrialStatus.ts
|
|
719
|
+
var TrialStatus = {
|
|
720
|
+
Active: "active",
|
|
721
|
+
Converted: "converted",
|
|
722
|
+
Expired: "expired"
|
|
723
|
+
};
|
|
724
|
+
function TrialStatusFromJSON(json) {
|
|
725
|
+
return TrialStatusFromJSONTyped(json, false);
|
|
726
|
+
}
|
|
727
|
+
function TrialStatusFromJSONTyped(json, ignoreDiscriminator) {
|
|
728
|
+
return json;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// src/types/api/models/DatastreamCompanyPlan.ts
|
|
732
|
+
function DatastreamCompanyPlanFromJSON(json) {
|
|
733
|
+
return DatastreamCompanyPlanFromJSONTyped(json, false);
|
|
734
|
+
}
|
|
735
|
+
function DatastreamCompanyPlanFromJSONTyped(json, ignoreDiscriminator) {
|
|
736
|
+
if (json == null) {
|
|
737
|
+
return json;
|
|
738
|
+
}
|
|
739
|
+
return {
|
|
740
|
+
id: json["id"],
|
|
741
|
+
name: json["name"],
|
|
742
|
+
trialEndDate: json["trial_end_date"] == null ? void 0 : new Date(json["trial_end_date"]),
|
|
743
|
+
trialStatus: json["trial_status"] == null ? void 0 : TrialStatusFromJSON(json["trial_status"])
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
|
|
737
747
|
// src/types/api/models/CheckFlagsResponseData.ts
|
|
738
748
|
function CheckFlagsResponseDataFromJSON(json) {
|
|
739
749
|
return CheckFlagsResponseDataFromJSONTyped(json, false);
|
|
@@ -743,7 +753,8 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
743
753
|
return json;
|
|
744
754
|
}
|
|
745
755
|
return {
|
|
746
|
-
flags: json["flags"].map(CheckFlagResponseDataFromJSON)
|
|
756
|
+
flags: json["flags"].map(CheckFlagResponseDataFromJSON),
|
|
757
|
+
plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
|
|
747
758
|
};
|
|
748
759
|
}
|
|
749
760
|
|
|
@@ -761,6 +772,28 @@ function CheckFlagsResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
761
772
|
};
|
|
762
773
|
}
|
|
763
774
|
|
|
775
|
+
// src/types/api/models/EventBodyFlagCheck.ts
|
|
776
|
+
function EventBodyFlagCheckToJSON(json) {
|
|
777
|
+
return EventBodyFlagCheckToJSONTyped(json, false);
|
|
778
|
+
}
|
|
779
|
+
function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
|
|
780
|
+
if (value == null) {
|
|
781
|
+
return value;
|
|
782
|
+
}
|
|
783
|
+
return {
|
|
784
|
+
company_id: value["companyId"],
|
|
785
|
+
error: value["error"],
|
|
786
|
+
flag_id: value["flagId"],
|
|
787
|
+
flag_key: value["flagKey"],
|
|
788
|
+
reason: value["reason"],
|
|
789
|
+
req_company: value["reqCompany"],
|
|
790
|
+
req_user: value["reqUser"],
|
|
791
|
+
rule_id: value["ruleId"],
|
|
792
|
+
user_id: value["userId"],
|
|
793
|
+
value: value["value"]
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
|
|
764
797
|
// src/types/index.ts
|
|
765
798
|
var RuleType = /* @__PURE__ */ ((RuleType2) => {
|
|
766
799
|
RuleType2["GLOBAL_OVERRIDE"] = "global_override";
|
|
@@ -817,6 +850,15 @@ var CheckFlagReturnFromJSON = (json) => {
|
|
|
817
850
|
value
|
|
818
851
|
};
|
|
819
852
|
};
|
|
853
|
+
var CheckPlanReturnFromJSON = (json) => {
|
|
854
|
+
const { id, name, trialEndDate, trialStatus } = DatastreamCompanyPlanFromJSON(json);
|
|
855
|
+
return {
|
|
856
|
+
id,
|
|
857
|
+
name,
|
|
858
|
+
trialEndDate: trialEndDate == null ? void 0 : trialEndDate,
|
|
859
|
+
trialStatus: trialStatus == null ? void 0 : trialStatus
|
|
860
|
+
};
|
|
861
|
+
};
|
|
820
862
|
|
|
821
863
|
// src/utils.ts
|
|
822
864
|
function contextString(context) {
|
|
@@ -835,7 +877,7 @@ function contextString(context) {
|
|
|
835
877
|
}
|
|
836
878
|
|
|
837
879
|
// src/version.ts
|
|
838
|
-
var version = "1.
|
|
880
|
+
var version = "1.3.1";
|
|
839
881
|
|
|
840
882
|
// src/index.ts
|
|
841
883
|
var anonymousIdKey = "schematicId";
|
|
@@ -854,10 +896,12 @@ var Schematic = class {
|
|
|
854
896
|
flagValueListeners = {};
|
|
855
897
|
isPending = true;
|
|
856
898
|
isPendingListeners = /* @__PURE__ */ new Set();
|
|
899
|
+
planListeners = /* @__PURE__ */ new Set();
|
|
857
900
|
storage;
|
|
858
901
|
useWebSocket = false;
|
|
859
902
|
checks = {};
|
|
860
903
|
featureUsageEventMap = {};
|
|
904
|
+
planChecks = {};
|
|
861
905
|
webSocketUrl = "wss://api.schematichq.com";
|
|
862
906
|
webSocketConnectionTimeout = 1e4;
|
|
863
907
|
webSocketReconnect = true;
|
|
@@ -1190,28 +1234,32 @@ var Schematic = class {
|
|
|
1190
1234
|
this.checks[contextStr] = {};
|
|
1191
1235
|
}
|
|
1192
1236
|
this.checks[contextStr][flagCheck.flag] = flagCheck;
|
|
1193
|
-
this.debug(`WebSocket flag update:`, {
|
|
1194
|
-
flag: flagCheck.flag,
|
|
1195
|
-
value: flagCheck.value,
|
|
1196
|
-
flagCheck
|
|
1197
|
-
});
|
|
1198
1237
|
if (typeof flagCheck.featureUsageEvent === "string") {
|
|
1199
1238
|
this.updateFeatureUsageEventMap(flagCheck);
|
|
1200
1239
|
}
|
|
1201
1240
|
if ((this.flagCheckListeners[flag.flag]?.size ?? 0) > 0 || (this.flagValueListeners[flag.flag]?.size ?? 0) > 0) {
|
|
1202
1241
|
this.submitFlagCheckEvent(flagCheck.flag, flagCheck, context);
|
|
1203
1242
|
}
|
|
1204
|
-
this.debug(
|
|
1205
|
-
flag
|
|
1206
|
-
|
|
1207
|
-
|
|
1243
|
+
this.debug(
|
|
1244
|
+
`WebSocket flag update received. Notifying listeners for ${flag.flag}`,
|
|
1245
|
+
{
|
|
1246
|
+
flag: flag.flag,
|
|
1247
|
+
value: flagCheck.value,
|
|
1248
|
+
flagCheck
|
|
1249
|
+
}
|
|
1250
|
+
);
|
|
1208
1251
|
this.notifyFlagCheckListeners(flag.flag, flagCheck);
|
|
1209
1252
|
this.notifyFlagValueListeners(flag.flag, flagCheck.value);
|
|
1210
|
-
this.debug(`Finished notifying listeners for flag ${flag.flag}`, {
|
|
1211
|
-
flag: flag.flag,
|
|
1212
|
-
value: flagCheck.value
|
|
1213
|
-
});
|
|
1214
1253
|
});
|
|
1254
|
+
if (message.plan !== void 0 && message.plan !== null) {
|
|
1255
|
+
const plan = CheckPlanReturnFromJSON(message.plan);
|
|
1256
|
+
const contextStr = contextString(context);
|
|
1257
|
+
this.planChecks[contextStr] = plan;
|
|
1258
|
+
this.debug(`WebSocket plan update received. Notifying listeners`, {
|
|
1259
|
+
plan
|
|
1260
|
+
});
|
|
1261
|
+
this.notifyPlanListeners(plan);
|
|
1262
|
+
}
|
|
1215
1263
|
this.flushContextDependentEventQueue();
|
|
1216
1264
|
this.setIsPending(false);
|
|
1217
1265
|
};
|
|
@@ -2107,6 +2155,11 @@ var Schematic = class {
|
|
|
2107
2155
|
(listener) => notifyPendingListener(listener, isPending)
|
|
2108
2156
|
);
|
|
2109
2157
|
};
|
|
2158
|
+
getPlan = () => {
|
|
2159
|
+
const contextStr = contextString(this.context);
|
|
2160
|
+
const plan = this.planChecks[contextStr];
|
|
2161
|
+
return plan;
|
|
2162
|
+
};
|
|
2110
2163
|
// flag checks state
|
|
2111
2164
|
getFlagCheck = (flagKey) => {
|
|
2112
2165
|
const contextStr = contextString(this.context);
|
|
@@ -2160,6 +2213,12 @@ var Schematic = class {
|
|
|
2160
2213
|
this.flagCheckListeners[flagKey].delete(listener);
|
|
2161
2214
|
};
|
|
2162
2215
|
};
|
|
2216
|
+
addPlanListener = (listener) => {
|
|
2217
|
+
this.planListeners.add(listener);
|
|
2218
|
+
return () => {
|
|
2219
|
+
this.planListeners.delete(listener);
|
|
2220
|
+
};
|
|
2221
|
+
};
|
|
2163
2222
|
notifyFlagCheckListeners = (flagKey, check) => {
|
|
2164
2223
|
const listeners = this.flagCheckListeners?.[flagKey] ?? [];
|
|
2165
2224
|
if (listeners.size > 0) {
|
|
@@ -2208,6 +2267,21 @@ var Schematic = class {
|
|
|
2208
2267
|
});
|
|
2209
2268
|
});
|
|
2210
2269
|
};
|
|
2270
|
+
notifyPlanListeners = (value) => {
|
|
2271
|
+
const listeners = this.planListeners ?? [];
|
|
2272
|
+
if (listeners.size > 0) {
|
|
2273
|
+
this.debug(`Notifying ${listeners.size} plan listeners`, { value });
|
|
2274
|
+
}
|
|
2275
|
+
listeners.forEach((listener, index) => {
|
|
2276
|
+
this.debug(`Calling listener ${index} for plan`, {
|
|
2277
|
+
value
|
|
2278
|
+
});
|
|
2279
|
+
notifyPlanListener(listener, value);
|
|
2280
|
+
this.debug(`Listener ${index} for plan completed`, {
|
|
2281
|
+
value
|
|
2282
|
+
});
|
|
2283
|
+
});
|
|
2284
|
+
};
|
|
2211
2285
|
};
|
|
2212
2286
|
var notifyPendingListener = (listener, value) => {
|
|
2213
2287
|
if (listener.length > 0) {
|
|
@@ -2230,4 +2304,11 @@ var notifyFlagValueListener = (listener, value) => {
|
|
|
2230
2304
|
listener();
|
|
2231
2305
|
}
|
|
2232
2306
|
};
|
|
2307
|
+
var notifyPlanListener = (listener, value) => {
|
|
2308
|
+
if (listener.length > 0) {
|
|
2309
|
+
listener(value);
|
|
2310
|
+
} else {
|
|
2311
|
+
listener();
|
|
2312
|
+
}
|
|
2313
|
+
};
|
|
2233
2314
|
/* @preserve */
|
package/dist/schematic.d.ts
CHANGED
|
@@ -194,6 +194,12 @@ declare interface CheckFlagsResponseData {
|
|
|
194
194
|
* @memberof CheckFlagsResponseData
|
|
195
195
|
*/
|
|
196
196
|
flags: Array<CheckFlagResponseData>;
|
|
197
|
+
/**
|
|
198
|
+
*
|
|
199
|
+
* @type {DatastreamCompanyPlan}
|
|
200
|
+
* @memberof CheckFlagsResponseData
|
|
201
|
+
*/
|
|
202
|
+
plan?: DatastreamCompanyPlan;
|
|
197
203
|
}
|
|
198
204
|
|
|
199
205
|
export declare function CheckFlagsResponseFromJSON(json: any): CheckFlagsResponse;
|
|
@@ -204,6 +210,51 @@ export declare type CheckOptions = {
|
|
|
204
210
|
key: string;
|
|
205
211
|
};
|
|
206
212
|
|
|
213
|
+
export declare type CheckPlanReturn = {
|
|
214
|
+
id: string;
|
|
215
|
+
name: string;
|
|
216
|
+
trialEndDate?: Date;
|
|
217
|
+
trialStatus?: TrialStatus;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
export declare const CheckPlanReturnFromJSON: (json: any) => CheckPlanReturn;
|
|
221
|
+
|
|
222
|
+
export declare type CheckPlanReturnListenerFn = (value: CheckPlanReturn) => void;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
*
|
|
226
|
+
* @export
|
|
227
|
+
* @interface DatastreamCompanyPlan
|
|
228
|
+
*/
|
|
229
|
+
declare interface DatastreamCompanyPlan {
|
|
230
|
+
/**
|
|
231
|
+
*
|
|
232
|
+
* @type {string}
|
|
233
|
+
* @memberof DatastreamCompanyPlan
|
|
234
|
+
*/
|
|
235
|
+
id: string;
|
|
236
|
+
/**
|
|
237
|
+
*
|
|
238
|
+
* @type {string}
|
|
239
|
+
* @memberof DatastreamCompanyPlan
|
|
240
|
+
*/
|
|
241
|
+
name: string;
|
|
242
|
+
/**
|
|
243
|
+
*
|
|
244
|
+
* @type {Date}
|
|
245
|
+
* @memberof DatastreamCompanyPlan
|
|
246
|
+
*/
|
|
247
|
+
trialEndDate?: Date | null;
|
|
248
|
+
/**
|
|
249
|
+
*
|
|
250
|
+
* @type {TrialStatus}
|
|
251
|
+
* @memberof DatastreamCompanyPlan
|
|
252
|
+
*/
|
|
253
|
+
trialStatus?: TrialStatus | null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export declare function DatastreamCompanyPlanFromJSON(json: any): DatastreamCompanyPlan;
|
|
257
|
+
|
|
207
258
|
export declare type EmptyListenerFn = () => void;
|
|
208
259
|
|
|
209
260
|
/**
|
|
@@ -462,6 +513,8 @@ export declare type Keys = Record<string, string>;
|
|
|
462
513
|
|
|
463
514
|
export declare type PendingListenerFn = BooleanListenerFn | EmptyListenerFn;
|
|
464
515
|
|
|
516
|
+
export declare type PlanListenerFn = CheckPlanReturnListenerFn | EmptyListenerFn;
|
|
517
|
+
|
|
465
518
|
export declare enum RuleType {
|
|
466
519
|
/** A global rule that, if present, will override all other rules for a flag */
|
|
467
520
|
GLOBAL_OVERRIDE = "global_override",
|
|
@@ -494,10 +547,12 @@ export declare class Schematic {
|
|
|
494
547
|
private flagValueListeners;
|
|
495
548
|
private isPending;
|
|
496
549
|
private isPendingListeners;
|
|
550
|
+
private planListeners;
|
|
497
551
|
private storage;
|
|
498
552
|
private useWebSocket;
|
|
499
553
|
private checks;
|
|
500
554
|
private featureUsageEventMap;
|
|
555
|
+
private planChecks;
|
|
501
556
|
private webSocketUrl;
|
|
502
557
|
private webSocketConnectionTimeout;
|
|
503
558
|
private webSocketReconnect;
|
|
@@ -702,16 +757,19 @@ export declare class Schematic {
|
|
|
702
757
|
getIsPending: () => boolean;
|
|
703
758
|
addIsPendingListener: (listener: PendingListenerFn) => () => void;
|
|
704
759
|
private setIsPending;
|
|
760
|
+
getPlan: () => CheckPlanReturn | undefined;
|
|
705
761
|
getFlagCheck: (flagKey: string) => CheckFlagReturn | undefined;
|
|
706
762
|
getFlagValue: (flagKey: string) => boolean | undefined;
|
|
707
763
|
/** Register an event listener that will be notified with the boolean value for a given flag when this value changes */
|
|
708
764
|
addFlagValueListener: (flagKey: string, listener: FlagValueListenerFn) => () => void;
|
|
709
765
|
/** Register an event listener that will be notified with the full flag check response for a given flag whenever this value changes */
|
|
710
766
|
addFlagCheckListener: (flagKey: string, listener: FlagCheckListenerFn) => () => void;
|
|
767
|
+
addPlanListener: (listener: PlanListenerFn) => () => void;
|
|
711
768
|
private notifyFlagCheckListeners;
|
|
712
769
|
/** Add or update a CheckFlagReturn in the featureUsageEventMap */
|
|
713
770
|
private updateFeatureUsageEventMap;
|
|
714
771
|
private notifyFlagValueListeners;
|
|
772
|
+
private notifyPlanListeners;
|
|
715
773
|
}
|
|
716
774
|
|
|
717
775
|
/** Context for checking flags and sending events */
|
|
@@ -776,6 +834,18 @@ export declare type StoragePersister = {
|
|
|
776
834
|
*/
|
|
777
835
|
export declare type Traits = Record<string, any>;
|
|
778
836
|
|
|
837
|
+
/**
|
|
838
|
+
*
|
|
839
|
+
* @export
|
|
840
|
+
*/
|
|
841
|
+
export declare const TrialStatus: {
|
|
842
|
+
readonly Active: "active";
|
|
843
|
+
readonly Converted: "converted";
|
|
844
|
+
readonly Expired: "expired";
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
export declare type TrialStatus = (typeof TrialStatus)[keyof typeof TrialStatus];
|
|
848
|
+
|
|
779
849
|
export declare enum UsagePeriod {
|
|
780
850
|
ALL_TIME = "all_time",
|
|
781
851
|
CURRENT_DAY = "current_day",
|
package/dist/schematic.esm.js
CHANGED
|
@@ -679,28 +679,6 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
679
679
|
};
|
|
680
680
|
}
|
|
681
681
|
|
|
682
|
-
// src/types/api/models/EventBodyFlagCheck.ts
|
|
683
|
-
function EventBodyFlagCheckToJSON(json) {
|
|
684
|
-
return EventBodyFlagCheckToJSONTyped(json, false);
|
|
685
|
-
}
|
|
686
|
-
function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
|
|
687
|
-
if (value == null) {
|
|
688
|
-
return value;
|
|
689
|
-
}
|
|
690
|
-
return {
|
|
691
|
-
company_id: value["companyId"],
|
|
692
|
-
error: value["error"],
|
|
693
|
-
flag_id: value["flagId"],
|
|
694
|
-
flag_key: value["flagKey"],
|
|
695
|
-
reason: value["reason"],
|
|
696
|
-
req_company: value["reqCompany"],
|
|
697
|
-
req_user: value["reqUser"],
|
|
698
|
-
rule_id: value["ruleId"],
|
|
699
|
-
user_id: value["userId"],
|
|
700
|
-
value: value["value"]
|
|
701
|
-
};
|
|
702
|
-
}
|
|
703
|
-
|
|
704
682
|
// src/types/api/models/CheckFlagResponse.ts
|
|
705
683
|
function CheckFlagResponseFromJSON(json) {
|
|
706
684
|
return CheckFlagResponseFromJSONTyped(json, false);
|
|
@@ -715,6 +693,35 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
715
693
|
};
|
|
716
694
|
}
|
|
717
695
|
|
|
696
|
+
// src/types/api/models/TrialStatus.ts
|
|
697
|
+
var TrialStatus = {
|
|
698
|
+
Active: "active",
|
|
699
|
+
Converted: "converted",
|
|
700
|
+
Expired: "expired"
|
|
701
|
+
};
|
|
702
|
+
function TrialStatusFromJSON(json) {
|
|
703
|
+
return TrialStatusFromJSONTyped(json, false);
|
|
704
|
+
}
|
|
705
|
+
function TrialStatusFromJSONTyped(json, ignoreDiscriminator) {
|
|
706
|
+
return json;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// src/types/api/models/DatastreamCompanyPlan.ts
|
|
710
|
+
function DatastreamCompanyPlanFromJSON(json) {
|
|
711
|
+
return DatastreamCompanyPlanFromJSONTyped(json, false);
|
|
712
|
+
}
|
|
713
|
+
function DatastreamCompanyPlanFromJSONTyped(json, ignoreDiscriminator) {
|
|
714
|
+
if (json == null) {
|
|
715
|
+
return json;
|
|
716
|
+
}
|
|
717
|
+
return {
|
|
718
|
+
id: json["id"],
|
|
719
|
+
name: json["name"],
|
|
720
|
+
trialEndDate: json["trial_end_date"] == null ? void 0 : new Date(json["trial_end_date"]),
|
|
721
|
+
trialStatus: json["trial_status"] == null ? void 0 : TrialStatusFromJSON(json["trial_status"])
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
|
|
718
725
|
// src/types/api/models/CheckFlagsResponseData.ts
|
|
719
726
|
function CheckFlagsResponseDataFromJSON(json) {
|
|
720
727
|
return CheckFlagsResponseDataFromJSONTyped(json, false);
|
|
@@ -724,7 +731,8 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
724
731
|
return json;
|
|
725
732
|
}
|
|
726
733
|
return {
|
|
727
|
-
flags: json["flags"].map(CheckFlagResponseDataFromJSON)
|
|
734
|
+
flags: json["flags"].map(CheckFlagResponseDataFromJSON),
|
|
735
|
+
plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
|
|
728
736
|
};
|
|
729
737
|
}
|
|
730
738
|
|
|
@@ -742,6 +750,28 @@ function CheckFlagsResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
742
750
|
};
|
|
743
751
|
}
|
|
744
752
|
|
|
753
|
+
// src/types/api/models/EventBodyFlagCheck.ts
|
|
754
|
+
function EventBodyFlagCheckToJSON(json) {
|
|
755
|
+
return EventBodyFlagCheckToJSONTyped(json, false);
|
|
756
|
+
}
|
|
757
|
+
function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
|
|
758
|
+
if (value == null) {
|
|
759
|
+
return value;
|
|
760
|
+
}
|
|
761
|
+
return {
|
|
762
|
+
company_id: value["companyId"],
|
|
763
|
+
error: value["error"],
|
|
764
|
+
flag_id: value["flagId"],
|
|
765
|
+
flag_key: value["flagKey"],
|
|
766
|
+
reason: value["reason"],
|
|
767
|
+
req_company: value["reqCompany"],
|
|
768
|
+
req_user: value["reqUser"],
|
|
769
|
+
rule_id: value["ruleId"],
|
|
770
|
+
user_id: value["userId"],
|
|
771
|
+
value: value["value"]
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
|
|
745
775
|
// src/types/index.ts
|
|
746
776
|
var RuleType = /* @__PURE__ */ ((RuleType2) => {
|
|
747
777
|
RuleType2["GLOBAL_OVERRIDE"] = "global_override";
|
|
@@ -798,6 +828,15 @@ var CheckFlagReturnFromJSON = (json) => {
|
|
|
798
828
|
value
|
|
799
829
|
};
|
|
800
830
|
};
|
|
831
|
+
var CheckPlanReturnFromJSON = (json) => {
|
|
832
|
+
const { id, name, trialEndDate, trialStatus } = DatastreamCompanyPlanFromJSON(json);
|
|
833
|
+
return {
|
|
834
|
+
id,
|
|
835
|
+
name,
|
|
836
|
+
trialEndDate: trialEndDate == null ? void 0 : trialEndDate,
|
|
837
|
+
trialStatus: trialStatus == null ? void 0 : trialStatus
|
|
838
|
+
};
|
|
839
|
+
};
|
|
801
840
|
|
|
802
841
|
// src/utils.ts
|
|
803
842
|
function contextString(context) {
|
|
@@ -816,7 +855,7 @@ function contextString(context) {
|
|
|
816
855
|
}
|
|
817
856
|
|
|
818
857
|
// src/version.ts
|
|
819
|
-
var version = "1.
|
|
858
|
+
var version = "1.3.1";
|
|
820
859
|
|
|
821
860
|
// src/index.ts
|
|
822
861
|
var anonymousIdKey = "schematicId";
|
|
@@ -835,10 +874,12 @@ var Schematic = class {
|
|
|
835
874
|
flagValueListeners = {};
|
|
836
875
|
isPending = true;
|
|
837
876
|
isPendingListeners = /* @__PURE__ */ new Set();
|
|
877
|
+
planListeners = /* @__PURE__ */ new Set();
|
|
838
878
|
storage;
|
|
839
879
|
useWebSocket = false;
|
|
840
880
|
checks = {};
|
|
841
881
|
featureUsageEventMap = {};
|
|
882
|
+
planChecks = {};
|
|
842
883
|
webSocketUrl = "wss://api.schematichq.com";
|
|
843
884
|
webSocketConnectionTimeout = 1e4;
|
|
844
885
|
webSocketReconnect = true;
|
|
@@ -1171,28 +1212,32 @@ var Schematic = class {
|
|
|
1171
1212
|
this.checks[contextStr] = {};
|
|
1172
1213
|
}
|
|
1173
1214
|
this.checks[contextStr][flagCheck.flag] = flagCheck;
|
|
1174
|
-
this.debug(`WebSocket flag update:`, {
|
|
1175
|
-
flag: flagCheck.flag,
|
|
1176
|
-
value: flagCheck.value,
|
|
1177
|
-
flagCheck
|
|
1178
|
-
});
|
|
1179
1215
|
if (typeof flagCheck.featureUsageEvent === "string") {
|
|
1180
1216
|
this.updateFeatureUsageEventMap(flagCheck);
|
|
1181
1217
|
}
|
|
1182
1218
|
if ((this.flagCheckListeners[flag.flag]?.size ?? 0) > 0 || (this.flagValueListeners[flag.flag]?.size ?? 0) > 0) {
|
|
1183
1219
|
this.submitFlagCheckEvent(flagCheck.flag, flagCheck, context);
|
|
1184
1220
|
}
|
|
1185
|
-
this.debug(
|
|
1186
|
-
flag
|
|
1187
|
-
|
|
1188
|
-
|
|
1221
|
+
this.debug(
|
|
1222
|
+
`WebSocket flag update received. Notifying listeners for ${flag.flag}`,
|
|
1223
|
+
{
|
|
1224
|
+
flag: flag.flag,
|
|
1225
|
+
value: flagCheck.value,
|
|
1226
|
+
flagCheck
|
|
1227
|
+
}
|
|
1228
|
+
);
|
|
1189
1229
|
this.notifyFlagCheckListeners(flag.flag, flagCheck);
|
|
1190
1230
|
this.notifyFlagValueListeners(flag.flag, flagCheck.value);
|
|
1191
|
-
this.debug(`Finished notifying listeners for flag ${flag.flag}`, {
|
|
1192
|
-
flag: flag.flag,
|
|
1193
|
-
value: flagCheck.value
|
|
1194
|
-
});
|
|
1195
1231
|
});
|
|
1232
|
+
if (message.plan !== void 0 && message.plan !== null) {
|
|
1233
|
+
const plan = CheckPlanReturnFromJSON(message.plan);
|
|
1234
|
+
const contextStr = contextString(context);
|
|
1235
|
+
this.planChecks[contextStr] = plan;
|
|
1236
|
+
this.debug(`WebSocket plan update received. Notifying listeners`, {
|
|
1237
|
+
plan
|
|
1238
|
+
});
|
|
1239
|
+
this.notifyPlanListeners(plan);
|
|
1240
|
+
}
|
|
1196
1241
|
this.flushContextDependentEventQueue();
|
|
1197
1242
|
this.setIsPending(false);
|
|
1198
1243
|
};
|
|
@@ -2088,6 +2133,11 @@ var Schematic = class {
|
|
|
2088
2133
|
(listener) => notifyPendingListener(listener, isPending)
|
|
2089
2134
|
);
|
|
2090
2135
|
};
|
|
2136
|
+
getPlan = () => {
|
|
2137
|
+
const contextStr = contextString(this.context);
|
|
2138
|
+
const plan = this.planChecks[contextStr];
|
|
2139
|
+
return plan;
|
|
2140
|
+
};
|
|
2091
2141
|
// flag checks state
|
|
2092
2142
|
getFlagCheck = (flagKey) => {
|
|
2093
2143
|
const contextStr = contextString(this.context);
|
|
@@ -2141,6 +2191,12 @@ var Schematic = class {
|
|
|
2141
2191
|
this.flagCheckListeners[flagKey].delete(listener);
|
|
2142
2192
|
};
|
|
2143
2193
|
};
|
|
2194
|
+
addPlanListener = (listener) => {
|
|
2195
|
+
this.planListeners.add(listener);
|
|
2196
|
+
return () => {
|
|
2197
|
+
this.planListeners.delete(listener);
|
|
2198
|
+
};
|
|
2199
|
+
};
|
|
2144
2200
|
notifyFlagCheckListeners = (flagKey, check) => {
|
|
2145
2201
|
const listeners = this.flagCheckListeners?.[flagKey] ?? [];
|
|
2146
2202
|
if (listeners.size > 0) {
|
|
@@ -2189,6 +2245,21 @@ var Schematic = class {
|
|
|
2189
2245
|
});
|
|
2190
2246
|
});
|
|
2191
2247
|
};
|
|
2248
|
+
notifyPlanListeners = (value) => {
|
|
2249
|
+
const listeners = this.planListeners ?? [];
|
|
2250
|
+
if (listeners.size > 0) {
|
|
2251
|
+
this.debug(`Notifying ${listeners.size} plan listeners`, { value });
|
|
2252
|
+
}
|
|
2253
|
+
listeners.forEach((listener, index) => {
|
|
2254
|
+
this.debug(`Calling listener ${index} for plan`, {
|
|
2255
|
+
value
|
|
2256
|
+
});
|
|
2257
|
+
notifyPlanListener(listener, value);
|
|
2258
|
+
this.debug(`Listener ${index} for plan completed`, {
|
|
2259
|
+
value
|
|
2260
|
+
});
|
|
2261
|
+
});
|
|
2262
|
+
};
|
|
2192
2263
|
};
|
|
2193
2264
|
var notifyPendingListener = (listener, value) => {
|
|
2194
2265
|
if (listener.length > 0) {
|
|
@@ -2211,13 +2282,23 @@ var notifyFlagValueListener = (listener, value) => {
|
|
|
2211
2282
|
listener();
|
|
2212
2283
|
}
|
|
2213
2284
|
};
|
|
2285
|
+
var notifyPlanListener = (listener, value) => {
|
|
2286
|
+
if (listener.length > 0) {
|
|
2287
|
+
listener(value);
|
|
2288
|
+
} else {
|
|
2289
|
+
listener();
|
|
2290
|
+
}
|
|
2291
|
+
};
|
|
2214
2292
|
export {
|
|
2215
2293
|
CheckFlagResponseFromJSON,
|
|
2216
2294
|
CheckFlagReturnFromJSON,
|
|
2217
2295
|
CheckFlagsResponseFromJSON,
|
|
2296
|
+
CheckPlanReturnFromJSON,
|
|
2297
|
+
DatastreamCompanyPlanFromJSON,
|
|
2218
2298
|
EventBodyFlagCheckToJSON,
|
|
2219
2299
|
RuleType,
|
|
2220
2300
|
Schematic,
|
|
2301
|
+
TrialStatus,
|
|
2221
2302
|
UsagePeriod
|
|
2222
2303
|
};
|
|
2223
2304
|
/* @preserve */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schematichq/schematic-js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
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
|
|
28
|
+
"openapi": "rm -rf src/types/api/ && npx openapi-generator-cli generate -c openapi-config.yaml && 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,20 +38,25 @@
|
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@eslint/js": "^10.0.1",
|
|
41
|
-
"@microsoft/api-extractor": "^7.
|
|
42
|
-
"@openapitools/openapi-generator-cli": "^2.
|
|
41
|
+
"@microsoft/api-extractor": "^7.58.1",
|
|
42
|
+
"@openapitools/openapi-generator-cli": "^2.31.0",
|
|
43
43
|
"@vitest/browser": "^4.0.18",
|
|
44
|
-
"esbuild": "^0.
|
|
45
|
-
"eslint": "^10.0
|
|
44
|
+
"esbuild": "^0.28.0",
|
|
45
|
+
"eslint": "^10.1.0",
|
|
46
46
|
"globals": "^17.4.0",
|
|
47
|
-
"happy-dom": "^20.
|
|
47
|
+
"happy-dom": "^20.8.9",
|
|
48
48
|
"husky": "^9.1.7",
|
|
49
|
-
"jsdom": "^
|
|
49
|
+
"jsdom": "^29.0.1",
|
|
50
50
|
"mock-socket": "^9.3.1",
|
|
51
51
|
"prettier": "^3.8.1",
|
|
52
|
-
"typescript": "^
|
|
53
|
-
"typescript-eslint": "^8.
|
|
52
|
+
"typescript": "^6.0.2",
|
|
53
|
+
"typescript-eslint": "^8.58.0",
|
|
54
54
|
"vitest": "^4.0.18"
|
|
55
55
|
},
|
|
56
|
+
"resolutions": {
|
|
57
|
+
"basic-ftp": ">=5.2.0",
|
|
58
|
+
"rollup": ">=4.59.0",
|
|
59
|
+
"undici": ">=7.24.0"
|
|
60
|
+
},
|
|
56
61
|
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
57
62
|
}
|