@schematichq/schematic-js 1.2.8 → 1.2.9
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 +100 -30
- package/dist/schematic.d.ts +21 -0
- package/dist/schematic.esm.js +100 -30
- package/package.json +3 -3
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";(()=>{var re=Object.create;var Q=Object.defineProperty;var se=Object.getOwnPropertyDescriptor;var ie=Object.getOwnPropertyNames;var ae=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var
|
|
2
|
-
`)===0?g.substr(1,g.length):g}).forEach(function(g){var y=g.split(":"),f=y.shift().trim();if(f){var D=y.join(":").trim();try{a.append(f,D)}catch(P){console.warn("Response "+P.message)}}}),a}V.call(F.prototype);function w(n,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 h(a.headers),this.url=a.url||"",this._initBody(n)}V.call(w.prototype),w.prototype.clone=function(){return new w(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new h(this.headers),url:this.url})},w.error=function(){var n=new w(null,{status:200,statusText:""});return n.ok=!1,n.status=0,n.type="error",n};var ne=[301,302,303,307,308];w.redirect=function(n,a){if(ne.indexOf(a)===-1)throw new RangeError("Invalid status code");return new w(null,{status:a,headers:{location:n}})},e.DOMException=i.DOMException;try{new e.DOMException}catch{e.DOMException=function(a,u){this.message=a,this.name=u;var g=Error(a);this.stack=g.stack},e.DOMException.prototype=Object.create(Error.prototype),e.DOMException.prototype.constructor=e.DOMException}function A(n,a){return new Promise(function(u,g){var y=new F(n,a);if(y.signal&&y.signal.aborted)return g(new e.DOMException("Aborted","AbortError"));var f=new XMLHttpRequest;function D(){f.abort()}f.onload=function(){var v={statusText:f.statusText,headers:te(f.getAllResponseHeaders()||"")};y.url.indexOf("file://")===0&&(f.status<200||f.status>599)?v.status=200:v.status=f.status,v.url="responseURL"in f?f.responseURL:v.headers.get("X-Request-URL");var x="response"in f?f.response:f.responseText;setTimeout(function(){u(new w(x,v))},0)},f.onerror=function(){setTimeout(function(){g(new TypeError("Network request failed"))},0)},f.ontimeout=function(){setTimeout(function(){g(new TypeError("Network request timed out"))},0)},f.onabort=function(){setTimeout(function(){g(new e.DOMException("Aborted","AbortError"))},0)};function P(v){try{return v===""&&i.location.href?i.location.href:v}catch{return v}}if(f.open(y.method,P(y.url),!0),y.credentials==="include"?f.withCredentials=!0:y.credentials==="omit"&&(f.withCredentials=!1),"responseType"in f&&(s.blob?f.responseType="blob":s.arrayBuffer&&(f.responseType="arraybuffer")),a&&typeof a.headers=="object"&&!(a.headers instanceof h||i.Headers&&a.headers instanceof i.Headers)){var W=[];Object.getOwnPropertyNames(a.headers).forEach(function(v){W.push(d(v)),f.setRequestHeader(v,p(a.headers[v]))}),y.headers.forEach(function(v,x){W.indexOf(x)===-1&&f.setRequestHeader(x,v)})}else y.headers.forEach(function(v,x){f.setRequestHeader(x,v)});y.signal&&(y.signal.addEventListener("abort",D),f.onreadystatechange=function(){f.readyState===4&&y.signal.removeEventListener("abort",D)}),f.send(typeof y._bodyInit>"u"?null:y._bodyInit)})}return A.polyfill=!0,i.fetch||(i.fetch=A,i.Headers=h,i.Request=F,i.Response=w),e.Headers=h,e.Request=F,e.Response=w,e.fetch=A,e})({})})(typeof self<"u"?self:z)});var k=[];for(let r=0;r<256;++r)k.push((r+256).toString(16).slice(1));function H(r,t=0){return(k[r[t+0]]+k[r[t+1]]+k[r[t+2]]+k[r[t+3]]+"-"+k[r[t+4]]+k[r[t+5]]+"-"+k[r[t+6]]+k[r[t+7]]+"-"+k[r[t+8]]+k[r[t+9]]+"-"+k[r[t+10]]+k[r[t+11]]+k[r[t+12]]+k[r[t+13]]+k[r[t+14]]+k[r[t+15]]).toLowerCase()}var L,de=new Uint8Array(16);function B(){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(de)}var fe=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),N={randomUUID:fe};function he(r,t,e){r=r||{};let i=r.random??r.rng?.()??B();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,t){if(e=e||0,e<0||e+16>t.length)throw new RangeError(`UUID byte range ${e}:${e+15} is out of buffer bounds`);for(let s=0;s<16;++s)t[e+s]=i[s];return t}return H(i)}function ge(r,t,e){return N.randomUUID&&!t&&!r?N.randomUUID():he(r,t,e)}var C=ge;var st=ue(K());function T(r){return pe(r,!1)}function pe(r,t){return r==null?r:{companyId:r.company_id==null?void 0:r.company_id,error:r.error==null?void 0:r.error,featureAllocation:r.feature_allocation==null?void 0:r.feature_allocation,featureUsage:r.feature_usage==null?void 0:r.feature_usage,featureUsageEvent:r.feature_usage_event==null?void 0:r.feature_usage_event,featureUsagePeriod:r.feature_usage_period==null?void 0:r.feature_usage_period,featureUsageResetAt:r.feature_usage_reset_at==null?void 0:new Date(r.feature_usage_reset_at),flag:r.flag,flagId:r.flag_id==null?void 0:r.flag_id,reason:r.reason,ruleId:r.rule_id==null?void 0:r.rule_id,ruleType:r.rule_type==null?void 0:r.rule_type,userId:r.user_id==null?void 0:r.user_id,value:r.value}}function M(r){return ye(r,!1)}function ye(r,t=!1){return r==null?r:{company_id:r.companyId,error:r.error,flag_id:r.flagId,flag_key:r.flagKey,reason:r.reason,req_company:r.reqCompany,req_user:r.reqUser,rule_id:r.ruleId,user_id:r.userId,value:r.value}}function U(r){return be(r,!1)}function be(r,t){return r==null?r:{data:T(r.data),params:r.params}}function X(r){return ve(r,!1)}function ve(r,t){return r==null?r:{flags:r.flags.map(T)}}function $(r){return ke(r,!1)}function ke(r,t){return r==null?r:{data:X(r.data),params:r.params}}var _=r=>{let{companyId:t,error:e,featureAllocation:i,featureUsage:s,featureUsageEvent:c,featureUsagePeriod:o,featureUsageResetAt:l,flag:d,flagId:p,reason:E,ruleId:h,ruleType:b,userId:m,value:S}=T(r);return{featureUsageExceeded:!S&&(b=="company_override_usage_exceeded"||b=="plan_entitlement_usage_exceeded"),companyId:t??void 0,error:e??void 0,featureAllocation:i??void 0,featureUsage:s??void 0,featureUsageEvent:c===null?void 0:c,featureUsagePeriod:o??void 0,featureUsageResetAt:l??void 0,flag:d,flagId:p??void 0,reason:E,ruleId:h??void 0,ruleType:b??void 0,userId:m??void 0,value:S}};function R(r){let t=Object.keys(r).reduce((e,i)=>{let c=Object.keys(r[i]||{}).sort().reduce((o,l)=>(o[l]=r[i][l],o),{});return e[i]=c,e},{});return JSON.stringify(t)}var O="1.2.8";var G="schematicId";var I=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;webSocketInitialRetryDelay=1e3;webSocketMaxRetryDelay=3e4;wsReconnectAttempts=0;wsReconnectTimer=null;wsIntentionalDisconnect=!1;maxEventQueueSize=100;maxEventRetries=5;eventRetryInitialDelay=1e3;eventRetryMaxDelay=3e4;retryTimer=null;constructor(t,e){if(this.apiKey=t,this.eventQueue=[],this.contextDependentEventQueue=[],this.useWebSocket=e?.useWebSocket??!1,this.debugEnabled=e?.debug??!1,this.offlineEnabled=e?.offline??!1,typeof window<"u"&&typeof window.location<"u"){let i=new URLSearchParams(window.location.search),s=i.get("schematic_debug");s!==null&&(s===""||s==="true"||s==="1")&&(this.debugEnabled=!0);let c=i.get("schematic_offline");c!==null&&(c===""||c==="true"||c==="1")&&(this.offlineEnabled=!0,this.debugEnabled=!0)}this.offlineEnabled&&e?.debug!==!1&&(this.debugEnabled=!0),this.offlineEnabled&&this.setIsPending(!1),this.additionalHeaders={"X-Schematic-Client-Version":`schematic-js@${O}`,...e?.additionalHeaders??{}},e?.storage?this.storage=e.storage:typeof localStorage<"u"&&(this.storage=localStorage),e?.apiUrl!==void 0&&(this.apiUrl=e.apiUrl),e?.eventUrl!==void 0&&(this.eventUrl=e.eventUrl),e?.webSocketUrl!==void 0&&(this.webSocketUrl=e.webSocketUrl),e?.webSocketConnectionTimeout!==void 0&&(this.webSocketConnectionTimeout=e.webSocketConnectionTimeout),e?.webSocketReconnect!==void 0&&(this.webSocketReconnect=e.webSocketReconnect),e?.webSocketMaxReconnectAttempts!==void 0&&(this.webSocketMaxReconnectAttempts=e.webSocketMaxReconnectAttempts),e?.webSocketInitialRetryDelay!==void 0&&(this.webSocketInitialRetryDelay=e.webSocketInitialRetryDelay),e?.webSocketMaxRetryDelay!==void 0&&(this.webSocketMaxRetryDelay=e.webSocketMaxRetryDelay),e?.maxEventQueueSize!==void 0&&(this.maxEventQueueSize=e.maxEventQueueSize),e?.maxEventRetries!==void 0&&(this.maxEventRetries=e.maxEventRetries),e?.eventRetryInitialDelay!==void 0&&(this.eventRetryInitialDelay=e.eventRetryInitialDelay),e?.eventRetryMaxDelay!==void 0&&(this.eventRetryMaxDelay=e.eventRetryMaxDelay),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")}async checkFlag(t){let{fallback:e=!1,key:i}=t,s=t.context||this.context,c=R(s);if(this.debug(`checkFlag: ${i}`,{context:s,fallback:e}),this.isOffline())return this.debug(`checkFlag offline result: ${i}`,{value:e,offlineMode:!0}),e;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(s)}).then(l=>{if(!l.ok)throw new Error("Network response was not ok");return l.json()}).then(l=>{let d=U(l);this.debug(`checkFlag result: ${i}`,d);let p=_(d.data);return typeof p.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(p),this.submitFlagCheckEvent(i,p,s),p.value}).catch(l=>{console.error("There was a problem with the fetch operation:",l);let d={flag:i,value:e,reason:"API request failed",error:l instanceof Error?l.message:String(l)};return this.submitFlagCheckEvent(i,d,s),e})}try{let o=this.checks[c];if(this.conn!==null&&typeof o<"u"&&typeof o[i]<"u")return this.debug(`checkFlag cached result: ${i}`,o[i]),o[i].value;if(this.isOffline())return e;try{await this.setContext(s)}catch(E){return console.error("WebSocket connection failed, falling back to REST:",E),this.fallbackToRest(i,s,e)}let d=(this.checks[c]??{})[i],p=d?.value??e;return this.debug(`checkFlag WebSocket result: ${i}`,typeof d<"u"?d:{value:e,fallbackUsed:!0}),typeof d<"u"&&this.submitFlagCheckEvent(i,d,s),p}catch(o){console.error("Unexpected error in checkFlag:",o);let l={flag:i,value:e,reason:"Unexpected error in flag check",error:o instanceof Error?o.message:String(o)};return this.submitFlagCheckEvent(i,l,s),e}}debug(t,...e){this.debugEnabled&&console.log(`[Schematic] ${t}`,...e)}isOffline(){return this.offlineEnabled}submitFlagCheckEvent(t,e,i){let s={flagKey:t,value:e.value,reason:e.reason,flagId:e.flagId,ruleId:e.ruleId,companyId:e.companyId,userId:e.userId,error:e.error,reqCompany:i.company,reqUser:i.user};return this.debug("submitting flag check event:",s),this.handleEvent("flag_check",M(s))}async fallbackToRest(t,e,i){if(this.isOffline())return this.debug(`fallbackToRest offline result: ${t}`,{value:i,offlineMode:!0}),i;try{let s=`${this.apiUrl}/flags/${t}/check`,c=await fetch(s,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:JSON.stringify(e)});if(!c.ok)throw new Error("Network response was not ok");let o=await c.json(),l=U(o);this.debug(`fallbackToRest result: ${t}`,l);let d=_(l.data);return typeof d.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(d),this.submitFlagCheckEvent(t,d,e),d.value}catch(s){console.error("REST API call failed, using fallback value:",s);let c={flag:t,value:i,reason:"API request failed (fallback)",error:s instanceof Error?s.message:String(s)};return this.submitFlagCheckEvent(t,c,e),i}}checkFlags=async t=>{if(t=t||this.context,this.debug("checkFlags",{context:t}),this.isOffline())return this.debug("checkFlags offline result: returning empty object"),{};let e=`${this.apiUrl}/flags/check`,i=JSON.stringify(t);return fetch(e,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:i}).then(s=>{if(!s.ok)throw new Error("Network response was not ok");return s.json()}).then(s=>{let c=$(s);return this.debug("checkFlags result:",c),(c?.data?.flags??[]).reduce((o,l)=>(o[l.flag]=l.value,o),{})}).catch(s=>(console.error("There was a problem with the fetch operation:",s),{}))};identify=t=>{this.debug("identify:",t);try{this.setContext({company:t.company?.keys,user:t.keys})}catch(e){console.error("Error setting context:",e)}return this.handleEvent("identify",t)};setContext=async t=>{if(this.isOffline()||!this.useWebSocket)return this.context=t,this.flushContextDependentEventQueue(),this.setIsPending(!1),Promise.resolve();try{this.setIsPending(!0),this.conn||(this.wsReconnectTimer!==null&&(this.debug("Cancelling scheduled reconnection, connecting immediately"),clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.conn=this.wsConnect());let e=await this.conn;await this.wsSendMessage(e,t)}catch(e){throw console.error("Failed to establish WebSocket connection:",e),e}};track=t=>{let{company:e,user:i,event:s,traits:c,quantity:o=1}=t;if(!this.hasContext(e,i)){this.debug(`track: queuing event "${s}" until context is available`);let d={api_key:this.apiKey,body:{company:e,event:s,traits:c??{},user:i,quantity:o},sent_at:new Date().toISOString(),tracker_event_id:C(),tracker_user_id:this.getAnonymousId(),type:"track"};return this.contextDependentEventQueue.push(d),Promise.resolve()}let l={company:e??this.context.company,event:s,traits:c??{},user:i??this.context.user,quantity:o};return this.debug("track:",l),s in this.featureUsageEventMap&&this.optimisticallyUpdateFeatureUsage(s,o),this.handleEvent("track",l)};optimisticallyUpdateFeatureUsage=(t,e=1)=>{let i=this.featureUsageEventMap[t];i!=null&&(this.debug(`Optimistically updating feature usage for event: ${t}`,{quantity:e}),Object.entries(i).forEach(([s,c])=>{if(c===void 0)return;let o={...c};if(typeof o.featureUsage=="number"){if(o.featureUsage+=e,typeof o.featureAllocation=="number"){let d=o.featureUsageExceeded===!0,p=o.featureUsage>=o.featureAllocation;p!==d&&(o.featureUsageExceeded=p,p&&(o.value=!1),this.debug(`Usage limit status changed for flag: ${s}`,{was:d?"exceeded":"within limits",now:p?"exceeded":"within limits",featureUsage:o.featureUsage,featureAllocation:o.featureAllocation,value:o.value}))}this.featureUsageEventMap[t]!==void 0&&(this.featureUsageEventMap[t][s]=o);let l=R(this.context);this.checks[l]!==void 0&&this.checks[l]!==null&&(this.checks[l][s]=o),this.notifyFlagCheckListeners(s,o),this.notifyFlagValueListeners(s,o.value)}}))};hasContext=(t,e)=>{let i=t!=null&&Object.keys(t).length>0||e!=null&&Object.keys(e).length>0,s=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||s};flushContextDependentEventQueue=()=>{for(this.debug(`flushing ${this.contextDependentEventQueue.length} context-dependent events`);this.contextDependentEventQueue.length>0;){let t=this.contextDependentEventQueue.shift();if(t)if(t.type==="track"&&typeof t.body=="object"&&t.body!==null){let e=t.body,i={...e,company:e.company??this.context.company,user:e.user??this.context.user},s={...t,body:i,sent_at:new Date().toISOString()};this.sendEvent(s)}else this.sendEvent(t)}};startRetryTimer=()=>{this.retryTimer===null&&(this.retryTimer=setInterval(()=>{this.flushEventQueue().catch(t=>{this.debug("Error in retry timer flush:",t)}),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 t=Date.now(),e=[],i=[];for(let s of this.eventQueue)s.next_retry_at===void 0||s.next_retry_at<=t?e.push(s):i.push(s);if(e.length===0){this.debug(`No events ready for retry yet (${i.length} still in backoff)`);return}this.debug(`Flushing event queue: ${e.length} ready, ${i.length} waiting`),this.eventQueue=i;for(let s of e)try{await this.sendEvent(s),this.debug("Queued event sent successfully:",s.type)}catch(c){this.debug("Failed to send queued event:",c)}};getAnonymousId=()=>{if(!this.storage)return C();let t=this.storage.getItem(G);if(typeof t<"u")return t;let e=C();return this.storage.setItem(G,e),e};handleEvent=(t,e)=>{let i={api_key:this.apiKey,body:e,sent_at:new Date().toISOString(),tracker_event_id:C(),tracker_user_id:this.getAnonymousId(),type:t};return typeof document<"u"&&document?.hidden?this.storeEvent(i):this.sendEvent(i)};sendEvent=async t=>{let e=`${this.eventUrl}/e`,i=JSON.stringify(t);if(this.debug("sending event:",{url:e,event:t}),this.isOffline())return this.debug("event not sent (offline mode):",{event:t}),Promise.resolve();try{let s=await fetch(e,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8"},body:i});if(!s.ok)throw new Error(`HTTP ${s.status}: ${s.statusText}`);this.debug("event sent:",{status:s.status,statusText:s.statusText})}catch(s){let c=(t.retry_count??0)+1;if(c<=this.maxEventRetries){this.debug(`Event failed to send (attempt ${c}/${this.maxEventRetries}), queueing for retry:`,s);let o=this.eventRetryInitialDelay*Math.pow(2,c-1),l=Math.min(o,this.eventRetryMaxDelay),d=Date.now()+l,p={...t,retry_count:c,next_retry_at:d};this.eventQueue.length<this.maxEventQueueSize?(this.eventQueue.push(p),this.debug(`Event queued for retry in ${l}ms (${this.eventQueue.length}/${this.maxEventQueueSize})`)):(this.debug(`Event queue full (${this.maxEventQueueSize}), dropping oldest event`),this.eventQueue.shift(),this.eventQueue.push(p)),this.startRetryTimer()}else this.debug(`Event failed permanently after ${this.maxEventRetries} attempts, dropping:`,s)}return Promise.resolve()};storeEvent=t=>(this.eventQueue.push(t),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{(await this.conn).close()}catch(t){console.error("Error during cleanup:",t)}finally{this.conn=null}};calculateReconnectDelay=()=>{let t=this.webSocketInitialRetryDelay*Math.pow(2,this.wsReconnectAttempts),e=Math.min(t,this.webSocketMaxRetryDelay),i=Math.random()*e*.5,s=e+i;return this.debug(`Reconnect delay calculated: ${s.toFixed(0)}ms (attempt ${this.wsReconnectAttempts+1}/${this.webSocketMaxReconnectAttempts})`),s};handleNetworkOffline=async()=>{if(this.conn!==null){try{(await this.conn).close()}catch(t){this.debug("Error closing connection on offline:",t)}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(t=>{this.debug("Error flushing event queue on network online:",t)}),this.attemptReconnect()};attemptReconnect=()=>{if(this.wsReconnectAttempts>=this.webSocketMaxReconnectAttempts){this.debug(`Maximum reconnection attempts (${this.webSocketMaxReconnectAttempts}) reached, giving up`);return}this.wsReconnectTimer!==null&&clearTimeout(this.wsReconnectTimer);let t=this.calculateReconnectDelay();this.debug(`Scheduling reconnection attempt ${this.wsReconnectAttempts+1}/${this.webSocketMaxReconnectAttempts} in ${t.toFixed(0)}ms`),this.wsReconnectTimer=setTimeout(async()=>{this.wsReconnectTimer=null,this.wsReconnectAttempts++,this.debug(`Attempting to reconnect (attempt ${this.wsReconnectAttempts}/${this.webSocketMaxReconnectAttempts})`);try{this.conn=this.wsConnect();let e=await this.conn;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.wsSendContextAfterReconnection(e,this.context)):this.debug("No context to re-send after reconnection - websocket ready for new context"),this.flushEventQueue().catch(i=>{this.debug("Error flushing event queue after websocket reconnection:",i)}),this.debug("Reconnection successful")}catch(e){this.debug("Reconnection attempt failed:",e)}},t)};wsConnect=()=>this.isOffline()?(this.debug("wsConnect: skipped (offline mode)"),Promise.reject(new Error("WebSocket connection skipped in offline mode"))):new Promise((t,e)=>{let i=`${this.webSocketUrl}/flags/bootstrap?apiKey=${this.apiKey}`;this.debug("connecting to WebSocket:",i);let s=new WebSocket(i),c=null,o=!1;c=setTimeout(()=>{o||(this.debug(`WebSocket connection timeout after ${this.webSocketConnectionTimeout}ms`),s.close(),e(new Error("WebSocket connection timeout")))},this.webSocketConnectionTimeout),s.onopen=()=>{o=!0,c!==null&&clearTimeout(c),this.wsReconnectAttempts=0,this.wsIntentionalDisconnect=!1,this.debug("WebSocket connection opened"),t(s)},s.onerror=l=>{o=!0,c!==null&&clearTimeout(c),this.debug("WebSocket connection error:",l),e(l)},s.onclose=()=>{o=!0,c!==null&&clearTimeout(c),this.debug("WebSocket connection closed"),this.conn=null,!this.wsIntentionalDisconnect&&this.webSocketReconnect&&this.attemptReconnect()}});wsSendContextAfterReconnection=(t,e)=>this.isOffline()?(this.debug("wsSendContextAfterReconnection: skipped (offline mode)"),this.setIsPending(!1),Promise.resolve()):new Promise(i=>{this.debug("WebSocket force sending context after reconnection:",e),this.context=e;let s=()=>{let c=!1,o=p=>{let E=JSON.parse(p.data);this.debug("WebSocket message received after reconnection:",E),R(e)in this.checks||(this.checks[R(e)]={}),(E.flags??[]).forEach(h=>{let b=_(h),m=R(e);this.checks[m]===void 0&&(this.checks[m]={}),this.checks[m][b.flag]=b}),this.useWebSocket=!0,t.removeEventListener("message",o),c||(c=!0,i(this.setIsPending(!1)))};t.addEventListener("message",o);let l=this.additionalHeaders["X-Schematic-Client-Version"]??`schematic-js@${O}`,d={apiKey:this.apiKey,clientVersion:l,data:e};this.debug("WebSocket sending forced message after reconnection:",d),t.send(JSON.stringify(d))};t.readyState===WebSocket.OPEN?(this.debug("WebSocket already open, sending forced message after reconnection"),s()):t.addEventListener("open",()=>{this.debug("WebSocket opened, sending forced message after reconnection"),s()})});wsSendMessage=(t,e)=>this.isOffline()?(this.debug("wsSendMessage: skipped (offline mode)"),this.setIsPending(!1),Promise.resolve()):new Promise((i,s)=>{if(R(e)==R(this.context))return this.debug("WebSocket context unchanged, skipping update"),i(this.setIsPending(!1));this.debug("WebSocket context updated:",e),this.context=e;let c=()=>{let o=!1,l=E=>{let h=JSON.parse(E.data);this.debug("WebSocket message received:",h),R(e)in this.checks||(this.checks[R(e)]={}),(h.flags??[]).forEach(b=>{let m=_(b),S=R(e);this.checks[S]===void 0&&(this.checks[S]={}),this.checks[S][m.flag]=m,this.debug("WebSocket flag update:",{flag:m.flag,value:m.value,flagCheck:m}),typeof m.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(m),(this.flagCheckListeners[b.flag]?.size>0||this.flagValueListeners[b.flag]?.size>0)&&this.submitFlagCheckEvent(m.flag,m,e),this.notifyFlagCheckListeners(b.flag,m),this.notifyFlagValueListeners(b.flag,m.value)}),this.flushContextDependentEventQueue(),this.setIsPending(!1),o||(o=!0,i())};t.addEventListener("message",l);let d=this.additionalHeaders["X-Schematic-Client-Version"]??`schematic-js@${O}`,p={apiKey:this.apiKey,clientVersion:d,data:e};this.debug("WebSocket sending message:",p),t.send(JSON.stringify(p))};t.readyState===WebSocket.OPEN?(this.debug("WebSocket already open, sending message"),c()):t.readyState===WebSocket.CONNECTING?(this.debug("WebSocket connecting, waiting for open to send message"),t.addEventListener("open",c)):(this.debug("WebSocket is closed, cannot send message"),s("WebSocket is not open or connecting"))});getIsPending=()=>this.isPending;addIsPendingListener=t=>(this.isPendingListeners.add(t),()=>{this.isPendingListeners.delete(t)});setIsPending=t=>{this.isPending=t,this.isPendingListeners.forEach(e=>Ee(e,t))};getFlagCheck=t=>{let e=R(this.context);return(this.checks[e]??{})[t]};getFlagValue=t=>this.getFlagCheck(t)?.value;addFlagValueListener=(t,e)=>(t in this.flagValueListeners||(this.flagValueListeners[t]=new Set),this.flagValueListeners[t].add(e),()=>{this.flagValueListeners[t].delete(e)});addFlagCheckListener=(t,e)=>(t in this.flagCheckListeners||(this.flagCheckListeners[t]=new Set),this.flagCheckListeners[t].add(e),()=>{this.flagCheckListeners[t].delete(e)});notifyFlagCheckListeners=(t,e)=>{let i=this.flagCheckListeners?.[t]??[];i.size>0&&this.debug(`Notifying ${i.size} flag check listeners for ${t}`,e),typeof e.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(e),i.forEach(s=>Re(s,e))};updateFeatureUsageEventMap=t=>{if(typeof t.featureUsageEvent!="string")return;let e=t.featureUsageEvent;(this.featureUsageEventMap[e]===void 0||this.featureUsageEventMap[e]===null)&&(this.featureUsageEventMap[e]={}),this.featureUsageEventMap[e]!==void 0&&(this.featureUsageEventMap[e][t.flag]=t),this.debug(`Updated featureUsageEventMap for event: ${e}, flag: ${t.flag}`,t)};notifyFlagValueListeners=(t,e)=>{let i=this.flagValueListeners?.[t]??[];i.size>0&&this.debug(`Notifying ${i.size} flag value listeners for ${t}`,{value:e}),i.forEach(s=>we(s,e))}},Ee=(r,t)=>{r.length>0?r(t):r()},Re=(r,t)=>{r.length>0?r(t):r()},we=(r,t)=>{r.length>0?r(t):r()};window.Schematic=I;})();
|
|
1
|
+
"use strict";(()=>{var re=Object.create;var Q=Object.defineProperty;var se=Object.getOwnPropertyDescriptor;var ie=Object.getOwnPropertyNames;var ae=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var le=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports);var ce=(r,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of ie(e))!oe.call(r,s)&&s!==t&&Q(r,s,{get:()=>e[s],enumerable:!(i=se(e,s))||i.enumerable});return r};var ue=(r,e,t)=>(t=r!=null?re(ae(r)):{},ce(e||!r||!r.__esModule?Q(t,"default",{value:r,enumerable:!0}):t,r));var K=le(z=>{(function(r){var e=(function(t){var i=typeof globalThis<"u"&&globalThis||typeof r<"u"&&r||typeof global<"u"&&global||{},s={searchParams:"URLSearchParams"in i,iterable:"Symbol"in i&&"iterator"in Symbol,blob:"FileReader"in i&&"Blob"in i&&(function(){try{return new Blob,!0}catch{return!1}})(),formData:"FormData"in i,arrayBuffer:"ArrayBuffer"in i};function l(n){return n&&DataView.prototype.isPrototypeOf(n)}if(s.arrayBuffer)var o=["[object Int8Array]","[object Uint8Array]","[object Uint8ClampedArray]","[object Int16Array]","[object Uint16Array]","[object Int32Array]","[object Uint32Array]","[object Float32Array]","[object Float64Array]"],c=ArrayBuffer.isView||function(n){return n&&o.indexOf(Object.prototype.toString.call(n))>-1};function d(n){if(typeof n!="string"&&(n=String(n)),/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(n)||n==="")throw new TypeError('Invalid character in header field name: "'+n+'"');return n.toLowerCase()}function g(n){return typeof n!="string"&&(n=String(n)),n}function E(n){var a={next:function(){var u=n.shift();return{done:u===void 0,value:u}}};return s.iterable&&(a[Symbol.iterator]=function(){return a}),a}function h(n){this.map={},n instanceof h?n.forEach(function(a,u){this.append(u,a)},this):Array.isArray(n)?n.forEach(function(a){if(a.length!=2)throw new TypeError("Headers constructor: expected name/value pair to be length 2, found"+a.length);this.append(a[0],a[1])},this):n&&Object.getOwnPropertyNames(n).forEach(function(a){this.append(a,n[a])},this)}h.prototype.append=function(n,a){n=d(n),a=g(a);var u=this.map[n];this.map[n]=u?u+", "+a:a},h.prototype.delete=function(n){delete this.map[d(n)]},h.prototype.get=function(n){return n=d(n),this.has(n)?this.map[n]:null},h.prototype.has=function(n){return this.map.hasOwnProperty(d(n))},h.prototype.set=function(n,a){this.map[d(n)]=g(a)},h.prototype.forEach=function(n,a){for(var u in this.map)this.map.hasOwnProperty(u)&&n.call(a,this.map[u],u,this)},h.prototype.keys=function(){var n=[];return this.forEach(function(a,u){n.push(u)}),E(n)},h.prototype.values=function(){var n=[];return this.forEach(function(a){n.push(a)}),E(n)},h.prototype.entries=function(){var n=[];return this.forEach(function(a,u){n.push([u,a])}),E(n)},s.iterable&&(h.prototype[Symbol.iterator]=h.prototype.entries);function b(n){if(!n._noBody){if(n.bodyUsed)return Promise.reject(new TypeError("Already read"));n.bodyUsed=!0}}function m(n){return new Promise(function(a,u){n.onload=function(){a(n.result)},n.onerror=function(){u(n.error)}})}function F(n){var a=new FileReader,u=m(a);return a.readAsArrayBuffer(n),u}function $(n){var a=new FileReader,u=m(a),p=/charset=([A-Za-z0-9_-]+)/.exec(n.type),y=p?p[1]:"utf-8";return a.readAsText(n,y),u}function Y(n){for(var a=new Uint8Array(n),u=new Array(a.length),p=0;p<a.length;p++)u[p]=String.fromCharCode(a[p]);return u.join("")}function J(n){if(n.slice)return n.slice(0);var a=new Uint8Array(n.byteLength);return a.set(new Uint8Array(n)),a.buffer}function q(){return this.bodyUsed=!1,this._initBody=function(n){this.bodyUsed=this.bodyUsed,this._bodyInit=n,n?typeof n=="string"?this._bodyText=n:s.blob&&Blob.prototype.isPrototypeOf(n)?this._bodyBlob=n:s.formData&&FormData.prototype.isPrototypeOf(n)?this._bodyFormData=n:s.searchParams&&URLSearchParams.prototype.isPrototypeOf(n)?this._bodyText=n.toString():s.arrayBuffer&&s.blob&&l(n)?(this._bodyArrayBuffer=J(n.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer])):s.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(n)||c(n))?this._bodyArrayBuffer=J(n):this._bodyText=n=Object.prototype.toString.call(n):(this._noBody=!0,this._bodyText=""),this.headers.get("content-type")||(typeof n=="string"?this.headers.set("content-type","text/plain;charset=UTF-8"):this._bodyBlob&&this._bodyBlob.type?this.headers.set("content-type",this._bodyBlob.type):s.searchParams&&URLSearchParams.prototype.isPrototypeOf(n)&&this.headers.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"))},s.blob&&(this.blob=function(){var n=b(this);if(n)return n;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 n=b(this);return n||(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(s.blob)return this.blob().then(F);throw new Error("could not read as ArrayBuffer")}},this.text=function(){var n=b(this);if(n)return n;if(this._bodyBlob)return $(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(Y(this._bodyArrayBuffer));if(this._bodyFormData)throw new Error("could not read FormData body as text");return Promise.resolve(this._bodyText)},s.formData&&(this.formData=function(){return this.text().then(ee)}),this.json=function(){return this.text().then(JSON.parse)},this}var Z=["CONNECT","DELETE","GET","HEAD","OPTIONS","PATCH","POST","PUT","TRACE"];function j(n){var a=n.toUpperCase();return Z.indexOf(a)>-1?a:n}function S(n,a){if(!(this instanceof S))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');a=a||{};var u=a.body;if(n instanceof S){if(n.bodyUsed)throw new TypeError("Already read");this.url=n.url,this.credentials=n.credentials,a.headers||(this.headers=new h(n.headers)),this.method=n.method,this.mode=n.mode,this.signal=n.signal,!u&&n._bodyInit!=null&&(u=n._bodyInit,n.bodyUsed=!0)}else this.url=String(n);if(this.credentials=a.credentials||this.credentials||"same-origin",(a.headers||!this.headers)&&(this.headers=new h(a.headers)),this.method=j(a.method||this.method||"GET"),this.mode=a.mode||this.mode||null,this.signal=a.signal||this.signal||(function(){if("AbortController"in i){var f=new AbortController;return f.signal}})(),this.referrer=null,(this.method==="GET"||this.method==="HEAD")&&u)throw new TypeError("Body not allowed for GET or HEAD requests");if(this._initBody(u),(this.method==="GET"||this.method==="HEAD")&&(a.cache==="no-store"||a.cache==="no-cache")){var p=/([?&])_=[^&]*/;if(p.test(this.url))this.url=this.url.replace(p,"$1_="+new Date().getTime());else{var y=/\?/;this.url+=(y.test(this.url)?"&":"?")+"_="+new Date().getTime()}}}S.prototype.clone=function(){return new S(this,{body:this._bodyInit})};function ee(n){var a=new FormData;return n.trim().split("&").forEach(function(u){if(u){var p=u.split("="),y=p.shift().replace(/\+/g," "),f=p.join("=").replace(/\+/g," ");a.append(decodeURIComponent(y),decodeURIComponent(f))}}),a}function te(n){var a=new h,u=n.replace(/\r?\n[\t ]+/g," ");return u.split("\r").map(function(p){return p.indexOf(`
|
|
2
|
+
`)===0?p.substr(1,p.length):p}).forEach(function(p){var y=p.split(":"),f=y.shift().trim();if(f){var _=y.join(":").trim();try{a.append(f,_)}catch(P){console.warn("Response "+P.message)}}}),a}q.call(S.prototype);function w(n,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 h(a.headers),this.url=a.url||"",this._initBody(n)}q.call(w.prototype),w.prototype.clone=function(){return new w(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new h(this.headers),url:this.url})},w.error=function(){var n=new w(null,{status:200,statusText:""});return n.ok=!1,n.status=0,n.type="error",n};var ne=[301,302,303,307,308];w.redirect=function(n,a){if(ne.indexOf(a)===-1)throw new RangeError("Invalid status code");return new w(null,{status:a,headers:{location:n}})},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 A(n,a){return new Promise(function(u,p){var y=new S(n,a);if(y.signal&&y.signal.aborted)return p(new t.DOMException("Aborted","AbortError"));var f=new XMLHttpRequest;function _(){f.abort()}f.onload=function(){var v={statusText:f.statusText,headers:te(f.getAllResponseHeaders()||"")};y.url.indexOf("file://")===0&&(f.status<200||f.status>599)?v.status=200:v.status=f.status,v.url="responseURL"in f?f.responseURL:v.headers.get("X-Request-URL");var x="response"in f?f.response:f.responseText;setTimeout(function(){u(new w(x,v))},0)},f.onerror=function(){setTimeout(function(){p(new TypeError("Network request failed"))},0)},f.ontimeout=function(){setTimeout(function(){p(new TypeError("Network request timed out"))},0)},f.onabort=function(){setTimeout(function(){p(new t.DOMException("Aborted","AbortError"))},0)};function P(v){try{return v===""&&i.location.href?i.location.href:v}catch{return v}}if(f.open(y.method,P(y.url),!0),y.credentials==="include"?f.withCredentials=!0:y.credentials==="omit"&&(f.withCredentials=!1),"responseType"in f&&(s.blob?f.responseType="blob":s.arrayBuffer&&(f.responseType="arraybuffer")),a&&typeof a.headers=="object"&&!(a.headers instanceof h||i.Headers&&a.headers instanceof i.Headers)){var W=[];Object.getOwnPropertyNames(a.headers).forEach(function(v){W.push(d(v)),f.setRequestHeader(v,g(a.headers[v]))}),y.headers.forEach(function(v,x){W.indexOf(x)===-1&&f.setRequestHeader(x,v)})}else y.headers.forEach(function(v,x){f.setRequestHeader(x,v)});y.signal&&(y.signal.addEventListener("abort",_),f.onreadystatechange=function(){f.readyState===4&&y.signal.removeEventListener("abort",_)}),f.send(typeof y._bodyInit>"u"?null:y._bodyInit)})}return A.polyfill=!0,i.fetch||(i.fetch=A,i.Headers=h,i.Request=S,i.Response=w),t.Headers=h,t.Request=S,t.Response=w,t.fetch=A,t})({})})(typeof self<"u"?self:z)});var k=[];for(let r=0;r<256;++r)k.push((r+256).toString(16).slice(1));function H(r,e=0){return(k[r[e+0]]+k[r[e+1]]+k[r[e+2]]+k[r[e+3]]+"-"+k[r[e+4]]+k[r[e+5]]+"-"+k[r[e+6]]+k[r[e+7]]+"-"+k[r[e+8]]+k[r[e+9]]+"-"+k[r[e+10]]+k[r[e+11]]+k[r[e+12]]+k[r[e+13]]+k[r[e+14]]+k[r[e+15]]).toLowerCase()}var L,de=new Uint8Array(16);function B(){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(de)}var fe=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),N={randomUUID:fe};function he(r,e,t){r=r||{};let i=r.random??r.rng?.()??B();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 s=0;s<16;++s)e[t+s]=i[s];return e}return H(i)}function ge(r,e,t){return N.randomUUID&&!e&&!r?N.randomUUID():he(r,e,t)}var C=ge;var st=ue(K());function T(r){return pe(r,!1)}function pe(r,e){return r==null?r:{companyId:r.company_id==null?void 0:r.company_id,error:r.error==null?void 0:r.error,featureAllocation:r.feature_allocation==null?void 0:r.feature_allocation,featureUsage:r.feature_usage==null?void 0:r.feature_usage,featureUsageEvent:r.feature_usage_event==null?void 0:r.feature_usage_event,featureUsagePeriod:r.feature_usage_period==null?void 0:r.feature_usage_period,featureUsageResetAt:r.feature_usage_reset_at==null?void 0:new Date(r.feature_usage_reset_at),flag:r.flag,flagId:r.flag_id==null?void 0:r.flag_id,reason:r.reason,ruleId:r.rule_id==null?void 0:r.rule_id,ruleType:r.rule_type==null?void 0:r.rule_type,userId:r.user_id==null?void 0:r.user_id,value:r.value}}function M(r){return ye(r,!1)}function ye(r,e=!1){return r==null?r:{company_id:r.companyId,error:r.error,flag_id:r.flagId,flag_key:r.flagKey,reason:r.reason,req_company:r.reqCompany,req_user:r.reqUser,rule_id:r.ruleId,user_id:r.userId,value:r.value}}function U(r){return be(r,!1)}function be(r,e){return r==null?r:{data:T(r.data),params:r.params}}function X(r){return ve(r,!1)}function ve(r,e){return r==null?r:{flags:r.flags.map(T)}}function V(r){return ke(r,!1)}function ke(r,e){return r==null?r:{data:X(r.data),params:r.params}}var D=r=>{let{companyId:e,error:t,featureAllocation:i,featureUsage:s,featureUsageEvent:l,featureUsagePeriod:o,featureUsageResetAt:c,flag:d,flagId:g,reason:E,ruleId:h,ruleType:b,userId:m,value:F}=T(r);return{featureUsageExceeded:!F&&(b=="company_override_usage_exceeded"||b=="plan_entitlement_usage_exceeded"),companyId:e??void 0,error:t??void 0,featureAllocation:i??void 0,featureUsage:s??void 0,featureUsageEvent:l===null?void 0:l,featureUsagePeriod:o??void 0,featureUsageResetAt:c??void 0,flag:d,flagId:g??void 0,reason:E,ruleId:h??void 0,ruleType:b??void 0,userId:m??void 0,value:F}};function R(r){let e=Object.keys(r).reduce((t,i)=>{let l=Object.keys(r[i]||{}).sort().reduce((o,c)=>(o[c]=r[i][c],o),{});return t[i]=l,t},{});return JSON.stringify(e)}var O="1.2.9";var G="schematicId";var I=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;webSocketInitialRetryDelay=1e3;webSocketMaxRetryDelay=3e4;wsReconnectAttempts=0;wsReconnectTimer=null;wsIntentionalDisconnect=!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),s=i.get("schematic_debug");s!==null&&(s===""||s==="true"||s==="1")&&(this.debugEnabled=!0);let l=i.get("schematic_offline");l!==null&&(l===""||l==="true"||l==="1")&&(this.offlineEnabled=!0,this.debugEnabled=!0)}this.offlineEnabled&&t?.debug!==!1&&(this.debugEnabled=!0),this.offlineEnabled&&this.setIsPending(!1),this.additionalHeaders={"X-Schematic-Client-Version":`schematic-js@${O}`,...t?.additionalHeaders??{}},t?.storage?this.storage=t.storage:typeof localStorage<"u"&&(this.storage=localStorage),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.flagValueDefaults?this.flagValueDefaults[e]:!1}resolveFallbackCheckFlagReturn(e,t,i="Fallback value used",s){if(t!==void 0)return{flag:e,value:t,reason:i,error:s};if(e in this.flagCheckDefaults){let l=this.flagCheckDefaults[e];return{...l,flag:e,reason:s!==void 0?i:l.reason,error:s}}return e in this.flagValueDefaults?{flag:e,value:this.flagValueDefaults[e],reason:i,error:s}:{flag:e,value:!1,reason:i,error:s}}async checkFlag(e){let{fallback:t,key:i}=e,s=e.context||this.context,l=R(s);if(this.debug(`checkFlag: ${i}`,{context:s,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(s)}).then(c=>{if(!c.ok)throw new Error("Network response was not ok");return c.json()}).then(c=>{let d=U(c);this.debug(`checkFlag result: ${i}`,d);let g=D(d.data);return typeof g.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(g),this.submitFlagCheckEvent(i,g,s),g.value}).catch(c=>{console.error("There was a problem with the fetch operation:",c);let d=this.resolveFallbackCheckFlagReturn(i,t,"API request failed",c instanceof Error?c.message:String(c));return this.submitFlagCheckEvent(i,d,s),d.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(s)}catch(E){return console.error("WebSocket connection failed, falling back to REST:",E),this.fallbackToRest(i,s,t)}let d=(this.checks[l]??{})[i],g=d?.value??this.resolveFallbackValue(i,t);return this.debug(`checkFlag WebSocket result: ${i}`,typeof d<"u"?d:{value:g,fallbackUsed:!0}),typeof d<"u"&&this.submitFlagCheckEvent(i,d,s),g}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,s),c.value}}debug(e,...t){this.debugEnabled&&console.log(`[Schematic] ${e}`,...t)}isOffline(){return this.offlineEnabled}submitFlagCheckEvent(e,t,i){let s={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:",s),this.handleEvent("flag_check",M(s))}async fallbackToRest(e,t,i){if(this.isOffline()){let s=this.resolveFallbackValue(e,i);return this.debug(`fallbackToRest offline result: ${e}`,{value:s,offlineMode:!0}),s}try{let s=`${this.apiUrl}/flags/${e}/check`,l=await fetch(s,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:JSON.stringify(t)});if(!l.ok)throw new Error("Network response was not ok");let o=await l.json(),c=U(o);this.debug(`fallbackToRest result: ${e}`,c);let d=D(c.data);return typeof d.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(d),this.submitFlagCheckEvent(e,d,t),d.value}catch(s){console.error("REST API call failed, using fallback value:",s);let l=this.resolveFallbackCheckFlagReturn(e,i,"API request failed (fallback)",s instanceof Error?s.message:String(s));return this.submitFlagCheckEvent(e,l,t),l.value}}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(s=>{if(!s.ok)throw new Error("Network response was not ok");return s.json()}).then(s=>{let l=V(s);return this.debug("checkFlags result:",l),(l?.data?.flags??[]).reduce((o,c)=>(o[c.flag]=c.value,o),{})}).catch(s=>(console.error("There was a problem with the fetch operation:",s),{}))};identify=e=>{this.debug("identify:",e);try{this.setContext({company:e.company?.keys,user:e.keys})}catch(t){console.error("Error setting context:",t)}return this.handleEvent("identify",e)};setContext=async e=>{if(this.isOffline()||!this.useWebSocket)return this.context=e,this.flushContextDependentEventQueue(),this.setIsPending(!1),Promise.resolve();try{this.setIsPending(!0),this.conn||(this.wsReconnectTimer!==null&&(this.debug("Cancelling scheduled reconnection, connecting immediately"),clearTimeout(this.wsReconnectTimer),this.wsReconnectTimer=null),this.conn=this.wsConnect());let t=await this.conn;await this.wsSendMessage(t,e)}catch(t){throw console.error("Failed to establish WebSocket connection:",t),t}};track=e=>{let{company:t,user:i,event:s,traits:l,quantity:o=1}=e;if(!this.hasContext(t,i)){this.debug(`track: queuing event "${s}" until context is available`);let d={api_key:this.apiKey,body:{company:t,event:s,traits:l??{},user:i,quantity:o},sent_at:new Date().toISOString(),tracker_event_id:C(),tracker_user_id:this.getAnonymousId(),type:"track"};return this.contextDependentEventQueue.push(d),Promise.resolve()}let c={company:t??this.context.company,event:s,traits:l??{},user:i??this.context.user,quantity:o};return this.debug("track:",c),s in this.featureUsageEventMap&&this.optimisticallyUpdateFeatureUsage(s,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(([s,l])=>{if(l===void 0)return;let o={...l};if(typeof o.featureUsage=="number"){if(o.featureUsage+=t,typeof o.featureAllocation=="number"){let d=o.featureUsageExceeded===!0,g=o.featureUsage>=o.featureAllocation;g!==d&&(o.featureUsageExceeded=g,g&&(o.value=!1),this.debug(`Usage limit status changed for flag: ${s}`,{was:d?"exceeded":"within limits",now:g?"exceeded":"within limits",featureUsage:o.featureUsage,featureAllocation:o.featureAllocation,value:o.value}))}this.featureUsageEventMap[e]!==void 0&&(this.featureUsageEventMap[e][s]=o);let c=R(this.context);this.checks[c]!==void 0&&this.checks[c]!==null&&(this.checks[c][s]=o),this.notifyFlagCheckListeners(s,o),this.notifyFlagValueListeners(s,o.value)}}))};hasContext=(e,t)=>{let i=e!=null&&Object.keys(e).length>0||t!=null&&Object.keys(t).length>0,s=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||s};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},s={...e,body:i,sent_at:new Date().toISOString()};this.sendEvent(s)}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 s of this.eventQueue)s.next_retry_at===void 0||s.next_retry_at<=e?t.push(s):i.push(s);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 s of t)try{await this.sendEvent(s),this.debug("Queued event sent successfully:",s.type)}catch(l){this.debug("Failed to send queued event:",l)}};getAnonymousId=()=>{if(!this.storage)return C();let e=this.storage.getItem(G);if(typeof e<"u")return e;let t=C();return this.storage.setItem(G,t),t};handleEvent=(e,t)=>{let i={api_key:this.apiKey,body:t,sent_at:new Date().toISOString(),tracker_event_id:C(),tracker_user_id:this.getAnonymousId(),type:e};return typeof document<"u"&&document?.hidden?this.storeEvent(i):this.sendEvent(i)};sendEvent=async e=>{let t=`${this.eventUrl}/e`,i=JSON.stringify(e);if(this.debug("sending event:",{url:t,event:e}),this.isOffline())return this.debug("event not sent (offline mode):",{event:e}),Promise.resolve();try{let s=await fetch(t,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8"},body:i});if(!s.ok)throw new Error(`HTTP ${s.status}: ${s.statusText}`);this.debug("event sent:",{status:s.status,statusText:s.statusText})}catch(s){let l=(e.retry_count??0)+1;if(l<=this.maxEventRetries){this.debug(`Event failed to send (attempt ${l}/${this.maxEventRetries}), queueing for retry:`,s);let o=this.eventRetryInitialDelay*Math.pow(2,l-1),c=Math.min(o,this.eventRetryMaxDelay),d=Date.now()+c,g={...e,retry_count:l,next_retry_at:d};this.eventQueue.length<this.maxEventQueueSize?(this.eventQueue.push(g),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(g)),this.startRetryTimer()}else this.debug(`Event failed permanently after ${this.maxEventRetries} attempts, dropping:`,s)}return Promise.resolve()};storeEvent=e=>(this.eventQueue.push(e),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{(await this.conn).close()}catch(e){console.error("Error during cleanup:",e)}finally{this.conn=null}};calculateReconnectDelay=()=>{let e=this.webSocketInitialRetryDelay*Math.pow(2,this.wsReconnectAttempts),t=Math.min(e,this.webSocketMaxRetryDelay),i=Math.random()*t*.5,s=t+i;return this.debug(`Reconnect delay calculated: ${s.toFixed(0)}ms (attempt ${this.wsReconnectAttempts+1}/${this.webSocketMaxReconnectAttempts})`),s};handleNetworkOffline=async()=>{if(this.conn!==null){try{(await this.conn).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}this.wsReconnectTimer!==null&&clearTimeout(this.wsReconnectTimer);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{this.conn=this.wsConnect();let t=await this.conn;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.wsSendContextAfterReconnection(t,this.context)):this.debug("No context to re-send after reconnection - websocket ready for new context"),this.flushEventQueue().catch(i=>{this.debug("Error flushing event queue after websocket reconnection:",i)}),this.debug("Reconnection successful")}catch(t){this.debug("Reconnection attempt failed:",t)}},e)};wsConnect=()=>this.isOffline()?(this.debug("wsConnect: skipped (offline mode)"),Promise.reject(new Error("WebSocket connection skipped in offline mode"))):new Promise((e,t)=>{let i=`${this.webSocketUrl}/flags/bootstrap?apiKey=${this.apiKey}`;this.debug("connecting to WebSocket:",i);let s=new WebSocket(i),l=null,o=!1;l=setTimeout(()=>{o||(this.debug(`WebSocket connection timeout after ${this.webSocketConnectionTimeout}ms`),s.close(),t(new Error("WebSocket connection timeout")))},this.webSocketConnectionTimeout),s.onopen=()=>{o=!0,l!==null&&clearTimeout(l),this.wsReconnectAttempts=0,this.wsIntentionalDisconnect=!1,this.debug("WebSocket connection opened"),e(s)},s.onerror=c=>{o=!0,l!==null&&clearTimeout(l),this.debug("WebSocket connection error:",c),t(c)},s.onclose=()=>{o=!0,l!==null&&clearTimeout(l),this.debug("WebSocket connection closed"),this.conn=null,!this.wsIntentionalDisconnect&&this.webSocketReconnect&&this.attemptReconnect()}});wsSendContextAfterReconnection=(e,t)=>this.isOffline()?(this.debug("wsSendContextAfterReconnection: skipped (offline mode)"),this.setIsPending(!1),Promise.resolve()):new Promise(i=>{this.debug("WebSocket force sending context after reconnection:",t),this.context=t;let s=()=>{let l=!1,o=g=>{let E=JSON.parse(g.data);this.debug("WebSocket message received after reconnection:",E),R(t)in this.checks||(this.checks[R(t)]={}),(E.flags??[]).forEach(h=>{let b=D(h),m=R(t);this.checks[m]===void 0&&(this.checks[m]={}),this.checks[m][b.flag]=b}),this.useWebSocket=!0,e.removeEventListener("message",o),l||(l=!0,i(this.setIsPending(!1)))};e.addEventListener("message",o);let c=this.additionalHeaders["X-Schematic-Client-Version"]??`schematic-js@${O}`,d={apiKey:this.apiKey,clientVersion:c,data:t};this.debug("WebSocket sending forced message after reconnection:",d),e.send(JSON.stringify(d))};e.readyState===WebSocket.OPEN?(this.debug("WebSocket already open, sending forced message after reconnection"),s()):e.addEventListener("open",()=>{this.debug("WebSocket opened, sending forced message after reconnection"),s()})});wsSendMessage=(e,t)=>this.isOffline()?(this.debug("wsSendMessage: skipped (offline mode)"),this.setIsPending(!1),Promise.resolve()):new Promise((i,s)=>{if(R(t)==R(this.context))return this.debug("WebSocket context unchanged, skipping update"),i(this.setIsPending(!1));this.debug("WebSocket context updated:",t),this.context=t;let l=()=>{let o=!1,c=E=>{let h=JSON.parse(E.data);this.debug("WebSocket message received:",h),R(t)in this.checks||(this.checks[R(t)]={}),(h.flags??[]).forEach(b=>{let m=D(b),F=R(t);this.checks[F]===void 0&&(this.checks[F]={}),this.checks[F][m.flag]=m,this.debug("WebSocket flag update:",{flag:m.flag,value:m.value,flagCheck:m}),typeof m.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(m),(this.flagCheckListeners[b.flag]?.size>0||this.flagValueListeners[b.flag]?.size>0)&&this.submitFlagCheckEvent(m.flag,m,t),this.notifyFlagCheckListeners(b.flag,m),this.notifyFlagValueListeners(b.flag,m.value)}),this.flushContextDependentEventQueue(),this.setIsPending(!1),o||(o=!0,i())};e.addEventListener("message",c);let d=this.additionalHeaders["X-Schematic-Client-Version"]??`schematic-js@${O}`,g={apiKey:this.apiKey,clientVersion:d,data:t};this.debug("WebSocket sending message:",g),e.send(JSON.stringify(g))};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.isPendingListeners.forEach(t=>Ee(t,e))};getFlagCheck=e=>{let t=R(this.context);return(this.checks[t]??{})[e]};getFlagValue=e=>this.getFlagCheck(e)?.value;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(s=>Re(s,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(s=>we(s,t))}},Ee=(r,e)=>{r.length>0?r(e):r()},Re=(r,e)=>{r.length>0?r(e):r()},we=(r,e)=>{r.length>0?r(e):r()};window.Schematic=I;})();
|
|
3
3
|
/* @preserve */
|
package/dist/schematic.cjs.js
CHANGED
|
@@ -800,7 +800,7 @@ function contextString(context) {
|
|
|
800
800
|
}
|
|
801
801
|
|
|
802
802
|
// src/version.ts
|
|
803
|
-
var version = "1.2.
|
|
803
|
+
var version = "1.2.9";
|
|
804
804
|
|
|
805
805
|
// src/index.ts
|
|
806
806
|
var anonymousIdKey = "schematicId";
|
|
@@ -841,6 +841,8 @@ var Schematic = class {
|
|
|
841
841
|
eventRetryMaxDelay = 3e4;
|
|
842
842
|
// Maximum retry delay in ms
|
|
843
843
|
retryTimer = null;
|
|
844
|
+
flagValueDefaults = {};
|
|
845
|
+
flagCheckDefaults = {};
|
|
844
846
|
constructor(apiKey, options) {
|
|
845
847
|
this.apiKey = apiKey;
|
|
846
848
|
this.eventQueue = [];
|
|
@@ -911,6 +913,12 @@ var Schematic = class {
|
|
|
911
913
|
if (options?.eventRetryMaxDelay !== void 0) {
|
|
912
914
|
this.eventRetryMaxDelay = options.eventRetryMaxDelay;
|
|
913
915
|
}
|
|
916
|
+
if (options?.flagValueDefaults !== void 0) {
|
|
917
|
+
this.flagValueDefaults = options.flagValueDefaults;
|
|
918
|
+
}
|
|
919
|
+
if (options?.flagCheckDefaults !== void 0) {
|
|
920
|
+
this.flagCheckDefaults = options.flagCheckDefaults;
|
|
921
|
+
}
|
|
914
922
|
if (typeof window !== "undefined" && window?.addEventListener) {
|
|
915
923
|
window.addEventListener("beforeunload", () => {
|
|
916
924
|
this.flushEventQueue();
|
|
@@ -935,6 +943,62 @@ var Schematic = class {
|
|
|
935
943
|
this.debug("Initialized with debug mode enabled");
|
|
936
944
|
}
|
|
937
945
|
}
|
|
946
|
+
/**
|
|
947
|
+
* Resolve fallback value according to priority order:
|
|
948
|
+
* 1. Callsite fallback value (if provided)
|
|
949
|
+
* 2. Initialization fallback value (flagValueDefaults)
|
|
950
|
+
* 3. Default to false
|
|
951
|
+
*/
|
|
952
|
+
resolveFallbackValue(key, callsiteFallback) {
|
|
953
|
+
if (callsiteFallback !== void 0) {
|
|
954
|
+
return callsiteFallback;
|
|
955
|
+
}
|
|
956
|
+
if (key in this.flagValueDefaults) {
|
|
957
|
+
return this.flagValueDefaults[key];
|
|
958
|
+
}
|
|
959
|
+
return false;
|
|
960
|
+
}
|
|
961
|
+
/**
|
|
962
|
+
* Resolve complete CheckFlagReturn object according to priority order:
|
|
963
|
+
* 1. Use callsite fallback for boolean value, construct CheckFlagReturn
|
|
964
|
+
* 2. Use flagCheckDefaults if available for this flag
|
|
965
|
+
* 3. Use flagValueDefaults if available for this flag, construct CheckFlagReturn
|
|
966
|
+
* 4. Default CheckFlagReturn with value: false
|
|
967
|
+
*/
|
|
968
|
+
resolveFallbackCheckFlagReturn(key, callsiteFallback, reason = "Fallback value used", error) {
|
|
969
|
+
if (callsiteFallback !== void 0) {
|
|
970
|
+
return {
|
|
971
|
+
flag: key,
|
|
972
|
+
value: callsiteFallback,
|
|
973
|
+
reason,
|
|
974
|
+
error
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
if (key in this.flagCheckDefaults) {
|
|
978
|
+
const defaultReturn = this.flagCheckDefaults[key];
|
|
979
|
+
return {
|
|
980
|
+
...defaultReturn,
|
|
981
|
+
flag: key,
|
|
982
|
+
// Ensure flag matches the requested key
|
|
983
|
+
reason: error !== void 0 ? reason : defaultReturn.reason,
|
|
984
|
+
error
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
if (key in this.flagValueDefaults) {
|
|
988
|
+
return {
|
|
989
|
+
flag: key,
|
|
990
|
+
value: this.flagValueDefaults[key],
|
|
991
|
+
reason,
|
|
992
|
+
error
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
return {
|
|
996
|
+
flag: key,
|
|
997
|
+
value: false,
|
|
998
|
+
reason,
|
|
999
|
+
error
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
938
1002
|
/**
|
|
939
1003
|
* Get value for a single flag.
|
|
940
1004
|
* In WebSocket mode, returns cached values if connection is active, otherwise establishes
|
|
@@ -943,16 +1007,21 @@ var Schematic = class {
|
|
|
943
1007
|
* In REST mode, makes an API call for each check.
|
|
944
1008
|
*/
|
|
945
1009
|
async checkFlag(options) {
|
|
946
|
-
const { fallback
|
|
1010
|
+
const { fallback, key } = options;
|
|
947
1011
|
const context = options.context || this.context;
|
|
948
1012
|
const contextStr = contextString(context);
|
|
949
1013
|
this.debug(`checkFlag: ${key}`, { context, fallback });
|
|
950
1014
|
if (this.isOffline()) {
|
|
1015
|
+
const resolvedFallbackResult = this.resolveFallbackCheckFlagReturn(
|
|
1016
|
+
key,
|
|
1017
|
+
fallback,
|
|
1018
|
+
"Offline mode - using initialization defaults"
|
|
1019
|
+
);
|
|
951
1020
|
this.debug(`checkFlag offline result: ${key}`, {
|
|
952
|
-
value:
|
|
1021
|
+
value: resolvedFallbackResult.value,
|
|
953
1022
|
offlineMode: true
|
|
954
1023
|
});
|
|
955
|
-
return
|
|
1024
|
+
return resolvedFallbackResult.value;
|
|
956
1025
|
}
|
|
957
1026
|
if (!this.useWebSocket) {
|
|
958
1027
|
const requestUrl = `${this.apiUrl}/flags/${key}/check`;
|
|
@@ -980,14 +1049,14 @@ var Schematic = class {
|
|
|
980
1049
|
return result.value;
|
|
981
1050
|
}).catch((error) => {
|
|
982
1051
|
console.error("There was a problem with the fetch operation:", error);
|
|
983
|
-
const errorResult =
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
error
|
|
988
|
-
|
|
1052
|
+
const errorResult = this.resolveFallbackCheckFlagReturn(
|
|
1053
|
+
key,
|
|
1054
|
+
fallback,
|
|
1055
|
+
"API request failed",
|
|
1056
|
+
error instanceof Error ? error.message : String(error)
|
|
1057
|
+
);
|
|
989
1058
|
this.submitFlagCheckEvent(key, errorResult, context);
|
|
990
|
-
return
|
|
1059
|
+
return errorResult.value;
|
|
991
1060
|
});
|
|
992
1061
|
}
|
|
993
1062
|
try {
|
|
@@ -997,7 +1066,7 @@ var Schematic = class {
|
|
|
997
1066
|
return existingVals[key].value;
|
|
998
1067
|
}
|
|
999
1068
|
if (this.isOffline()) {
|
|
1000
|
-
return fallback;
|
|
1069
|
+
return this.resolveFallbackValue(key, fallback);
|
|
1001
1070
|
}
|
|
1002
1071
|
try {
|
|
1003
1072
|
await this.setContext(context);
|
|
@@ -1010,10 +1079,10 @@ var Schematic = class {
|
|
|
1010
1079
|
}
|
|
1011
1080
|
const contextVals = this.checks[contextStr] ?? {};
|
|
1012
1081
|
const flagCheck = contextVals[key];
|
|
1013
|
-
const result = flagCheck?.value ?? fallback;
|
|
1082
|
+
const result = flagCheck?.value ?? this.resolveFallbackValue(key, fallback);
|
|
1014
1083
|
this.debug(
|
|
1015
1084
|
`checkFlag WebSocket result: ${key}`,
|
|
1016
|
-
typeof flagCheck !== "undefined" ? flagCheck : { value:
|
|
1085
|
+
typeof flagCheck !== "undefined" ? flagCheck : { value: result, fallbackUsed: true }
|
|
1017
1086
|
);
|
|
1018
1087
|
if (typeof flagCheck !== "undefined") {
|
|
1019
1088
|
this.submitFlagCheckEvent(key, flagCheck, context);
|
|
@@ -1021,14 +1090,14 @@ var Schematic = class {
|
|
|
1021
1090
|
return result;
|
|
1022
1091
|
} catch (error) {
|
|
1023
1092
|
console.error("Unexpected error in checkFlag:", error);
|
|
1024
|
-
const errorResult =
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
error
|
|
1029
|
-
|
|
1093
|
+
const errorResult = this.resolveFallbackCheckFlagReturn(
|
|
1094
|
+
key,
|
|
1095
|
+
fallback,
|
|
1096
|
+
"Unexpected error in flag check",
|
|
1097
|
+
error instanceof Error ? error.message : String(error)
|
|
1098
|
+
);
|
|
1030
1099
|
this.submitFlagCheckEvent(key, errorResult, context);
|
|
1031
|
-
return
|
|
1100
|
+
return errorResult.value;
|
|
1032
1101
|
}
|
|
1033
1102
|
}
|
|
1034
1103
|
/**
|
|
@@ -1071,11 +1140,12 @@ var Schematic = class {
|
|
|
1071
1140
|
*/
|
|
1072
1141
|
async fallbackToRest(key, context, fallback) {
|
|
1073
1142
|
if (this.isOffline()) {
|
|
1143
|
+
const resolvedFallback = this.resolveFallbackValue(key, fallback);
|
|
1074
1144
|
this.debug(`fallbackToRest offline result: ${key}`, {
|
|
1075
|
-
value:
|
|
1145
|
+
value: resolvedFallback,
|
|
1076
1146
|
offlineMode: true
|
|
1077
1147
|
});
|
|
1078
|
-
return
|
|
1148
|
+
return resolvedFallback;
|
|
1079
1149
|
}
|
|
1080
1150
|
try {
|
|
1081
1151
|
const requestUrl = `${this.apiUrl}/flags/${key}/check`;
|
|
@@ -1102,14 +1172,14 @@ var Schematic = class {
|
|
|
1102
1172
|
return result.value;
|
|
1103
1173
|
} catch (error) {
|
|
1104
1174
|
console.error("REST API call failed, using fallback value:", error);
|
|
1105
|
-
const errorResult =
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
error
|
|
1110
|
-
|
|
1175
|
+
const errorResult = this.resolveFallbackCheckFlagReturn(
|
|
1176
|
+
key,
|
|
1177
|
+
fallback,
|
|
1178
|
+
"API request failed (fallback)",
|
|
1179
|
+
error instanceof Error ? error.message : String(error)
|
|
1180
|
+
);
|
|
1111
1181
|
this.submitFlagCheckEvent(key, errorResult, context);
|
|
1112
|
-
return
|
|
1182
|
+
return errorResult.value;
|
|
1113
1183
|
}
|
|
1114
1184
|
}
|
|
1115
1185
|
/**
|
package/dist/schematic.d.ts
CHANGED
|
@@ -383,7 +383,24 @@ export declare class Schematic {
|
|
|
383
383
|
private eventRetryInitialDelay;
|
|
384
384
|
private eventRetryMaxDelay;
|
|
385
385
|
private retryTimer;
|
|
386
|
+
private flagValueDefaults;
|
|
387
|
+
private flagCheckDefaults;
|
|
386
388
|
constructor(apiKey: string, options?: SchematicOptions);
|
|
389
|
+
/**
|
|
390
|
+
* Resolve fallback value according to priority order:
|
|
391
|
+
* 1. Callsite fallback value (if provided)
|
|
392
|
+
* 2. Initialization fallback value (flagValueDefaults)
|
|
393
|
+
* 3. Default to false
|
|
394
|
+
*/
|
|
395
|
+
private resolveFallbackValue;
|
|
396
|
+
/**
|
|
397
|
+
* Resolve complete CheckFlagReturn object according to priority order:
|
|
398
|
+
* 1. Use callsite fallback for boolean value, construct CheckFlagReturn
|
|
399
|
+
* 2. Use flagCheckDefaults if available for this flag
|
|
400
|
+
* 3. Use flagValueDefaults if available for this flag, construct CheckFlagReturn
|
|
401
|
+
* 4. Default CheckFlagReturn with value: false
|
|
402
|
+
*/
|
|
403
|
+
private resolveFallbackCheckFlagReturn;
|
|
387
404
|
/**
|
|
388
405
|
* Get value for a single flag.
|
|
389
406
|
* In WebSocket mode, returns cached values if connection is active, otherwise establishes
|
|
@@ -547,6 +564,10 @@ export declare type SchematicOptions = {
|
|
|
547
564
|
eventRetryInitialDelay?: number;
|
|
548
565
|
/** Maximum retry delay in milliseconds for failed events (default: 30000) */
|
|
549
566
|
eventRetryMaxDelay?: number;
|
|
567
|
+
/** Default boolean values for flags when Schematic API cannot be reached and no callsite fallback is provided */
|
|
568
|
+
flagValueDefaults?: Record<string, boolean>;
|
|
569
|
+
/** Default CheckFlagReturn objects for flags when Schematic API cannot be reached and no callsite fallback is provided */
|
|
570
|
+
flagCheckDefaults?: Record<string, CheckFlagReturn>;
|
|
550
571
|
};
|
|
551
572
|
|
|
552
573
|
/** Optional type for implementing custom client-side storage */
|
package/dist/schematic.esm.js
CHANGED
|
@@ -781,7 +781,7 @@ function contextString(context) {
|
|
|
781
781
|
}
|
|
782
782
|
|
|
783
783
|
// src/version.ts
|
|
784
|
-
var version = "1.2.
|
|
784
|
+
var version = "1.2.9";
|
|
785
785
|
|
|
786
786
|
// src/index.ts
|
|
787
787
|
var anonymousIdKey = "schematicId";
|
|
@@ -822,6 +822,8 @@ var Schematic = class {
|
|
|
822
822
|
eventRetryMaxDelay = 3e4;
|
|
823
823
|
// Maximum retry delay in ms
|
|
824
824
|
retryTimer = null;
|
|
825
|
+
flagValueDefaults = {};
|
|
826
|
+
flagCheckDefaults = {};
|
|
825
827
|
constructor(apiKey, options) {
|
|
826
828
|
this.apiKey = apiKey;
|
|
827
829
|
this.eventQueue = [];
|
|
@@ -892,6 +894,12 @@ var Schematic = class {
|
|
|
892
894
|
if (options?.eventRetryMaxDelay !== void 0) {
|
|
893
895
|
this.eventRetryMaxDelay = options.eventRetryMaxDelay;
|
|
894
896
|
}
|
|
897
|
+
if (options?.flagValueDefaults !== void 0) {
|
|
898
|
+
this.flagValueDefaults = options.flagValueDefaults;
|
|
899
|
+
}
|
|
900
|
+
if (options?.flagCheckDefaults !== void 0) {
|
|
901
|
+
this.flagCheckDefaults = options.flagCheckDefaults;
|
|
902
|
+
}
|
|
895
903
|
if (typeof window !== "undefined" && window?.addEventListener) {
|
|
896
904
|
window.addEventListener("beforeunload", () => {
|
|
897
905
|
this.flushEventQueue();
|
|
@@ -916,6 +924,62 @@ var Schematic = class {
|
|
|
916
924
|
this.debug("Initialized with debug mode enabled");
|
|
917
925
|
}
|
|
918
926
|
}
|
|
927
|
+
/**
|
|
928
|
+
* Resolve fallback value according to priority order:
|
|
929
|
+
* 1. Callsite fallback value (if provided)
|
|
930
|
+
* 2. Initialization fallback value (flagValueDefaults)
|
|
931
|
+
* 3. Default to false
|
|
932
|
+
*/
|
|
933
|
+
resolveFallbackValue(key, callsiteFallback) {
|
|
934
|
+
if (callsiteFallback !== void 0) {
|
|
935
|
+
return callsiteFallback;
|
|
936
|
+
}
|
|
937
|
+
if (key in this.flagValueDefaults) {
|
|
938
|
+
return this.flagValueDefaults[key];
|
|
939
|
+
}
|
|
940
|
+
return false;
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Resolve complete CheckFlagReturn object according to priority order:
|
|
944
|
+
* 1. Use callsite fallback for boolean value, construct CheckFlagReturn
|
|
945
|
+
* 2. Use flagCheckDefaults if available for this flag
|
|
946
|
+
* 3. Use flagValueDefaults if available for this flag, construct CheckFlagReturn
|
|
947
|
+
* 4. Default CheckFlagReturn with value: false
|
|
948
|
+
*/
|
|
949
|
+
resolveFallbackCheckFlagReturn(key, callsiteFallback, reason = "Fallback value used", error) {
|
|
950
|
+
if (callsiteFallback !== void 0) {
|
|
951
|
+
return {
|
|
952
|
+
flag: key,
|
|
953
|
+
value: callsiteFallback,
|
|
954
|
+
reason,
|
|
955
|
+
error
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
if (key in this.flagCheckDefaults) {
|
|
959
|
+
const defaultReturn = this.flagCheckDefaults[key];
|
|
960
|
+
return {
|
|
961
|
+
...defaultReturn,
|
|
962
|
+
flag: key,
|
|
963
|
+
// Ensure flag matches the requested key
|
|
964
|
+
reason: error !== void 0 ? reason : defaultReturn.reason,
|
|
965
|
+
error
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
if (key in this.flagValueDefaults) {
|
|
969
|
+
return {
|
|
970
|
+
flag: key,
|
|
971
|
+
value: this.flagValueDefaults[key],
|
|
972
|
+
reason,
|
|
973
|
+
error
|
|
974
|
+
};
|
|
975
|
+
}
|
|
976
|
+
return {
|
|
977
|
+
flag: key,
|
|
978
|
+
value: false,
|
|
979
|
+
reason,
|
|
980
|
+
error
|
|
981
|
+
};
|
|
982
|
+
}
|
|
919
983
|
/**
|
|
920
984
|
* Get value for a single flag.
|
|
921
985
|
* In WebSocket mode, returns cached values if connection is active, otherwise establishes
|
|
@@ -924,16 +988,21 @@ var Schematic = class {
|
|
|
924
988
|
* In REST mode, makes an API call for each check.
|
|
925
989
|
*/
|
|
926
990
|
async checkFlag(options) {
|
|
927
|
-
const { fallback
|
|
991
|
+
const { fallback, key } = options;
|
|
928
992
|
const context = options.context || this.context;
|
|
929
993
|
const contextStr = contextString(context);
|
|
930
994
|
this.debug(`checkFlag: ${key}`, { context, fallback });
|
|
931
995
|
if (this.isOffline()) {
|
|
996
|
+
const resolvedFallbackResult = this.resolveFallbackCheckFlagReturn(
|
|
997
|
+
key,
|
|
998
|
+
fallback,
|
|
999
|
+
"Offline mode - using initialization defaults"
|
|
1000
|
+
);
|
|
932
1001
|
this.debug(`checkFlag offline result: ${key}`, {
|
|
933
|
-
value:
|
|
1002
|
+
value: resolvedFallbackResult.value,
|
|
934
1003
|
offlineMode: true
|
|
935
1004
|
});
|
|
936
|
-
return
|
|
1005
|
+
return resolvedFallbackResult.value;
|
|
937
1006
|
}
|
|
938
1007
|
if (!this.useWebSocket) {
|
|
939
1008
|
const requestUrl = `${this.apiUrl}/flags/${key}/check`;
|
|
@@ -961,14 +1030,14 @@ var Schematic = class {
|
|
|
961
1030
|
return result.value;
|
|
962
1031
|
}).catch((error) => {
|
|
963
1032
|
console.error("There was a problem with the fetch operation:", error);
|
|
964
|
-
const errorResult =
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
error
|
|
969
|
-
|
|
1033
|
+
const errorResult = this.resolveFallbackCheckFlagReturn(
|
|
1034
|
+
key,
|
|
1035
|
+
fallback,
|
|
1036
|
+
"API request failed",
|
|
1037
|
+
error instanceof Error ? error.message : String(error)
|
|
1038
|
+
);
|
|
970
1039
|
this.submitFlagCheckEvent(key, errorResult, context);
|
|
971
|
-
return
|
|
1040
|
+
return errorResult.value;
|
|
972
1041
|
});
|
|
973
1042
|
}
|
|
974
1043
|
try {
|
|
@@ -978,7 +1047,7 @@ var Schematic = class {
|
|
|
978
1047
|
return existingVals[key].value;
|
|
979
1048
|
}
|
|
980
1049
|
if (this.isOffline()) {
|
|
981
|
-
return fallback;
|
|
1050
|
+
return this.resolveFallbackValue(key, fallback);
|
|
982
1051
|
}
|
|
983
1052
|
try {
|
|
984
1053
|
await this.setContext(context);
|
|
@@ -991,10 +1060,10 @@ var Schematic = class {
|
|
|
991
1060
|
}
|
|
992
1061
|
const contextVals = this.checks[contextStr] ?? {};
|
|
993
1062
|
const flagCheck = contextVals[key];
|
|
994
|
-
const result = flagCheck?.value ?? fallback;
|
|
1063
|
+
const result = flagCheck?.value ?? this.resolveFallbackValue(key, fallback);
|
|
995
1064
|
this.debug(
|
|
996
1065
|
`checkFlag WebSocket result: ${key}`,
|
|
997
|
-
typeof flagCheck !== "undefined" ? flagCheck : { value:
|
|
1066
|
+
typeof flagCheck !== "undefined" ? flagCheck : { value: result, fallbackUsed: true }
|
|
998
1067
|
);
|
|
999
1068
|
if (typeof flagCheck !== "undefined") {
|
|
1000
1069
|
this.submitFlagCheckEvent(key, flagCheck, context);
|
|
@@ -1002,14 +1071,14 @@ var Schematic = class {
|
|
|
1002
1071
|
return result;
|
|
1003
1072
|
} catch (error) {
|
|
1004
1073
|
console.error("Unexpected error in checkFlag:", error);
|
|
1005
|
-
const errorResult =
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
error
|
|
1010
|
-
|
|
1074
|
+
const errorResult = this.resolveFallbackCheckFlagReturn(
|
|
1075
|
+
key,
|
|
1076
|
+
fallback,
|
|
1077
|
+
"Unexpected error in flag check",
|
|
1078
|
+
error instanceof Error ? error.message : String(error)
|
|
1079
|
+
);
|
|
1011
1080
|
this.submitFlagCheckEvent(key, errorResult, context);
|
|
1012
|
-
return
|
|
1081
|
+
return errorResult.value;
|
|
1013
1082
|
}
|
|
1014
1083
|
}
|
|
1015
1084
|
/**
|
|
@@ -1052,11 +1121,12 @@ var Schematic = class {
|
|
|
1052
1121
|
*/
|
|
1053
1122
|
async fallbackToRest(key, context, fallback) {
|
|
1054
1123
|
if (this.isOffline()) {
|
|
1124
|
+
const resolvedFallback = this.resolveFallbackValue(key, fallback);
|
|
1055
1125
|
this.debug(`fallbackToRest offline result: ${key}`, {
|
|
1056
|
-
value:
|
|
1126
|
+
value: resolvedFallback,
|
|
1057
1127
|
offlineMode: true
|
|
1058
1128
|
});
|
|
1059
|
-
return
|
|
1129
|
+
return resolvedFallback;
|
|
1060
1130
|
}
|
|
1061
1131
|
try {
|
|
1062
1132
|
const requestUrl = `${this.apiUrl}/flags/${key}/check`;
|
|
@@ -1083,14 +1153,14 @@ var Schematic = class {
|
|
|
1083
1153
|
return result.value;
|
|
1084
1154
|
} catch (error) {
|
|
1085
1155
|
console.error("REST API call failed, using fallback value:", error);
|
|
1086
|
-
const errorResult =
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
error
|
|
1091
|
-
|
|
1156
|
+
const errorResult = this.resolveFallbackCheckFlagReturn(
|
|
1157
|
+
key,
|
|
1158
|
+
fallback,
|
|
1159
|
+
"API request failed (fallback)",
|
|
1160
|
+
error instanceof Error ? error.message : String(error)
|
|
1161
|
+
);
|
|
1092
1162
|
this.submitFlagCheckEvent(key, errorResult, context);
|
|
1093
|
-
return
|
|
1163
|
+
return errorResult.value;
|
|
1094
1164
|
}
|
|
1095
1165
|
}
|
|
1096
1166
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schematichq/schematic-js",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.9",
|
|
4
4
|
"main": "dist/schematic.cjs.js",
|
|
5
5
|
"module": "dist/schematic.esm.js",
|
|
6
6
|
"types": "dist/schematic.d.ts",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@eslint/js": "^9.39.1",
|
|
41
41
|
"@microsoft/api-extractor": "^7.55.0",
|
|
42
42
|
"@openapitools/openapi-generator-cli": "^2.25.1",
|
|
43
|
-
"@vitest/browser": "^4.0.
|
|
43
|
+
"@vitest/browser": "^4.0.10",
|
|
44
44
|
"esbuild": "^0.27.0",
|
|
45
45
|
"eslint": "^9.39.1",
|
|
46
46
|
"globals": "^16.5.0",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"prettier": "^3.6.2",
|
|
52
52
|
"typescript": "^5.9.3",
|
|
53
53
|
"typescript-eslint": "^8.47.0",
|
|
54
|
-
"vitest": "^4.0.
|
|
54
|
+
"vitest": "^4.0.10"
|
|
55
55
|
},
|
|
56
56
|
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
57
57
|
}
|