@schematichq/schematic-js 1.2.20 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/schematic.browser.js +2 -2
- package/dist/schematic.cjs.js +111 -42
- package/dist/schematic.d.ts +63 -0
- package/dist/schematic.esm.js +111 -42
- package/package.json +14 -9
|
@@ -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 x(n){return ke(n,!1)}function ke(n,e){return n==null?n:{companyId:n.company_id==null?void 0:n.company_id,entitlement:n.entitlement==null?void 0:K(n.entitlement),error:n.error==null?void 0:n.error,featureAllocation:n.feature_allocation==null?void 0:n.feature_allocation,featureUsage:n.feature_usage==null?void 0:n.feature_usage,featureUsageEvent:n.feature_usage_event==null?void 0:n.feature_usage_event,featureUsagePeriod:n.feature_usage_period==null?void 0:n.feature_usage_period,featureUsageResetAt:n.feature_usage_reset_at==null?void 0:new Date(n.feature_usage_reset_at),flag:n.flag,flagId:n.flag_id==null?void 0:n.flag_id,reason:n.reason,ruleId:n.rule_id==null?void 0:n.rule_id,ruleType:n.rule_type==null?void 0:n.rule_type,userId:n.user_id==null?void 0:n.user_id,value:n.value}}function N(n){return ve(n,!1)}function ve(n,e=!1){return n==null?n:{company_id:n.companyId,error:n.error,flag_id:n.flagId,flag_key:n.flagKey,reason:n.reason,req_company:n.reqCompany,req_user:n.reqUser,rule_id:n.ruleId,user_id:n.userId,value:n.value}}function L(n){return we(n,!1)}function we(n,e){return n==null?n:{data:x(n.data),params:n.params}}function Y(n){return Re(n,!1)}function Re(n,e){return n==null?n:{flags:n.flags.map(x)}}function B(n){return Fe(n,!1)}function Fe(n,e){return n==null?n:{data:Y(n.data),params:n.params}}var M=n=>{let{companyId:e,error:t,featureAllocation:i,featureUsage:r,featureUsageEvent:l,featureUsagePeriod:o,featureUsageResetAt:c,flag:f,flagId:h,reason:k,ruleId:g,ruleType:v,userId:C,value:T}=x(n);return{featureUsageExceeded:!T&&(v=="company_override_usage_exceeded"||v=="plan_entitlement_usage_exceeded"),companyId:e??void 0,error:t??void 0,featureAllocation:i??void 0,featureUsage:r??void 0,featureUsageEvent:l===null?void 0:l,featureUsagePeriod:o??void 0,featureUsageResetAt:c??void 0,flag:f,flagId:h??void 0,reason:k,ruleId:g??void 0,ruleType:v??void 0,userId:C??void 0,value:T}};function E(n){let e=Object.keys(n).reduce((t,i)=>{let l=Object.keys(n[i]||{}).sort().reduce((o,c)=>(o[c]=n[i][c],o),{});return t[i]=l,t},{});return JSON.stringify(e)}var V="1.2.20";var Z="schematicId";var D=class{additionalHeaders={};apiKey;apiUrl="https://api.schematichq.com";conn=null;context={};debugEnabled=!1;offlineEnabled=!1;eventQueue;contextDependentEventQueue;eventUrl="https://c.schematichq.com";flagCheckListeners={};flagValueListeners={};isPending=!0;isPendingListeners=new Set;storage;useWebSocket=!1;checks={};featureUsageEventMap={};webSocketUrl="wss://api.schematichq.com";webSocketConnectionTimeout=1e4;webSocketReconnect=!0;webSocketMaxReconnectAttempts=7;webSocketMaxConnectionAttempts=3;webSocketInitialRetryDelay=1e3;webSocketMaxRetryDelay=3e4;wsReconnectAttempts=0;wsReconnectTimer=null;wsIntentionalDisconnect=!1;currentWebSocket=null;isConnecting=!1;maxEventQueueSize=100;maxEventRetries=5;eventRetryInitialDelay=1e3;eventRetryMaxDelay=3e4;retryTimer=null;flagValueDefaults={};flagCheckDefaults={};constructor(e,t){if(this.apiKey=e,this.eventQueue=[],this.contextDependentEventQueue=[],this.useWebSocket=t?.useWebSocket??!1,this.debugEnabled=t?.debug??!1,this.offlineEnabled=t?.offline??!1,typeof window<"u"&&typeof window.location<"u"){let i=new URLSearchParams(window.location.search),r=i.get("schematic_debug");r!==null&&(r===""||r==="true"||r==="1")&&(this.debugEnabled=!0);let l=i.get("schematic_offline");l!==null&&(l===""||l==="true"||l==="1")&&(this.offlineEnabled=!0,this.debugEnabled=!0)}if(this.offlineEnabled&&t?.debug!==!1&&(this.debugEnabled=!0),this.offlineEnabled&&this.setIsPending(!1),this.additionalHeaders={"X-Schematic-Client-Version":`schematic-js@${V}`,...t?.additionalHeaders??{}},t?.storage)this.storage=t.storage;else try{typeof localStorage<"u"&&(this.storage=localStorage)}catch{}t?.apiUrl!==void 0&&(this.apiUrl=t.apiUrl),t?.eventUrl!==void 0&&(this.eventUrl=t.eventUrl),t?.webSocketUrl!==void 0&&(this.webSocketUrl=t.webSocketUrl),t?.webSocketConnectionTimeout!==void 0&&(this.webSocketConnectionTimeout=t.webSocketConnectionTimeout),t?.webSocketReconnect!==void 0&&(this.webSocketReconnect=t.webSocketReconnect),t?.webSocketMaxReconnectAttempts!==void 0&&(this.webSocketMaxReconnectAttempts=t.webSocketMaxReconnectAttempts),t?.webSocketInitialRetryDelay!==void 0&&(this.webSocketInitialRetryDelay=t.webSocketInitialRetryDelay),t?.webSocketMaxRetryDelay!==void 0&&(this.webSocketMaxRetryDelay=t.webSocketMaxRetryDelay),t?.maxEventQueueSize!==void 0&&(this.maxEventQueueSize=t.maxEventQueueSize),t?.maxEventRetries!==void 0&&(this.maxEventRetries=t.maxEventRetries),t?.eventRetryInitialDelay!==void 0&&(this.eventRetryInitialDelay=t.eventRetryInitialDelay),t?.eventRetryMaxDelay!==void 0&&(this.eventRetryMaxDelay=t.eventRetryMaxDelay),t?.flagValueDefaults!==void 0&&(this.flagValueDefaults=t.flagValueDefaults),t?.flagCheckDefaults!==void 0&&(this.flagCheckDefaults=t.flagCheckDefaults),typeof window<"u"&&window?.addEventListener&&(window.addEventListener("beforeunload",()=>{this.flushEventQueue(),this.flushContextDependentEventQueue()}),this.useWebSocket&&(window.addEventListener("offline",()=>{this.debug("Browser went offline, closing WebSocket connection"),this.handleNetworkOffline()}),window.addEventListener("online",()=>{this.debug("Browser came online, attempting to reconnect WebSocket"),this.handleNetworkOnline()}))),this.offlineEnabled?this.debug("Initialized with offline mode enabled - no network requests will be made"):this.debugEnabled&&this.debug("Initialized with debug mode enabled")}resolveFallbackValue(e,t){return t!==void 0?t:e in this.flagCheckDefaults?this.flagCheckDefaults[e].value:e in this.flagValueDefaults?this.flagValueDefaults[e]:!1}resolveFallbackCheckFlagReturn(e,t,i="Fallback value used",r){if(t!==void 0)return{flag:e,value:t,reason:i,error:r};if(e in this.flagCheckDefaults){let l=this.flagCheckDefaults[e];return{...l,flag:e,reason:r!==void 0?i:l.reason,error:r}}return e in this.flagValueDefaults?{flag:e,value:this.flagValueDefaults[e],reason:i,error:r}:{flag:e,value:!1,reason:i,error:r}}async checkFlag(e){let{fallback:t,key:i}=e,r=e.context||this.context,l=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(c=>{if(!c.ok)throw new Error("Network response was not ok");return c.json()}).then(c=>{let f=L(c);this.debug(`checkFlag result: ${i}`,f);let h=M(f.data);return typeof h.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(h),this.submitFlagCheckEvent(i,h,r),h.value}).catch(c=>{console.warn("There was a problem with the fetch operation:",c);let f=this.resolveFallbackCheckFlagReturn(i,t,"API request failed",c instanceof Error?c.message:String(c));return this.submitFlagCheckEvent(i,f,r),f.value})}try{let o=this.checks[l];if(this.conn!==null&&typeof o<"u"&&typeof o[i]<"u")return this.debug(`checkFlag cached result: ${i}`,o[i]),o[i].value;if(this.isOffline())return this.resolveFallbackValue(i,t);try{await this.setContext(r)}catch(k){console.warn("WebSocket connection failed, using fallback value:",k);let g=this.resolveFallbackCheckFlagReturn(i,t,"WebSocket connection failed",k instanceof Error?k.message:String(k));return this.submitFlagCheckEvent(i,g,r),g.value}let f=(this.checks[l]??{})[i],h=f?.value??this.resolveFallbackValue(i,t);if(this.debug(`checkFlag WebSocket result: ${i}`,typeof f<"u"?f:{value:h,fallbackUsed:!0}),typeof f<"u")this.submitFlagCheckEvent(i,f,r);else{let k=this.resolveFallbackCheckFlagReturn(i,t,"No flag values available");this.submitFlagCheckEvent(i,k,r)}return h}catch(o){console.error("Unexpected error in checkFlag:",o);let c=this.resolveFallbackCheckFlagReturn(i,t,"Unexpected error in flag check",o instanceof Error?o.message:String(o));return this.submitFlagCheckEvent(i,c,r),c.value}}debug(e,...t){this.debugEnabled&&console.log(`[Schematic] ${e}`,...t)}createPersistentMessageHandler(e){return t=>{let i=JSON.parse(t.data);this.debug("WebSocket persistent message received:",i),E(e)in this.checks||(this.checks[E(e)]={}),(i.flags??[]).forEach(r=>{let l=M(r),o=E(e);this.checks[o]===void 0&&(this.checks[o]={}),this.checks[o][l.flag]=l,this.debug("WebSocket flag update:",{flag:l.flag,value:l.value,flagCheck:l}),typeof l.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(l),((this.flagCheckListeners[r.flag]?.size??0)>0||(this.flagValueListeners[r.flag]?.size??0)>0)&&this.submitFlagCheckEvent(l.flag,l,e),this.debug(`About to notify listeners for flag ${r.flag}`,{flag:r.flag,value:l.value}),this.notifyFlagCheckListeners(r.flag,l),this.notifyFlagValueListeners(r.flag,l.value),this.debug(`Finished notifying listeners for flag ${r.flag}`,{flag:r.flag,value:l.value})}),this.flushContextDependentEventQueue(),this.setIsPending(!1)}}isOffline(){return this.offlineEnabled}submitFlagCheckEvent(e,t,i){let r={flagKey:e,value:t.value,reason:t.reason,flagId:t.flagId,ruleId:t.ruleId,companyId:t.companyId,userId:t.userId,error:t.error,reqCompany:i.company,reqUser:i.user};return this.debug("submitting flag check event:",r),this.handleEvent("flag_check",N(r))}checkFlags=async e=>{if(e=e||this.context,this.debug("checkFlags",{context:e}),this.isOffline())return this.debug("checkFlags offline result: returning empty object"),{};let t=`${this.apiUrl}/flags/check`,i=JSON.stringify(e);return fetch(t,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:i}).then(r=>{if(!r.ok)throw new Error("Network response was not ok");return r.json()}).then(r=>{let l=B(r);return this.debug("checkFlags result:",l),(l?.data?.flags??[]).reduce((o,c)=>(o[c.flag]=c.value,o),{})}).catch(r=>(console.warn("There was a problem with the fetch operation:",r),{}))};identify=e=>(this.debug("identify:",e),this.setContext({company:e.company?.keys,user:e.keys}).catch(t=>{console.warn("Error setting context:",t)}),this.handleEvent("identify",e));setContext=async e=>{if(this.isOffline()||!this.useWebSocket)return this.context=e,this.flushContextDependentEventQueue(),this.setIsPending(!1),Promise.resolve();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:l,quantity:o=1}=e;if(!this.hasContext(t,i)){this.debug(`track: queuing event "${r}" until context is available`);let f={api_key:this.apiKey,body:{company:t,event:r,traits:l??{},user:i,quantity:o},sent_at:new Date().toISOString(),tracker_event_id:S(),tracker_user_id:this.getAnonymousId(),type:"track"};return this.contextDependentEventQueue.push(f),Promise.resolve()}let c={company:t??this.context.company,event:r,traits:l??{},user:i??this.context.user,quantity:o};return this.debug("track:",c),r in this.featureUsageEventMap&&this.optimisticallyUpdateFeatureUsage(r,o),this.handleEvent("track",c)};optimisticallyUpdateFeatureUsage=(e,t=1)=>{let i=this.featureUsageEventMap[e];i!=null&&(this.debug(`Optimistically updating feature usage for event: ${e}`,{quantity:t}),Object.entries(i).forEach(([r,l])=>{if(l===void 0)return;let o={...l};if(typeof o.featureUsage=="number"){if(o.featureUsage+=t,typeof o.featureAllocation=="number"){let f=o.featureUsageExceeded===!0,h=o.featureUsage>=o.featureAllocation;h!==f&&(o.featureUsageExceeded=h,h&&(o.value=!1),this.debug(`Usage limit status changed for flag: ${r}`,{was:f?"exceeded":"within limits",now:h?"exceeded":"within limits",featureUsage:o.featureUsage,featureAllocation:o.featureAllocation,value:o.value}))}this.featureUsageEventMap[e]!==void 0&&(this.featureUsageEventMap[e][r]=o);let c=E(this.context);this.checks[c]!==void 0&&this.checks[c]!==null&&(this.checks[c][r]=o),this.notifyFlagCheckListeners(r,o),this.notifyFlagValueListeners(r,o.value)}}))};hasContext=(e,t)=>{let i=e!=null&&Object.keys(e).length>0||t!=null&&Object.keys(t).length>0,r=this.context.company!==void 0&&this.context.company!==null&&Object.keys(this.context.company).length>0||this.context.user!==void 0&&this.context.user!==null&&Object.keys(this.context.user).length>0;return i||r};flushContextDependentEventQueue=()=>{for(this.debug(`flushing ${this.contextDependentEventQueue.length} context-dependent events`);this.contextDependentEventQueue.length>0;){let e=this.contextDependentEventQueue.shift();if(e)if(e.type==="track"&&typeof e.body=="object"&&e.body!==null){let t=e.body,i={...t,company:t.company??this.context.company,user:t.user??this.context.user},r={...e,body:i,sent_at:new Date().toISOString()};this.sendEvent(r)}else this.sendEvent(e)}};startRetryTimer=()=>{this.retryTimer===null&&(this.retryTimer=setInterval(()=>{this.flushEventQueue().catch(e=>{this.debug("Error in retry timer flush:",e)}),this.eventQueue.length===0&&this.stopRetryTimer()},5e3),this.debug("Started retry timer"))};stopRetryTimer=()=>{this.retryTimer!==null&&(clearInterval(this.retryTimer),this.retryTimer=null,this.debug("Stopped retry timer"))};flushEventQueue=async()=>{if(this.eventQueue.length===0)return;let e=Date.now(),t=[],i=[];for(let r of this.eventQueue)r.next_retry_at===void 0||r.next_retry_at<=e?t.push(r):i.push(r);if(t.length===0){this.debug(`No events ready for retry yet (${i.length} still in backoff)`);return}this.debug(`Flushing event queue: ${t.length} ready, ${i.length} waiting`),this.eventQueue=i;for(let r of t)try{await this.sendEvent(r),this.debug("Queued event sent successfully:",r.type)}catch(l){this.debug("Failed to send queued event:",l)}};getAnonymousId=()=>{if(!this.storage)return S();let e=this.storage.getItem(Z);if(typeof e<"u")return e;let t=S();return this.storage.setItem(Z,t),t};handleEvent=(e,t)=>{let i={api_key:this.apiKey,body:t,sent_at:new Date().toISOString(),tracker_event_id:S(),tracker_user_id:this.getAnonymousId(),type:e};return typeof document<"u"&&document?.hidden?this.storeEvent(i):this.sendEvent(i)};sendEvent=async e=>{let t=`${this.eventUrl}/e`,i=JSON.stringify(e);if(this.debug("sending event:",{url:t,event:e}),this.isOffline())return this.debug("event not sent (offline mode):",{event:e}),Promise.resolve();try{let r=await fetch(t,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8"},body:i});if(!r.ok)throw new Error(`HTTP ${r.status}: ${r.statusText}`);this.debug("event sent:",{status:r.status,statusText:r.statusText})}catch(r){let l=(e.retry_count??0)+1;if(l<=this.maxEventRetries){this.debug(`Event failed to send (attempt ${l}/${this.maxEventRetries}), queueing for retry:`,r);let o=this.eventRetryInitialDelay*Math.pow(2,l-1),c=Math.min(o,this.eventRetryMaxDelay),f=Date.now()+c,h={...e,retry_count:l,next_retry_at:f};this.eventQueue.length<this.maxEventQueueSize?(this.eventQueue.push(h),this.debug(`Event queued for retry in ${c}ms (${this.eventQueue.length}/${this.maxEventQueueSize})`)):(this.debug(`Event queue full (${this.maxEventQueueSize}), dropping oldest event`),this.eventQueue.shift(),this.eventQueue.push(h)),this.startRetryTimer()}else this.debug(`Event failed permanently after ${this.maxEventRetries} attempts, dropping:`,r)}return Promise.resolve()};storeEvent=e=>(this.eventQueue.push(e),Promise.resolve());forceReconnect=async()=>this.reconnect({force:!0});reconnectIfNeeded=async()=>this.reconnect({force:!1});reconnect=async e=>{let{force:t}=e,i=t?"forceReconnect":"reconnectIfNeeded";if(this.isOffline())return this.debug(`${i}: skipped (offline mode)`),Promise.resolve();if(!t&&this.conn!==null)try{if((await this.conn).readyState===WebSocket.OPEN)return this.debug(`${i}: connection is healthy, skipping`),Promise.resolve()}catch{}if(this.debug(`${i}: ${t?"forcing immediate reconnection":"reconnecting"}`),this.wsIntentionalDisconnect=!1,this.wsReconnectTimer!==null&&(this.debug(`${i}: cancelling pending reconnection timer`),clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.wsReconnectAttempts=0,this.conn!==null){this.debug(`${i}: closing existing connection`);try{let r=await this.conn;this.currentWebSocket===r&&(this.currentWebSocket=null),(r.readyState===WebSocket.OPEN||r.readyState===WebSocket.CONNECTING)&&r.close()}catch(r){this.debug(`${i}: error closing existing connection:`,r)}this.conn=null,this.isConnecting=!1}if(this.context.company!==void 0||this.context.user!==void 0){this.debug(`${i}: reconnecting with existing context`);try{this.isConnecting=!0,this.conn=this.wsConnect();let r=await this.conn;this.isConnecting=!1,await this.wsSendMessage(r,this.context,!0),this.debug(`${i}: reconnection successful`)}catch(r){this.isConnecting=!1,this.debug(`${i}: reconnection failed:`,r)}}else this.debug(`${i}: no context set, skipping reconnection`);return Promise.resolve()};cleanup=async()=>{if(this.isOffline())return this.debug("cleanup: skipped (offline mode)"),Promise.resolve();if(this.wsIntentionalDisconnect=!0,this.wsReconnectTimer!==null&&(clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.stopRetryTimer(),this.conn)try{let e=await this.conn;this.currentWebSocket===e&&(this.debug("Cleaning up current websocket tracking"),this.currentWebSocket=null),e.close()}catch(e){console.warn("Error during cleanup:",e)}finally{this.conn=null,this.currentWebSocket=null,this.isConnecting=!1}};calculateReconnectDelay=()=>{let e=this.webSocketInitialRetryDelay*Math.pow(2,this.wsReconnectAttempts),t=Math.min(e,this.webSocketMaxRetryDelay),i=Math.random()*t*.5,r=t+i;return this.debug(`Reconnect delay calculated: ${r.toFixed(0)}ms (attempt ${this.wsReconnectAttempts+1}/${this.webSocketMaxReconnectAttempts})`),r};handleNetworkOffline=async()=>{if(this.conn!==null){try{let e=await this.conn;(e.readyState===WebSocket.OPEN||e.readyState===WebSocket.CONNECTING)&&e.close()}catch(e){this.debug("Error closing connection on offline:",e)}this.conn=null}this.wsReconnectTimer!==null&&(clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null)};handleNetworkOnline=()=>{this.debug("Network online, attempting reconnection and flushing queued events"),this.wsReconnectAttempts=0,this.wsReconnectTimer!==null&&(clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.flushEventQueue().catch(e=>{this.debug("Error flushing event queue on network online:",e)}),this.attemptReconnect()};attemptReconnect=()=>{if(this.wsReconnectAttempts>=this.webSocketMaxReconnectAttempts){this.debug(`Maximum reconnection attempts (${this.webSocketMaxReconnectAttempts}) reached, giving up`);return}if(this.wsReconnectTimer!==null){this.debug("Reconnection attempt already scheduled, ignoring duplicate request");return}let e=this.calculateReconnectDelay();this.debug(`Scheduling reconnection attempt ${this.wsReconnectAttempts+1}/${this.webSocketMaxReconnectAttempts} in ${e.toFixed(0)}ms`),this.wsReconnectTimer=setTimeout(async()=>{this.wsReconnectTimer=null,this.wsReconnectAttempts++,this.debug(`Attempting to reconnect (attempt ${this.wsReconnectAttempts}/${this.webSocketMaxReconnectAttempts})`);try{if(this.conn!==null){this.debug("Cleaning up existing connection before reconnection");try{let t=await this.conn;this.currentWebSocket===t&&(this.debug("Existing websocket is current, will be replaced"),this.currentWebSocket=null),(t.readyState===WebSocket.OPEN||t.readyState===WebSocket.CONNECTING)&&t.close()}catch(t){this.debug("Error cleaning up existing connection:",t)}this.conn=null,this.currentWebSocket=null,this.isConnecting=!1}this.isConnecting=!0;try{this.conn=this.wsConnect();let t=await this.conn;this.isConnecting=!1,this.debug("Reconnection context check:",{hasCompany:this.context.company!==void 0,hasUser:this.context.user!==void 0,context:this.context}),this.context.company!==void 0||this.context.user!==void 0?(this.debug("Reconnected, force re-sending context"),await this.wsSendMessage(t,this.context,!0)):(this.debug("No context to re-send after reconnection - websocket ready for new context"),this.debug("Setting up tracking for reconnected websocket (no context to send)"),this.currentWebSocket=t),this.flushEventQueue().catch(i=>{this.debug("Error flushing event queue after websocket reconnection:",i)}),this.debug("Reconnection successful")}catch(t){throw this.isConnecting=!1,t}}catch(t){this.debug("Reconnection attempt failed:",t)}},e)};wsConnect=async()=>{if(this.isOffline())throw this.debug("wsConnect: skipped (offline mode)"),new Error("WebSocket connection skipped in offline mode");let e=null,t=this.webSocketMaxConnectionAttempts;for(let i=0;i<t;i++)try{let r=await this.wsConnectOnce();return this.wsReconnectAttempts=0,r}catch(r){if(e=r instanceof Error?r:new Error(String(r)),!(e.message==="WebSocket connection timeout"))throw this.debug("WebSocket connection failed with non-timeout error, not retrying:",e.message),e;if(i<t-1){let o=this.webSocketInitialRetryDelay*Math.pow(2,i),c=Math.min(o,this.webSocketMaxRetryDelay),f=c*.2*Math.random(),h=c+f;this.debug(`WebSocket connection timeout (attempt ${i+1}/${t}), retrying in ${h.toFixed(0)}ms`),await new Promise(k=>setTimeout(k,h))}else this.debug(`WebSocket connection timeout (attempt ${i+1}/${t}), no more retries`)}throw e??new Error("WebSocket connection failed")};wsConnectOnce=()=>new Promise((e,t)=>{let i=`${this.webSocketUrl}/flags/bootstrap?apiKey=${this.apiKey}`;this.debug("connecting to WebSocket:",i);let r=new WebSocket(i),l=Math.random().toString(36).substring(7);this.debug(`Creating WebSocket connection ${l} to ${i}`);let o=null,c=!1;o=setTimeout(()=>{c||(c=!0,this.debug(`WebSocket connection timeout after ${this.webSocketConnectionTimeout}ms`),r.close(),t(new Error("WebSocket connection timeout")))},this.webSocketConnectionTimeout),r.onopen=()=>{c||(c=!0,o!==null&&clearTimeout(o),this.wsIntentionalDisconnect=!1,this.debug(`WebSocket connection ${l} opened successfully`),e(r))},r.onerror=f=>{if(c)return;c=!0,o!==null&&clearTimeout(o),this.debug(`WebSocket connection ${l} error:`,f);let h=new Error("WebSocket connection failed during handshake");t(h)},r.onclose=()=>{o!==null&&clearTimeout(o),this.debug(`WebSocket connection ${l} closed`),this.conn=null,this.currentWebSocket===r&&(this.currentWebSocket=null,this.isConnecting=!1),!c&&!this.wsIntentionalDisconnect&&this.webSocketReconnect&&this.attemptReconnect()}});wsSendMessage=(e,t,i=!1)=>this.isOffline()?(this.debug("wsSendMessage: skipped (offline mode)"),this.setIsPending(!1),Promise.resolve()):new Promise((r,l)=>{if(!i&&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 c=!1,f=this.createPersistentMessageHandler(t),h=v=>{f(v),c||(c=!0,r())};e.addEventListener("message",h),e.addEventListener("close",v=>{c||(c=!0,v.code===4001?l(new Error(`Authentication failed: ${v.reason!==""?v.reason:"Invalid API key"}`)):l(new Error("WebSocket connection closed unexpectedly")))}),this.currentWebSocket=e;let k=this.additionalHeaders["X-Schematic-Client-Version"]??`schematic-js@${V}`,g={apiKey:this.apiKey,clientVersion:k,data:t};this.debug("WebSocket sending message:",g),e.send(JSON.stringify(g))};e.readyState===WebSocket.OPEN?(this.debug("WebSocket already open, sending message"),o()):e.readyState===WebSocket.CONNECTING?(this.debug("WebSocket connecting, waiting for open to send message"),e.addEventListener("open",o)):(this.debug("WebSocket is closed, cannot send message"),l("WebSocket is not open or connecting"))});getIsPending=()=>this.isPending;addIsPendingListener=e=>(this.isPendingListeners.add(e),()=>{this.isPendingListeners.delete(e)});setIsPending=e=>{this.isPending!==e&&(this.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 this.resolveFallbackCheckFlagReturn(e,void 0,"Default value used")};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=>xe(r,t))};updateFeatureUsageEventMap=e=>{if(typeof e.featureUsageEvent!="string")return;let t=e.featureUsageEvent;(this.featureUsageEventMap[t]===void 0||this.featureUsageEventMap[t]===null)&&(this.featureUsageEventMap[t]={}),this.featureUsageEventMap[t]!==void 0&&(this.featureUsageEventMap[t][e.flag]=e),this.debug(`Updated featureUsageEventMap for event: ${t}, flag: ${e.flag}`,e)};notifyFlagValueListeners=(e,t)=>{let i=this.flagValueListeners?.[e]??[];i.size>0&&this.debug(`Notifying ${i.size} flag value listeners for ${e}`,{value:t}),i.forEach((r,l)=>{this.debug(`Calling listener ${l} for flag ${e}`,{flagKey:e,value:t}),Ce(r,t),this.debug(`Listener ${l} for flag ${e} completed`,{flagKey:e,value:t})})}},Se=(n,e)=>{n.length>0?n(e):n()},xe=(n,e)=>{n.length>0?n(e):n()},Ce=(n,e)=>{n.length>0?n(e):n()};window.Schematic=D;})();
|
|
1
|
+
"use strict";(()=>{var we=Object.create;var ne=Object.defineProperty;var Ie=Object.getOwnPropertyDescriptor;var Ve=Object.getOwnPropertyNames;var Ue=Object.getPrototypeOf,Ge=Object.prototype.hasOwnProperty;var ve=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports);var Le=(n,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Ve(e))!Ge.call(n,r)&&r!==t&&ne(n,r,{get:()=>e[r],enumerable:!(i=Ie(e,r))||i.enumerable});return n};var Me=(n,e,t)=>(t=n!=null?we(Ue(n)):{},Le(e||!n||!n.__esModule?ne(t,"default",{value:n,enumerable:!0}):t,n));var ae=ve(re=>{(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 s(a){return a&&DataView.prototype.isPrototypeOf(a)}if(r.arrayBuffer)var l=["[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&&l.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 D(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)}),D(a)},y.prototype.values=function(){var a=[];return this.forEach(function(o){a.push(o)}),D(a)},y.prototype.entries=function(){var a=[];return this.forEach(function(o,d){a.push([d,o])}),D(a)},r.iterable&&(y.prototype[Symbol.iterator]=y.prototype.entries);function S(a){if(!a._noBody){if(a.bodyUsed)return Promise.reject(new TypeError("Already read"));a.bodyUsed=!0}}function x(a){return new Promise(function(o,d){a.onload=function(){o(a.result)},a.onerror=function(){d(a.error)}})}function N(a){var o=new FileReader,d=x(o);return o.readAsArrayBuffer(a),d}function Y(a){var o=new FileReader,d=x(o),m=/charset=([A-Za-z0-9_-]+)/.exec(a.type),g=m?m[1]:"utf-8";return o.readAsText(a,g),d}function Ne(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 j(a){if(a.slice)return a.slice(0);var o=new Uint8Array(a.byteLength);return o.set(new Uint8Array(a)),o.buffer}function ee(){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&&s(a)?(this._bodyArrayBuffer=j(a.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer])):r.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(a)||p(a))?this._bodyArrayBuffer=j(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=S(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=S(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(N);throw new Error("could not read as ArrayBuffer")}},this.text=function(){var a=S(this);if(a)return a;if(this._bodyBlob)return Y(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(Ne(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(Je)}),this.json=function(){return this.text().then(JSON.parse)},this}var Fe=["CONNECT","DELETE","GET","HEAD","OPTIONS","PATCH","POST","PUT","TRACE"];function Ee(a){var o=a.toUpperCase();return Fe.indexOf(o)>-1?o:a}function P(a,o){if(!(this instanceof P))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 P){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=Ee(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()}}}P.prototype.clone=function(){return new P(this,{body:this._bodyInit})};function Je(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 ke(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 F=g.join(":").trim();try{o.append(c,F)}catch(v){console.warn("Response "+v.message)}}}),o}ee.call(P.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)}ee.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 Ae=[301,302,303,307,308];R.redirect=function(a,o){if(Ae.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 G(a,o){return new Promise(function(d,m){var g=new P(a,o);if(g.signal&&g.signal.aborted)return m(new t.DOMException("Aborted","AbortError"));var c=new XMLHttpRequest;function F(){c.abort()}c.onload=function(){var T={statusText:c.statusText,headers:ke(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 b="response"in c?c.response:c.responseText;setTimeout(function(){d(new R(b,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 te=[];Object.getOwnPropertyNames(o.headers).forEach(function(T){te.push(u(T)),c.setRequestHeader(T,f(o.headers[T]))}),g.headers.forEach(function(T,b){te.indexOf(b)===-1&&c.setRequestHeader(b,T)})}else g.headers.forEach(function(T,b){c.setRequestHeader(b,T)});g.signal&&(g.signal.addEventListener("abort",F),c.onreadystatechange=function(){c.readyState===4&&g.signal.removeEventListener("abort",F)}),c.send(typeof g._bodyInit>"u"?null:g._bodyInit)})}return G.polyfill=!0,i.fetch||(i.fetch=G,i.Headers=y,i.Request=P,i.Response=R),t.Headers=y,t.Request=P,t.Response=R,t.fetch=G,t})({})})(typeof self<"u"?self:re)});var h=[];for(let n=0;n<256;++n)h.push((n+256).toString(16).slice(1));function ie(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 L,qe=new Uint8Array(16);function M(){if(!L){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");L=crypto.getRandomValues.bind(crypto)}return L(qe)}var We=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),q={randomUUID:We};function $e(n,e,t){n=n||{};let i=n.random??n.rng?.()??M();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 ie(i)}function ze(n,e,t){return q.randomUUID&&!e&&!n?q.randomUUID():$e(n,e,t)}var O=ze;var oy=Me(ae());function z(n){return mt(n,!1)}function mt(n,e){return n}function ue(n){return Tt(n,!1)}function Tt(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:z(n.value_type)}}function C(n){return ht(n,!1)}function ht(n,e){return n==null?n:{companyId:n.company_id==null?void 0:n.company_id,entitlement:n.entitlement==null?void 0:ue(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 H(n){return St(n,!1)}function St(n,e){return n==null?n:{data:C(n.data),params:n.params}}function B(n){return _t(n,!1)}function _t(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)}}function Q(n){return Rt(n,!1)}function Rt(n,e){return n==null?n:{flags:n.flags.map(C),plan:n.plan==null?void 0:B(n.plan)}}function K(n){return bt(n,!1)}function bt(n,e){return n==null?n:{data:Q(n.data),params:n.params}}function w(n){return Ot(n,!1)}function Ot(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 X=n=>{let{companyId:e,error:t,featureAllocation:i,featureUsage:r,featureUsageEvent:s,featureUsagePeriod:l,featureUsageResetAt:p,flag:u,flagId:f,reason:D,ruleId:y,ruleType:S,userId:x,value:N}=C(n);return{featureUsageExceeded:!N&&(S=="company_override_usage_exceeded"||S=="plan_entitlement_usage_exceeded"),companyId:e??void 0,error:t??void 0,featureAllocation:i??void 0,featureUsage:r??void 0,featureUsageEvent:s===null?void 0:s,featureUsagePeriod:l??void 0,featureUsageResetAt:p??void 0,flag:u,flagId:f??void 0,reason:D,ruleId:y??void 0,ruleType:S??void 0,userId:x??void 0,value:N}},xe=n=>{let{id:e,name:t,trialEndDate:i}=B(n);return{id:e,name:t,trialEndDate:i??void 0}};function _(n){let e=Object.keys(n).reduce((t,i)=>{let s=Object.keys(n[i]||{}).sort().reduce((l,p)=>(l[p]=n[i][p],l),{});return t[i]=s,t},{});return JSON.stringify(e)}var Z="1.3.0";var Be="schematicId";var U=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 s=i.get("schematic_offline");s!==null&&(s===""||s==="true"||s==="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@${Z}`,...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 s=this.flagCheckDefaults[e];return{...s,flag:e,reason:r!==void 0?i:s.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,s=_(r);if(this.debug(`checkFlag: ${i}`,{context:r,fallback:t}),this.isOffline()){let l=this.resolveFallbackCheckFlagReturn(i,t,"Offline mode - using initialization defaults");return this.debug(`checkFlag offline result: ${i}`,{value:l.value,offlineMode:!0}),l.value}if(!this.useWebSocket){let l=`${this.apiUrl}/flags/${i}/check`;return fetch(l,{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=H(p);this.debug(`checkFlag result: ${i}`,u);let f=X(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 l=this.checks[s];if(this.conn!==null&&typeof l<"u"&&typeof l[i]<"u")return this.debug(`checkFlag cached result: ${i}`,l[i]),l[i].value;if(this.isOffline())return this.resolveFallbackValue(i,t);try{await this.setContext(r)}catch(D){console.warn("WebSocket connection failed, using fallback value:",D);let y=this.resolveFallbackCheckFlagReturn(i,t,"WebSocket connection failed",D instanceof Error?D.message:String(D));return this.submitFlagCheckEvent(i,y,r),y.value}let u=(this.checks[s]??{})[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 D=this.resolveFallbackCheckFlagReturn(i,t,"No flag values available");this.submitFlagCheckEvent(i,D,r)}return f}catch(l){console.error("Unexpected error in checkFlag:",l);let p=this.resolveFallbackCheckFlagReturn(i,t,"Unexpected error in flag check",l instanceof Error?l.message:String(l));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),_(e)in this.checks||(this.checks[_(e)]={}),(i.flags??[]).forEach(r=>{let s=X(r),l=_(e);this.checks[l]===void 0&&(this.checks[l]={}),this.checks[l][s.flag]=s,typeof s.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(s),((this.flagCheckListeners[r.flag]?.size??0)>0||(this.flagValueListeners[r.flag]?.size??0)>0)&&this.submitFlagCheckEvent(s.flag,s,e),this.debug(`WebSocket flag update received. Notifying listeners for ${r.flag}`,{flag:r.flag,value:s.value,flagCheck:s}),this.notifyFlagCheckListeners(r.flag,s),this.notifyFlagValueListeners(r.flag,s.value)}),i.plan!==void 0&&i.plan!==null){let r=xe(i.plan),s=_(e);this.planChecks[s]=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",w(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 s=K(r);return this.debug("checkFlags result:",s),(s?.data?.flags??[]).reduce((l,p)=>(l[p.flag]=p.value,l),{})}).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)===_(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:s,quantity:l=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:s??{},user:i,quantity:l},sent_at:new Date().toISOString(),tracker_event_id:O(),tracker_user_id:this.getAnonymousId(),type:"track"};return this.contextDependentEventQueue.push(u),Promise.resolve()}let p={company:t??this.context.company,event:r,traits:s??{},user:i??this.context.user,quantity:l};return this.debug("track:",p),r in this.featureUsageEventMap&&this.optimisticallyUpdateFeatureUsage(r,l),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,s])=>{if(s===void 0)return;let l={...s};if(typeof l.featureUsage=="number"){if(l.featureUsage+=t,typeof l.featureAllocation=="number"){let u=l.featureUsageExceeded===!0,f=l.featureUsage>=l.featureAllocation;f!==u&&(l.featureUsageExceeded=f,f&&(l.value=!1),this.debug(`Usage limit status changed for flag: ${r}`,{was:u?"exceeded":"within limits",now:f?"exceeded":"within limits",featureUsage:l.featureUsage,featureAllocation:l.featureAllocation,value:l.value}))}this.featureUsageEventMap[e]!==void 0&&(this.featureUsageEventMap[e][r]=l);let p=_(this.context);this.checks[p]!==void 0&&this.checks[p]!==null&&(this.checks[p][r]=l),this.notifyFlagCheckListeners(r,l),this.notifyFlagValueListeners(r,l.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(s){this.debug("Failed to send queued event:",s)}};getAnonymousId=()=>{if(!this.storage)return O();let e=this.storage.getItem(Be);if(typeof e<"u")return e;let t=O();return this.storage.setItem(Be,t),t};handleEvent=(e,t)=>{let i={api_key:this.apiKey,body:t,sent_at:new Date().toISOString(),tracker_event_id:O(),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 s=(e.retry_count??0)+1;if(s<=this.maxEventRetries){this.debug(`Event failed to send (attempt ${s}/${this.maxEventRetries}), queueing for retry:`,r);let l=this.eventRetryInitialDelay*Math.pow(2,s-1),p=Math.min(l,this.eventRetryMaxDelay),u=Date.now()+p,f={...e,retry_count:s,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 l=this.webSocketInitialRetryDelay*Math.pow(2,i),p=Math.min(l,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(D=>setTimeout(D,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),s=Math.random().toString(36).substring(7);this.debug(`Creating WebSocket connection ${s} to ${i}`);let l=null,p=!1;l=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,l!==null&&clearTimeout(l),this.wsIntentionalDisconnect=!1,this.debug(`WebSocket connection ${s} opened successfully`),e(r))},r.onerror=u=>{if(p)return;p=!0,l!==null&&clearTimeout(l),this.debug(`WebSocket connection ${s} error:`,u);let f=new Error("WebSocket connection failed during handshake");t(f)},r.onclose=()=>{l!==null&&clearTimeout(l),this.debug(`WebSocket connection ${s} 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,s)=>{if(!i&&_(t)==_(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 l=()=>{let p=!1,u=this.createPersistentMessageHandler(t),f=S=>{u(S),p||(p=!0,r())};e.addEventListener("message",f),e.addEventListener("close",S=>{p||(p=!0,S.code===4001?s(new Error(`Authentication failed: ${S.reason!==""?S.reason:"Invalid API key"}`)):s(new Error("WebSocket connection closed unexpectedly")))}),this.currentWebSocket=e;let D=this.additionalHeaders["X-Schematic-Client-Version"]??`schematic-js@${Z}`,y={apiKey:this.apiKey,clientVersion:D,data:t};this.debug("WebSocket sending message:",y),e.send(JSON.stringify(y))};e.readyState===WebSocket.OPEN?(this.debug("WebSocket already open, sending message"),l()):e.readyState===WebSocket.CONNECTING?(this.debug("WebSocket connecting, waiting for open to send message"),e.addEventListener("open",l)):(this.debug("WebSocket is closed, cannot send message"),s("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=>Mt(t,e)))};getPlan=()=>{let e=_(this.context);return this.planChecks[e]};getFlagCheck=e=>{let t=_(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=_(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=>qt(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,s)=>{this.debug(`Calling listener ${s} for flag ${e}`,{flagKey:e,value:t}),Wt(r,t),this.debug(`Listener ${s} 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}),$t(i,e),this.debug(`Listener ${r} for plan completed`,{value:e})})}},Mt=(n,e)=>{n.length>0?n(e):n()},qt=(n,e)=>{n.length>0?n(e):n()},Wt=(n,e)=>{n.length>0?n(e):n()},$t=(n,e)=>{n.length>0?n(e):n()};window.Schematic=U;})();
|
|
3
3
|
/* @preserve */
|
package/dist/schematic.cjs.js
CHANGED
|
@@ -572,6 +572,8 @@ __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,
|
|
@@ -698,28 +700,6 @@ function CheckFlagResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
698
700
|
};
|
|
699
701
|
}
|
|
700
702
|
|
|
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
703
|
// src/types/api/models/CheckFlagResponse.ts
|
|
724
704
|
function CheckFlagResponseFromJSON(json) {
|
|
725
705
|
return CheckFlagResponseFromJSONTyped(json, false);
|
|
@@ -734,6 +714,21 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
734
714
|
};
|
|
735
715
|
}
|
|
736
716
|
|
|
717
|
+
// src/types/api/models/DatastreamCompanyPlan.ts
|
|
718
|
+
function DatastreamCompanyPlanFromJSON(json) {
|
|
719
|
+
return DatastreamCompanyPlanFromJSONTyped(json, false);
|
|
720
|
+
}
|
|
721
|
+
function DatastreamCompanyPlanFromJSONTyped(json, ignoreDiscriminator) {
|
|
722
|
+
if (json == null) {
|
|
723
|
+
return json;
|
|
724
|
+
}
|
|
725
|
+
return {
|
|
726
|
+
id: json["id"],
|
|
727
|
+
name: json["name"],
|
|
728
|
+
trialEndDate: json["trial_end_date"] == null ? void 0 : new Date(json["trial_end_date"])
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
|
|
737
732
|
// src/types/api/models/CheckFlagsResponseData.ts
|
|
738
733
|
function CheckFlagsResponseDataFromJSON(json) {
|
|
739
734
|
return CheckFlagsResponseDataFromJSONTyped(json, false);
|
|
@@ -743,7 +738,8 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
743
738
|
return json;
|
|
744
739
|
}
|
|
745
740
|
return {
|
|
746
|
-
flags: json["flags"].map(CheckFlagResponseDataFromJSON)
|
|
741
|
+
flags: json["flags"].map(CheckFlagResponseDataFromJSON),
|
|
742
|
+
plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
|
|
747
743
|
};
|
|
748
744
|
}
|
|
749
745
|
|
|
@@ -761,6 +757,28 @@ function CheckFlagsResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
761
757
|
};
|
|
762
758
|
}
|
|
763
759
|
|
|
760
|
+
// src/types/api/models/EventBodyFlagCheck.ts
|
|
761
|
+
function EventBodyFlagCheckToJSON(json) {
|
|
762
|
+
return EventBodyFlagCheckToJSONTyped(json, false);
|
|
763
|
+
}
|
|
764
|
+
function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
|
|
765
|
+
if (value == null) {
|
|
766
|
+
return value;
|
|
767
|
+
}
|
|
768
|
+
return {
|
|
769
|
+
company_id: value["companyId"],
|
|
770
|
+
error: value["error"],
|
|
771
|
+
flag_id: value["flagId"],
|
|
772
|
+
flag_key: value["flagKey"],
|
|
773
|
+
reason: value["reason"],
|
|
774
|
+
req_company: value["reqCompany"],
|
|
775
|
+
req_user: value["reqUser"],
|
|
776
|
+
rule_id: value["ruleId"],
|
|
777
|
+
user_id: value["userId"],
|
|
778
|
+
value: value["value"]
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
|
|
764
782
|
// src/types/index.ts
|
|
765
783
|
var RuleType = /* @__PURE__ */ ((RuleType2) => {
|
|
766
784
|
RuleType2["GLOBAL_OVERRIDE"] = "global_override";
|
|
@@ -817,6 +835,14 @@ var CheckFlagReturnFromJSON = (json) => {
|
|
|
817
835
|
value
|
|
818
836
|
};
|
|
819
837
|
};
|
|
838
|
+
var CheckPlanReturnFromJSON = (json) => {
|
|
839
|
+
const { id, name, trialEndDate } = DatastreamCompanyPlanFromJSON(json);
|
|
840
|
+
return {
|
|
841
|
+
id,
|
|
842
|
+
name,
|
|
843
|
+
trialEndDate: trialEndDate == null ? void 0 : trialEndDate
|
|
844
|
+
};
|
|
845
|
+
};
|
|
820
846
|
|
|
821
847
|
// src/utils.ts
|
|
822
848
|
function contextString(context) {
|
|
@@ -835,7 +861,7 @@ function contextString(context) {
|
|
|
835
861
|
}
|
|
836
862
|
|
|
837
863
|
// src/version.ts
|
|
838
|
-
var version = "1.
|
|
864
|
+
var version = "1.3.0";
|
|
839
865
|
|
|
840
866
|
// src/index.ts
|
|
841
867
|
var anonymousIdKey = "schematicId";
|
|
@@ -854,10 +880,12 @@ var Schematic = class {
|
|
|
854
880
|
flagValueListeners = {};
|
|
855
881
|
isPending = true;
|
|
856
882
|
isPendingListeners = /* @__PURE__ */ new Set();
|
|
883
|
+
planListeners = /* @__PURE__ */ new Set();
|
|
857
884
|
storage;
|
|
858
885
|
useWebSocket = false;
|
|
859
886
|
checks = {};
|
|
860
887
|
featureUsageEventMap = {};
|
|
888
|
+
planChecks = {};
|
|
861
889
|
webSocketUrl = "wss://api.schematichq.com";
|
|
862
890
|
webSocketConnectionTimeout = 1e4;
|
|
863
891
|
webSocketReconnect = true;
|
|
@@ -883,6 +911,7 @@ var Schematic = class {
|
|
|
883
911
|
retryTimer = null;
|
|
884
912
|
flagValueDefaults = {};
|
|
885
913
|
flagCheckDefaults = {};
|
|
914
|
+
fallbackCheckCache = {};
|
|
886
915
|
constructor(apiKey, options) {
|
|
887
916
|
this.apiKey = apiKey;
|
|
888
917
|
this.eventQueue = [];
|
|
@@ -1189,28 +1218,32 @@ var Schematic = class {
|
|
|
1189
1218
|
this.checks[contextStr] = {};
|
|
1190
1219
|
}
|
|
1191
1220
|
this.checks[contextStr][flagCheck.flag] = flagCheck;
|
|
1192
|
-
this.debug(`WebSocket flag update:`, {
|
|
1193
|
-
flag: flagCheck.flag,
|
|
1194
|
-
value: flagCheck.value,
|
|
1195
|
-
flagCheck
|
|
1196
|
-
});
|
|
1197
1221
|
if (typeof flagCheck.featureUsageEvent === "string") {
|
|
1198
1222
|
this.updateFeatureUsageEventMap(flagCheck);
|
|
1199
1223
|
}
|
|
1200
1224
|
if ((this.flagCheckListeners[flag.flag]?.size ?? 0) > 0 || (this.flagValueListeners[flag.flag]?.size ?? 0) > 0) {
|
|
1201
1225
|
this.submitFlagCheckEvent(flagCheck.flag, flagCheck, context);
|
|
1202
1226
|
}
|
|
1203
|
-
this.debug(
|
|
1204
|
-
flag
|
|
1205
|
-
|
|
1206
|
-
|
|
1227
|
+
this.debug(
|
|
1228
|
+
`WebSocket flag update received. Notifying listeners for ${flag.flag}`,
|
|
1229
|
+
{
|
|
1230
|
+
flag: flag.flag,
|
|
1231
|
+
value: flagCheck.value,
|
|
1232
|
+
flagCheck
|
|
1233
|
+
}
|
|
1234
|
+
);
|
|
1207
1235
|
this.notifyFlagCheckListeners(flag.flag, flagCheck);
|
|
1208
1236
|
this.notifyFlagValueListeners(flag.flag, flagCheck.value);
|
|
1209
|
-
this.debug(`Finished notifying listeners for flag ${flag.flag}`, {
|
|
1210
|
-
flag: flag.flag,
|
|
1211
|
-
value: flagCheck.value
|
|
1212
|
-
});
|
|
1213
1237
|
});
|
|
1238
|
+
if (message.plan !== void 0 && message.plan !== null) {
|
|
1239
|
+
const plan = CheckPlanReturnFromJSON(message.plan);
|
|
1240
|
+
const contextStr = contextString(context);
|
|
1241
|
+
this.planChecks[contextStr] = plan;
|
|
1242
|
+
this.debug(`WebSocket plan update received. Notifying listeners`, {
|
|
1243
|
+
plan
|
|
1244
|
+
});
|
|
1245
|
+
this.notifyPlanListeners(plan);
|
|
1246
|
+
}
|
|
1214
1247
|
this.flushContextDependentEventQueue();
|
|
1215
1248
|
this.setIsPending(false);
|
|
1216
1249
|
};
|
|
@@ -2106,6 +2139,11 @@ var Schematic = class {
|
|
|
2106
2139
|
(listener) => notifyPendingListener(listener, isPending)
|
|
2107
2140
|
);
|
|
2108
2141
|
};
|
|
2142
|
+
getPlan = () => {
|
|
2143
|
+
const contextStr = contextString(this.context);
|
|
2144
|
+
const plan = this.planChecks[contextStr];
|
|
2145
|
+
return plan;
|
|
2146
|
+
};
|
|
2109
2147
|
// flag checks state
|
|
2110
2148
|
getFlagCheck = (flagKey) => {
|
|
2111
2149
|
const contextStr = contextString(this.context);
|
|
@@ -2115,11 +2153,14 @@ var Schematic = class {
|
|
|
2115
2153
|
return check;
|
|
2116
2154
|
}
|
|
2117
2155
|
if (flagKey in this.flagCheckDefaults || flagKey in this.flagValueDefaults) {
|
|
2118
|
-
|
|
2119
|
-
flagKey
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2156
|
+
if (!(flagKey in this.fallbackCheckCache)) {
|
|
2157
|
+
this.fallbackCheckCache[flagKey] = this.resolveFallbackCheckFlagReturn(
|
|
2158
|
+
flagKey,
|
|
2159
|
+
void 0,
|
|
2160
|
+
"Default value used"
|
|
2161
|
+
);
|
|
2162
|
+
}
|
|
2163
|
+
return this.fallbackCheckCache[flagKey];
|
|
2123
2164
|
}
|
|
2124
2165
|
return void 0;
|
|
2125
2166
|
};
|
|
@@ -2156,6 +2197,12 @@ var Schematic = class {
|
|
|
2156
2197
|
this.flagCheckListeners[flagKey].delete(listener);
|
|
2157
2198
|
};
|
|
2158
2199
|
};
|
|
2200
|
+
addPlanListener = (listener) => {
|
|
2201
|
+
this.planListeners.add(listener);
|
|
2202
|
+
return () => {
|
|
2203
|
+
this.planListeners.delete(listener);
|
|
2204
|
+
};
|
|
2205
|
+
};
|
|
2159
2206
|
notifyFlagCheckListeners = (flagKey, check) => {
|
|
2160
2207
|
const listeners = this.flagCheckListeners?.[flagKey] ?? [];
|
|
2161
2208
|
if (listeners.size > 0) {
|
|
@@ -2204,6 +2251,21 @@ var Schematic = class {
|
|
|
2204
2251
|
});
|
|
2205
2252
|
});
|
|
2206
2253
|
};
|
|
2254
|
+
notifyPlanListeners = (value) => {
|
|
2255
|
+
const listeners = this.planListeners ?? [];
|
|
2256
|
+
if (listeners.size > 0) {
|
|
2257
|
+
this.debug(`Notifying ${listeners.size} plan listeners`, { value });
|
|
2258
|
+
}
|
|
2259
|
+
listeners.forEach((listener, index) => {
|
|
2260
|
+
this.debug(`Calling listener ${index} for plan`, {
|
|
2261
|
+
value
|
|
2262
|
+
});
|
|
2263
|
+
notifyPlanListener(listener, value);
|
|
2264
|
+
this.debug(`Listener ${index} for plan completed`, {
|
|
2265
|
+
value
|
|
2266
|
+
});
|
|
2267
|
+
});
|
|
2268
|
+
};
|
|
2207
2269
|
};
|
|
2208
2270
|
var notifyPendingListener = (listener, value) => {
|
|
2209
2271
|
if (listener.length > 0) {
|
|
@@ -2226,4 +2288,11 @@ var notifyFlagValueListener = (listener, value) => {
|
|
|
2226
2288
|
listener();
|
|
2227
2289
|
}
|
|
2228
2290
|
};
|
|
2291
|
+
var notifyPlanListener = (listener, value) => {
|
|
2292
|
+
if (listener.length > 0) {
|
|
2293
|
+
listener(value);
|
|
2294
|
+
} else {
|
|
2295
|
+
listener();
|
|
2296
|
+
}
|
|
2297
|
+
};
|
|
2229
2298
|
/* @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,55 @@ 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
|
+
};
|
|
218
|
+
|
|
219
|
+
export declare const CheckPlanReturnFromJSON: (json: any) => CheckPlanReturn;
|
|
220
|
+
|
|
221
|
+
export declare type CheckPlanReturnListenerFn = (value: CheckPlanReturn) => void;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Schematic API
|
|
225
|
+
* Schematic API
|
|
226
|
+
*
|
|
227
|
+
* The version of the OpenAPI document: 0.1
|
|
228
|
+
*
|
|
229
|
+
*
|
|
230
|
+
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
|
231
|
+
* https://openapi-generator.tech
|
|
232
|
+
* Do not edit the class manually.
|
|
233
|
+
*/
|
|
234
|
+
/**
|
|
235
|
+
*
|
|
236
|
+
* @export
|
|
237
|
+
* @interface DatastreamCompanyPlan
|
|
238
|
+
*/
|
|
239
|
+
declare interface DatastreamCompanyPlan {
|
|
240
|
+
/**
|
|
241
|
+
*
|
|
242
|
+
* @type {string}
|
|
243
|
+
* @memberof DatastreamCompanyPlan
|
|
244
|
+
*/
|
|
245
|
+
id: string;
|
|
246
|
+
/**
|
|
247
|
+
*
|
|
248
|
+
* @type {string}
|
|
249
|
+
* @memberof DatastreamCompanyPlan
|
|
250
|
+
*/
|
|
251
|
+
name: string;
|
|
252
|
+
/**
|
|
253
|
+
*
|
|
254
|
+
* @type {Date}
|
|
255
|
+
* @memberof DatastreamCompanyPlan
|
|
256
|
+
*/
|
|
257
|
+
trialEndDate?: Date | null;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export declare function DatastreamCompanyPlanFromJSON(json: any): DatastreamCompanyPlan;
|
|
261
|
+
|
|
207
262
|
export declare type EmptyListenerFn = () => void;
|
|
208
263
|
|
|
209
264
|
/**
|
|
@@ -462,6 +517,8 @@ export declare type Keys = Record<string, string>;
|
|
|
462
517
|
|
|
463
518
|
export declare type PendingListenerFn = BooleanListenerFn | EmptyListenerFn;
|
|
464
519
|
|
|
520
|
+
export declare type PlanListenerFn = CheckPlanReturnListenerFn | EmptyListenerFn;
|
|
521
|
+
|
|
465
522
|
export declare enum RuleType {
|
|
466
523
|
/** A global rule that, if present, will override all other rules for a flag */
|
|
467
524
|
GLOBAL_OVERRIDE = "global_override",
|
|
@@ -494,10 +551,12 @@ export declare class Schematic {
|
|
|
494
551
|
private flagValueListeners;
|
|
495
552
|
private isPending;
|
|
496
553
|
private isPendingListeners;
|
|
554
|
+
private planListeners;
|
|
497
555
|
private storage;
|
|
498
556
|
private useWebSocket;
|
|
499
557
|
private checks;
|
|
500
558
|
private featureUsageEventMap;
|
|
559
|
+
private planChecks;
|
|
501
560
|
private webSocketUrl;
|
|
502
561
|
private webSocketConnectionTimeout;
|
|
503
562
|
private webSocketReconnect;
|
|
@@ -517,6 +576,7 @@ export declare class Schematic {
|
|
|
517
576
|
private retryTimer;
|
|
518
577
|
private flagValueDefaults;
|
|
519
578
|
private flagCheckDefaults;
|
|
579
|
+
private fallbackCheckCache;
|
|
520
580
|
constructor(apiKey: string, options?: SchematicOptions);
|
|
521
581
|
/**
|
|
522
582
|
* Resolve fallback value according to priority order:
|
|
@@ -701,16 +761,19 @@ export declare class Schematic {
|
|
|
701
761
|
getIsPending: () => boolean;
|
|
702
762
|
addIsPendingListener: (listener: PendingListenerFn) => () => void;
|
|
703
763
|
private setIsPending;
|
|
764
|
+
getPlan: () => CheckPlanReturn | undefined;
|
|
704
765
|
getFlagCheck: (flagKey: string) => CheckFlagReturn | undefined;
|
|
705
766
|
getFlagValue: (flagKey: string) => boolean | undefined;
|
|
706
767
|
/** Register an event listener that will be notified with the boolean value for a given flag when this value changes */
|
|
707
768
|
addFlagValueListener: (flagKey: string, listener: FlagValueListenerFn) => () => void;
|
|
708
769
|
/** Register an event listener that will be notified with the full flag check response for a given flag whenever this value changes */
|
|
709
770
|
addFlagCheckListener: (flagKey: string, listener: FlagCheckListenerFn) => () => void;
|
|
771
|
+
addPlanListener: (listener: PlanListenerFn) => () => void;
|
|
710
772
|
private notifyFlagCheckListeners;
|
|
711
773
|
/** Add or update a CheckFlagReturn in the featureUsageEventMap */
|
|
712
774
|
private updateFeatureUsageEventMap;
|
|
713
775
|
private notifyFlagValueListeners;
|
|
776
|
+
private notifyPlanListeners;
|
|
714
777
|
}
|
|
715
778
|
|
|
716
779
|
/** Context for checking flags and sending events */
|
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,21 @@ function CheckFlagResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
715
693
|
};
|
|
716
694
|
}
|
|
717
695
|
|
|
696
|
+
// src/types/api/models/DatastreamCompanyPlan.ts
|
|
697
|
+
function DatastreamCompanyPlanFromJSON(json) {
|
|
698
|
+
return DatastreamCompanyPlanFromJSONTyped(json, false);
|
|
699
|
+
}
|
|
700
|
+
function DatastreamCompanyPlanFromJSONTyped(json, ignoreDiscriminator) {
|
|
701
|
+
if (json == null) {
|
|
702
|
+
return json;
|
|
703
|
+
}
|
|
704
|
+
return {
|
|
705
|
+
id: json["id"],
|
|
706
|
+
name: json["name"],
|
|
707
|
+
trialEndDate: json["trial_end_date"] == null ? void 0 : new Date(json["trial_end_date"])
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
|
|
718
711
|
// src/types/api/models/CheckFlagsResponseData.ts
|
|
719
712
|
function CheckFlagsResponseDataFromJSON(json) {
|
|
720
713
|
return CheckFlagsResponseDataFromJSONTyped(json, false);
|
|
@@ -724,7 +717,8 @@ function CheckFlagsResponseDataFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
724
717
|
return json;
|
|
725
718
|
}
|
|
726
719
|
return {
|
|
727
|
-
flags: json["flags"].map(CheckFlagResponseDataFromJSON)
|
|
720
|
+
flags: json["flags"].map(CheckFlagResponseDataFromJSON),
|
|
721
|
+
plan: json["plan"] == null ? void 0 : DatastreamCompanyPlanFromJSON(json["plan"])
|
|
728
722
|
};
|
|
729
723
|
}
|
|
730
724
|
|
|
@@ -742,6 +736,28 @@ function CheckFlagsResponseFromJSONTyped(json, ignoreDiscriminator) {
|
|
|
742
736
|
};
|
|
743
737
|
}
|
|
744
738
|
|
|
739
|
+
// src/types/api/models/EventBodyFlagCheck.ts
|
|
740
|
+
function EventBodyFlagCheckToJSON(json) {
|
|
741
|
+
return EventBodyFlagCheckToJSONTyped(json, false);
|
|
742
|
+
}
|
|
743
|
+
function EventBodyFlagCheckToJSONTyped(value, ignoreDiscriminator = false) {
|
|
744
|
+
if (value == null) {
|
|
745
|
+
return value;
|
|
746
|
+
}
|
|
747
|
+
return {
|
|
748
|
+
company_id: value["companyId"],
|
|
749
|
+
error: value["error"],
|
|
750
|
+
flag_id: value["flagId"],
|
|
751
|
+
flag_key: value["flagKey"],
|
|
752
|
+
reason: value["reason"],
|
|
753
|
+
req_company: value["reqCompany"],
|
|
754
|
+
req_user: value["reqUser"],
|
|
755
|
+
rule_id: value["ruleId"],
|
|
756
|
+
user_id: value["userId"],
|
|
757
|
+
value: value["value"]
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
|
|
745
761
|
// src/types/index.ts
|
|
746
762
|
var RuleType = /* @__PURE__ */ ((RuleType2) => {
|
|
747
763
|
RuleType2["GLOBAL_OVERRIDE"] = "global_override";
|
|
@@ -798,6 +814,14 @@ var CheckFlagReturnFromJSON = (json) => {
|
|
|
798
814
|
value
|
|
799
815
|
};
|
|
800
816
|
};
|
|
817
|
+
var CheckPlanReturnFromJSON = (json) => {
|
|
818
|
+
const { id, name, trialEndDate } = DatastreamCompanyPlanFromJSON(json);
|
|
819
|
+
return {
|
|
820
|
+
id,
|
|
821
|
+
name,
|
|
822
|
+
trialEndDate: trialEndDate == null ? void 0 : trialEndDate
|
|
823
|
+
};
|
|
824
|
+
};
|
|
801
825
|
|
|
802
826
|
// src/utils.ts
|
|
803
827
|
function contextString(context) {
|
|
@@ -816,7 +840,7 @@ function contextString(context) {
|
|
|
816
840
|
}
|
|
817
841
|
|
|
818
842
|
// src/version.ts
|
|
819
|
-
var version = "1.
|
|
843
|
+
var version = "1.3.0";
|
|
820
844
|
|
|
821
845
|
// src/index.ts
|
|
822
846
|
var anonymousIdKey = "schematicId";
|
|
@@ -835,10 +859,12 @@ var Schematic = class {
|
|
|
835
859
|
flagValueListeners = {};
|
|
836
860
|
isPending = true;
|
|
837
861
|
isPendingListeners = /* @__PURE__ */ new Set();
|
|
862
|
+
planListeners = /* @__PURE__ */ new Set();
|
|
838
863
|
storage;
|
|
839
864
|
useWebSocket = false;
|
|
840
865
|
checks = {};
|
|
841
866
|
featureUsageEventMap = {};
|
|
867
|
+
planChecks = {};
|
|
842
868
|
webSocketUrl = "wss://api.schematichq.com";
|
|
843
869
|
webSocketConnectionTimeout = 1e4;
|
|
844
870
|
webSocketReconnect = true;
|
|
@@ -864,6 +890,7 @@ var Schematic = class {
|
|
|
864
890
|
retryTimer = null;
|
|
865
891
|
flagValueDefaults = {};
|
|
866
892
|
flagCheckDefaults = {};
|
|
893
|
+
fallbackCheckCache = {};
|
|
867
894
|
constructor(apiKey, options) {
|
|
868
895
|
this.apiKey = apiKey;
|
|
869
896
|
this.eventQueue = [];
|
|
@@ -1170,28 +1197,32 @@ var Schematic = class {
|
|
|
1170
1197
|
this.checks[contextStr] = {};
|
|
1171
1198
|
}
|
|
1172
1199
|
this.checks[contextStr][flagCheck.flag] = flagCheck;
|
|
1173
|
-
this.debug(`WebSocket flag update:`, {
|
|
1174
|
-
flag: flagCheck.flag,
|
|
1175
|
-
value: flagCheck.value,
|
|
1176
|
-
flagCheck
|
|
1177
|
-
});
|
|
1178
1200
|
if (typeof flagCheck.featureUsageEvent === "string") {
|
|
1179
1201
|
this.updateFeatureUsageEventMap(flagCheck);
|
|
1180
1202
|
}
|
|
1181
1203
|
if ((this.flagCheckListeners[flag.flag]?.size ?? 0) > 0 || (this.flagValueListeners[flag.flag]?.size ?? 0) > 0) {
|
|
1182
1204
|
this.submitFlagCheckEvent(flagCheck.flag, flagCheck, context);
|
|
1183
1205
|
}
|
|
1184
|
-
this.debug(
|
|
1185
|
-
flag
|
|
1186
|
-
|
|
1187
|
-
|
|
1206
|
+
this.debug(
|
|
1207
|
+
`WebSocket flag update received. Notifying listeners for ${flag.flag}`,
|
|
1208
|
+
{
|
|
1209
|
+
flag: flag.flag,
|
|
1210
|
+
value: flagCheck.value,
|
|
1211
|
+
flagCheck
|
|
1212
|
+
}
|
|
1213
|
+
);
|
|
1188
1214
|
this.notifyFlagCheckListeners(flag.flag, flagCheck);
|
|
1189
1215
|
this.notifyFlagValueListeners(flag.flag, flagCheck.value);
|
|
1190
|
-
this.debug(`Finished notifying listeners for flag ${flag.flag}`, {
|
|
1191
|
-
flag: flag.flag,
|
|
1192
|
-
value: flagCheck.value
|
|
1193
|
-
});
|
|
1194
1216
|
});
|
|
1217
|
+
if (message.plan !== void 0 && message.plan !== null) {
|
|
1218
|
+
const plan = CheckPlanReturnFromJSON(message.plan);
|
|
1219
|
+
const contextStr = contextString(context);
|
|
1220
|
+
this.planChecks[contextStr] = plan;
|
|
1221
|
+
this.debug(`WebSocket plan update received. Notifying listeners`, {
|
|
1222
|
+
plan
|
|
1223
|
+
});
|
|
1224
|
+
this.notifyPlanListeners(plan);
|
|
1225
|
+
}
|
|
1195
1226
|
this.flushContextDependentEventQueue();
|
|
1196
1227
|
this.setIsPending(false);
|
|
1197
1228
|
};
|
|
@@ -2087,6 +2118,11 @@ var Schematic = class {
|
|
|
2087
2118
|
(listener) => notifyPendingListener(listener, isPending)
|
|
2088
2119
|
);
|
|
2089
2120
|
};
|
|
2121
|
+
getPlan = () => {
|
|
2122
|
+
const contextStr = contextString(this.context);
|
|
2123
|
+
const plan = this.planChecks[contextStr];
|
|
2124
|
+
return plan;
|
|
2125
|
+
};
|
|
2090
2126
|
// flag checks state
|
|
2091
2127
|
getFlagCheck = (flagKey) => {
|
|
2092
2128
|
const contextStr = contextString(this.context);
|
|
@@ -2096,11 +2132,14 @@ var Schematic = class {
|
|
|
2096
2132
|
return check;
|
|
2097
2133
|
}
|
|
2098
2134
|
if (flagKey in this.flagCheckDefaults || flagKey in this.flagValueDefaults) {
|
|
2099
|
-
|
|
2100
|
-
flagKey
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2135
|
+
if (!(flagKey in this.fallbackCheckCache)) {
|
|
2136
|
+
this.fallbackCheckCache[flagKey] = this.resolveFallbackCheckFlagReturn(
|
|
2137
|
+
flagKey,
|
|
2138
|
+
void 0,
|
|
2139
|
+
"Default value used"
|
|
2140
|
+
);
|
|
2141
|
+
}
|
|
2142
|
+
return this.fallbackCheckCache[flagKey];
|
|
2104
2143
|
}
|
|
2105
2144
|
return void 0;
|
|
2106
2145
|
};
|
|
@@ -2137,6 +2176,12 @@ var Schematic = class {
|
|
|
2137
2176
|
this.flagCheckListeners[flagKey].delete(listener);
|
|
2138
2177
|
};
|
|
2139
2178
|
};
|
|
2179
|
+
addPlanListener = (listener) => {
|
|
2180
|
+
this.planListeners.add(listener);
|
|
2181
|
+
return () => {
|
|
2182
|
+
this.planListeners.delete(listener);
|
|
2183
|
+
};
|
|
2184
|
+
};
|
|
2140
2185
|
notifyFlagCheckListeners = (flagKey, check) => {
|
|
2141
2186
|
const listeners = this.flagCheckListeners?.[flagKey] ?? [];
|
|
2142
2187
|
if (listeners.size > 0) {
|
|
@@ -2185,6 +2230,21 @@ var Schematic = class {
|
|
|
2185
2230
|
});
|
|
2186
2231
|
});
|
|
2187
2232
|
};
|
|
2233
|
+
notifyPlanListeners = (value) => {
|
|
2234
|
+
const listeners = this.planListeners ?? [];
|
|
2235
|
+
if (listeners.size > 0) {
|
|
2236
|
+
this.debug(`Notifying ${listeners.size} plan listeners`, { value });
|
|
2237
|
+
}
|
|
2238
|
+
listeners.forEach((listener, index) => {
|
|
2239
|
+
this.debug(`Calling listener ${index} for plan`, {
|
|
2240
|
+
value
|
|
2241
|
+
});
|
|
2242
|
+
notifyPlanListener(listener, value);
|
|
2243
|
+
this.debug(`Listener ${index} for plan completed`, {
|
|
2244
|
+
value
|
|
2245
|
+
});
|
|
2246
|
+
});
|
|
2247
|
+
};
|
|
2188
2248
|
};
|
|
2189
2249
|
var notifyPendingListener = (listener, value) => {
|
|
2190
2250
|
if (listener.length > 0) {
|
|
@@ -2207,10 +2267,19 @@ var notifyFlagValueListener = (listener, value) => {
|
|
|
2207
2267
|
listener();
|
|
2208
2268
|
}
|
|
2209
2269
|
};
|
|
2270
|
+
var notifyPlanListener = (listener, value) => {
|
|
2271
|
+
if (listener.length > 0) {
|
|
2272
|
+
listener(value);
|
|
2273
|
+
} else {
|
|
2274
|
+
listener();
|
|
2275
|
+
}
|
|
2276
|
+
};
|
|
2210
2277
|
export {
|
|
2211
2278
|
CheckFlagResponseFromJSON,
|
|
2212
2279
|
CheckFlagReturnFromJSON,
|
|
2213
2280
|
CheckFlagsResponseFromJSON,
|
|
2281
|
+
CheckPlanReturnFromJSON,
|
|
2282
|
+
DatastreamCompanyPlanFromJSON,
|
|
2214
2283
|
EventBodyFlagCheckToJSON,
|
|
2215
2284
|
RuleType,
|
|
2216
2285
|
Schematic,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schematichq/schematic-js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
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.57.
|
|
42
|
-
"@openapitools/openapi-generator-cli": "^2.30.
|
|
41
|
+
"@microsoft/api-extractor": "^7.57.7",
|
|
42
|
+
"@openapitools/openapi-generator-cli": "^2.30.2",
|
|
43
43
|
"@vitest/browser": "^4.0.18",
|
|
44
|
-
"esbuild": "^0.27.
|
|
45
|
-
"eslint": "^10.0.
|
|
44
|
+
"esbuild": "^0.27.4",
|
|
45
|
+
"eslint": "^10.0.3",
|
|
46
46
|
"globals": "^17.4.0",
|
|
47
|
-
"happy-dom": "^20.
|
|
47
|
+
"happy-dom": "^20.8.4",
|
|
48
48
|
"husky": "^9.1.7",
|
|
49
|
-
"jsdom": "^
|
|
49
|
+
"jsdom": "^29.0.0",
|
|
50
50
|
"mock-socket": "^9.3.1",
|
|
51
51
|
"prettier": "^3.8.1",
|
|
52
52
|
"typescript": "^5.9.3",
|
|
53
|
-
"typescript-eslint": "^8.
|
|
53
|
+
"typescript-eslint": "^8.57.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
|
}
|