@splitlab/js-client 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var v=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var z=Object.prototype.hasOwnProperty;var j=(n,e)=>{for(var t in e)v(n,t,{get:e[t],enumerable:!0})},A=(n,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of D(e))!z.call(n,s)&&s!==t&&v(n,s,{get:()=>e[s],enumerable:!(i=O(e,s))||i.enumerable});return n};var B=n=>A(v({},"__esModule",{value:!0}),n);var Q={};j(Q,{SplitLabClient:()=>w,hashToFloat:()=>g.hashToFloat,murmurhash3:()=>g.murmurhash3});module.exports=B(Q);var g=require("@splitlab/core"),C=require("@splitlab/core");var U=require("@splitlab/core");var c=typeof globalThis<"u"&&typeof globalThis.document<"u";function R(){if(!c)return null;let n=globalThis,e=n.navigator,t=n.location,i=n.document,s=n.screen,r=(0,U.parseUserAgent)(e?.userAgent);return{pathname:t?.pathname??null,hostname:t?.hostname??null,referrer:i?.referrer||null,search_params:t?.search||null,page_title:i?.title||null,hash:t?.hash||null,user_agent:e?.userAgent??null,browser:r.browser,browser_version:r.browser_version,os:r.os,os_version:r.os_version,device_type:r.device_type,screen_width:s?.width??null,screen_height:s?.height??null,viewport_width:n.innerWidth??null,viewport_height:n.innerHeight??null,language:e?.language??null,timezone:F()}}function F(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch{return null}}var H=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],I="__ot_utm";function T(){if(!c)return{};try{let i=globalThis.sessionStorage?.getItem(I);if(i)return JSON.parse(i)}catch{}let n=new URLSearchParams(globalThis.location?.search||""),e={},t=!1;for(let i of H){let s=n.get(i);s&&(e[i]=s,t=!0)}if(t)try{globalThis.sessionStorage?.setItem(I,JSON.stringify(e))}catch{}return e}var u="_sl_did",m="_sl_sid",k=63072e3,E="__ot_did";function b(n){if(!c)return null;try{let e=globalThis.document?.cookie?.match(new RegExp("(?:^|; )"+n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"=([^;]*)"));return e?decodeURIComponent(e[1]):null}catch{return null}}function h(n,e,t){if(c)try{globalThis.document.cookie=`${n}=${encodeURIComponent(e)}; path=/; max-age=${t}; SameSite=Lax`}catch{}}function x(n){if(!c)return f();let e=Math.floor(n/1e3),t=b(m);if(t)return h(m,t,e),t;let i=f();return h(m,i,e),i}function P(){if(!c)return f();let n=b(u);if(n)return n;let e=null;try{let t=globalThis.localStorage;e=t?.getItem(E)||null,e&&t?.removeItem(E)}catch{}return e||(e=f()),h(u,e,k),e}function $(n){!c||b(u)===n||h(u,n,k)}var _="__ot_ref";function L(){if(!c)return null;try{let n=globalThis.sessionStorage,e=n?.getItem(_);if(e!==null)return e||null;let t=globalThis.document?.referrer||"";return n?.setItem(_,t),t||null}catch{return globalThis.document?.referrer||null}}function f(){let n=Date.now().toString(36),e=Math.random().toString(36).substring(2,10);return`${n}-${e}`}var y=typeof globalThis<"u"&&typeof globalThis.document<"u",w=class{constructor(e){this.evalResult=null;this.serverConfig=null;this.eventQueue=[];this.flushTimer=null;this.initialized=!1;this.visibilityHandler=null;this.beforeUnloadHandler=null;this.lastEtag=null;this.eventSource=null;this.deviceId=null;this.utmParams={};this.initialReferrer=null;this.pageviewCleanup=null;this.trackedExposures=new Set;this.config={apiKey:e.apiKey,baseUrl:e.baseUrl.replace(/\/$/,""),ingestUrl:(e.ingestUrl||e.baseUrl).replace(/\/$/,""),distinctId:e.distinctId??null,attributes:e.attributes||{},autoFlushInterval:e.autoFlushInterval??8e3,autoFlushSize:e.autoFlushSize??20,enableLocalEvaluation:e.enableLocalEvaluation??!0,realtimeUpdates:e.realtimeUpdates??!1,onConfigUpdate:e.onConfigUpdate??null,captureContext:e.captureContext??y,captureUtm:e.captureUtm??!0,trackSessions:e.trackSessions??!0,sessionTimeout:e.sessionTimeout??30*6e4,persistDeviceId:e.persistDeviceId??!0,trackPageviews:e.trackPageviews??!1,superProperties:e.superProperties??{},environment:e.environment??"production"},this.config.captureUtm&&(this.utmParams=T()),this.config.captureContext&&(this.initialReferrer=L()),e.bootstrap?.deviceId?(this.deviceId=e.bootstrap.deviceId,$(e.bootstrap.deviceId)):this.deviceId=P()}get effectiveDistinctId(){return this.config.distinctId||this.deviceId}get bucketingId(){return this.deviceId}async initialize(){let e=this.initialized;if(!e)if(this.config.enableLocalEvaluation)try{let{config:t,etag:i}=await this.fetchConfig();this.serverConfig=t,this.lastEtag=i,this.evalResult=(0,C.localEvaluate)(this.serverConfig,this.bucketingId,this.config.attributes)}catch(t){this.serverConfig||(console.warn("SplitLab: config fetch failed, using safe defaults",t),this.serverConfig={experiments:[],flags:[]},this.evalResult={experiments:{},flags:{}})}else{let t={distinct_id:this.effectiveDistinctId};Object.keys(this.config.attributes).length>0&&(t.attributes=this.config.attributes);let i=await this.request("POST","/api/sdk/evaluate",t);this.evalResult={experiments:i.experiments,flags:i.flags}}this.flushTimer=setInterval(()=>{this.flush().catch(()=>{})},this.config.autoFlushInterval),this.config.realtimeUpdates&&this.config.enableLocalEvaluation&&this.connectConfigStream(),y&&(this.visibilityHandler=()=>{globalThis.document?.visibilityState==="hidden"?this.flushSync():this.config.enableLocalEvaluation&&this.refresh().catch(()=>{})},globalThis.document?.addEventListener("visibilitychange",this.visibilityHandler),this.beforeUnloadHandler=()=>{this.flushSync()},globalThis.addEventListener("beforeunload",this.beforeUnloadHandler)),this.config.trackPageviews&&y&&this.setupPageviewTracking(),this.initialized=!0,e&&this.refresh().catch(()=>{})}getVariant(e){if(!this.initialized||!this.evalResult)throw new Error("SplitLabClient not initialized. Call initialize() first.");let t=this.evalResult.experiments[e]??null;return t!==null&&!this.trackedExposures.has(e)&&(this.trackedExposures.add(e),this.track("$exposure",{experiment_key:e,variant_key:t}).catch(()=>{})),t}isFeatureEnabled(e){if(!this.initialized||!this.evalResult)throw new Error("SplitLabClient not initialized. Call initialize() first.");return this.evalResult.flags[e]??!1}hydrateFromBootstrap(e){this.serverConfig=e.serverConfig,this.lastEtag=e.etag,this.evalResult=e.evalResult,this.initialized=!0}async track(e,t){this.eventQueue.push({distinct_id:this.effectiveDistinctId,event_name:e,properties:this.mergeUserProperties(t),timestamp:new Date().toISOString()}),this.eventQueue.length>=this.config.autoFlushSize&&await this.flush()}async trackPageview(e){await this.track("$pageview",e)}setSuperProperties(e){Object.assign(this.config.superProperties,e)}unsetSuperProperty(e){delete this.config.superProperties[e]}async flush(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];try{let t=JSON.stringify({context:this.buildContext(),events:e}),i=await K(t),s=JSON.stringify({_e:i}),r=`${this.config.ingestUrl}/ingest/batch?key=${encodeURIComponent(this.config.apiKey)}`,o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:s});if(!o.ok)throw new Error(`${o.status}`)}catch{this.eventQueue=e.concat(this.eventQueue)}}async identify(e,t){let i=this.effectiveDistinctId;this.config.distinctId=e,i!==e&&await this.track("$identify",{...t,previous_distinct_id:i}),this.config.enableLocalEvaluation||(this.evalResult=null,this.initialized=!1,await this.initialize())}async refresh(){if(this.config.enableLocalEvaluation)try{let{config:e,etag:t,notModified:i}=await this.fetchConfig();if(i)return;this.serverConfig=e,this.lastEtag=t,this.evalResult=(0,C.localEvaluate)(this.serverConfig,this.bucketingId,this.config.attributes),this.config.onConfigUpdate&&this.config.onConfigUpdate()}catch{}else{let e={distinct_id:this.effectiveDistinctId};Object.keys(this.config.attributes).length>0&&(e.attributes=this.config.attributes);let t=await this.request("POST","/api/sdk/evaluate",e);this.evalResult={experiments:t.experiments,flags:t.flags}}}getDistinctId(){return this.effectiveDistinctId}getDeviceId(){return this.deviceId}setAttributes(e){this.config.attributes={...this.config.attributes,...e}}async destroy(){await this.flush(),this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),this.eventSource&&(this.eventSource.close(),this.eventSource=null),this.visibilityHandler&&(globalThis.document?.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.beforeUnloadHandler&&typeof globalThis.removeEventListener=="function"&&(globalThis.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null),this.pageviewCleanup&&(this.pageviewCleanup(),this.pageviewCleanup=null),this.initialized=!1}buildContext(){let e={};if(this.config.captureContext){let t=R();if(t){for(let[i,s]of Object.entries(t))s!==null&&s!==""&&s!==void 0&&(e[i]=s);this.initialReferrer&&(e.referrer=this.initialReferrer)}}if(this.config.captureUtm)for(let[t,i]of Object.entries(this.utmParams))i&&(e[t]=i);this.config.trackSessions&&(e.session_id=x(this.config.sessionTimeout)),this.config.persistDeviceId&&this.deviceId&&(e.device_id=this.deviceId);for(let[t,i]of Object.entries(this.config.superProperties))i!==void 0&&(e[t]=i);return e}mergeUserProperties(e){if(!e)return;let t={};for(let[i,s]of Object.entries(e))s!==void 0&&(t[i]=s);return Object.keys(t).length>0?t:void 0}setupPageviewTracking(){let e=globalThis,t=e.history;if(!t?.pushState)return;let i=e.location?.href,s=t.pushState.bind(t);t.pushState=(...l)=>{s(...l),this.onUrlChange(i),i=e.location?.href};let r=t.replaceState.bind(t);t.replaceState=(...l)=>{r(...l),this.onUrlChange(i),i=e.location?.href};let o=()=>{this.onUrlChange(i),i=e.location?.href};e.addEventListener("popstate",o),this.trackPageview().catch(()=>{}),this.pageviewCleanup=()=>{t.pushState=s,t.replaceState=r,e.removeEventListener("popstate",o)}}onUrlChange(e){globalThis.location?.href!==e&&setTimeout(()=>{this.trackPageview({previous_url:e||null}).catch(()=>{})},0)}async fetchConfig(){let e={};this.lastEtag&&(e["If-None-Match"]=this.lastEtag);let t=this.config.environment!=="production"?`&env=${encodeURIComponent(this.config.environment)}`:"",i=await fetch(`${this.config.baseUrl}/api/sdk/config?key=${encodeURIComponent(this.config.apiKey)}${t}`,{method:"GET",headers:e});if(i.status===304)return{config:this.serverConfig,etag:this.lastEtag,notModified:!0};if(!i.ok){let o=await i.text().catch(()=>"");throw new Error(`SplitLab API error ${i.status}: ${o}`)}let s=i.headers.get("etag");return{config:await i.json(),etag:s}}connectConfigStream(){if(typeof EventSource>"u")return;let e=this.config.environment!=="production"?`&env=${encodeURIComponent(this.config.environment)}`:"",t=`${this.config.baseUrl}/api/sdk/config/stream?key=${encodeURIComponent(this.config.apiKey)}${e}`;this.eventSource=new EventSource(t),this.eventSource.addEventListener("config_updated",()=>{this.refresh().catch(()=>{})}),this.eventSource.onerror=()=>{}}flushSync(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];let t=JSON.stringify({context:this.buildContext(),events:e}),i=typeof btoa=="function"?btoa(unescape(encodeURIComponent(t))):t,r=typeof btoa=="function"?JSON.stringify({_e:i}):t,o=`${this.config.ingestUrl}/ingest/batch?key=${encodeURIComponent(this.config.apiKey)}`;if(typeof globalThis.navigator?.sendBeacon=="function"){let l=new Blob([r],{type:"application/json"});try{if(globalThis.navigator.sendBeacon(o,l))return}catch{}}if(typeof fetch=="function")try{fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:r,keepalive:!0}).catch(()=>{})}catch{}}async request(e,t,i){let s=await fetch(`${this.config.baseUrl}${t}`,{method:e,headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:i?JSON.stringify(i):void 0});if(!s.ok){let r=await s.text().catch(()=>"");throw new Error(`SplitLab API error ${s.status}: ${r}`)}return s.json()}};async function K(n){let e=new TextEncoder().encode(n);if(typeof CompressionStream<"u")try{let t=new CompressionStream("gzip"),i=t.writable.getWriter();i.write(e),i.close();let s=t.readable.getReader(),r=[];for(;;){let{done:a,value:p}=await s.read();if(a)break;r.push(p)}let o=r.reduce((a,p)=>a+p.length,0),l=new Uint8Array(o),d=0;for(let a of r)l.set(a,d),d+=a.length;let S="";for(let a=0;a<l.length;a++)S+=String.fromCharCode(l[a]);return btoa(S)}catch{}return btoa(unescape(encodeURIComponent(n)))}0&&(module.exports={SplitLabClient,hashToFloat,murmurhash3});
1
+ "use strict";var v=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var z=Object.prototype.hasOwnProperty;var j=(n,e)=>{for(var t in e)v(n,t,{get:e[t],enumerable:!0})},A=(n,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of O(e))!z.call(n,s)&&s!==t&&v(n,s,{get:()=>e[s],enumerable:!(i=L(e,s))||i.enumerable});return n};var B=n=>A(v({},"__esModule",{value:!0}),n);var M={};j(M,{SplitLabClient:()=>w,hashToFloat:()=>g.hashToFloat,murmurhash3:()=>g.murmurhash3});module.exports=B(M);var g=require("@splitlab/core"),C=require("@splitlab/core");var R=require("@splitlab/core");var c=typeof globalThis<"u"&&typeof globalThis.document<"u";function U(){if(!c)return null;let n=globalThis,e=n.navigator,t=n.location,i=n.document,s=n.screen,r=(0,R.parseUserAgent)(e?.userAgent);return{pathname:t?.pathname??null,hostname:t?.hostname??null,referrer:i?.referrer||null,search_params:t?.search||null,page_title:i?.title||null,hash:t?.hash||null,user_agent:e?.userAgent??null,browser:r.browser,browser_version:r.browser_version,os:r.os,os_version:r.os_version,device_type:r.device_type,screen_width:s?.width??null,screen_height:s?.height??null,viewport_width:n.innerWidth??null,viewport_height:n.innerHeight??null,language:e?.language??null,timezone:F()}}function F(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch{return null}}var H=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],_="__ot_utm";function T(){if(!c)return{};try{let i=globalThis.sessionStorage?.getItem(_);if(i)return JSON.parse(i)}catch{}let n=new URLSearchParams(globalThis.location?.search||""),e={},t=!1;for(let i of H){let s=n.get(i);s&&(e[i]=s,t=!0)}if(t)try{globalThis.sessionStorage?.setItem(_,JSON.stringify(e))}catch{}return e}var u="_sl_did",m="_sl_sid",k=63072e3,I="__ot_did";function y(n){if(!c)return null;try{let e=globalThis.document?.cookie?.match(new RegExp("(?:^|; )"+n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"=([^;]*)"));return e?decodeURIComponent(e[1]):null}catch{return null}}function h(n,e,t){if(c)try{globalThis.document.cookie=`${n}=${encodeURIComponent(e)}; path=/; max-age=${t}; SameSite=Lax`}catch{}}function x(n){if(!c)return f();let e=Math.floor(n/1e3),t=y(m);if(t)return h(m,t,e),t;let i=f();return h(m,i,e),i}function P(){if(!c)return f();let n=y(u);if(n)return n;let e=null;try{let t=globalThis.localStorage;e=t?.getItem(I)||null,e&&t?.removeItem(I)}catch{}return e||(e=f()),h(u,e,k),e}function $(n){!c||y(u)===n||h(u,n,k)}var E="__ot_ref";function D(){if(!c)return null;try{let n=globalThis.sessionStorage,e=n?.getItem(E);if(e!==null)return e||null;let t=globalThis.document?.referrer||"";return n?.setItem(E,t),t||null}catch{return globalThis.document?.referrer||null}}function f(){let n=Date.now().toString(36),e=Math.random().toString(36).substring(2,10);return`${n}-${e}`}var b=typeof globalThis<"u"&&typeof globalThis.document<"u",w=class{constructor(e){this.evalResult=null;this.serverConfig=null;this.eventQueue=[];this.flushTimer=null;this.initialized=!1;this.visibilityHandler=null;this.beforeUnloadHandler=null;this.lastEtag=null;this.eventSource=null;this.deviceId=null;this.utmParams={};this.initialReferrer=null;this.pageviewCleanup=null;this.trackedExposures=new Set;this.config={apiKey:e.apiKey,baseUrl:e.baseUrl.replace(/\/$/,""),ingestUrl:(e.ingestUrl||e.baseUrl).replace(/\/$/,""),distinctId:e.distinctId??null,attributes:e.attributes||{},autoFlushInterval:e.autoFlushInterval??8e3,autoFlushSize:e.autoFlushSize??20,enableLocalEvaluation:e.enableLocalEvaluation??!0,realtimeUpdates:e.realtimeUpdates??!1,onConfigUpdate:e.onConfigUpdate??null,captureContext:e.captureContext??b,captureUtm:e.captureUtm??!0,trackSessions:e.trackSessions??!0,sessionTimeout:e.sessionTimeout??30*6e4,persistDeviceId:e.persistDeviceId??!0,trackPageviews:e.trackPageviews??!1,superProperties:e.superProperties??{},environment:e.environment??"production"},this.config.captureUtm&&(this.utmParams=T()),this.config.captureContext&&(this.initialReferrer=D()),e.bootstrap?.deviceId?(this.deviceId=e.bootstrap.deviceId,$(e.bootstrap.deviceId)):this.deviceId=P()}get effectiveDistinctId(){return this.config.distinctId||this.deviceId}get bucketingId(){return this.deviceId}async initialize(){let e=this.initialized;if(!e)if(this.config.enableLocalEvaluation)try{let{config:t,etag:i}=await this.fetchConfig();this.serverConfig=t,this.lastEtag=i,this.evalResult=(0,C.localEvaluate)(this.serverConfig,this.bucketingId,this.config.attributes)}catch(t){this.serverConfig||(console.warn("SplitLab: config fetch failed, using safe defaults",t),this.serverConfig={experiments:[],flags:[]},this.evalResult={experiments:{},flags:{}})}else{let t={distinct_id:this.effectiveDistinctId};Object.keys(this.config.attributes).length>0&&(t.attributes=this.config.attributes);let i=await this.request("POST","/api/sdk/evaluate",t);this.evalResult={experiments:i.experiments,flags:i.flags}}this.flushTimer=setInterval(()=>{this.flush().catch(()=>{})},this.config.autoFlushInterval),this.config.realtimeUpdates&&this.config.enableLocalEvaluation&&this.connectConfigStream(),b&&(this.visibilityHandler=()=>{globalThis.document?.visibilityState==="hidden"?this.flushSync():this.config.enableLocalEvaluation&&this.refresh().catch(()=>{})},globalThis.document?.addEventListener("visibilitychange",this.visibilityHandler),this.beforeUnloadHandler=()=>{this.flushSync()},globalThis.addEventListener("beforeunload",this.beforeUnloadHandler)),this.config.trackPageviews&&b&&this.setupPageviewTracking(),this.initialized=!0,e&&this.refresh().catch(()=>{})}getVariant(e){if(!this.initialized||!this.evalResult)throw new Error("SplitLabClient not initialized. Call initialize() first.");let t=this.evalResult.experiments[e]??null;return t!==null&&!this.trackedExposures.has(e)&&(this.trackedExposures.add(e),this.track("$exposure",{experiment_key:e,variant_key:t}).catch(()=>{})),t}isFeatureEnabled(e){if(!this.initialized||!this.evalResult)throw new Error("SplitLabClient not initialized. Call initialize() first.");return this.evalResult.flags[e]??!1}hydrateFromBootstrap(e){this.serverConfig=e.serverConfig,this.lastEtag=e.etag,this.evalResult=e.evalResult,this.initialized=!0}async track(e,t){this.eventQueue.push({distinct_id:this.effectiveDistinctId,event_name:e,properties:this.mergeUserProperties(t),timestamp:new Date().toISOString()}),this.eventQueue.length>=this.config.autoFlushSize&&await this.flush()}async trackPageview(e){await this.track("$pageview",e)}setSuperProperties(e){Object.assign(this.config.superProperties,e)}unsetSuperProperty(e){delete this.config.superProperties[e]}async flush(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];try{let t=JSON.stringify({context:this.buildContext(),events:e}),i=await K(t),s=JSON.stringify({_e:i}),r=`${this.config.ingestUrl}/ingest/batch?key=${encodeURIComponent(this.config.apiKey)}`,o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:s});if(!o.ok)throw new Error(`${o.status}`)}catch{this.eventQueue=e.concat(this.eventQueue)}}async identify(e,t){let i=this.effectiveDistinctId;this.config.distinctId=e,i!==e&&await this.track("$identify",{...t,previous_distinct_id:i}),this.config.enableLocalEvaluation||(this.evalResult=null,this.initialized=!1,await this.initialize())}async refresh(){if(this.config.enableLocalEvaluation)try{let{config:e,etag:t,notModified:i}=await this.fetchConfig();if(i)return;this.serverConfig=e,this.lastEtag=t,this.evalResult=(0,C.localEvaluate)(this.serverConfig,this.bucketingId,this.config.attributes),this.config.onConfigUpdate&&this.config.onConfigUpdate()}catch{}else{let e={distinct_id:this.effectiveDistinctId};Object.keys(this.config.attributes).length>0&&(e.attributes=this.config.attributes);let t=await this.request("POST","/api/sdk/evaluate",e);this.evalResult={experiments:t.experiments,flags:t.flags}}}getDistinctId(){return this.effectiveDistinctId}getDeviceId(){return this.deviceId}setAttributes(e){this.config.attributes={...this.config.attributes,...e}}async destroy(){await this.flush(),this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),this.eventSource&&(this.eventSource.close(),this.eventSource=null),this.visibilityHandler&&(globalThis.document?.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.beforeUnloadHandler&&typeof globalThis.removeEventListener=="function"&&(globalThis.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null),this.pageviewCleanup&&(this.pageviewCleanup(),this.pageviewCleanup=null),this.initialized=!1}buildContext(){let e={};if(this.config.captureContext){let t=U();if(t){for(let[i,s]of Object.entries(t))s!==null&&s!==""&&s!==void 0&&(e[i]=s);this.initialReferrer&&(e.referrer=this.initialReferrer)}}if(this.config.captureUtm)for(let[t,i]of Object.entries(this.utmParams))i&&(e[t]=i);this.config.trackSessions&&(e.session_id=x(this.config.sessionTimeout)),this.config.persistDeviceId&&this.deviceId&&(e.device_id=this.deviceId);for(let[t,i]of Object.entries(this.config.superProperties))i!==void 0&&(e[t]=i);return this.remapCustomDimensions(e)}remapCustomDimensions(e){if(!this.serverConfig?.custom_dimensions?.length)return e;let t={...e};for(let i of this.serverConfig.custom_dimensions)i.property_key in t&&(t[`dim_${i.index}`]=t[i.property_key],delete t[i.property_key]);return t}mergeUserProperties(e){if(!e)return;let t={};for(let[i,s]of Object.entries(e))s!==void 0&&(t[i]=s);if(Object.keys(t).length!==0)return this.remapCustomDimensions(t)}setupPageviewTracking(){let e=globalThis,t=e.history;if(!t?.pushState)return;let i=e.location?.href,s=t.pushState.bind(t);t.pushState=(...l)=>{s(...l),this.onUrlChange(i),i=e.location?.href};let r=t.replaceState.bind(t);t.replaceState=(...l)=>{r(...l),this.onUrlChange(i),i=e.location?.href};let o=()=>{this.onUrlChange(i),i=e.location?.href};e.addEventListener("popstate",o),this.trackPageview().catch(()=>{}),this.pageviewCleanup=()=>{t.pushState=s,t.replaceState=r,e.removeEventListener("popstate",o)}}onUrlChange(e){globalThis.location?.href!==e&&setTimeout(()=>{this.trackPageview({previous_url:e||null}).catch(()=>{})},0)}async fetchConfig(){let e={};this.lastEtag&&(e["If-None-Match"]=this.lastEtag);let t=this.config.environment!=="production"?`&env=${encodeURIComponent(this.config.environment)}`:"",i=await fetch(`${this.config.baseUrl}/api/sdk/config?key=${encodeURIComponent(this.config.apiKey)}${t}`,{method:"GET",headers:e});if(i.status===304)return{config:this.serverConfig,etag:this.lastEtag,notModified:!0};if(!i.ok){let o=await i.text().catch(()=>"");throw new Error(`SplitLab API error ${i.status}: ${o}`)}let s=i.headers.get("etag");return{config:await i.json(),etag:s}}connectConfigStream(){if(typeof EventSource>"u")return;let e=this.config.environment!=="production"?`&env=${encodeURIComponent(this.config.environment)}`:"",t=`${this.config.baseUrl}/api/sdk/config/stream?key=${encodeURIComponent(this.config.apiKey)}${e}`;this.eventSource=new EventSource(t),this.eventSource.addEventListener("config_updated",()=>{this.refresh().catch(()=>{})}),this.eventSource.onerror=()=>{}}flushSync(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];let t=JSON.stringify({context:this.buildContext(),events:e}),i=typeof btoa=="function"?btoa(unescape(encodeURIComponent(t))):t,r=typeof btoa=="function"?JSON.stringify({_e:i}):t,o=`${this.config.ingestUrl}/ingest/batch?key=${encodeURIComponent(this.config.apiKey)}`;if(typeof globalThis.navigator?.sendBeacon=="function"){let l=new Blob([r],{type:"application/json"});try{if(globalThis.navigator.sendBeacon(o,l))return}catch{}}if(typeof fetch=="function")try{fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:r,keepalive:!0}).catch(()=>{})}catch{}}async request(e,t,i){let s=await fetch(`${this.config.baseUrl}${t}`,{method:e,headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:i?JSON.stringify(i):void 0});if(!s.ok){let r=await s.text().catch(()=>"");throw new Error(`SplitLab API error ${s.status}: ${r}`)}return s.json()}};async function K(n){let e=new TextEncoder().encode(n);if(typeof CompressionStream<"u")try{let t=new CompressionStream("gzip"),i=t.writable.getWriter();i.write(e),i.close();let s=t.readable.getReader(),r=[];for(;;){let{done:a,value:p}=await s.read();if(a)break;r.push(p)}let o=r.reduce((a,p)=>a+p.length,0),l=new Uint8Array(o),d=0;for(let a of r)l.set(a,d),d+=a.length;let S="";for(let a=0;a<l.length;a++)S+=String.fromCharCode(l[a]);return btoa(S)}catch{}return btoa(unescape(encodeURIComponent(n)))}0&&(module.exports={SplitLabClient,hashToFloat,murmurhash3});
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _splitlab_core from '@splitlab/core';
2
2
  import { BootstrapData } from '@splitlab/core';
3
- export { BootstrapData, EvalResult, ExclusionGroupConfig, ExperimentConfig, FlagConfig, SegmentConfig, ServerConfig, TargetingCondition, TargetingGroup, TargetingRules, TrackEvent, Variant, hashToFloat, murmurhash3 } from '@splitlab/core';
3
+ export { BootstrapData, CustomDimensionMapping, EvalResult, ExclusionGroupConfig, ExperimentConfig, FlagConfig, SegmentConfig, ServerConfig, TargetingCondition, TargetingGroup, TargetingRules, TrackEvent, Variant, hashToFloat, murmurhash3 } from '@splitlab/core';
4
4
 
5
5
  interface SplitLabConfig {
6
6
  apiKey: string;
@@ -109,6 +109,8 @@ declare class SplitLabClient {
109
109
  destroy(): Promise<void>;
110
110
  /** Shared context sent once per batch (not duplicated per-event). */
111
111
  private buildContext;
112
+ /** Remap user property keys to dim_N slots based on custom dimension config. */
113
+ private remapCustomDimensions;
112
114
  /** Per-event properties: only user-supplied props (no auto-captured context). */
113
115
  private mergeUserProperties;
114
116
  private setupPageviewTracking;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _splitlab_core from '@splitlab/core';
2
2
  import { BootstrapData } from '@splitlab/core';
3
- export { BootstrapData, EvalResult, ExclusionGroupConfig, ExperimentConfig, FlagConfig, SegmentConfig, ServerConfig, TargetingCondition, TargetingGroup, TargetingRules, TrackEvent, Variant, hashToFloat, murmurhash3 } from '@splitlab/core';
3
+ export { BootstrapData, CustomDimensionMapping, EvalResult, ExclusionGroupConfig, ExperimentConfig, FlagConfig, SegmentConfig, ServerConfig, TargetingCondition, TargetingGroup, TargetingRules, TrackEvent, Variant, hashToFloat, murmurhash3 } from '@splitlab/core';
4
4
 
5
5
  interface SplitLabConfig {
6
6
  apiKey: string;
@@ -109,6 +109,8 @@ declare class SplitLabClient {
109
109
  destroy(): Promise<void>;
110
110
  /** Shared context sent once per batch (not duplicated per-event). */
111
111
  private buildContext;
112
+ /** Remap user property keys to dim_N slots based on custom dimension config. */
113
+ private remapCustomDimensions;
112
114
  /** Per-event properties: only user-supplied props (no auto-captured context). */
113
115
  private mergeUserProperties;
114
116
  private setupPageviewTracking;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{murmurhash3 as H,hashToFloat as K}from"@splitlab/core";import{localEvaluate as k}from"@splitlab/core";import{parseUserAgent as P}from"@splitlab/core";var c=typeof globalThis<"u"&&typeof globalThis.document<"u";function S(){if(!c)return null;let n=globalThis,e=n.navigator,t=n.location,i=n.document,s=n.screen,r=P(e?.userAgent);return{pathname:t?.pathname??null,hostname:t?.hostname??null,referrer:i?.referrer||null,search_params:t?.search||null,page_title:i?.title||null,hash:t?.hash||null,user_agent:e?.userAgent??null,browser:r.browser,browser_version:r.browser_version,os:r.os,os_version:r.os_version,device_type:r.device_type,screen_width:s?.width??null,screen_height:s?.height??null,viewport_width:n.innerWidth??null,viewport_height:n.innerHeight??null,language:e?.language??null,timezone:$()}}function $(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch{return null}}var L=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],y="__ot_utm";function I(){if(!c)return{};try{let i=globalThis.sessionStorage?.getItem(y);if(i)return JSON.parse(i)}catch{}let n=new URLSearchParams(globalThis.location?.search||""),e={},t=!1;for(let i of L){let s=n.get(i);s&&(e[i]=s,t=!0)}if(t)try{globalThis.sessionStorage?.setItem(y,JSON.stringify(e))}catch{}return e}var u="_sl_did",p="_sl_sid",E=63072e3,C="__ot_did";function v(n){if(!c)return null;try{let e=globalThis.document?.cookie?.match(new RegExp("(?:^|; )"+n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"=([^;]*)"));return e?decodeURIComponent(e[1]):null}catch{return null}}function h(n,e,t){if(c)try{globalThis.document.cookie=`${n}=${encodeURIComponent(e)}; path=/; max-age=${t}; SameSite=Lax`}catch{}}function _(n){if(!c)return f();let e=Math.floor(n/1e3),t=v(p);if(t)return h(p,t,e),t;let i=f();return h(p,i,e),i}function U(){if(!c)return f();let n=v(u);if(n)return n;let e=null;try{let t=globalThis.localStorage;e=t?.getItem(C)||null,e&&t?.removeItem(C)}catch{}return e||(e=f()),h(u,e,E),e}function R(n){!c||v(u)===n||h(u,n,E)}var w="__ot_ref";function T(){if(!c)return null;try{let n=globalThis.sessionStorage,e=n?.getItem(w);if(e!==null)return e||null;let t=globalThis.document?.referrer||"";return n?.setItem(w,t),t||null}catch{return globalThis.document?.referrer||null}}function f(){let n=Date.now().toString(36),e=Math.random().toString(36).substring(2,10);return`${n}-${e}`}var m=typeof globalThis<"u"&&typeof globalThis.document<"u",x=class{constructor(e){this.evalResult=null;this.serverConfig=null;this.eventQueue=[];this.flushTimer=null;this.initialized=!1;this.visibilityHandler=null;this.beforeUnloadHandler=null;this.lastEtag=null;this.eventSource=null;this.deviceId=null;this.utmParams={};this.initialReferrer=null;this.pageviewCleanup=null;this.trackedExposures=new Set;this.config={apiKey:e.apiKey,baseUrl:e.baseUrl.replace(/\/$/,""),ingestUrl:(e.ingestUrl||e.baseUrl).replace(/\/$/,""),distinctId:e.distinctId??null,attributes:e.attributes||{},autoFlushInterval:e.autoFlushInterval??8e3,autoFlushSize:e.autoFlushSize??20,enableLocalEvaluation:e.enableLocalEvaluation??!0,realtimeUpdates:e.realtimeUpdates??!1,onConfigUpdate:e.onConfigUpdate??null,captureContext:e.captureContext??m,captureUtm:e.captureUtm??!0,trackSessions:e.trackSessions??!0,sessionTimeout:e.sessionTimeout??30*6e4,persistDeviceId:e.persistDeviceId??!0,trackPageviews:e.trackPageviews??!1,superProperties:e.superProperties??{},environment:e.environment??"production"},this.config.captureUtm&&(this.utmParams=I()),this.config.captureContext&&(this.initialReferrer=T()),e.bootstrap?.deviceId?(this.deviceId=e.bootstrap.deviceId,R(e.bootstrap.deviceId)):this.deviceId=U()}get effectiveDistinctId(){return this.config.distinctId||this.deviceId}get bucketingId(){return this.deviceId}async initialize(){let e=this.initialized;if(!e)if(this.config.enableLocalEvaluation)try{let{config:t,etag:i}=await this.fetchConfig();this.serverConfig=t,this.lastEtag=i,this.evalResult=k(this.serverConfig,this.bucketingId,this.config.attributes)}catch(t){this.serverConfig||(console.warn("SplitLab: config fetch failed, using safe defaults",t),this.serverConfig={experiments:[],flags:[]},this.evalResult={experiments:{},flags:{}})}else{let t={distinct_id:this.effectiveDistinctId};Object.keys(this.config.attributes).length>0&&(t.attributes=this.config.attributes);let i=await this.request("POST","/api/sdk/evaluate",t);this.evalResult={experiments:i.experiments,flags:i.flags}}this.flushTimer=setInterval(()=>{this.flush().catch(()=>{})},this.config.autoFlushInterval),this.config.realtimeUpdates&&this.config.enableLocalEvaluation&&this.connectConfigStream(),m&&(this.visibilityHandler=()=>{globalThis.document?.visibilityState==="hidden"?this.flushSync():this.config.enableLocalEvaluation&&this.refresh().catch(()=>{})},globalThis.document?.addEventListener("visibilitychange",this.visibilityHandler),this.beforeUnloadHandler=()=>{this.flushSync()},globalThis.addEventListener("beforeunload",this.beforeUnloadHandler)),this.config.trackPageviews&&m&&this.setupPageviewTracking(),this.initialized=!0,e&&this.refresh().catch(()=>{})}getVariant(e){if(!this.initialized||!this.evalResult)throw new Error("SplitLabClient not initialized. Call initialize() first.");let t=this.evalResult.experiments[e]??null;return t!==null&&!this.trackedExposures.has(e)&&(this.trackedExposures.add(e),this.track("$exposure",{experiment_key:e,variant_key:t}).catch(()=>{})),t}isFeatureEnabled(e){if(!this.initialized||!this.evalResult)throw new Error("SplitLabClient not initialized. Call initialize() first.");return this.evalResult.flags[e]??!1}hydrateFromBootstrap(e){this.serverConfig=e.serverConfig,this.lastEtag=e.etag,this.evalResult=e.evalResult,this.initialized=!0}async track(e,t){this.eventQueue.push({distinct_id:this.effectiveDistinctId,event_name:e,properties:this.mergeUserProperties(t),timestamp:new Date().toISOString()}),this.eventQueue.length>=this.config.autoFlushSize&&await this.flush()}async trackPageview(e){await this.track("$pageview",e)}setSuperProperties(e){Object.assign(this.config.superProperties,e)}unsetSuperProperty(e){delete this.config.superProperties[e]}async flush(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];try{let t=JSON.stringify({context:this.buildContext(),events:e}),i=await O(t),s=JSON.stringify({_e:i}),r=`${this.config.ingestUrl}/ingest/batch?key=${encodeURIComponent(this.config.apiKey)}`,o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:s});if(!o.ok)throw new Error(`${o.status}`)}catch{this.eventQueue=e.concat(this.eventQueue)}}async identify(e,t){let i=this.effectiveDistinctId;this.config.distinctId=e,i!==e&&await this.track("$identify",{...t,previous_distinct_id:i}),this.config.enableLocalEvaluation||(this.evalResult=null,this.initialized=!1,await this.initialize())}async refresh(){if(this.config.enableLocalEvaluation)try{let{config:e,etag:t,notModified:i}=await this.fetchConfig();if(i)return;this.serverConfig=e,this.lastEtag=t,this.evalResult=k(this.serverConfig,this.bucketingId,this.config.attributes),this.config.onConfigUpdate&&this.config.onConfigUpdate()}catch{}else{let e={distinct_id:this.effectiveDistinctId};Object.keys(this.config.attributes).length>0&&(e.attributes=this.config.attributes);let t=await this.request("POST","/api/sdk/evaluate",e);this.evalResult={experiments:t.experiments,flags:t.flags}}}getDistinctId(){return this.effectiveDistinctId}getDeviceId(){return this.deviceId}setAttributes(e){this.config.attributes={...this.config.attributes,...e}}async destroy(){await this.flush(),this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),this.eventSource&&(this.eventSource.close(),this.eventSource=null),this.visibilityHandler&&(globalThis.document?.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.beforeUnloadHandler&&typeof globalThis.removeEventListener=="function"&&(globalThis.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null),this.pageviewCleanup&&(this.pageviewCleanup(),this.pageviewCleanup=null),this.initialized=!1}buildContext(){let e={};if(this.config.captureContext){let t=S();if(t){for(let[i,s]of Object.entries(t))s!==null&&s!==""&&s!==void 0&&(e[i]=s);this.initialReferrer&&(e.referrer=this.initialReferrer)}}if(this.config.captureUtm)for(let[t,i]of Object.entries(this.utmParams))i&&(e[t]=i);this.config.trackSessions&&(e.session_id=_(this.config.sessionTimeout)),this.config.persistDeviceId&&this.deviceId&&(e.device_id=this.deviceId);for(let[t,i]of Object.entries(this.config.superProperties))i!==void 0&&(e[t]=i);return e}mergeUserProperties(e){if(!e)return;let t={};for(let[i,s]of Object.entries(e))s!==void 0&&(t[i]=s);return Object.keys(t).length>0?t:void 0}setupPageviewTracking(){let e=globalThis,t=e.history;if(!t?.pushState)return;let i=e.location?.href,s=t.pushState.bind(t);t.pushState=(...l)=>{s(...l),this.onUrlChange(i),i=e.location?.href};let r=t.replaceState.bind(t);t.replaceState=(...l)=>{r(...l),this.onUrlChange(i),i=e.location?.href};let o=()=>{this.onUrlChange(i),i=e.location?.href};e.addEventListener("popstate",o),this.trackPageview().catch(()=>{}),this.pageviewCleanup=()=>{t.pushState=s,t.replaceState=r,e.removeEventListener("popstate",o)}}onUrlChange(e){globalThis.location?.href!==e&&setTimeout(()=>{this.trackPageview({previous_url:e||null}).catch(()=>{})},0)}async fetchConfig(){let e={};this.lastEtag&&(e["If-None-Match"]=this.lastEtag);let t=this.config.environment!=="production"?`&env=${encodeURIComponent(this.config.environment)}`:"",i=await fetch(`${this.config.baseUrl}/api/sdk/config?key=${encodeURIComponent(this.config.apiKey)}${t}`,{method:"GET",headers:e});if(i.status===304)return{config:this.serverConfig,etag:this.lastEtag,notModified:!0};if(!i.ok){let o=await i.text().catch(()=>"");throw new Error(`SplitLab API error ${i.status}: ${o}`)}let s=i.headers.get("etag");return{config:await i.json(),etag:s}}connectConfigStream(){if(typeof EventSource>"u")return;let e=this.config.environment!=="production"?`&env=${encodeURIComponent(this.config.environment)}`:"",t=`${this.config.baseUrl}/api/sdk/config/stream?key=${encodeURIComponent(this.config.apiKey)}${e}`;this.eventSource=new EventSource(t),this.eventSource.addEventListener("config_updated",()=>{this.refresh().catch(()=>{})}),this.eventSource.onerror=()=>{}}flushSync(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];let t=JSON.stringify({context:this.buildContext(),events:e}),i=typeof btoa=="function"?btoa(unescape(encodeURIComponent(t))):t,r=typeof btoa=="function"?JSON.stringify({_e:i}):t,o=`${this.config.ingestUrl}/ingest/batch?key=${encodeURIComponent(this.config.apiKey)}`;if(typeof globalThis.navigator?.sendBeacon=="function"){let l=new Blob([r],{type:"application/json"});try{if(globalThis.navigator.sendBeacon(o,l))return}catch{}}if(typeof fetch=="function")try{fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:r,keepalive:!0}).catch(()=>{})}catch{}}async request(e,t,i){let s=await fetch(`${this.config.baseUrl}${t}`,{method:e,headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:i?JSON.stringify(i):void 0});if(!s.ok){let r=await s.text().catch(()=>"");throw new Error(`SplitLab API error ${s.status}: ${r}`)}return s.json()}};async function O(n){let e=new TextEncoder().encode(n);if(typeof CompressionStream<"u")try{let t=new CompressionStream("gzip"),i=t.writable.getWriter();i.write(e),i.close();let s=t.readable.getReader(),r=[];for(;;){let{done:a,value:d}=await s.read();if(a)break;r.push(d)}let o=r.reduce((a,d)=>a+d.length,0),l=new Uint8Array(o),g=0;for(let a of r)l.set(a,g),g+=a.length;let b="";for(let a=0;a<l.length;a++)b+=String.fromCharCode(l[a]);return btoa(b)}catch{}return btoa(unescape(encodeURIComponent(n)))}export{x as SplitLabClient,K as hashToFloat,H as murmurhash3};
1
+ import{murmurhash3 as H,hashToFloat as K}from"@splitlab/core";import{localEvaluate as k}from"@splitlab/core";import{parseUserAgent as P}from"@splitlab/core";var c=typeof globalThis<"u"&&typeof globalThis.document<"u";function S(){if(!c)return null;let n=globalThis,e=n.navigator,t=n.location,i=n.document,s=n.screen,r=P(e?.userAgent);return{pathname:t?.pathname??null,hostname:t?.hostname??null,referrer:i?.referrer||null,search_params:t?.search||null,page_title:i?.title||null,hash:t?.hash||null,user_agent:e?.userAgent??null,browser:r.browser,browser_version:r.browser_version,os:r.os,os_version:r.os_version,device_type:r.device_type,screen_width:s?.width??null,screen_height:s?.height??null,viewport_width:n.innerWidth??null,viewport_height:n.innerHeight??null,language:e?.language??null,timezone:$()}}function $(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch{return null}}var D=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],b="__ot_utm";function _(){if(!c)return{};try{let i=globalThis.sessionStorage?.getItem(b);if(i)return JSON.parse(i)}catch{}let n=new URLSearchParams(globalThis.location?.search||""),e={},t=!1;for(let i of D){let s=n.get(i);s&&(e[i]=s,t=!0)}if(t)try{globalThis.sessionStorage?.setItem(b,JSON.stringify(e))}catch{}return e}var u="_sl_did",p="_sl_sid",I=63072e3,C="__ot_did";function v(n){if(!c)return null;try{let e=globalThis.document?.cookie?.match(new RegExp("(?:^|; )"+n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"=([^;]*)"));return e?decodeURIComponent(e[1]):null}catch{return null}}function h(n,e,t){if(c)try{globalThis.document.cookie=`${n}=${encodeURIComponent(e)}; path=/; max-age=${t}; SameSite=Lax`}catch{}}function E(n){if(!c)return f();let e=Math.floor(n/1e3),t=v(p);if(t)return h(p,t,e),t;let i=f();return h(p,i,e),i}function R(){if(!c)return f();let n=v(u);if(n)return n;let e=null;try{let t=globalThis.localStorage;e=t?.getItem(C)||null,e&&t?.removeItem(C)}catch{}return e||(e=f()),h(u,e,I),e}function U(n){!c||v(u)===n||h(u,n,I)}var w="__ot_ref";function T(){if(!c)return null;try{let n=globalThis.sessionStorage,e=n?.getItem(w);if(e!==null)return e||null;let t=globalThis.document?.referrer||"";return n?.setItem(w,t),t||null}catch{return globalThis.document?.referrer||null}}function f(){let n=Date.now().toString(36),e=Math.random().toString(36).substring(2,10);return`${n}-${e}`}var m=typeof globalThis<"u"&&typeof globalThis.document<"u",x=class{constructor(e){this.evalResult=null;this.serverConfig=null;this.eventQueue=[];this.flushTimer=null;this.initialized=!1;this.visibilityHandler=null;this.beforeUnloadHandler=null;this.lastEtag=null;this.eventSource=null;this.deviceId=null;this.utmParams={};this.initialReferrer=null;this.pageviewCleanup=null;this.trackedExposures=new Set;this.config={apiKey:e.apiKey,baseUrl:e.baseUrl.replace(/\/$/,""),ingestUrl:(e.ingestUrl||e.baseUrl).replace(/\/$/,""),distinctId:e.distinctId??null,attributes:e.attributes||{},autoFlushInterval:e.autoFlushInterval??8e3,autoFlushSize:e.autoFlushSize??20,enableLocalEvaluation:e.enableLocalEvaluation??!0,realtimeUpdates:e.realtimeUpdates??!1,onConfigUpdate:e.onConfigUpdate??null,captureContext:e.captureContext??m,captureUtm:e.captureUtm??!0,trackSessions:e.trackSessions??!0,sessionTimeout:e.sessionTimeout??30*6e4,persistDeviceId:e.persistDeviceId??!0,trackPageviews:e.trackPageviews??!1,superProperties:e.superProperties??{},environment:e.environment??"production"},this.config.captureUtm&&(this.utmParams=_()),this.config.captureContext&&(this.initialReferrer=T()),e.bootstrap?.deviceId?(this.deviceId=e.bootstrap.deviceId,U(e.bootstrap.deviceId)):this.deviceId=R()}get effectiveDistinctId(){return this.config.distinctId||this.deviceId}get bucketingId(){return this.deviceId}async initialize(){let e=this.initialized;if(!e)if(this.config.enableLocalEvaluation)try{let{config:t,etag:i}=await this.fetchConfig();this.serverConfig=t,this.lastEtag=i,this.evalResult=k(this.serverConfig,this.bucketingId,this.config.attributes)}catch(t){this.serverConfig||(console.warn("SplitLab: config fetch failed, using safe defaults",t),this.serverConfig={experiments:[],flags:[]},this.evalResult={experiments:{},flags:{}})}else{let t={distinct_id:this.effectiveDistinctId};Object.keys(this.config.attributes).length>0&&(t.attributes=this.config.attributes);let i=await this.request("POST","/api/sdk/evaluate",t);this.evalResult={experiments:i.experiments,flags:i.flags}}this.flushTimer=setInterval(()=>{this.flush().catch(()=>{})},this.config.autoFlushInterval),this.config.realtimeUpdates&&this.config.enableLocalEvaluation&&this.connectConfigStream(),m&&(this.visibilityHandler=()=>{globalThis.document?.visibilityState==="hidden"?this.flushSync():this.config.enableLocalEvaluation&&this.refresh().catch(()=>{})},globalThis.document?.addEventListener("visibilitychange",this.visibilityHandler),this.beforeUnloadHandler=()=>{this.flushSync()},globalThis.addEventListener("beforeunload",this.beforeUnloadHandler)),this.config.trackPageviews&&m&&this.setupPageviewTracking(),this.initialized=!0,e&&this.refresh().catch(()=>{})}getVariant(e){if(!this.initialized||!this.evalResult)throw new Error("SplitLabClient not initialized. Call initialize() first.");let t=this.evalResult.experiments[e]??null;return t!==null&&!this.trackedExposures.has(e)&&(this.trackedExposures.add(e),this.track("$exposure",{experiment_key:e,variant_key:t}).catch(()=>{})),t}isFeatureEnabled(e){if(!this.initialized||!this.evalResult)throw new Error("SplitLabClient not initialized. Call initialize() first.");return this.evalResult.flags[e]??!1}hydrateFromBootstrap(e){this.serverConfig=e.serverConfig,this.lastEtag=e.etag,this.evalResult=e.evalResult,this.initialized=!0}async track(e,t){this.eventQueue.push({distinct_id:this.effectiveDistinctId,event_name:e,properties:this.mergeUserProperties(t),timestamp:new Date().toISOString()}),this.eventQueue.length>=this.config.autoFlushSize&&await this.flush()}async trackPageview(e){await this.track("$pageview",e)}setSuperProperties(e){Object.assign(this.config.superProperties,e)}unsetSuperProperty(e){delete this.config.superProperties[e]}async flush(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];try{let t=JSON.stringify({context:this.buildContext(),events:e}),i=await L(t),s=JSON.stringify({_e:i}),r=`${this.config.ingestUrl}/ingest/batch?key=${encodeURIComponent(this.config.apiKey)}`,o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:s});if(!o.ok)throw new Error(`${o.status}`)}catch{this.eventQueue=e.concat(this.eventQueue)}}async identify(e,t){let i=this.effectiveDistinctId;this.config.distinctId=e,i!==e&&await this.track("$identify",{...t,previous_distinct_id:i}),this.config.enableLocalEvaluation||(this.evalResult=null,this.initialized=!1,await this.initialize())}async refresh(){if(this.config.enableLocalEvaluation)try{let{config:e,etag:t,notModified:i}=await this.fetchConfig();if(i)return;this.serverConfig=e,this.lastEtag=t,this.evalResult=k(this.serverConfig,this.bucketingId,this.config.attributes),this.config.onConfigUpdate&&this.config.onConfigUpdate()}catch{}else{let e={distinct_id:this.effectiveDistinctId};Object.keys(this.config.attributes).length>0&&(e.attributes=this.config.attributes);let t=await this.request("POST","/api/sdk/evaluate",e);this.evalResult={experiments:t.experiments,flags:t.flags}}}getDistinctId(){return this.effectiveDistinctId}getDeviceId(){return this.deviceId}setAttributes(e){this.config.attributes={...this.config.attributes,...e}}async destroy(){await this.flush(),this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),this.eventSource&&(this.eventSource.close(),this.eventSource=null),this.visibilityHandler&&(globalThis.document?.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.beforeUnloadHandler&&typeof globalThis.removeEventListener=="function"&&(globalThis.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null),this.pageviewCleanup&&(this.pageviewCleanup(),this.pageviewCleanup=null),this.initialized=!1}buildContext(){let e={};if(this.config.captureContext){let t=S();if(t){for(let[i,s]of Object.entries(t))s!==null&&s!==""&&s!==void 0&&(e[i]=s);this.initialReferrer&&(e.referrer=this.initialReferrer)}}if(this.config.captureUtm)for(let[t,i]of Object.entries(this.utmParams))i&&(e[t]=i);this.config.trackSessions&&(e.session_id=E(this.config.sessionTimeout)),this.config.persistDeviceId&&this.deviceId&&(e.device_id=this.deviceId);for(let[t,i]of Object.entries(this.config.superProperties))i!==void 0&&(e[t]=i);return this.remapCustomDimensions(e)}remapCustomDimensions(e){if(!this.serverConfig?.custom_dimensions?.length)return e;let t={...e};for(let i of this.serverConfig.custom_dimensions)i.property_key in t&&(t[`dim_${i.index}`]=t[i.property_key],delete t[i.property_key]);return t}mergeUserProperties(e){if(!e)return;let t={};for(let[i,s]of Object.entries(e))s!==void 0&&(t[i]=s);if(Object.keys(t).length!==0)return this.remapCustomDimensions(t)}setupPageviewTracking(){let e=globalThis,t=e.history;if(!t?.pushState)return;let i=e.location?.href,s=t.pushState.bind(t);t.pushState=(...l)=>{s(...l),this.onUrlChange(i),i=e.location?.href};let r=t.replaceState.bind(t);t.replaceState=(...l)=>{r(...l),this.onUrlChange(i),i=e.location?.href};let o=()=>{this.onUrlChange(i),i=e.location?.href};e.addEventListener("popstate",o),this.trackPageview().catch(()=>{}),this.pageviewCleanup=()=>{t.pushState=s,t.replaceState=r,e.removeEventListener("popstate",o)}}onUrlChange(e){globalThis.location?.href!==e&&setTimeout(()=>{this.trackPageview({previous_url:e||null}).catch(()=>{})},0)}async fetchConfig(){let e={};this.lastEtag&&(e["If-None-Match"]=this.lastEtag);let t=this.config.environment!=="production"?`&env=${encodeURIComponent(this.config.environment)}`:"",i=await fetch(`${this.config.baseUrl}/api/sdk/config?key=${encodeURIComponent(this.config.apiKey)}${t}`,{method:"GET",headers:e});if(i.status===304)return{config:this.serverConfig,etag:this.lastEtag,notModified:!0};if(!i.ok){let o=await i.text().catch(()=>"");throw new Error(`SplitLab API error ${i.status}: ${o}`)}let s=i.headers.get("etag");return{config:await i.json(),etag:s}}connectConfigStream(){if(typeof EventSource>"u")return;let e=this.config.environment!=="production"?`&env=${encodeURIComponent(this.config.environment)}`:"",t=`${this.config.baseUrl}/api/sdk/config/stream?key=${encodeURIComponent(this.config.apiKey)}${e}`;this.eventSource=new EventSource(t),this.eventSource.addEventListener("config_updated",()=>{this.refresh().catch(()=>{})}),this.eventSource.onerror=()=>{}}flushSync(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];let t=JSON.stringify({context:this.buildContext(),events:e}),i=typeof btoa=="function"?btoa(unescape(encodeURIComponent(t))):t,r=typeof btoa=="function"?JSON.stringify({_e:i}):t,o=`${this.config.ingestUrl}/ingest/batch?key=${encodeURIComponent(this.config.apiKey)}`;if(typeof globalThis.navigator?.sendBeacon=="function"){let l=new Blob([r],{type:"application/json"});try{if(globalThis.navigator.sendBeacon(o,l))return}catch{}}if(typeof fetch=="function")try{fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:r,keepalive:!0}).catch(()=>{})}catch{}}async request(e,t,i){let s=await fetch(`${this.config.baseUrl}${t}`,{method:e,headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:i?JSON.stringify(i):void 0});if(!s.ok){let r=await s.text().catch(()=>"");throw new Error(`SplitLab API error ${s.status}: ${r}`)}return s.json()}};async function L(n){let e=new TextEncoder().encode(n);if(typeof CompressionStream<"u")try{let t=new CompressionStream("gzip"),i=t.writable.getWriter();i.write(e),i.close();let s=t.readable.getReader(),r=[];for(;;){let{done:a,value:d}=await s.read();if(a)break;r.push(d)}let o=r.reduce((a,d)=>a+d.length,0),l=new Uint8Array(o),g=0;for(let a of r)l.set(a,g),g+=a.length;let y="";for(let a=0;a<l.length;a++)y+=String.fromCharCode(l[a]);return btoa(y)}catch{}return btoa(unescape(encodeURIComponent(n)))}export{x as SplitLabClient,K as hashToFloat,H as murmurhash3};
@@ -1 +1 @@
1
- "use strict";var SplitLab=(()=>{var S=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var H=Object.prototype.hasOwnProperty;var K=(n,e)=>{for(var t in e)S(n,t,{get:e[t],enumerable:!0})},Q=(n,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of N(e))!H.call(n,a)&&a!==t&&S(n,a,{get:()=>e[a],enumerable:!(i=j(e,a))||i.enumerable});return n};var J=n=>Q(S({},"__esModule",{value:!0}),n);var X={};K(X,{SplitLabClient:()=>E,hashToFloat:()=>U,murmurhash3:()=>g});function g(n,e=0){let t=e>>>0,i=n.length,a=i>>2,r=3432918353,o=461845907;for(let u=0;u<a;u++){let l=n.charCodeAt(u*4)&255|(n.charCodeAt(u*4+1)&255)<<8|(n.charCodeAt(u*4+2)&255)<<16|(n.charCodeAt(u*4+3)&255)<<24;l=Math.imul(l,r),l=l<<15|l>>>17,l=Math.imul(l,o),t^=l,t=t<<13|t>>>19,t=Math.imul(t,5)+3864292196}let c=a*4,s=0;switch(i&3){case 3:s^=(n.charCodeAt(c+2)&255)<<16;case 2:s^=(n.charCodeAt(c+1)&255)<<8;case 1:s^=n.charCodeAt(c)&255,s=Math.imul(s,r),s=s<<15|s>>>17,s=Math.imul(s,o),t^=s}return t^=i,t^=t>>>16,t=Math.imul(t,2246822507),t^=t>>>13,t=Math.imul(t,3266489909),t^=t>>>16,t>>>0}function U(n,e){return g(n,e)/4294967295}function C(n,e,t={}){let i={},a={},r=n.segments||[],o=n.exclusion_groups||[],c=new Map;for(let s of o)for(let[u,l]of Object.entries(s.experiments))c.set(u,{layer_key:s.layer_key,...l});for(let s of n.experiments){if(s.targeting_rules&&!v(s.targeting_rules,t,r)){i[s.key]=null;continue}let u=c.get(s.key);if(u){let f=g(u.layer_key+":"+e)%1e4;if(f<u.bucket_start||f>=u.bucket_end){i[s.key]=null;continue}}let l=g(s.key+":"+e);if(l%1e4/100>=s.traffic_percentage){i[s.key]=null;continue}let d=s.variants.reduce((f,F)=>f+F.weight,0),B=l%d,I=0,p=null;for(let f of s.variants)if(I+=f.weight,B<I){p=f.key;break}p||(p=s.variants[s.variants.length-1].key),i[s.key]=p}for(let s of n.flags){if(s.rules&&!v(s.rules,t,r)){a[s.key]=!1;continue}let u=g(s.key+":"+e)%100;a[s.key]=u<s.rollout_percentage}return{experiments:i,flags:a}}function v(n,e,t=[]){if(!n.groups||n.groups.length===0)return!0;let i=r=>{if(!r.attribute)return!0;if(r.attribute==="$segment"){if(!Array.isArray(r.value))return!1;let c=r.value.map(String);return r.operator==="in"?c.some(s=>{let u=t.find(l=>l.id===s||l.key===s);return u?v(u.rules,e,t):!1}):r.operator==="not_in"?!c.some(s=>{let u=t.find(l=>l.id===s||l.key===s);return u?v(u.rules,e,t):!1}):!1}let o=e[r.attribute];if(o==null)return!1;switch(r.operator){case"is":return String(o)===String(r.value);case"is_not":return String(o)!==String(r.value);case"contains":return String(o).toLowerCase().includes(String(r.value).toLowerCase());case"not_contains":return!String(o).toLowerCase().includes(String(r.value).toLowerCase());case"gt":return Number(o)>Number(r.value);case"lt":return Number(o)<Number(r.value);case"gte":return Number(o)>=Number(r.value);case"lte":return Number(o)<=Number(r.value);case"in":return Array.isArray(r.value)&&r.value.map(String).includes(String(o));case"not_in":return Array.isArray(r.value)&&!r.value.map(String).includes(String(o));default:return!1}},a=r=>r.conditions.every(i);return n.match==="any"?n.groups.some(a):n.groups.every(a)}var G=[[/Edg(?:e|A|iOS)?\/(\S+)/,"Edge"],[/OPR\/(\S+)/,"Opera"],[/SamsungBrowser\/(\S+)/,"Samsung Internet"],[/UCBrowser\/(\S+)/,"UC Browser"],[/Firefox\/(\S+)/,"Firefox"],[/CriOS\/(\S+)/,"Chrome"],[/FxiOS\/(\S+)/,"Firefox"],[/Chrome\/(\S+)/,"Chrome"],[/Safari\/(\S+)/,"Safari"]],V=[[/Windows NT (\d+\.\d+)/,"Windows"],[/Mac OS X ([\d_]+)/,"macOS"],[/Android ([\d.]+)/,"Android"],[/iPhone OS ([\d_]+)/,"iOS"],[/iPad.*OS ([\d_]+)/,"iPadOS"],[/CrOS/,"ChromeOS"],[/Linux/,"Linux"]];function x(n){if(!n)return{browser:null,browser_version:null,os:null,os_version:null,device_type:null};let e=null,t=null,i=null,a=null;if(/Safari/.test(n)&&!/Chrome|CriOS|Chromium|Edg|OPR|SamsungBrowser|UCBrowser/.test(n)){let o=n.match(/Version\/(\S+)/);e="Safari",t=o?o[1]:null}else for(let[o,c]of G){let s=n.match(o);if(s){e=c,t=s[1]||null;break}}for(let[o,c]of V){let s=n.match(o);if(s){i=c,a=s[1]?.replace(/_/g,".")||null;break}}let r="desktop";return/Mobi|Android.*Mobile|iPhone/.test(n)?r="mobile":/iPad|Android(?!.*Mobile)|Tablet/.test(n)&&(r="tablet"),{browser:e,browser_version:t,os:i,os_version:a,device_type:r}}var h=typeof globalThis<"u"&&typeof globalThis.document<"u";function O(){if(!h)return null;let n=globalThis,e=n.navigator,t=n.location,i=n.document,a=n.screen,r=x(e?.userAgent);return{pathname:t?.pathname??null,hostname:t?.hostname??null,referrer:i?.referrer||null,search_params:t?.search||null,page_title:i?.title||null,hash:t?.hash||null,user_agent:e?.userAgent??null,browser:r.browser,browser_version:r.browser_version,os:r.os,os_version:r.os_version,device_type:r.device_type,screen_width:a?.width??null,screen_height:a?.height??null,viewport_width:n.innerWidth??null,viewport_height:n.innerHeight??null,language:e?.language??null,timezone:Y()}}function Y(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch{return null}}var W=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],R="__ot_utm";function A(){if(!h)return{};try{let i=globalThis.sessionStorage?.getItem(R);if(i)return JSON.parse(i)}catch{}let n=new URLSearchParams(globalThis.location?.search||""),e={},t=!1;for(let i of W){let a=n.get(i);a&&(e[i]=a,t=!0)}if(t)try{globalThis.sessionStorage?.setItem(R,JSON.stringify(e))}catch{}return e}var m="_sl_did",w="_sl_sid",L=63072e3,T="__ot_did";function _(n){if(!h)return null;try{let e=globalThis.document?.cookie?.match(new RegExp("(?:^|; )"+n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"=([^;]*)"));return e?decodeURIComponent(e[1]):null}catch{return null}}function y(n,e,t){if(h)try{globalThis.document.cookie=`${n}=${encodeURIComponent(e)}; path=/; max-age=${t}; SameSite=Lax`}catch{}}function $(n){if(!h)return b();let e=Math.floor(n/1e3),t=_(w);if(t)return y(w,t,e),t;let i=b();return y(w,i,e),i}function D(){if(!h)return b();let n=_(m);if(n)return n;let e=null;try{let t=globalThis.localStorage;e=t?.getItem(T)||null,e&&t?.removeItem(T)}catch{}return e||(e=b()),y(m,e,L),e}function z(n){!h||_(m)===n||y(m,n,L)}var P="__ot_ref";function M(){if(!h)return null;try{let n=globalThis.sessionStorage,e=n?.getItem(P);if(e!==null)return e||null;let t=globalThis.document?.referrer||"";return n?.setItem(P,t),t||null}catch{return globalThis.document?.referrer||null}}function b(){let n=Date.now().toString(36),e=Math.random().toString(36).substring(2,10);return`${n}-${e}`}var k=typeof globalThis<"u"&&typeof globalThis.document<"u",E=class{constructor(e){this.evalResult=null;this.serverConfig=null;this.eventQueue=[];this.flushTimer=null;this.initialized=!1;this.visibilityHandler=null;this.beforeUnloadHandler=null;this.lastEtag=null;this.eventSource=null;this.deviceId=null;this.utmParams={};this.initialReferrer=null;this.pageviewCleanup=null;this.trackedExposures=new Set;this.config={apiKey:e.apiKey,baseUrl:e.baseUrl.replace(/\/$/,""),ingestUrl:(e.ingestUrl||e.baseUrl).replace(/\/$/,""),distinctId:e.distinctId??null,attributes:e.attributes||{},autoFlushInterval:e.autoFlushInterval??8e3,autoFlushSize:e.autoFlushSize??20,enableLocalEvaluation:e.enableLocalEvaluation??!0,realtimeUpdates:e.realtimeUpdates??!1,onConfigUpdate:e.onConfigUpdate??null,captureContext:e.captureContext??k,captureUtm:e.captureUtm??!0,trackSessions:e.trackSessions??!0,sessionTimeout:e.sessionTimeout??30*6e4,persistDeviceId:e.persistDeviceId??!0,trackPageviews:e.trackPageviews??!1,superProperties:e.superProperties??{},environment:e.environment??"production"},this.config.captureUtm&&(this.utmParams=A()),this.config.captureContext&&(this.initialReferrer=M()),e.bootstrap?.deviceId?(this.deviceId=e.bootstrap.deviceId,z(e.bootstrap.deviceId)):this.deviceId=D()}get effectiveDistinctId(){return this.config.distinctId||this.deviceId}get bucketingId(){return this.deviceId}async initialize(){let e=this.initialized;if(!e)if(this.config.enableLocalEvaluation)try{let{config:t,etag:i}=await this.fetchConfig();this.serverConfig=t,this.lastEtag=i,this.evalResult=C(this.serverConfig,this.bucketingId,this.config.attributes)}catch(t){this.serverConfig||(console.warn("SplitLab: config fetch failed, using safe defaults",t),this.serverConfig={experiments:[],flags:[]},this.evalResult={experiments:{},flags:{}})}else{let t={distinct_id:this.effectiveDistinctId};Object.keys(this.config.attributes).length>0&&(t.attributes=this.config.attributes);let i=await this.request("POST","/api/sdk/evaluate",t);this.evalResult={experiments:i.experiments,flags:i.flags}}this.flushTimer=setInterval(()=>{this.flush().catch(()=>{})},this.config.autoFlushInterval),this.config.realtimeUpdates&&this.config.enableLocalEvaluation&&this.connectConfigStream(),k&&(this.visibilityHandler=()=>{globalThis.document?.visibilityState==="hidden"?this.flushSync():this.config.enableLocalEvaluation&&this.refresh().catch(()=>{})},globalThis.document?.addEventListener("visibilitychange",this.visibilityHandler),this.beforeUnloadHandler=()=>{this.flushSync()},globalThis.addEventListener("beforeunload",this.beforeUnloadHandler)),this.config.trackPageviews&&k&&this.setupPageviewTracking(),this.initialized=!0,e&&this.refresh().catch(()=>{})}getVariant(e){if(!this.initialized||!this.evalResult)throw new Error("SplitLabClient not initialized. Call initialize() first.");let t=this.evalResult.experiments[e]??null;return t!==null&&!this.trackedExposures.has(e)&&(this.trackedExposures.add(e),this.track("$exposure",{experiment_key:e,variant_key:t}).catch(()=>{})),t}isFeatureEnabled(e){if(!this.initialized||!this.evalResult)throw new Error("SplitLabClient not initialized. Call initialize() first.");return this.evalResult.flags[e]??!1}hydrateFromBootstrap(e){this.serverConfig=e.serverConfig,this.lastEtag=e.etag,this.evalResult=e.evalResult,this.initialized=!0}async track(e,t){this.eventQueue.push({distinct_id:this.effectiveDistinctId,event_name:e,properties:this.mergeUserProperties(t),timestamp:new Date().toISOString()}),this.eventQueue.length>=this.config.autoFlushSize&&await this.flush()}async trackPageview(e){await this.track("$pageview",e)}setSuperProperties(e){Object.assign(this.config.superProperties,e)}unsetSuperProperty(e){delete this.config.superProperties[e]}async flush(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];try{let t=JSON.stringify({context:this.buildContext(),events:e}),i=await q(t),a=JSON.stringify({_e:i}),r=`${this.config.ingestUrl}/ingest/batch?key=${encodeURIComponent(this.config.apiKey)}`,o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:a});if(!o.ok)throw new Error(`${o.status}`)}catch{this.eventQueue=e.concat(this.eventQueue)}}async identify(e,t){let i=this.effectiveDistinctId;this.config.distinctId=e,i!==e&&await this.track("$identify",{...t,previous_distinct_id:i}),this.config.enableLocalEvaluation||(this.evalResult=null,this.initialized=!1,await this.initialize())}async refresh(){if(this.config.enableLocalEvaluation)try{let{config:e,etag:t,notModified:i}=await this.fetchConfig();if(i)return;this.serverConfig=e,this.lastEtag=t,this.evalResult=C(this.serverConfig,this.bucketingId,this.config.attributes),this.config.onConfigUpdate&&this.config.onConfigUpdate()}catch{}else{let e={distinct_id:this.effectiveDistinctId};Object.keys(this.config.attributes).length>0&&(e.attributes=this.config.attributes);let t=await this.request("POST","/api/sdk/evaluate",e);this.evalResult={experiments:t.experiments,flags:t.flags}}}getDistinctId(){return this.effectiveDistinctId}getDeviceId(){return this.deviceId}setAttributes(e){this.config.attributes={...this.config.attributes,...e}}async destroy(){await this.flush(),this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),this.eventSource&&(this.eventSource.close(),this.eventSource=null),this.visibilityHandler&&(globalThis.document?.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.beforeUnloadHandler&&typeof globalThis.removeEventListener=="function"&&(globalThis.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null),this.pageviewCleanup&&(this.pageviewCleanup(),this.pageviewCleanup=null),this.initialized=!1}buildContext(){let e={};if(this.config.captureContext){let t=O();if(t){for(let[i,a]of Object.entries(t))a!==null&&a!==""&&a!==void 0&&(e[i]=a);this.initialReferrer&&(e.referrer=this.initialReferrer)}}if(this.config.captureUtm)for(let[t,i]of Object.entries(this.utmParams))i&&(e[t]=i);this.config.trackSessions&&(e.session_id=$(this.config.sessionTimeout)),this.config.persistDeviceId&&this.deviceId&&(e.device_id=this.deviceId);for(let[t,i]of Object.entries(this.config.superProperties))i!==void 0&&(e[t]=i);return e}mergeUserProperties(e){if(!e)return;let t={};for(let[i,a]of Object.entries(e))a!==void 0&&(t[i]=a);return Object.keys(t).length>0?t:void 0}setupPageviewTracking(){let e=globalThis,t=e.history;if(!t?.pushState)return;let i=e.location?.href,a=t.pushState.bind(t);t.pushState=(...c)=>{a(...c),this.onUrlChange(i),i=e.location?.href};let r=t.replaceState.bind(t);t.replaceState=(...c)=>{r(...c),this.onUrlChange(i),i=e.location?.href};let o=()=>{this.onUrlChange(i),i=e.location?.href};e.addEventListener("popstate",o),this.trackPageview().catch(()=>{}),this.pageviewCleanup=()=>{t.pushState=a,t.replaceState=r,e.removeEventListener("popstate",o)}}onUrlChange(e){globalThis.location?.href!==e&&setTimeout(()=>{this.trackPageview({previous_url:e||null}).catch(()=>{})},0)}async fetchConfig(){let e={};this.lastEtag&&(e["If-None-Match"]=this.lastEtag);let t=this.config.environment!=="production"?`&env=${encodeURIComponent(this.config.environment)}`:"",i=await fetch(`${this.config.baseUrl}/api/sdk/config?key=${encodeURIComponent(this.config.apiKey)}${t}`,{method:"GET",headers:e});if(i.status===304)return{config:this.serverConfig,etag:this.lastEtag,notModified:!0};if(!i.ok){let o=await i.text().catch(()=>"");throw new Error(`SplitLab API error ${i.status}: ${o}`)}let a=i.headers.get("etag");return{config:await i.json(),etag:a}}connectConfigStream(){if(typeof EventSource>"u")return;let e=this.config.environment!=="production"?`&env=${encodeURIComponent(this.config.environment)}`:"",t=`${this.config.baseUrl}/api/sdk/config/stream?key=${encodeURIComponent(this.config.apiKey)}${e}`;this.eventSource=new EventSource(t),this.eventSource.addEventListener("config_updated",()=>{this.refresh().catch(()=>{})}),this.eventSource.onerror=()=>{}}flushSync(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];let t=JSON.stringify({context:this.buildContext(),events:e}),i=typeof btoa=="function"?btoa(unescape(encodeURIComponent(t))):t,r=typeof btoa=="function"?JSON.stringify({_e:i}):t,o=`${this.config.ingestUrl}/ingest/batch?key=${encodeURIComponent(this.config.apiKey)}`;if(typeof globalThis.navigator?.sendBeacon=="function"){let c=new Blob([r],{type:"application/json"});try{if(globalThis.navigator.sendBeacon(o,c))return}catch{}}if(typeof fetch=="function")try{fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:r,keepalive:!0}).catch(()=>{})}catch{}}async request(e,t,i){let a=await fetch(`${this.config.baseUrl}${t}`,{method:e,headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:i?JSON.stringify(i):void 0});if(!a.ok){let r=await a.text().catch(()=>"");throw new Error(`SplitLab API error ${a.status}: ${r}`)}return a.json()}};async function q(n){let e=new TextEncoder().encode(n);if(typeof CompressionStream<"u")try{let t=new CompressionStream("gzip"),i=t.writable.getWriter();i.write(e),i.close();let a=t.readable.getReader(),r=[];for(;;){let{done:l,value:d}=await a.read();if(l)break;r.push(d)}let o=r.reduce((l,d)=>l+d.length,0),c=new Uint8Array(o),s=0;for(let l of r)c.set(l,s),s+=l.length;let u="";for(let l=0;l<c.length;l++)u+=String.fromCharCode(c[l]);return btoa(u)}catch{}return btoa(unescape(encodeURIComponent(n)))}return J(X);})();
1
+ "use strict";var SplitLab=(()=>{var S=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var H=Object.prototype.hasOwnProperty;var K=(n,e)=>{for(var t in e)S(n,t,{get:e[t],enumerable:!0})},Q=(n,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of N(e))!H.call(n,o)&&o!==t&&S(n,o,{get:()=>e[o],enumerable:!(i=j(e,o))||i.enumerable});return n};var J=n=>Q(S({},"__esModule",{value:!0}),n);var X={};K(X,{SplitLabClient:()=>E,hashToFloat:()=>x,murmurhash3:()=>g});function g(n,e=0){let t=e>>>0,i=n.length,o=i>>2,r=3432918353,a=461845907;for(let u=0;u<o;u++){let l=n.charCodeAt(u*4)&255|(n.charCodeAt(u*4+1)&255)<<8|(n.charCodeAt(u*4+2)&255)<<16|(n.charCodeAt(u*4+3)&255)<<24;l=Math.imul(l,r),l=l<<15|l>>>17,l=Math.imul(l,a),t^=l,t=t<<13|t>>>19,t=Math.imul(t,5)+3864292196}let c=o*4,s=0;switch(i&3){case 3:s^=(n.charCodeAt(c+2)&255)<<16;case 2:s^=(n.charCodeAt(c+1)&255)<<8;case 1:s^=n.charCodeAt(c)&255,s=Math.imul(s,r),s=s<<15|s>>>17,s=Math.imul(s,a),t^=s}return t^=i,t^=t>>>16,t=Math.imul(t,2246822507),t^=t>>>13,t=Math.imul(t,3266489909),t^=t>>>16,t>>>0}function x(n,e){return g(n,e)/4294967295}function C(n,e,t={}){let i={},o={},r=n.segments||[],a=n.exclusion_groups||[],c=new Map;for(let s of a)for(let[u,l]of Object.entries(s.experiments))c.set(u,{layer_key:s.layer_key,...l});for(let s of n.experiments){if(s.targeting_rules&&!v(s.targeting_rules,t,r)){i[s.key]=null;continue}let u=c.get(s.key);if(u){let f=g(u.layer_key+":"+e)%1e4;if(f<u.bucket_start||f>=u.bucket_end){i[s.key]=null;continue}}let l=g(s.key+":"+e);if(l%1e4/100>=s.traffic_percentage){i[s.key]=null;continue}let d=s.variants.reduce((f,F)=>f+F.weight,0),B=l%d,I=0,p=null;for(let f of s.variants)if(I+=f.weight,B<I){p=f.key;break}p||(p=s.variants[s.variants.length-1].key),i[s.key]=p}for(let s of n.flags){if(s.rules&&!v(s.rules,t,r)){o[s.key]=!1;continue}let u=g(s.key+":"+e)%100;o[s.key]=u<s.rollout_percentage}return{experiments:i,flags:o}}function v(n,e,t=[]){if(!n.groups||n.groups.length===0)return!0;let i=r=>{if(!r.attribute)return!0;if(r.attribute==="$segment"){if(!Array.isArray(r.value))return!1;let c=r.value.map(String);return r.operator==="in"?c.some(s=>{let u=t.find(l=>l.id===s||l.key===s);return u?v(u.rules,e,t):!1}):r.operator==="not_in"?!c.some(s=>{let u=t.find(l=>l.id===s||l.key===s);return u?v(u.rules,e,t):!1}):!1}let a=e[r.attribute];if(a==null)return!1;switch(r.operator){case"is":return String(a)===String(r.value);case"is_not":return String(a)!==String(r.value);case"contains":return String(a).toLowerCase().includes(String(r.value).toLowerCase());case"not_contains":return!String(a).toLowerCase().includes(String(r.value).toLowerCase());case"gt":return Number(a)>Number(r.value);case"lt":return Number(a)<Number(r.value);case"gte":return Number(a)>=Number(r.value);case"lte":return Number(a)<=Number(r.value);case"in":return Array.isArray(r.value)&&r.value.map(String).includes(String(a));case"not_in":return Array.isArray(r.value)&&!r.value.map(String).includes(String(a));default:return!1}},o=r=>r.conditions.every(i);return n.match==="any"?n.groups.some(o):n.groups.every(o)}var G=[[/Edg(?:e|A|iOS)?\/(\S+)/,"Edge"],[/OPR\/(\S+)/,"Opera"],[/SamsungBrowser\/(\S+)/,"Samsung Internet"],[/UCBrowser\/(\S+)/,"UC Browser"],[/Firefox\/(\S+)/,"Firefox"],[/CriOS\/(\S+)/,"Chrome"],[/FxiOS\/(\S+)/,"Firefox"],[/Chrome\/(\S+)/,"Chrome"],[/Safari\/(\S+)/,"Safari"]],V=[[/Windows NT (\d+\.\d+)/,"Windows"],[/Mac OS X ([\d_]+)/,"macOS"],[/Android ([\d.]+)/,"Android"],[/iPhone OS ([\d_]+)/,"iOS"],[/iPad.*OS ([\d_]+)/,"iPadOS"],[/CrOS/,"ChromeOS"],[/Linux/,"Linux"]];function R(n){if(!n)return{browser:null,browser_version:null,os:null,os_version:null,device_type:null};let e=null,t=null,i=null,o=null;if(/Safari/.test(n)&&!/Chrome|CriOS|Chromium|Edg|OPR|SamsungBrowser|UCBrowser/.test(n)){let a=n.match(/Version\/(\S+)/);e="Safari",t=a?a[1]:null}else for(let[a,c]of G){let s=n.match(a);if(s){e=c,t=s[1]||null;break}}for(let[a,c]of V){let s=n.match(a);if(s){i=c,o=s[1]?.replace(/_/g,".")||null;break}}let r="desktop";return/Mobi|Android.*Mobile|iPhone/.test(n)?r="mobile":/iPad|Android(?!.*Mobile)|Tablet/.test(n)&&(r="tablet"),{browser:e,browser_version:t,os:i,os_version:o,device_type:r}}var h=typeof globalThis<"u"&&typeof globalThis.document<"u";function O(){if(!h)return null;let n=globalThis,e=n.navigator,t=n.location,i=n.document,o=n.screen,r=R(e?.userAgent);return{pathname:t?.pathname??null,hostname:t?.hostname??null,referrer:i?.referrer||null,search_params:t?.search||null,page_title:i?.title||null,hash:t?.hash||null,user_agent:e?.userAgent??null,browser:r.browser,browser_version:r.browser_version,os:r.os,os_version:r.os_version,device_type:r.device_type,screen_width:o?.width??null,screen_height:o?.height??null,viewport_width:n.innerWidth??null,viewport_height:n.innerHeight??null,language:e?.language??null,timezone:Y()}}function Y(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch{return null}}var W=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],U="__ot_utm";function A(){if(!h)return{};try{let i=globalThis.sessionStorage?.getItem(U);if(i)return JSON.parse(i)}catch{}let n=new URLSearchParams(globalThis.location?.search||""),e={},t=!1;for(let i of W){let o=n.get(i);o&&(e[i]=o,t=!0)}if(t)try{globalThis.sessionStorage?.setItem(U,JSON.stringify(e))}catch{}return e}var m="_sl_did",w="_sl_sid",L=63072e3,T="__ot_did";function _(n){if(!h)return null;try{let e=globalThis.document?.cookie?.match(new RegExp("(?:^|; )"+n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")+"=([^;]*)"));return e?decodeURIComponent(e[1]):null}catch{return null}}function y(n,e,t){if(h)try{globalThis.document.cookie=`${n}=${encodeURIComponent(e)}; path=/; max-age=${t}; SameSite=Lax`}catch{}}function $(n){if(!h)return b();let e=Math.floor(n/1e3),t=_(w);if(t)return y(w,t,e),t;let i=b();return y(w,i,e),i}function D(){if(!h)return b();let n=_(m);if(n)return n;let e=null;try{let t=globalThis.localStorage;e=t?.getItem(T)||null,e&&t?.removeItem(T)}catch{}return e||(e=b()),y(m,e,L),e}function M(n){!h||_(m)===n||y(m,n,L)}var P="__ot_ref";function z(){if(!h)return null;try{let n=globalThis.sessionStorage,e=n?.getItem(P);if(e!==null)return e||null;let t=globalThis.document?.referrer||"";return n?.setItem(P,t),t||null}catch{return globalThis.document?.referrer||null}}function b(){let n=Date.now().toString(36),e=Math.random().toString(36).substring(2,10);return`${n}-${e}`}var k=typeof globalThis<"u"&&typeof globalThis.document<"u",E=class{constructor(e){this.evalResult=null;this.serverConfig=null;this.eventQueue=[];this.flushTimer=null;this.initialized=!1;this.visibilityHandler=null;this.beforeUnloadHandler=null;this.lastEtag=null;this.eventSource=null;this.deviceId=null;this.utmParams={};this.initialReferrer=null;this.pageviewCleanup=null;this.trackedExposures=new Set;this.config={apiKey:e.apiKey,baseUrl:e.baseUrl.replace(/\/$/,""),ingestUrl:(e.ingestUrl||e.baseUrl).replace(/\/$/,""),distinctId:e.distinctId??null,attributes:e.attributes||{},autoFlushInterval:e.autoFlushInterval??8e3,autoFlushSize:e.autoFlushSize??20,enableLocalEvaluation:e.enableLocalEvaluation??!0,realtimeUpdates:e.realtimeUpdates??!1,onConfigUpdate:e.onConfigUpdate??null,captureContext:e.captureContext??k,captureUtm:e.captureUtm??!0,trackSessions:e.trackSessions??!0,sessionTimeout:e.sessionTimeout??30*6e4,persistDeviceId:e.persistDeviceId??!0,trackPageviews:e.trackPageviews??!1,superProperties:e.superProperties??{},environment:e.environment??"production"},this.config.captureUtm&&(this.utmParams=A()),this.config.captureContext&&(this.initialReferrer=z()),e.bootstrap?.deviceId?(this.deviceId=e.bootstrap.deviceId,M(e.bootstrap.deviceId)):this.deviceId=D()}get effectiveDistinctId(){return this.config.distinctId||this.deviceId}get bucketingId(){return this.deviceId}async initialize(){let e=this.initialized;if(!e)if(this.config.enableLocalEvaluation)try{let{config:t,etag:i}=await this.fetchConfig();this.serverConfig=t,this.lastEtag=i,this.evalResult=C(this.serverConfig,this.bucketingId,this.config.attributes)}catch(t){this.serverConfig||(console.warn("SplitLab: config fetch failed, using safe defaults",t),this.serverConfig={experiments:[],flags:[]},this.evalResult={experiments:{},flags:{}})}else{let t={distinct_id:this.effectiveDistinctId};Object.keys(this.config.attributes).length>0&&(t.attributes=this.config.attributes);let i=await this.request("POST","/api/sdk/evaluate",t);this.evalResult={experiments:i.experiments,flags:i.flags}}this.flushTimer=setInterval(()=>{this.flush().catch(()=>{})},this.config.autoFlushInterval),this.config.realtimeUpdates&&this.config.enableLocalEvaluation&&this.connectConfigStream(),k&&(this.visibilityHandler=()=>{globalThis.document?.visibilityState==="hidden"?this.flushSync():this.config.enableLocalEvaluation&&this.refresh().catch(()=>{})},globalThis.document?.addEventListener("visibilitychange",this.visibilityHandler),this.beforeUnloadHandler=()=>{this.flushSync()},globalThis.addEventListener("beforeunload",this.beforeUnloadHandler)),this.config.trackPageviews&&k&&this.setupPageviewTracking(),this.initialized=!0,e&&this.refresh().catch(()=>{})}getVariant(e){if(!this.initialized||!this.evalResult)throw new Error("SplitLabClient not initialized. Call initialize() first.");let t=this.evalResult.experiments[e]??null;return t!==null&&!this.trackedExposures.has(e)&&(this.trackedExposures.add(e),this.track("$exposure",{experiment_key:e,variant_key:t}).catch(()=>{})),t}isFeatureEnabled(e){if(!this.initialized||!this.evalResult)throw new Error("SplitLabClient not initialized. Call initialize() first.");return this.evalResult.flags[e]??!1}hydrateFromBootstrap(e){this.serverConfig=e.serverConfig,this.lastEtag=e.etag,this.evalResult=e.evalResult,this.initialized=!0}async track(e,t){this.eventQueue.push({distinct_id:this.effectiveDistinctId,event_name:e,properties:this.mergeUserProperties(t),timestamp:new Date().toISOString()}),this.eventQueue.length>=this.config.autoFlushSize&&await this.flush()}async trackPageview(e){await this.track("$pageview",e)}setSuperProperties(e){Object.assign(this.config.superProperties,e)}unsetSuperProperty(e){delete this.config.superProperties[e]}async flush(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];try{let t=JSON.stringify({context:this.buildContext(),events:e}),i=await q(t),o=JSON.stringify({_e:i}),r=`${this.config.ingestUrl}/ingest/batch?key=${encodeURIComponent(this.config.apiKey)}`,a=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:o});if(!a.ok)throw new Error(`${a.status}`)}catch{this.eventQueue=e.concat(this.eventQueue)}}async identify(e,t){let i=this.effectiveDistinctId;this.config.distinctId=e,i!==e&&await this.track("$identify",{...t,previous_distinct_id:i}),this.config.enableLocalEvaluation||(this.evalResult=null,this.initialized=!1,await this.initialize())}async refresh(){if(this.config.enableLocalEvaluation)try{let{config:e,etag:t,notModified:i}=await this.fetchConfig();if(i)return;this.serverConfig=e,this.lastEtag=t,this.evalResult=C(this.serverConfig,this.bucketingId,this.config.attributes),this.config.onConfigUpdate&&this.config.onConfigUpdate()}catch{}else{let e={distinct_id:this.effectiveDistinctId};Object.keys(this.config.attributes).length>0&&(e.attributes=this.config.attributes);let t=await this.request("POST","/api/sdk/evaluate",e);this.evalResult={experiments:t.experiments,flags:t.flags}}}getDistinctId(){return this.effectiveDistinctId}getDeviceId(){return this.deviceId}setAttributes(e){this.config.attributes={...this.config.attributes,...e}}async destroy(){await this.flush(),this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),this.eventSource&&(this.eventSource.close(),this.eventSource=null),this.visibilityHandler&&(globalThis.document?.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=null),this.beforeUnloadHandler&&typeof globalThis.removeEventListener=="function"&&(globalThis.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null),this.pageviewCleanup&&(this.pageviewCleanup(),this.pageviewCleanup=null),this.initialized=!1}buildContext(){let e={};if(this.config.captureContext){let t=O();if(t){for(let[i,o]of Object.entries(t))o!==null&&o!==""&&o!==void 0&&(e[i]=o);this.initialReferrer&&(e.referrer=this.initialReferrer)}}if(this.config.captureUtm)for(let[t,i]of Object.entries(this.utmParams))i&&(e[t]=i);this.config.trackSessions&&(e.session_id=$(this.config.sessionTimeout)),this.config.persistDeviceId&&this.deviceId&&(e.device_id=this.deviceId);for(let[t,i]of Object.entries(this.config.superProperties))i!==void 0&&(e[t]=i);return this.remapCustomDimensions(e)}remapCustomDimensions(e){if(!this.serverConfig?.custom_dimensions?.length)return e;let t={...e};for(let i of this.serverConfig.custom_dimensions)i.property_key in t&&(t[`dim_${i.index}`]=t[i.property_key],delete t[i.property_key]);return t}mergeUserProperties(e){if(!e)return;let t={};for(let[i,o]of Object.entries(e))o!==void 0&&(t[i]=o);if(Object.keys(t).length!==0)return this.remapCustomDimensions(t)}setupPageviewTracking(){let e=globalThis,t=e.history;if(!t?.pushState)return;let i=e.location?.href,o=t.pushState.bind(t);t.pushState=(...c)=>{o(...c),this.onUrlChange(i),i=e.location?.href};let r=t.replaceState.bind(t);t.replaceState=(...c)=>{r(...c),this.onUrlChange(i),i=e.location?.href};let a=()=>{this.onUrlChange(i),i=e.location?.href};e.addEventListener("popstate",a),this.trackPageview().catch(()=>{}),this.pageviewCleanup=()=>{t.pushState=o,t.replaceState=r,e.removeEventListener("popstate",a)}}onUrlChange(e){globalThis.location?.href!==e&&setTimeout(()=>{this.trackPageview({previous_url:e||null}).catch(()=>{})},0)}async fetchConfig(){let e={};this.lastEtag&&(e["If-None-Match"]=this.lastEtag);let t=this.config.environment!=="production"?`&env=${encodeURIComponent(this.config.environment)}`:"",i=await fetch(`${this.config.baseUrl}/api/sdk/config?key=${encodeURIComponent(this.config.apiKey)}${t}`,{method:"GET",headers:e});if(i.status===304)return{config:this.serverConfig,etag:this.lastEtag,notModified:!0};if(!i.ok){let a=await i.text().catch(()=>"");throw new Error(`SplitLab API error ${i.status}: ${a}`)}let o=i.headers.get("etag");return{config:await i.json(),etag:o}}connectConfigStream(){if(typeof EventSource>"u")return;let e=this.config.environment!=="production"?`&env=${encodeURIComponent(this.config.environment)}`:"",t=`${this.config.baseUrl}/api/sdk/config/stream?key=${encodeURIComponent(this.config.apiKey)}${e}`;this.eventSource=new EventSource(t),this.eventSource.addEventListener("config_updated",()=>{this.refresh().catch(()=>{})}),this.eventSource.onerror=()=>{}}flushSync(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];let t=JSON.stringify({context:this.buildContext(),events:e}),i=typeof btoa=="function"?btoa(unescape(encodeURIComponent(t))):t,r=typeof btoa=="function"?JSON.stringify({_e:i}):t,a=`${this.config.ingestUrl}/ingest/batch?key=${encodeURIComponent(this.config.apiKey)}`;if(typeof globalThis.navigator?.sendBeacon=="function"){let c=new Blob([r],{type:"application/json"});try{if(globalThis.navigator.sendBeacon(a,c))return}catch{}}if(typeof fetch=="function")try{fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:r,keepalive:!0}).catch(()=>{})}catch{}}async request(e,t,i){let o=await fetch(`${this.config.baseUrl}${t}`,{method:e,headers:{"Content-Type":"application/json","X-API-Key":this.config.apiKey},body:i?JSON.stringify(i):void 0});if(!o.ok){let r=await o.text().catch(()=>"");throw new Error(`SplitLab API error ${o.status}: ${r}`)}return o.json()}};async function q(n){let e=new TextEncoder().encode(n);if(typeof CompressionStream<"u")try{let t=new CompressionStream("gzip"),i=t.writable.getWriter();i.write(e),i.close();let o=t.readable.getReader(),r=[];for(;;){let{done:l,value:d}=await o.read();if(l)break;r.push(d)}let a=r.reduce((l,d)=>l+d.length,0),c=new Uint8Array(a),s=0;for(let l of r)c.set(l,s),s+=l.length;let u="";for(let l=0;l<c.length;l++)u+=String.fromCharCode(c[l]);return btoa(u)}catch{}return btoa(unescape(encodeURIComponent(n)))}return J(X);})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitlab/js-client",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Lightweight JavaScript client SDK for SplitLab A/B testing and analytics",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -30,7 +30,7 @@
30
30
  "dev": "tsup --watch"
31
31
  },
32
32
  "dependencies": {
33
- "@splitlab/core": "^0.3.2"
33
+ "@splitlab/core": "^0.4.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "tsup": "^8.0.0",