@schematichq/schematic-js 1.2.3 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
- "use strict";(()=>{var ne=Object.create;var $=Object.defineProperty;var se=Object.getOwnPropertyDescriptor;var ae=Object.getOwnPropertyNames;var ie=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var le=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports);var ue=(n,e,r,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of ae(e))!oe.call(n,a)&&a!==r&&$(n,a,{get:()=>e[a],enumerable:!(s=se(e,a))||s.enumerable});return n};var ce=(n,e,r)=>(r=n!=null?ne(ie(n)):{},ue(e||!n||!n.__esModule?$(r,"default",{value:n,enumerable:!0}):r,n));var X=le(z=>{(function(n){var e=function(r){var s=typeof globalThis<"u"&&globalThis||typeof n<"u"&&n||typeof global<"u"&&global||{},a={searchParams:"URLSearchParams"in s,iterable:"Symbol"in s&&"iterator"in Symbol,blob:"FileReader"in s&&"Blob"in s&&function(){try{return new Blob,!0}catch{return!1}}(),formData:"FormData"in s,arrayBuffer:"ArrayBuffer"in s};function f(t){return t&&DataView.prototype.isPrototypeOf(t)}if(a.arrayBuffer)var o=["[object Int8Array]","[object Uint8Array]","[object Uint8ClampedArray]","[object Int16Array]","[object Uint16Array]","[object Int32Array]","[object Uint32Array]","[object Float32Array]","[object Float64Array]"],u=ArrayBuffer.isView||function(t){return t&&o.indexOf(Object.prototype.toString.call(t))>-1};function d(t){if(typeof t!="string"&&(t=String(t)),/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(t)||t==="")throw new TypeError('Invalid character in header field name: "'+t+'"');return t.toLowerCase()}function y(t){return typeof t!="string"&&(t=String(t)),t}function F(t){var i={next:function(){var l=t.shift();return{done:l===void 0,value:l}}};return a.iterable&&(i[Symbol.iterator]=function(){return i}),i}function g(t){this.map={},t instanceof g?t.forEach(function(i,l){this.append(l,i)},this):Array.isArray(t)?t.forEach(function(i){if(i.length!=2)throw new TypeError("Headers constructor: expected name/value pair to be length 2, found"+i.length);this.append(i[0],i[1])},this):t&&Object.getOwnPropertyNames(t).forEach(function(i){this.append(i,t[i])},this)}g.prototype.append=function(t,i){t=d(t),i=y(i);var l=this.map[t];this.map[t]=l?l+", "+i:i},g.prototype.delete=function(t){delete this.map[d(t)]},g.prototype.get=function(t){return t=d(t),this.has(t)?this.map[t]:null},g.prototype.has=function(t){return this.map.hasOwnProperty(d(t))},g.prototype.set=function(t,i){this.map[d(t)]=y(i)},g.prototype.forEach=function(t,i){for(var l in this.map)this.map.hasOwnProperty(l)&&t.call(i,this.map[l],l,this)},g.prototype.keys=function(){var t=[];return this.forEach(function(i,l){t.push(l)}),F(t)},g.prototype.values=function(){var t=[];return this.forEach(function(i){t.push(i)}),F(t)},g.prototype.entries=function(){var t=[];return this.forEach(function(i,l){t.push([l,i])}),F(t)},a.iterable&&(g.prototype[Symbol.iterator]=g.prototype.entries);function v(t){if(!t._noBody){if(t.bodyUsed)return Promise.reject(new TypeError("Already read"));t.bodyUsed=!0}}function m(t){return new Promise(function(i,l){t.onload=function(){i(t.result)},t.onerror=function(){l(t.error)}})}function S(t){var i=new FileReader,l=m(i);return i.readAsArrayBuffer(t),l}function V(t){var i=new FileReader,l=m(i),h=/charset=([A-Za-z0-9_-]+)/.exec(t.type),p=h?h[1]:"utf-8";return i.readAsText(t,p),l}function Y(t){for(var i=new Uint8Array(t),l=new Array(i.length),h=0;h<i.length;h++)l[h]=String.fromCharCode(i[h]);return l.join("")}function q(t){if(t.slice)return t.slice(0);var i=new Uint8Array(t.byteLength);return i.set(new Uint8Array(t)),i.buffer}function H(){return this.bodyUsed=!1,this._initBody=function(t){this.bodyUsed=this.bodyUsed,this._bodyInit=t,t?typeof t=="string"?this._bodyText=t:a.blob&&Blob.prototype.isPrototypeOf(t)?this._bodyBlob=t:a.formData&&FormData.prototype.isPrototypeOf(t)?this._bodyFormData=t:a.searchParams&&URLSearchParams.prototype.isPrototypeOf(t)?this._bodyText=t.toString():a.arrayBuffer&&a.blob&&f(t)?(this._bodyArrayBuffer=q(t.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer])):a.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(t)||u(t))?this._bodyArrayBuffer=q(t):this._bodyText=t=Object.prototype.toString.call(t):(this._noBody=!0,this._bodyText=""),this.headers.get("content-type")||(typeof t=="string"?this.headers.set("content-type","text/plain;charset=UTF-8"):this._bodyBlob&&this._bodyBlob.type?this.headers.set("content-type",this._bodyBlob.type):a.searchParams&&URLSearchParams.prototype.isPrototypeOf(t)&&this.headers.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"))},a.blob&&(this.blob=function(){var t=v(this);if(t)return t;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 t=v(this);return t||(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(a.blob)return this.blob().then(S);throw new Error("could not read as ArrayBuffer")}},this.text=function(){var t=v(this);if(t)return t;if(this._bodyBlob)return V(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)},a.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(t){var i=t.toUpperCase();return Z.indexOf(i)>-1?i:t}function R(t,i){if(!(this instanceof R))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');i=i||{};var l=i.body;if(t instanceof R){if(t.bodyUsed)throw new TypeError("Already read");this.url=t.url,this.credentials=t.credentials,i.headers||(this.headers=new g(t.headers)),this.method=t.method,this.mode=t.mode,this.signal=t.signal,!l&&t._bodyInit!=null&&(l=t._bodyInit,t.bodyUsed=!0)}else this.url=String(t);if(this.credentials=i.credentials||this.credentials||"same-origin",(i.headers||!this.headers)&&(this.headers=new g(i.headers)),this.method=j(i.method||this.method||"GET"),this.mode=i.mode||this.mode||null,this.signal=i.signal||this.signal||function(){if("AbortController"in s){var c=new AbortController;return c.signal}}(),this.referrer=null,(this.method==="GET"||this.method==="HEAD")&&l)throw new TypeError("Body not allowed for GET or HEAD requests");if(this._initBody(l),(this.method==="GET"||this.method==="HEAD")&&(i.cache==="no-store"||i.cache==="no-cache")){var h=/([?&])_=[^&]*/;if(h.test(this.url))this.url=this.url.replace(h,"$1_="+new Date().getTime());else{var p=/\?/;this.url+=(p.test(this.url)?"&":"?")+"_="+new Date().getTime()}}}R.prototype.clone=function(){return new R(this,{body:this._bodyInit})};function ee(t){var i=new FormData;return t.trim().split("&").forEach(function(l){if(l){var h=l.split("="),p=h.shift().replace(/\+/g," "),c=h.join("=").replace(/\+/g," ");i.append(decodeURIComponent(p),decodeURIComponent(c))}}),i}function te(t){var i=new g,l=t.replace(/\r?\n[\t ]+/g," ");return l.split("\r").map(function(h){return h.indexOf(`
2
- `)===0?h.substr(1,h.length):h}).forEach(function(h){var p=h.split(":"),c=p.shift().trim();if(c){var U=p.join(":").trim();try{i.append(c,U)}catch(A){console.warn("Response "+A.message)}}}),i}H.call(R.prototype);function E(t,i){if(!(this instanceof E))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');if(i||(i={}),this.type="default",this.status=i.status===void 0?200:i.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=i.statusText===void 0?"":""+i.statusText,this.headers=new g(i.headers),this.url=i.url||"",this._initBody(t)}H.call(E.prototype),E.prototype.clone=function(){return new E(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new g(this.headers),url:this.url})},E.error=function(){var t=new E(null,{status:200,statusText:""});return t.ok=!1,t.status=0,t.type="error",t};var re=[301,302,303,307,308];E.redirect=function(t,i){if(re.indexOf(i)===-1)throw new RangeError("Invalid status code");return new E(null,{status:i,headers:{location:t}})},r.DOMException=s.DOMException;try{new r.DOMException}catch{r.DOMException=function(i,l){this.message=i,this.name=l;var h=Error(i);this.stack=h.stack},r.DOMException.prototype=Object.create(Error.prototype),r.DOMException.prototype.constructor=r.DOMException}function I(t,i){return new Promise(function(l,h){var p=new R(t,i);if(p.signal&&p.signal.aborted)return h(new r.DOMException("Aborted","AbortError"));var c=new XMLHttpRequest;function U(){c.abort()}c.onload=function(){var b={statusText:c.statusText,headers:te(c.getAllResponseHeaders()||"")};p.url.indexOf("file://")===0&&(c.status<200||c.status>599)?b.status=200:b.status=c.status,b.url="responseURL"in c?c.responseURL:b.headers.get("X-Request-URL");var w="response"in c?c.response:c.responseText;setTimeout(function(){l(new E(w,b))},0)},c.onerror=function(){setTimeout(function(){h(new TypeError("Network request failed"))},0)},c.ontimeout=function(){setTimeout(function(){h(new TypeError("Network request timed out"))},0)},c.onabort=function(){setTimeout(function(){h(new r.DOMException("Aborted","AbortError"))},0)};function A(b){try{return b===""&&s.location.href?s.location.href:b}catch{return b}}if(c.open(p.method,A(p.url),!0),p.credentials==="include"?c.withCredentials=!0:p.credentials==="omit"&&(c.withCredentials=!1),"responseType"in c&&(a.blob?c.responseType="blob":a.arrayBuffer&&(c.responseType="arraybuffer")),i&&typeof i.headers=="object"&&!(i.headers instanceof g||s.Headers&&i.headers instanceof s.Headers)){var W=[];Object.getOwnPropertyNames(i.headers).forEach(function(b){W.push(d(b)),c.setRequestHeader(b,y(i.headers[b]))}),p.headers.forEach(function(b,w){W.indexOf(w)===-1&&c.setRequestHeader(w,b)})}else p.headers.forEach(function(b,w){c.setRequestHeader(w,b)});p.signal&&(p.signal.addEventListener("abort",U),c.onreadystatechange=function(){c.readyState===4&&p.signal.removeEventListener("abort",U)}),c.send(typeof p._bodyInit>"u"?null:p._bodyInit)})}return I.polyfill=!0,s.fetch||(s.fetch=I,s.Headers=g,s.Request=R,s.Response=E),r.Headers=g,r.Request=R,r.Response=E,r.fetch=I,r}({})})(typeof self<"u"?self:z)});var k=[];for(let n=0;n<256;++n)k.push((n+256).toString(16).slice(1));function K(n,e=0){return(k[n[e+0]]+k[n[e+1]]+k[n[e+2]]+k[n[e+3]]+"-"+k[n[e+4]]+k[n[e+5]]+"-"+k[n[e+6]]+k[n[e+7]]+"-"+k[n[e+8]]+k[n[e+9]]+"-"+k[n[e+10]]+k[n[e+11]]+k[n[e+12]]+k[n[e+13]]+k[n[e+14]]+k[n[e+15]]).toLowerCase()}var P,fe=new Uint8Array(16);function L(){if(!P){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");P=crypto.getRandomValues.bind(crypto)}return P(fe)}var de=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),B={randomUUID:de};function he(n,e,r){if(B.randomUUID&&!e&&!n)return B.randomUUID();n=n||{};let s=n.random??n.rng?.()??L();if(s.length<16)throw new Error("Random bytes length must be >= 16");if(s[6]=s[6]&15|64,s[8]=s[8]&63|128,e){if(r=r||0,r<0||r+16>e.length)throw new RangeError(`UUID byte range ${r}:${r+15} is out of buffer bounds`);for(let a=0;a<16;++a)e[r+a]=s[a];return e}return K(s)}var _=he;var rt=ce(X());function x(n){return pe(n,!1)}function pe(n,e){return n==null?n:{companyId:n.company_id==null?void 0:n.company_id,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 ye(n,!1)}function ye(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 T(n){return be(n,!1)}function be(n,e){return n==null?n:{data:x(n.data),params:n.params}}function G(n){return ke(n,!1)}function ke(n,e){return n==null?n:{flags:n.flags.map(x)}}function J(n){return ve(n,!1)}function ve(n,e){return n==null?n:{data:G(n.data),params:n.params}}var O=n=>{let{companyId:e,error:r,featureAllocation:s,featureUsage:a,featureUsageEvent:f,featureUsagePeriod:o,featureUsageResetAt:u,flag:d,flagId:y,reason:F,ruleId:g,ruleType:v,userId:m,value:S}=x(n);return{featureUsageExceeded:!S&&(v=="company_override_usage_exceeded"||v=="plan_entitlement_usage_exceeded"),companyId:e??void 0,error:r??void 0,featureAllocation:s??void 0,featureUsage:a??void 0,featureUsageEvent:f===null?void 0:f,featureUsagePeriod:o??void 0,featureUsageResetAt:u??void 0,flag:d,flagId:y??void 0,reason:F,ruleId:g??void 0,ruleType:v??void 0,userId:m??void 0,value:S}};function C(n){let e=Object.keys(n).reduce((r,s)=>{let f=Object.keys(n[s]||{}).sort().reduce((o,u)=>(o[u]=n[s][u],o),{});return r[s]=f,r},{});return JSON.stringify(e)}var M="1.2.3";var Q="schematicId";var D=class{additionalHeaders={};apiKey;apiUrl="https://api.schematichq.com";conn=null;context={};debugEnabled=!1;offlineEnabled=!1;eventQueue;eventUrl="https://c.schematichq.com";flagCheckListeners={};flagValueListeners={};isPending=!0;isPendingListeners=new Set;storage;useWebSocket=!1;checks={};featureUsageEventMap={};webSocketUrl="wss://api.schematichq.com";constructor(e,r){if(this.apiKey=e,this.eventQueue=[],this.useWebSocket=r?.useWebSocket??!1,this.debugEnabled=r?.debug??!1,this.offlineEnabled=r?.offline??!1,typeof window<"u"&&typeof window.location<"u"){let s=new URLSearchParams(window.location.search),a=s.get("schematic_debug");a!==null&&(a===""||a==="true"||a==="1")&&(this.debugEnabled=!0);let f=s.get("schematic_offline");f!==null&&(f===""||f==="true"||f==="1")&&(this.offlineEnabled=!0,this.debugEnabled=!0)}this.offlineEnabled&&r?.debug!==!1&&(this.debugEnabled=!0),this.offlineEnabled&&this.setIsPending(!1),this.additionalHeaders={"X-Schematic-Client-Version":`schematic-js@${M}`,...r?.additionalHeaders??{}},r?.storage?this.storage=r.storage:typeof localStorage<"u"&&(this.storage=localStorage),r?.apiUrl!==void 0&&(this.apiUrl=r.apiUrl),r?.eventUrl!==void 0&&(this.eventUrl=r.eventUrl),r?.webSocketUrl!==void 0&&(this.webSocketUrl=r.webSocketUrl),typeof window<"u"&&window?.addEventListener&&window.addEventListener("beforeunload",()=>{this.flushEventQueue()}),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(e){let{fallback:r=!1,key:s}=e,a=e.context||this.context,f=C(a);if(this.debug(`checkFlag: ${s}`,{context:a,fallback:r}),this.isOffline())return this.debug(`checkFlag offline result: ${s}`,{value:r,offlineMode:!0}),r;if(!this.useWebSocket){let o=`${this.apiUrl}/flags/${s}/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(a)}).then(u=>{if(!u.ok)throw new Error("Network response was not ok");return u.json()}).then(u=>{let d=T(u);this.debug(`checkFlag result: ${s}`,d);let y=O(d.data);return typeof y.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(y),this.submitFlagCheckEvent(s,y,a),y.value}).catch(u=>{console.error("There was a problem with the fetch operation:",u);let d={flag:s,value:r,reason:"API request failed",error:u instanceof Error?u.message:String(u)};return this.submitFlagCheckEvent(s,d,a),r})}try{let o=this.checks[f];if(this.conn!==null&&typeof o<"u"&&typeof o[s]<"u")return this.debug(`checkFlag cached result: ${s}`,o[s]),o[s].value;if(this.isOffline())return r;try{await this.setContext(a)}catch(F){return console.error("WebSocket connection failed, falling back to REST:",F),this.fallbackToRest(s,a,r)}let d=(this.checks[f]??{})[s],y=d?.value??r;return this.debug(`checkFlag WebSocket result: ${s}`,typeof d<"u"?d:{value:r,fallbackUsed:!0}),typeof d<"u"&&this.submitFlagCheckEvent(s,d,a),y}catch(o){console.error("Unexpected error in checkFlag:",o);let u={flag:s,value:r,reason:"Unexpected error in flag check",error:o instanceof Error?o.message:String(o)};return this.submitFlagCheckEvent(s,u,a),r}}debug(e,...r){this.debugEnabled&&console.log(`[Schematic] ${e}`,...r)}isOffline(){return this.offlineEnabled}submitFlagCheckEvent(e,r,s){let a={flagKey:e,value:r.value,reason:r.reason,flagId:r.flagId,ruleId:r.ruleId,companyId:r.companyId,userId:r.userId,error:r.error,reqCompany:s.company,reqUser:s.user};return this.debug("submitting flag check event:",a),this.handleEvent("flag_check",N(a))}async fallbackToRest(e,r,s){if(this.isOffline())return this.debug(`fallbackToRest offline result: ${e}`,{value:s,offlineMode:!0}),s;try{let a=`${this.apiUrl}/flags/${e}/check`,f=await fetch(a,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:JSON.stringify(r)});if(!f.ok)throw new Error("Network response was not ok");let o=await f.json(),u=T(o);this.debug(`fallbackToRest result: ${e}`,u);let d=O(u.data);return typeof d.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(d),this.submitFlagCheckEvent(e,d,r),d.value}catch(a){console.error("REST API call failed, using fallback value:",a);let f={flag:e,value:s,reason:"API request failed (fallback)",error:a instanceof Error?a.message:String(a)};return this.submitFlagCheckEvent(e,f,r),s}}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 r=`${this.apiUrl}/flags/check`,s=JSON.stringify(e);return fetch(r,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:s}).then(a=>{if(!a.ok)throw new Error("Network response was not ok");return a.json()}).then(a=>{let f=J(a);return this.debug("checkFlags result:",f),(f?.data?.flags??[]).reduce((o,u)=>(o[u.flag]=u.value,o),{})}).catch(a=>(console.error("There was a problem with the fetch operation:",a),{}))};identify=e=>{this.debug("identify:",e);try{this.setContext({company:e.company?.keys,user:e.keys})}catch(r){console.error("Error setting context:",r)}return this.handleEvent("identify",e)};setContext=async e=>{if(this.isOffline()||!this.useWebSocket)return this.context=e,this.setIsPending(!1),Promise.resolve();try{this.setIsPending(!0),this.conn||(this.conn=this.wsConnect());let r=await this.conn;await this.wsSendMessage(r,e)}catch(r){throw console.error("Failed to establish WebSocket connection:",r),r}};track=e=>{let{company:r,user:s,event:a,traits:f,quantity:o=1}=e,u={company:r??this.context.company,event:a,traits:f??{},user:s??this.context.user,quantity:o};return this.debug("track:",u),a in this.featureUsageEventMap&&this.optimisticallyUpdateFeatureUsage(a,o),this.handleEvent("track",u)};optimisticallyUpdateFeatureUsage=(e,r=1)=>{let s=this.featureUsageEventMap[e];s!=null&&(this.debug(`Optimistically updating feature usage for event: ${e}`,{quantity:r}),Object.entries(s).forEach(([a,f])=>{if(f===void 0)return;let o={...f};if(typeof o.featureUsage=="number"){if(o.featureUsage+=r,typeof o.featureAllocation=="number"){let d=o.featureUsageExceeded===!0,y=o.featureUsage>=o.featureAllocation;y!==d&&(o.featureUsageExceeded=y,y&&(o.value=!1),this.debug(`Usage limit status changed for flag: ${a}`,{was:d?"exceeded":"within limits",now:y?"exceeded":"within limits",featureUsage:o.featureUsage,featureAllocation:o.featureAllocation,value:o.value}))}this.featureUsageEventMap[e]!==void 0&&(this.featureUsageEventMap[e][a]=o);let u=C(this.context);this.checks[u]!==void 0&&this.checks[u]!==null&&(this.checks[u][a]=o),this.notifyFlagCheckListeners(a,o),this.notifyFlagValueListeners(a,o.value)}}))};flushEventQueue=()=>{for(;this.eventQueue.length>0;){let e=this.eventQueue.shift();e&&this.sendEvent(e)}};getAnonymousId=()=>{if(!this.storage)return _();let e=this.storage.getItem(Q);if(typeof e<"u")return e;let r=_();return this.storage.setItem(Q,r),r};handleEvent=(e,r)=>{let s={api_key:this.apiKey,body:r,sent_at:new Date().toISOString(),tracker_event_id:_(),tracker_user_id:this.getAnonymousId(),type:e};return document?.hidden?this.storeEvent(s):this.sendEvent(s)};sendEvent=async e=>{let r=`${this.eventUrl}/e`,s=JSON.stringify(e);if(this.debug("sending event:",{url:r,event:e}),this.isOffline())return this.debug("event not sent (offline mode):",{event:e}),Promise.resolve();try{let a=await fetch(r,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8"},body:s});this.debug("event sent:",{status:a.status,statusText:a.statusText})}catch(a){console.error("Error sending Schematic event: ",a)}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.conn)try{(await this.conn).close()}catch(e){console.error("Error during cleanup:",e)}finally{this.conn=null}};wsConnect=()=>this.isOffline()?(this.debug("wsConnect: skipped (offline mode)"),Promise.reject(new Error("WebSocket connection skipped in offline mode"))):new Promise((e,r)=>{let s=`${this.webSocketUrl}/flags/bootstrap?apiKey=${this.apiKey}`;this.debug("connecting to WebSocket:",s);let a=new WebSocket(s);a.onopen=()=>{this.debug("WebSocket connection opened"),e(a)},a.onerror=f=>{this.debug("WebSocket connection error:",f),r(f)},a.onclose=()=>{this.debug("WebSocket connection closed"),this.conn=null}});wsSendMessage=(e,r)=>this.isOffline()?(this.debug("wsSendMessage: skipped (offline mode)"),this.setIsPending(!1),Promise.resolve()):new Promise((s,a)=>{if(C(r)==C(this.context))return this.debug("WebSocket context unchanged, skipping update"),s(this.setIsPending(!1));this.debug("WebSocket context updated:",r),this.context=r;let f=()=>{let o=!1,u=F=>{let g=JSON.parse(F.data);this.debug("WebSocket message received:",g),C(r)in this.checks||(this.checks[C(r)]={}),(g.flags??[]).forEach(v=>{let m=O(v),S=C(r);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[v.flag]?.size>0||this.flagValueListeners[v.flag]?.size>0)&&this.submitFlagCheckEvent(m.flag,m,r),this.notifyFlagCheckListeners(v.flag,m),this.notifyFlagValueListeners(v.flag,m.value)}),this.setIsPending(!1),o||(o=!0,s())};e.addEventListener("message",u);let d=this.additionalHeaders["X-Schematic-Client-Version"]??`schematic-js@${M}`,y={apiKey:this.apiKey,clientVersion:d,data:r};this.debug("WebSocket sending message:",y),e.send(JSON.stringify(y))};e.readyState===WebSocket.OPEN?(this.debug("WebSocket already open, sending message"),f()):e.readyState===WebSocket.CONNECTING?(this.debug("WebSocket connecting, waiting for open to send message"),e.addEventListener("open",f)):(this.debug("WebSocket is closed, cannot send message"),a("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(r=>Ee(r,e))};getFlagCheck=e=>{let r=C(this.context);return(this.checks[r]??{})[e]};getFlagValue=e=>this.getFlagCheck(e)?.value;addFlagValueListener=(e,r)=>(e in this.flagValueListeners||(this.flagValueListeners[e]=new Set),this.flagValueListeners[e].add(r),()=>{this.flagValueListeners[e].delete(r)});addFlagCheckListener=(e,r)=>(e in this.flagCheckListeners||(this.flagCheckListeners[e]=new Set),this.flagCheckListeners[e].add(r),()=>{this.flagCheckListeners[e].delete(r)});notifyFlagCheckListeners=(e,r)=>{let s=this.flagCheckListeners?.[e]??[];s.size>0&&this.debug(`Notifying ${s.size} flag check listeners for ${e}`,r),typeof r.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(r),s.forEach(a=>Fe(a,r))};updateFeatureUsageEventMap=e=>{if(typeof e.featureUsageEvent!="string")return;let r=e.featureUsageEvent;(this.featureUsageEventMap[r]===void 0||this.featureUsageEventMap[r]===null)&&(this.featureUsageEventMap[r]={}),this.featureUsageEventMap[r]!==void 0&&(this.featureUsageEventMap[r][e.flag]=e),this.debug(`Updated featureUsageEventMap for event: ${r}, flag: ${e.flag}`,e)};notifyFlagValueListeners=(e,r)=>{let s=this.flagValueListeners?.[e]??[];s.size>0&&this.debug(`Notifying ${s.size} flag value listeners for ${e}`,{value:r}),s.forEach(a=>Ce(a,r))}},Ee=(n,e)=>{n.length>0?n(e):n()},Fe=(n,e)=>{n.length>0?n(e):n()},Ce=(n,e)=>{n.length>0?n(e):n()};window.Schematic=D;})();
1
+ "use strict";(()=>{var re=Object.create;var W=Object.defineProperty;var se=Object.getOwnPropertyDescriptor;var ae=Object.getOwnPropertyNames;var ie=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var le=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports);var ue=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of ae(e))!oe.call(r,a)&&a!==t&&W(r,a,{get:()=>e[a],enumerable:!(s=se(e,a))||s.enumerable});return r};var ce=(r,e,t)=>(t=r!=null?re(ie(r)):{},ue(e||!r||!r.__esModule?W(t,"default",{value:r,enumerable:!0}):t,r));var z=le(Q=>{(function(r){var e=(function(t){var s=typeof globalThis<"u"&&globalThis||typeof r<"u"&&r||typeof global<"u"&&global||{},a={searchParams:"URLSearchParams"in s,iterable:"Symbol"in s&&"iterator"in Symbol,blob:"FileReader"in s&&"Blob"in s&&(function(){try{return new Blob,!0}catch{return!1}})(),formData:"FormData"in s,arrayBuffer:"ArrayBuffer"in s};function c(n){return n&&DataView.prototype.isPrototypeOf(n)}if(a.arrayBuffer)var o=["[object Int8Array]","[object Uint8Array]","[object Uint8ClampedArray]","[object Int16Array]","[object Uint16Array]","[object Int32Array]","[object Uint32Array]","[object Float32Array]","[object Float64Array]"],u=ArrayBuffer.isView||function(n){return n&&o.indexOf(Object.prototype.toString.call(n))>-1};function f(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 y(n){return typeof n!="string"&&(n=String(n)),n}function F(n){var i={next:function(){var l=n.shift();return{done:l===void 0,value:l}}};return a.iterable&&(i[Symbol.iterator]=function(){return i}),i}function g(n){this.map={},n instanceof g?n.forEach(function(i,l){this.append(l,i)},this):Array.isArray(n)?n.forEach(function(i){if(i.length!=2)throw new TypeError("Headers constructor: expected name/value pair to be length 2, found"+i.length);this.append(i[0],i[1])},this):n&&Object.getOwnPropertyNames(n).forEach(function(i){this.append(i,n[i])},this)}g.prototype.append=function(n,i){n=f(n),i=y(i);var l=this.map[n];this.map[n]=l?l+", "+i:i},g.prototype.delete=function(n){delete this.map[f(n)]},g.prototype.get=function(n){return n=f(n),this.has(n)?this.map[n]:null},g.prototype.has=function(n){return this.map.hasOwnProperty(f(n))},g.prototype.set=function(n,i){this.map[f(n)]=y(i)},g.prototype.forEach=function(n,i){for(var l in this.map)this.map.hasOwnProperty(l)&&n.call(i,this.map[l],l,this)},g.prototype.keys=function(){var n=[];return this.forEach(function(i,l){n.push(l)}),F(n)},g.prototype.values=function(){var n=[];return this.forEach(function(i){n.push(i)}),F(n)},g.prototype.entries=function(){var n=[];return this.forEach(function(i,l){n.push([l,i])}),F(n)},a.iterable&&(g.prototype[Symbol.iterator]=g.prototype.entries);function k(n){if(!n._noBody){if(n.bodyUsed)return Promise.reject(new TypeError("Already read"));n.bodyUsed=!0}}function m(n){return new Promise(function(i,l){n.onload=function(){i(n.result)},n.onerror=function(){l(n.error)}})}function x(n){var i=new FileReader,l=m(i);return i.readAsArrayBuffer(n),l}function V(n){var i=new FileReader,l=m(i),h=/charset=([A-Za-z0-9_-]+)/.exec(n.type),p=h?h[1]:"utf-8";return i.readAsText(n,p),l}function Y(n){for(var i=new Uint8Array(n),l=new Array(i.length),h=0;h<i.length;h++)l[h]=String.fromCharCode(i[h]);return l.join("")}function q(n){if(n.slice)return n.slice(0);var i=new Uint8Array(n.byteLength);return i.set(new Uint8Array(n)),i.buffer}function $(){return this.bodyUsed=!1,this._initBody=function(n){this.bodyUsed=this.bodyUsed,this._bodyInit=n,n?typeof n=="string"?this._bodyText=n:a.blob&&Blob.prototype.isPrototypeOf(n)?this._bodyBlob=n:a.formData&&FormData.prototype.isPrototypeOf(n)?this._bodyFormData=n:a.searchParams&&URLSearchParams.prototype.isPrototypeOf(n)?this._bodyText=n.toString():a.arrayBuffer&&a.blob&&c(n)?(this._bodyArrayBuffer=q(n.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer])):a.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(n)||u(n))?this._bodyArrayBuffer=q(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):a.searchParams&&URLSearchParams.prototype.isPrototypeOf(n)&&this.headers.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"))},a.blob&&(this.blob=function(){var n=k(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=k(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(a.blob)return this.blob().then(x);throw new Error("could not read as ArrayBuffer")}},this.text=function(){var n=k(this);if(n)return n;if(this._bodyBlob)return V(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)},a.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 i=n.toUpperCase();return Z.indexOf(i)>-1?i:n}function S(n,i){if(!(this instanceof S))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');i=i||{};var l=i.body;if(n instanceof S){if(n.bodyUsed)throw new TypeError("Already read");this.url=n.url,this.credentials=n.credentials,i.headers||(this.headers=new g(n.headers)),this.method=n.method,this.mode=n.mode,this.signal=n.signal,!l&&n._bodyInit!=null&&(l=n._bodyInit,n.bodyUsed=!0)}else this.url=String(n);if(this.credentials=i.credentials||this.credentials||"same-origin",(i.headers||!this.headers)&&(this.headers=new g(i.headers)),this.method=j(i.method||this.method||"GET"),this.mode=i.mode||this.mode||null,this.signal=i.signal||this.signal||(function(){if("AbortController"in s){var d=new AbortController;return d.signal}})(),this.referrer=null,(this.method==="GET"||this.method==="HEAD")&&l)throw new TypeError("Body not allowed for GET or HEAD requests");if(this._initBody(l),(this.method==="GET"||this.method==="HEAD")&&(i.cache==="no-store"||i.cache==="no-cache")){var h=/([?&])_=[^&]*/;if(h.test(this.url))this.url=this.url.replace(h,"$1_="+new Date().getTime());else{var p=/\?/;this.url+=(p.test(this.url)?"&":"?")+"_="+new Date().getTime()}}}S.prototype.clone=function(){return new S(this,{body:this._bodyInit})};function ee(n){var i=new FormData;return n.trim().split("&").forEach(function(l){if(l){var h=l.split("="),p=h.shift().replace(/\+/g," "),d=h.join("=").replace(/\+/g," ");i.append(decodeURIComponent(p),decodeURIComponent(d))}}),i}function te(n){var i=new g,l=n.replace(/\r?\n[\t ]+/g," ");return l.split("\r").map(function(h){return h.indexOf(`
2
+ `)===0?h.substr(1,h.length):h}).forEach(function(h){var p=h.split(":"),d=p.shift().trim();if(d){var U=p.join(":").trim();try{i.append(d,U)}catch(A){console.warn("Response "+A.message)}}}),i}$.call(S.prototype);function E(n,i){if(!(this instanceof E))throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');if(i||(i={}),this.type="default",this.status=i.status===void 0?200:i.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=i.statusText===void 0?"":""+i.statusText,this.headers=new g(i.headers),this.url=i.url||"",this._initBody(n)}$.call(E.prototype),E.prototype.clone=function(){return new E(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new g(this.headers),url:this.url})},E.error=function(){var n=new E(null,{status:200,statusText:""});return n.ok=!1,n.status=0,n.type="error",n};var ne=[301,302,303,307,308];E.redirect=function(n,i){if(ne.indexOf(i)===-1)throw new RangeError("Invalid status code");return new E(null,{status:i,headers:{location:n}})},t.DOMException=s.DOMException;try{new t.DOMException}catch{t.DOMException=function(i,l){this.message=i,this.name=l;var h=Error(i);this.stack=h.stack},t.DOMException.prototype=Object.create(Error.prototype),t.DOMException.prototype.constructor=t.DOMException}function I(n,i){return new Promise(function(l,h){var p=new S(n,i);if(p.signal&&p.signal.aborted)return h(new t.DOMException("Aborted","AbortError"));var d=new XMLHttpRequest;function U(){d.abort()}d.onload=function(){var b={statusText:d.statusText,headers:te(d.getAllResponseHeaders()||"")};p.url.indexOf("file://")===0&&(d.status<200||d.status>599)?b.status=200:b.status=d.status,b.url="responseURL"in d?d.responseURL:b.headers.get("X-Request-URL");var R="response"in d?d.response:d.responseText;setTimeout(function(){l(new E(R,b))},0)},d.onerror=function(){setTimeout(function(){h(new TypeError("Network request failed"))},0)},d.ontimeout=function(){setTimeout(function(){h(new TypeError("Network request timed out"))},0)},d.onabort=function(){setTimeout(function(){h(new t.DOMException("Aborted","AbortError"))},0)};function A(b){try{return b===""&&s.location.href?s.location.href:b}catch{return b}}if(d.open(p.method,A(p.url),!0),p.credentials==="include"?d.withCredentials=!0:p.credentials==="omit"&&(d.withCredentials=!1),"responseType"in d&&(a.blob?d.responseType="blob":a.arrayBuffer&&(d.responseType="arraybuffer")),i&&typeof i.headers=="object"&&!(i.headers instanceof g||s.Headers&&i.headers instanceof s.Headers)){var H=[];Object.getOwnPropertyNames(i.headers).forEach(function(b){H.push(f(b)),d.setRequestHeader(b,y(i.headers[b]))}),p.headers.forEach(function(b,R){H.indexOf(R)===-1&&d.setRequestHeader(R,b)})}else p.headers.forEach(function(b,R){d.setRequestHeader(R,b)});p.signal&&(p.signal.addEventListener("abort",U),d.onreadystatechange=function(){d.readyState===4&&p.signal.removeEventListener("abort",U)}),d.send(typeof p._bodyInit>"u"?null:p._bodyInit)})}return I.polyfill=!0,s.fetch||(s.fetch=I,s.Headers=g,s.Request=S,s.Response=E),t.Headers=g,t.Request=S,t.Response=E,t.fetch=I,t})({})})(typeof self<"u"?self:Q)});var v=[];for(let r=0;r<256;++r)v.push((r+256).toString(16).slice(1));function K(r,e=0){return(v[r[e+0]]+v[r[e+1]]+v[r[e+2]]+v[r[e+3]]+"-"+v[r[e+4]]+v[r[e+5]]+"-"+v[r[e+6]]+v[r[e+7]]+"-"+v[r[e+8]]+v[r[e+9]]+"-"+v[r[e+10]]+v[r[e+11]]+v[r[e+12]]+v[r[e+13]]+v[r[e+14]]+v[r[e+15]]).toLowerCase()}var P,de=new Uint8Array(16);function B(){if(!P){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");P=crypto.getRandomValues.bind(crypto)}return P(de)}var fe=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),L={randomUUID:fe};function he(r,e,t){r=r||{};let s=r.random??r.rng?.()??B();if(s.length<16)throw new Error("Random bytes length must be >= 16");if(s[6]=s[6]&15|64,s[8]=s[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 a=0;a<16;++a)e[t+a]=s[a];return e}return K(s)}function ge(r,e,t){return L.randomUUID&&!e&&!r?L.randomUUID():he(r,e,t)}var _=ge;var st=ce(z());function w(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 N(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 T(r){return be(r,!1)}function be(r,e){return r==null?r:{data:w(r.data),params:r.params}}function X(r){return ve(r,!1)}function ve(r,e){return r==null?r:{flags:r.flags.map(w)}}function J(r){return ke(r,!1)}function ke(r,e){return r==null?r:{data:X(r.data),params:r.params}}var O=r=>{let{companyId:e,error:t,featureAllocation:s,featureUsage:a,featureUsageEvent:c,featureUsagePeriod:o,featureUsageResetAt:u,flag:f,flagId:y,reason:F,ruleId:g,ruleType:k,userId:m,value:x}=w(r);return{featureUsageExceeded:!x&&(k=="company_override_usage_exceeded"||k=="plan_entitlement_usage_exceeded"),companyId:e??void 0,error:t??void 0,featureAllocation:s??void 0,featureUsage:a??void 0,featureUsageEvent:c===null?void 0:c,featureUsagePeriod:o??void 0,featureUsageResetAt:u??void 0,flag:f,flagId:y??void 0,reason:F,ruleId:g??void 0,ruleType:k??void 0,userId:m??void 0,value:x}};function C(r){let e=Object.keys(r).reduce((t,s)=>{let c=Object.keys(r[s]||{}).sort().reduce((o,u)=>(o[u]=r[s][u],o),{});return t[s]=c,t},{});return JSON.stringify(e)}var M="1.2.5";var G="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";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 s=new URLSearchParams(window.location.search),a=s.get("schematic_debug");a!==null&&(a===""||a==="true"||a==="1")&&(this.debugEnabled=!0);let c=s.get("schematic_offline");c!==null&&(c===""||c==="true"||c==="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@${M}`,...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),typeof window<"u"&&window?.addEventListener&&window.addEventListener("beforeunload",()=>{this.flushEventQueue(),this.flushContextDependentEventQueue()}),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(e){let{fallback:t=!1,key:s}=e,a=e.context||this.context,c=C(a);if(this.debug(`checkFlag: ${s}`,{context:a,fallback:t}),this.isOffline())return this.debug(`checkFlag offline result: ${s}`,{value:t,offlineMode:!0}),t;if(!this.useWebSocket){let o=`${this.apiUrl}/flags/${s}/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(a)}).then(u=>{if(!u.ok)throw new Error("Network response was not ok");return u.json()}).then(u=>{let f=T(u);this.debug(`checkFlag result: ${s}`,f);let y=O(f.data);return typeof y.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(y),this.submitFlagCheckEvent(s,y,a),y.value}).catch(u=>{console.error("There was a problem with the fetch operation:",u);let f={flag:s,value:t,reason:"API request failed",error:u instanceof Error?u.message:String(u)};return this.submitFlagCheckEvent(s,f,a),t})}try{let o=this.checks[c];if(this.conn!==null&&typeof o<"u"&&typeof o[s]<"u")return this.debug(`checkFlag cached result: ${s}`,o[s]),o[s].value;if(this.isOffline())return t;try{await this.setContext(a)}catch(F){return console.error("WebSocket connection failed, falling back to REST:",F),this.fallbackToRest(s,a,t)}let f=(this.checks[c]??{})[s],y=f?.value??t;return this.debug(`checkFlag WebSocket result: ${s}`,typeof f<"u"?f:{value:t,fallbackUsed:!0}),typeof f<"u"&&this.submitFlagCheckEvent(s,f,a),y}catch(o){console.error("Unexpected error in checkFlag:",o);let u={flag:s,value:t,reason:"Unexpected error in flag check",error:o instanceof Error?o.message:String(o)};return this.submitFlagCheckEvent(s,u,a),t}}debug(e,...t){this.debugEnabled&&console.log(`[Schematic] ${e}`,...t)}isOffline(){return this.offlineEnabled}submitFlagCheckEvent(e,t,s){let a={flagKey:e,value:t.value,reason:t.reason,flagId:t.flagId,ruleId:t.ruleId,companyId:t.companyId,userId:t.userId,error:t.error,reqCompany:s.company,reqUser:s.user};return this.debug("submitting flag check event:",a),this.handleEvent("flag_check",N(a))}async fallbackToRest(e,t,s){if(this.isOffline())return this.debug(`fallbackToRest offline result: ${e}`,{value:s,offlineMode:!0}),s;try{let a=`${this.apiUrl}/flags/${e}/check`,c=await fetch(a,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8","X-Schematic-Api-Key":this.apiKey},body:JSON.stringify(t)});if(!c.ok)throw new Error("Network response was not ok");let o=await c.json(),u=T(o);this.debug(`fallbackToRest result: ${e}`,u);let f=O(u.data);return typeof f.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(f),this.submitFlagCheckEvent(e,f,t),f.value}catch(a){console.error("REST API call failed, using fallback value:",a);let c={flag:e,value:s,reason:"API request failed (fallback)",error:a instanceof Error?a.message:String(a)};return this.submitFlagCheckEvent(e,c,t),s}}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`,s=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:s}).then(a=>{if(!a.ok)throw new Error("Network response was not ok");return a.json()}).then(a=>{let c=J(a);return this.debug("checkFlags result:",c),(c?.data?.flags??[]).reduce((o,u)=>(o[u.flag]=u.value,o),{})}).catch(a=>(console.error("There was a problem with the fetch operation:",a),{}))};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.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:s,event:a,traits:c,quantity:o=1}=e;if(!this.hasContext(t,s)){this.debug(`track: queuing event "${a}" until context is available`);let f={api_key:this.apiKey,body:{company:t,event:a,traits:c??{},user:s,quantity:o},sent_at:new Date().toISOString(),tracker_event_id:_(),tracker_user_id:this.getAnonymousId(),type:"track"};return this.contextDependentEventQueue.push(f),Promise.resolve()}let u={company:t??this.context.company,event:a,traits:c??{},user:s??this.context.user,quantity:o};return this.debug("track:",u),a in this.featureUsageEventMap&&this.optimisticallyUpdateFeatureUsage(a,o),this.handleEvent("track",u)};optimisticallyUpdateFeatureUsage=(e,t=1)=>{let s=this.featureUsageEventMap[e];s!=null&&(this.debug(`Optimistically updating feature usage for event: ${e}`,{quantity:t}),Object.entries(s).forEach(([a,c])=>{if(c===void 0)return;let o={...c};if(typeof o.featureUsage=="number"){if(o.featureUsage+=t,typeof o.featureAllocation=="number"){let f=o.featureUsageExceeded===!0,y=o.featureUsage>=o.featureAllocation;y!==f&&(o.featureUsageExceeded=y,y&&(o.value=!1),this.debug(`Usage limit status changed for flag: ${a}`,{was:f?"exceeded":"within limits",now:y?"exceeded":"within limits",featureUsage:o.featureUsage,featureAllocation:o.featureAllocation,value:o.value}))}this.featureUsageEventMap[e]!==void 0&&(this.featureUsageEventMap[e][a]=o);let u=C(this.context);this.checks[u]!==void 0&&this.checks[u]!==null&&(this.checks[u][a]=o),this.notifyFlagCheckListeners(a,o),this.notifyFlagValueListeners(a,o.value)}}))};hasContext=(e,t)=>{let s=e!=null&&Object.keys(e).length>0||t!=null&&Object.keys(t).length>0,a=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 s||a};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,s={...t,company:t.company??this.context.company,user:t.user??this.context.user},a={...e,body:s,sent_at:new Date().toISOString()};this.sendEvent(a)}else this.sendEvent(e)}};flushEventQueue=()=>{for(;this.eventQueue.length>0;){let e=this.eventQueue.shift();e&&this.sendEvent(e)}};getAnonymousId=()=>{if(!this.storage)return _();let e=this.storage.getItem(G);if(typeof e<"u")return e;let t=_();return this.storage.setItem(G,t),t};handleEvent=(e,t)=>{let s={api_key:this.apiKey,body:t,sent_at:new Date().toISOString(),tracker_event_id:_(),tracker_user_id:this.getAnonymousId(),type:e};return document?.hidden?this.storeEvent(s):this.sendEvent(s)};sendEvent=async e=>{let t=`${this.eventUrl}/e`,s=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 a=await fetch(t,{method:"POST",headers:{...this.additionalHeaders??{},"Content-Type":"application/json;charset=UTF-8"},body:s});this.debug("event sent:",{status:a.status,statusText:a.statusText})}catch(a){console.error("Error sending Schematic event: ",a)}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.conn)try{(await this.conn).close()}catch(e){console.error("Error during cleanup:",e)}finally{this.conn=null}};wsConnect=()=>this.isOffline()?(this.debug("wsConnect: skipped (offline mode)"),Promise.reject(new Error("WebSocket connection skipped in offline mode"))):new Promise((e,t)=>{let s=`${this.webSocketUrl}/flags/bootstrap?apiKey=${this.apiKey}`;this.debug("connecting to WebSocket:",s);let a=new WebSocket(s);a.onopen=()=>{this.debug("WebSocket connection opened"),e(a)},a.onerror=c=>{this.debug("WebSocket connection error:",c),t(c)},a.onclose=()=>{this.debug("WebSocket connection closed"),this.conn=null}});wsSendMessage=(e,t)=>this.isOffline()?(this.debug("wsSendMessage: skipped (offline mode)"),this.setIsPending(!1),Promise.resolve()):new Promise((s,a)=>{if(C(t)==C(this.context))return this.debug("WebSocket context unchanged, skipping update"),s(this.setIsPending(!1));this.debug("WebSocket context updated:",t),this.context=t;let c=()=>{let o=!1,u=F=>{let g=JSON.parse(F.data);this.debug("WebSocket message received:",g),C(t)in this.checks||(this.checks[C(t)]={}),(g.flags??[]).forEach(k=>{let m=O(k),x=C(t);this.checks[x]===void 0&&(this.checks[x]={}),this.checks[x][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[k.flag]?.size>0||this.flagValueListeners[k.flag]?.size>0)&&this.submitFlagCheckEvent(m.flag,m,t),this.notifyFlagCheckListeners(k.flag,m),this.notifyFlagValueListeners(k.flag,m.value)}),this.flushContextDependentEventQueue(),this.setIsPending(!1),o||(o=!0,s())};e.addEventListener("message",u);let f=this.additionalHeaders["X-Schematic-Client-Version"]??`schematic-js@${M}`,y={apiKey:this.apiKey,clientVersion:f,data:t};this.debug("WebSocket sending message:",y),e.send(JSON.stringify(y))};e.readyState===WebSocket.OPEN?(this.debug("WebSocket already open, sending message"),c()):e.readyState===WebSocket.CONNECTING?(this.debug("WebSocket connecting, waiting for open to send message"),e.addEventListener("open",c)):(this.debug("WebSocket is closed, cannot send message"),a("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=C(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 s=this.flagCheckListeners?.[e]??[];s.size>0&&this.debug(`Notifying ${s.size} flag check listeners for ${e}`,t),typeof t.featureUsageEvent=="string"&&this.updateFeatureUsageEventMap(t),s.forEach(a=>Fe(a,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 s=this.flagValueListeners?.[e]??[];s.size>0&&this.debug(`Notifying ${s.size} flag value listeners for ${e}`,{value:t}),s.forEach(a=>Ce(a,t))}},Ee=(r,e)=>{r.length>0?r(e):r()},Fe=(r,e)=>{r.length>0?r(e):r()},Ce=(r,e)=>{r.length>0?r(e):r()};window.Schematic=D;})();
3
3
  /* @preserve */
@@ -34,20 +34,20 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
34
34
  var require_browser_polyfill = __commonJS({
35
35
  "node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
36
36
  (function(self2) {
37
- var irrelevant = function(exports2) {
37
+ var irrelevant = (function(exports2) {
38
38
  var g = typeof globalThis !== "undefined" && globalThis || typeof self2 !== "undefined" && self2 || // eslint-disable-next-line no-undef
39
39
  typeof global !== "undefined" && global || {};
40
40
  var support = {
41
41
  searchParams: "URLSearchParams" in g,
42
42
  iterable: "Symbol" in g && "iterator" in Symbol,
43
- blob: "FileReader" in g && "Blob" in g && function() {
43
+ blob: "FileReader" in g && "Blob" in g && (function() {
44
44
  try {
45
45
  new Blob();
46
46
  return true;
47
47
  } catch (e) {
48
48
  return false;
49
49
  }
50
- }(),
50
+ })(),
51
51
  formData: "FormData" in g,
52
52
  arrayBuffer: "ArrayBuffer" in g
53
53
  };
@@ -349,12 +349,12 @@ var require_browser_polyfill = __commonJS({
349
349
  }
350
350
  this.method = normalizeMethod(options.method || this.method || "GET");
351
351
  this.mode = options.mode || this.mode || null;
352
- this.signal = options.signal || this.signal || function() {
352
+ this.signal = options.signal || this.signal || (function() {
353
353
  if ("AbortController" in g) {
354
354
  var ctrl = new AbortController();
355
355
  return ctrl.signal;
356
356
  }
357
- }();
357
+ })();
358
358
  this.referrer = null;
359
359
  if ((this.method === "GET" || this.method === "HEAD") && body) {
360
360
  throw new TypeError("Body not allowed for GET or HEAD requests");
@@ -561,7 +561,7 @@ var require_browser_polyfill = __commonJS({
561
561
  exports2.Response = Response;
562
562
  exports2.fetch = fetch2;
563
563
  return exports2;
564
- }({});
564
+ })({});
565
565
  })(typeof self !== "undefined" ? self : exports);
566
566
  }
567
567
  });
@@ -579,7 +579,7 @@ __export(index_exports, {
579
579
  });
580
580
  module.exports = __toCommonJS(index_exports);
581
581
 
582
- // node_modules/uuid/dist/esm-browser/stringify.js
582
+ // node_modules/uuid/dist/stringify.js
583
583
  var byteToHex = [];
584
584
  for (let i = 0; i < 256; ++i) {
585
585
  byteToHex.push((i + 256).toString(16).slice(1));
@@ -588,7 +588,7 @@ function unsafeStringify(arr, offset = 0) {
588
588
  return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
589
589
  }
590
590
 
591
- // node_modules/uuid/dist/esm-browser/rng.js
591
+ // node_modules/uuid/dist/rng.js
592
592
  var getRandomValues;
593
593
  var rnds8 = new Uint8Array(16);
594
594
  function rng() {
@@ -601,15 +601,12 @@ function rng() {
601
601
  return getRandomValues(rnds8);
602
602
  }
603
603
 
604
- // node_modules/uuid/dist/esm-browser/native.js
604
+ // node_modules/uuid/dist/native.js
605
605
  var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
606
606
  var native_default = { randomUUID };
607
607
 
608
- // node_modules/uuid/dist/esm-browser/v4.js
609
- function v4(options, buf, offset) {
610
- if (native_default.randomUUID && !buf && !options) {
611
- return native_default.randomUUID();
612
- }
608
+ // node_modules/uuid/dist/v4.js
609
+ function _v4(options, buf, offset) {
613
610
  options = options || {};
614
611
  const rnds = options.random ?? options.rng?.() ?? rng();
615
612
  if (rnds.length < 16) {
@@ -629,6 +626,12 @@ function v4(options, buf, offset) {
629
626
  }
630
627
  return unsafeStringify(rnds);
631
628
  }
629
+ function v4(options, buf, offset) {
630
+ if (native_default.randomUUID && !buf && !options) {
631
+ return native_default.randomUUID();
632
+ }
633
+ return _v4(options, buf, offset);
634
+ }
632
635
  var v4_default = v4;
633
636
 
634
637
  // src/index.ts
@@ -797,7 +800,7 @@ function contextString(context) {
797
800
  }
798
801
 
799
802
  // src/version.ts
800
- var version = "1.2.3";
803
+ var version = "1.2.5";
801
804
 
802
805
  // src/index.ts
803
806
  var anonymousIdKey = "schematicId";
@@ -810,6 +813,7 @@ var Schematic = class {
810
813
  debugEnabled = false;
811
814
  offlineEnabled = false;
812
815
  eventQueue;
816
+ contextDependentEventQueue;
813
817
  eventUrl = "https://c.schematichq.com";
814
818
  flagCheckListeners = {};
815
819
  flagValueListeners = {};
@@ -823,6 +827,7 @@ var Schematic = class {
823
827
  constructor(apiKey, options) {
824
828
  this.apiKey = apiKey;
825
829
  this.eventQueue = [];
830
+ this.contextDependentEventQueue = [];
826
831
  this.useWebSocket = options?.useWebSocket ?? false;
827
832
  this.debugEnabled = options?.debug ?? false;
828
833
  this.offlineEnabled = options?.offline ?? false;
@@ -865,6 +870,7 @@ var Schematic = class {
865
870
  if (typeof window !== "undefined" && window?.addEventListener) {
866
871
  window.addEventListener("beforeunload", () => {
867
872
  this.flushEventQueue();
873
+ this.flushContextDependentEventQueue();
868
874
  });
869
875
  }
870
876
  if (this.offlineEnabled) {
@@ -1123,6 +1129,7 @@ var Schematic = class {
1123
1129
  setContext = async (context) => {
1124
1130
  if (this.isOffline() || !this.useWebSocket) {
1125
1131
  this.context = context;
1132
+ this.flushContextDependentEventQueue();
1126
1133
  this.setIsPending(false);
1127
1134
  return Promise.resolve();
1128
1135
  }
@@ -1145,6 +1152,25 @@ var Schematic = class {
1145
1152
  */
1146
1153
  track = (body) => {
1147
1154
  const { company, user, event, traits, quantity = 1 } = body;
1155
+ if (!this.hasContext(company, user)) {
1156
+ this.debug(`track: queuing event "${event}" until context is available`);
1157
+ const queuedEvent = {
1158
+ api_key: this.apiKey,
1159
+ body: {
1160
+ company,
1161
+ event,
1162
+ traits: traits ?? {},
1163
+ user,
1164
+ quantity
1165
+ },
1166
+ sent_at: (/* @__PURE__ */ new Date()).toISOString(),
1167
+ tracker_event_id: v4_default(),
1168
+ tracker_user_id: this.getAnonymousId(),
1169
+ type: "track"
1170
+ };
1171
+ this.contextDependentEventQueue.push(queuedEvent);
1172
+ return Promise.resolve();
1173
+ }
1148
1174
  const trackData = {
1149
1175
  company: company ?? this.context.company,
1150
1176
  event,
@@ -1207,6 +1233,38 @@ var Schematic = class {
1207
1233
  /**
1208
1234
  * Event processing
1209
1235
  */
1236
+ hasContext = (company, user) => {
1237
+ const hasProvidedContext = company !== void 0 && company !== null && Object.keys(company).length > 0 || user !== void 0 && user !== null && Object.keys(user).length > 0;
1238
+ const hasInstanceContext = 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;
1239
+ return hasProvidedContext || hasInstanceContext;
1240
+ };
1241
+ flushContextDependentEventQueue = () => {
1242
+ this.debug(
1243
+ `flushing ${this.contextDependentEventQueue.length} context-dependent events`
1244
+ );
1245
+ while (this.contextDependentEventQueue.length > 0) {
1246
+ const event = this.contextDependentEventQueue.shift();
1247
+ if (event) {
1248
+ if (event.type === "track" && typeof event.body === "object" && event.body !== null) {
1249
+ const trackBody = event.body;
1250
+ const updatedBody = {
1251
+ ...trackBody,
1252
+ company: trackBody.company ?? this.context.company,
1253
+ user: trackBody.user ?? this.context.user
1254
+ };
1255
+ const updatedEvent = {
1256
+ ...event,
1257
+ body: updatedBody,
1258
+ sent_at: (/* @__PURE__ */ new Date()).toISOString()
1259
+ // Update timestamp to actual send time
1260
+ };
1261
+ this.sendEvent(updatedEvent);
1262
+ } else {
1263
+ this.sendEvent(event);
1264
+ }
1265
+ }
1266
+ }
1267
+ };
1210
1268
  flushEventQueue = () => {
1211
1269
  while (this.eventQueue.length > 0) {
1212
1270
  const event = this.eventQueue.shift();
@@ -1365,6 +1423,7 @@ var Schematic = class {
1365
1423
  this.notifyFlagCheckListeners(flag.flag, flagCheck);
1366
1424
  this.notifyFlagValueListeners(flag.flag, flagCheck.value);
1367
1425
  });
1426
+ this.flushContextDependentEventQueue();
1368
1427
  this.setIsPending(false);
1369
1428
  if (!resolved) {
1370
1429
  resolved = true;
@@ -32,7 +32,7 @@ declare interface CheckFlagResponse {
32
32
  * Do not edit the class manually.
33
33
  */
34
34
  /**
35
- * The returned resource
35
+ *
36
36
  * @export
37
37
  * @interface CheckFlagResponseData
38
38
  */
@@ -183,7 +183,7 @@ declare interface CheckFlagsResponse {
183
183
  }
184
184
 
185
185
  /**
186
- * The created resource
186
+ *
187
187
  * @export
188
188
  * @interface CheckFlagsResponseData
189
189
  */
@@ -357,6 +357,7 @@ export declare class Schematic {
357
357
  private debugEnabled;
358
358
  private offlineEnabled;
359
359
  private eventQueue;
360
+ private contextDependentEventQueue;
360
361
  private eventUrl;
361
362
  private flagCheckListeners;
362
363
  private flagValueListeners;
@@ -431,6 +432,8 @@ export declare class Schematic {
431
432
  /**
432
433
  * Event processing
433
434
  */
435
+ private hasContext;
436
+ private flushContextDependentEventQueue;
434
437
  private flushEventQueue;
435
438
  private getAnonymousId;
436
439
  private handleEvent;
@@ -28,20 +28,20 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var require_browser_polyfill = __commonJS({
29
29
  "node_modules/cross-fetch/dist/browser-polyfill.js"(exports) {
30
30
  (function(self2) {
31
- var irrelevant = function(exports2) {
31
+ var irrelevant = (function(exports2) {
32
32
  var g = typeof globalThis !== "undefined" && globalThis || typeof self2 !== "undefined" && self2 || // eslint-disable-next-line no-undef
33
33
  typeof global !== "undefined" && global || {};
34
34
  var support = {
35
35
  searchParams: "URLSearchParams" in g,
36
36
  iterable: "Symbol" in g && "iterator" in Symbol,
37
- blob: "FileReader" in g && "Blob" in g && function() {
37
+ blob: "FileReader" in g && "Blob" in g && (function() {
38
38
  try {
39
39
  new Blob();
40
40
  return true;
41
41
  } catch (e) {
42
42
  return false;
43
43
  }
44
- }(),
44
+ })(),
45
45
  formData: "FormData" in g,
46
46
  arrayBuffer: "ArrayBuffer" in g
47
47
  };
@@ -343,12 +343,12 @@ var require_browser_polyfill = __commonJS({
343
343
  }
344
344
  this.method = normalizeMethod(options.method || this.method || "GET");
345
345
  this.mode = options.mode || this.mode || null;
346
- this.signal = options.signal || this.signal || function() {
346
+ this.signal = options.signal || this.signal || (function() {
347
347
  if ("AbortController" in g) {
348
348
  var ctrl = new AbortController();
349
349
  return ctrl.signal;
350
350
  }
351
- }();
351
+ })();
352
352
  this.referrer = null;
353
353
  if ((this.method === "GET" || this.method === "HEAD") && body) {
354
354
  throw new TypeError("Body not allowed for GET or HEAD requests");
@@ -555,12 +555,12 @@ var require_browser_polyfill = __commonJS({
555
555
  exports2.Response = Response;
556
556
  exports2.fetch = fetch2;
557
557
  return exports2;
558
- }({});
558
+ })({});
559
559
  })(typeof self !== "undefined" ? self : exports);
560
560
  }
561
561
  });
562
562
 
563
- // node_modules/uuid/dist/esm-browser/stringify.js
563
+ // node_modules/uuid/dist/stringify.js
564
564
  var byteToHex = [];
565
565
  for (let i = 0; i < 256; ++i) {
566
566
  byteToHex.push((i + 256).toString(16).slice(1));
@@ -569,7 +569,7 @@ function unsafeStringify(arr, offset = 0) {
569
569
  return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
570
570
  }
571
571
 
572
- // node_modules/uuid/dist/esm-browser/rng.js
572
+ // node_modules/uuid/dist/rng.js
573
573
  var getRandomValues;
574
574
  var rnds8 = new Uint8Array(16);
575
575
  function rng() {
@@ -582,15 +582,12 @@ function rng() {
582
582
  return getRandomValues(rnds8);
583
583
  }
584
584
 
585
- // node_modules/uuid/dist/esm-browser/native.js
585
+ // node_modules/uuid/dist/native.js
586
586
  var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
587
587
  var native_default = { randomUUID };
588
588
 
589
- // node_modules/uuid/dist/esm-browser/v4.js
590
- function v4(options, buf, offset) {
591
- if (native_default.randomUUID && !buf && !options) {
592
- return native_default.randomUUID();
593
- }
589
+ // node_modules/uuid/dist/v4.js
590
+ function _v4(options, buf, offset) {
594
591
  options = options || {};
595
592
  const rnds = options.random ?? options.rng?.() ?? rng();
596
593
  if (rnds.length < 16) {
@@ -610,6 +607,12 @@ function v4(options, buf, offset) {
610
607
  }
611
608
  return unsafeStringify(rnds);
612
609
  }
610
+ function v4(options, buf, offset) {
611
+ if (native_default.randomUUID && !buf && !options) {
612
+ return native_default.randomUUID();
613
+ }
614
+ return _v4(options, buf, offset);
615
+ }
613
616
  var v4_default = v4;
614
617
 
615
618
  // src/index.ts
@@ -778,7 +781,7 @@ function contextString(context) {
778
781
  }
779
782
 
780
783
  // src/version.ts
781
- var version = "1.2.3";
784
+ var version = "1.2.5";
782
785
 
783
786
  // src/index.ts
784
787
  var anonymousIdKey = "schematicId";
@@ -791,6 +794,7 @@ var Schematic = class {
791
794
  debugEnabled = false;
792
795
  offlineEnabled = false;
793
796
  eventQueue;
797
+ contextDependentEventQueue;
794
798
  eventUrl = "https://c.schematichq.com";
795
799
  flagCheckListeners = {};
796
800
  flagValueListeners = {};
@@ -804,6 +808,7 @@ var Schematic = class {
804
808
  constructor(apiKey, options) {
805
809
  this.apiKey = apiKey;
806
810
  this.eventQueue = [];
811
+ this.contextDependentEventQueue = [];
807
812
  this.useWebSocket = options?.useWebSocket ?? false;
808
813
  this.debugEnabled = options?.debug ?? false;
809
814
  this.offlineEnabled = options?.offline ?? false;
@@ -846,6 +851,7 @@ var Schematic = class {
846
851
  if (typeof window !== "undefined" && window?.addEventListener) {
847
852
  window.addEventListener("beforeunload", () => {
848
853
  this.flushEventQueue();
854
+ this.flushContextDependentEventQueue();
849
855
  });
850
856
  }
851
857
  if (this.offlineEnabled) {
@@ -1104,6 +1110,7 @@ var Schematic = class {
1104
1110
  setContext = async (context) => {
1105
1111
  if (this.isOffline() || !this.useWebSocket) {
1106
1112
  this.context = context;
1113
+ this.flushContextDependentEventQueue();
1107
1114
  this.setIsPending(false);
1108
1115
  return Promise.resolve();
1109
1116
  }
@@ -1126,6 +1133,25 @@ var Schematic = class {
1126
1133
  */
1127
1134
  track = (body) => {
1128
1135
  const { company, user, event, traits, quantity = 1 } = body;
1136
+ if (!this.hasContext(company, user)) {
1137
+ this.debug(`track: queuing event "${event}" until context is available`);
1138
+ const queuedEvent = {
1139
+ api_key: this.apiKey,
1140
+ body: {
1141
+ company,
1142
+ event,
1143
+ traits: traits ?? {},
1144
+ user,
1145
+ quantity
1146
+ },
1147
+ sent_at: (/* @__PURE__ */ new Date()).toISOString(),
1148
+ tracker_event_id: v4_default(),
1149
+ tracker_user_id: this.getAnonymousId(),
1150
+ type: "track"
1151
+ };
1152
+ this.contextDependentEventQueue.push(queuedEvent);
1153
+ return Promise.resolve();
1154
+ }
1129
1155
  const trackData = {
1130
1156
  company: company ?? this.context.company,
1131
1157
  event,
@@ -1188,6 +1214,38 @@ var Schematic = class {
1188
1214
  /**
1189
1215
  * Event processing
1190
1216
  */
1217
+ hasContext = (company, user) => {
1218
+ const hasProvidedContext = company !== void 0 && company !== null && Object.keys(company).length > 0 || user !== void 0 && user !== null && Object.keys(user).length > 0;
1219
+ const hasInstanceContext = 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;
1220
+ return hasProvidedContext || hasInstanceContext;
1221
+ };
1222
+ flushContextDependentEventQueue = () => {
1223
+ this.debug(
1224
+ `flushing ${this.contextDependentEventQueue.length} context-dependent events`
1225
+ );
1226
+ while (this.contextDependentEventQueue.length > 0) {
1227
+ const event = this.contextDependentEventQueue.shift();
1228
+ if (event) {
1229
+ if (event.type === "track" && typeof event.body === "object" && event.body !== null) {
1230
+ const trackBody = event.body;
1231
+ const updatedBody = {
1232
+ ...trackBody,
1233
+ company: trackBody.company ?? this.context.company,
1234
+ user: trackBody.user ?? this.context.user
1235
+ };
1236
+ const updatedEvent = {
1237
+ ...event,
1238
+ body: updatedBody,
1239
+ sent_at: (/* @__PURE__ */ new Date()).toISOString()
1240
+ // Update timestamp to actual send time
1241
+ };
1242
+ this.sendEvent(updatedEvent);
1243
+ } else {
1244
+ this.sendEvent(event);
1245
+ }
1246
+ }
1247
+ }
1248
+ };
1191
1249
  flushEventQueue = () => {
1192
1250
  while (this.eventQueue.length > 0) {
1193
1251
  const event = this.eventQueue.shift();
@@ -1346,6 +1404,7 @@ var Schematic = class {
1346
1404
  this.notifyFlagCheckListeners(flag.flag, flagCheck);
1347
1405
  this.notifyFlagValueListeners(flag.flag, flagCheck.value);
1348
1406
  });
1407
+ this.flushContextDependentEventQueue();
1349
1408
  this.setIsPending(false);
1350
1409
  if (!resolved) {
1351
1410
  resolved = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schematichq/schematic-js",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "main": "dist/schematic.cjs.js",
5
5
  "module": "dist/schematic.esm.js",
6
6
  "types": "dist/schematic.d.ts",
@@ -26,30 +26,33 @@
26
26
  "format": "prettier --write src/*.ts",
27
27
  "lint": "eslint src --report-unused-disable-directives --fix",
28
28
  "openapi": "rm -rf src/types/api/ && npx openapi-generator-cli generate -c openapi-config.yaml --global-property models=\"EventBody:EventBodyFlagCheck:EventBodyIdentify:EventBodyIdentifyCompany:EventBodyTrack:CheckFlagResponse:CheckFlagResponseData:CheckFlagsResponse:CheckFlagsResponseData\",supportingFiles=runtime.ts && prettier --write \"src/types/api/**/*.{ts,tsx}\"",
29
- "test": "jest --config jest.config.js"
29
+ "prepare": "husky",
30
+ "test": "jest --config jest.config.js",
31
+ "tsc": "npx tsc"
30
32
  },
31
33
  "dependencies": {
32
34
  "cross-fetch": "^4.1.0",
33
- "uuid": "^11.0.5"
35
+ "uuid": "^13.0.0"
34
36
  },
35
37
  "devDependencies": {
36
38
  "@eslint/js": "^9.24.0",
37
39
  "@microsoft/api-extractor": "^7.52.2",
38
40
  "@openapitools/openapi-generator-cli": "^2.18.4",
39
- "@types/jest": "^29.5.14",
41
+ "@types/jest": "^30.0.0",
40
42
  "@types/uuid": "^10.0.0",
41
43
  "esbuild": "^0.25.2",
42
44
  "esbuild-jest": "^0.5.0",
43
45
  "eslint": "^9.24.0",
44
46
  "globals": "^16.0.0",
45
- "jest": "^29.7.0",
46
- "jest-environment-jsdom": "^29.7.0",
47
- "jest-esbuild": "^0.3.0",
47
+ "husky": "^9.1.7",
48
+ "jest": "^30.0.0",
49
+ "jest-environment-jsdom": "^30.0.0",
50
+ "jest-esbuild": "^0.4.0",
48
51
  "jest-fetch-mock": "^3.0.3",
49
52
  "mock-socket": "^9.3.1",
50
- "prettier": "^3.4.2",
53
+ "prettier": "^3.6.2",
51
54
  "ts-jest": "^29.3.0",
52
- "typescript": "^5.7.3",
55
+ "typescript": "^5.9.2",
53
56
  "typescript-eslint": "^8.29.1"
54
57
  },
55
58
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"