@splitlab/node 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var f=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var C=(n,e)=>{for(var t in e)f(n,t,{get:e[t],enumerable:!0})},b=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of m(e))!y.call(n,i)&&i!==t&&f(n,i,{get:()=>e[i],enumerable:!(r=d(e,i))||r.enumerable});return n};var R=n=>b(f({},"__esModule",{value:!0}),n);var T={};C(T,{SplitLabServer:()=>u,hashToFloat:()=>o.hashToFloat,murmurhash3:()=>o.murmurhash3});module.exports=R(T);var o=require("@splitlab/core"),s=require("@splitlab/core"),u=class{constructor(e){this.serverConfig=null;this.eventQueue=[];this.flushTimer=null;this.configRefreshTimer=null;this.lastEtag=null;this.ready=!1;this.apiKey=e.apiKey,this.baseUrl=e.baseUrl.replace(/\/$/,""),this.ingestUrl=(e.ingestUrl||e.baseUrl).replace(/\/$/,""),this.configRefreshInterval=e.configRefreshInterval??3e4,this.flushInterval=e.flushInterval??1e4,this.flushSize=e.flushSize??100,this.onConfigUpdate=e.onConfigUpdate??null}async initialize(){let{config:e,etag:t}=await this.fetchConfig();this.serverConfig=e,this.lastEtag=t,this.configRefreshTimer=setInterval(()=>{this.refresh().catch(()=>{})},this.configRefreshInterval),this.flushTimer=setInterval(()=>{this.flush().catch(()=>{})},this.flushInterval),this.ready=!0}isReady(){return this.ready}async destroy(){this.configRefreshTimer!==null&&(clearInterval(this.configRefreshTimer),this.configRefreshTimer=null),this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),await this.flush(),this.ready=!1}getVariant(e,t,r){if(!this.serverConfig)return null;let i=this.serverConfig.experiments.find(a=>a.key===e);if(!i||i.targeting_rules&&!(0,s.evaluateRules)(i.targeting_rules,r||{}))return null;let l=(0,s.murmurhash3)(i.key+":"+t);if(l%1e4/100>=i.traffic_percentage)return null;let h=i.variants.reduce((a,p)=>a+p.weight,0),v=l%h,g=0;for(let a of i.variants)if(g+=a.weight,v<g)return a.key;return i.variants[i.variants.length-1].key}isFeatureEnabled(e,t,r){if(!this.serverConfig)return!1;let i=this.serverConfig.flags.find(h=>h.key===e);return!i||i.rules&&!(0,s.evaluateRules)(i.rules,r||{})?!1:(0,s.murmurhash3)(i.key+":"+t)%100<i.rollout_percentage}evaluateAll(e,t){return this.serverConfig?(0,s.localEvaluate)(this.serverConfig,e,t||{}):{experiments:{},flags:{}}}track(e,t,r){this.eventQueue.push({distinct_id:e,event_name:t,properties:r,timestamp:new Date().toISOString()}),this.eventQueue.length>=this.flushSize&&this.flush().catch(()=>{})}async flush(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];try{(await fetch(`${this.ingestUrl}/ingest/batch`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.apiKey},body:JSON.stringify({events:e})})).ok||(this.eventQueue=e.concat(this.eventQueue))}catch{this.eventQueue=e.concat(this.eventQueue)}}async refresh(){try{let{config:e,etag:t,notModified:r}=await this.fetchConfig();if(r)return;this.serverConfig=e,this.lastEtag=t,this.onConfigUpdate&&this.onConfigUpdate()}catch{}}async fetchConfig(){let e={"Content-Type":"application/json"};this.lastEtag&&(e["If-None-Match"]=this.lastEtag);let t=await fetch(`${this.baseUrl}/api/sdk/config?key=${encodeURIComponent(this.apiKey)}`,{method:"GET",headers:e});if(t.status===304)return{config:this.serverConfig,etag:this.lastEtag,notModified:!0};if(!t.ok){let l=await t.text().catch(()=>"");throw new Error(`SplitLab API error ${t.status}: ${l}`)}let r=t.headers.get("etag");return{config:await t.json(),etag:r}}};0&&(module.exports={SplitLabServer,hashToFloat,murmurhash3});
1
+ "use strict";var u=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var R=(r,e)=>{for(var i in e)u(r,i,{get:e[i],enumerable:!0})},b=(r,e,i,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of y(e))!C.call(r,t)&&t!==i&&u(r,t,{get:()=>e[t],enumerable:!(n=d(e,t))||n.enumerable});return r};var T=r=>b(u({},"__esModule",{value:!0}),r);var I={};R(I,{SplitLabServer:()=>g,hashToFloat:()=>h.hashToFloat,murmurhash3:()=>h.murmurhash3});module.exports=T(I);var h=require("@splitlab/core"),s=require("@splitlab/core"),g=class{constructor(e){this.serverConfig=null;this.eventQueue=[];this.flushTimer=null;this.configRefreshTimer=null;this.lastEtag=null;this.ready=!1;this.apiKey=e.apiKey,this.baseUrl=e.baseUrl.replace(/\/$/,""),this.ingestUrl=(e.ingestUrl||e.baseUrl).replace(/\/$/,""),this.configRefreshInterval=e.configRefreshInterval??3e4,this.flushInterval=e.flushInterval??1e4,this.flushSize=e.flushSize??100,this.onConfigUpdate=e.onConfigUpdate??null,this.environment=e.environment??"production"}async initialize(){let{config:e,etag:i}=await this.fetchConfig();this.serverConfig=e,this.lastEtag=i,this.configRefreshTimer=setInterval(()=>{this.refresh().catch(()=>{})},this.configRefreshInterval),this.flushTimer=setInterval(()=>{this.flush().catch(()=>{})},this.flushInterval),this.ready=!0}isReady(){return this.ready}async destroy(){this.configRefreshTimer!==null&&(clearInterval(this.configRefreshTimer),this.configRefreshTimer=null),this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),await this.flush(),this.ready=!1}getVariant(e,i,n){if(!this.serverConfig)return null;let t=this.serverConfig.experiments.find(a=>a.key===e);if(!t)return null;let l=this.serverConfig.segments||[];if(t.targeting_rules&&!(0,s.evaluateRules)(t.targeting_rules,n||{},l))return null;let o=(0,s.murmurhash3)(t.key+":"+i);if(o%1e4/100>=t.traffic_percentage)return null;let f=t.variants.reduce((a,m)=>a+m.weight,0),p=o%f,c=0;for(let a of t.variants)if(c+=a.weight,p<c)return a.key;return t.variants[t.variants.length-1].key}isFeatureEnabled(e,i,n){if(!this.serverConfig)return!1;let t=this.serverConfig.flags.find(f=>f.key===e);if(!t)return!1;let l=this.serverConfig.segments||[];return t.rules&&!(0,s.evaluateRules)(t.rules,n||{},l)?!1:(0,s.murmurhash3)(t.key+":"+i)%100<t.rollout_percentage}evaluateAll(e,i){return this.serverConfig?(0,s.localEvaluate)(this.serverConfig,e,i||{}):{experiments:{},flags:{}}}track(e,i,n){this.eventQueue.push({distinct_id:e,event_name:i,properties:n,timestamp:new Date().toISOString()}),this.eventQueue.length>=this.flushSize&&this.flush().catch(()=>{})}async flush(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];try{(await fetch(`${this.ingestUrl}/ingest/batch`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.apiKey},body:JSON.stringify({events:e})})).ok||(this.eventQueue=e.concat(this.eventQueue))}catch{this.eventQueue=e.concat(this.eventQueue)}}async refresh(){try{let{config:e,etag:i,notModified:n}=await this.fetchConfig();if(n)return;this.serverConfig=e,this.lastEtag=i,this.onConfigUpdate&&this.onConfigUpdate()}catch{}}async fetchConfig(){let e={"Content-Type":"application/json"};this.lastEtag&&(e["If-None-Match"]=this.lastEtag);let i=this.environment!=="production"?`&env=${encodeURIComponent(this.environment)}`:"",n=await fetch(`${this.baseUrl}/api/sdk/config?key=${encodeURIComponent(this.apiKey)}${i}`,{method:"GET",headers:e});if(n.status===304)return{config:this.serverConfig,etag:this.lastEtag,notModified:!0};if(!n.ok){let o=await n.text().catch(()=>"");throw new Error(`SplitLab API error ${n.status}: ${o}`)}let t=n.headers.get("etag");return{config:await n.json(),etag:t}}};0&&(module.exports={SplitLabServer,hashToFloat,murmurhash3});
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { EvalResult } from '@splitlab/core';
2
- export { EvalResult, ExperimentConfig, FlagConfig, ServerConfig, TargetingCondition, TargetingGroup, TargetingRules, TrackEvent, Variant, hashToFloat, murmurhash3 } from '@splitlab/core';
2
+ export { EvalResult, ExclusionGroupConfig, ExperimentConfig, FlagConfig, SegmentConfig, ServerConfig, TargetingCondition, TargetingGroup, TargetingRules, TrackEvent, Variant, hashToFloat, murmurhash3 } from '@splitlab/core';
3
3
 
4
4
  interface SplitLabServerConfig {
5
5
  apiKey: string;
@@ -13,6 +13,8 @@ interface SplitLabServerConfig {
13
13
  flushSize?: number;
14
14
  /** Callback when config changes (after refresh). */
15
15
  onConfigUpdate?: () => void;
16
+ /** Environment to fetch config for (e.g. 'development', 'staging', 'production'). Default: 'production'. */
17
+ environment?: string;
16
18
  }
17
19
  declare class SplitLabServer {
18
20
  private apiKey;
@@ -22,6 +24,7 @@ declare class SplitLabServer {
22
24
  private flushInterval;
23
25
  private flushSize;
24
26
  private onConfigUpdate;
27
+ private environment;
25
28
  private serverConfig;
26
29
  private eventQueue;
27
30
  private flushTimer;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { EvalResult } from '@splitlab/core';
2
- export { EvalResult, ExperimentConfig, FlagConfig, ServerConfig, TargetingCondition, TargetingGroup, TargetingRules, TrackEvent, Variant, hashToFloat, murmurhash3 } from '@splitlab/core';
2
+ export { EvalResult, ExclusionGroupConfig, ExperimentConfig, FlagConfig, SegmentConfig, ServerConfig, TargetingCondition, TargetingGroup, TargetingRules, TrackEvent, Variant, hashToFloat, murmurhash3 } from '@splitlab/core';
3
3
 
4
4
  interface SplitLabServerConfig {
5
5
  apiKey: string;
@@ -13,6 +13,8 @@ interface SplitLabServerConfig {
13
13
  flushSize?: number;
14
14
  /** Callback when config changes (after refresh). */
15
15
  onConfigUpdate?: () => void;
16
+ /** Environment to fetch config for (e.g. 'development', 'staging', 'production'). Default: 'production'. */
17
+ environment?: string;
16
18
  }
17
19
  declare class SplitLabServer {
18
20
  private apiKey;
@@ -22,6 +24,7 @@ declare class SplitLabServer {
22
24
  private flushInterval;
23
25
  private flushSize;
24
26
  private onConfigUpdate;
27
+ private environment;
25
28
  private serverConfig;
26
29
  private eventQueue;
27
30
  private flushTimer;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{murmurhash3 as C,hashToFloat as b}from"@splitlab/core";import{murmurhash3 as o,localEvaluate as v,evaluateRules as h}from"@splitlab/core";var f=class{constructor(e){this.serverConfig=null;this.eventQueue=[];this.flushTimer=null;this.configRefreshTimer=null;this.lastEtag=null;this.ready=!1;this.apiKey=e.apiKey,this.baseUrl=e.baseUrl.replace(/\/$/,""),this.ingestUrl=(e.ingestUrl||e.baseUrl).replace(/\/$/,""),this.configRefreshInterval=e.configRefreshInterval??3e4,this.flushInterval=e.flushInterval??1e4,this.flushSize=e.flushSize??100,this.onConfigUpdate=e.onConfigUpdate??null}async initialize(){let{config:e,etag:t}=await this.fetchConfig();this.serverConfig=e,this.lastEtag=t,this.configRefreshTimer=setInterval(()=>{this.refresh().catch(()=>{})},this.configRefreshInterval),this.flushTimer=setInterval(()=>{this.flush().catch(()=>{})},this.flushInterval),this.ready=!0}isReady(){return this.ready}async destroy(){this.configRefreshTimer!==null&&(clearInterval(this.configRefreshTimer),this.configRefreshTimer=null),this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),await this.flush(),this.ready=!1}getVariant(e,t,r){if(!this.serverConfig)return null;let i=this.serverConfig.experiments.find(n=>n.key===e);if(!i||i.targeting_rules&&!h(i.targeting_rules,r||{}))return null;let s=o(i.key+":"+t);if(s%1e4/100>=i.traffic_percentage)return null;let a=i.variants.reduce((n,c)=>n+c.weight,0),g=s%a,l=0;for(let n of i.variants)if(l+=n.weight,g<l)return n.key;return i.variants[i.variants.length-1].key}isFeatureEnabled(e,t,r){if(!this.serverConfig)return!1;let i=this.serverConfig.flags.find(a=>a.key===e);return!i||i.rules&&!h(i.rules,r||{})?!1:o(i.key+":"+t)%100<i.rollout_percentage}evaluateAll(e,t){return this.serverConfig?v(this.serverConfig,e,t||{}):{experiments:{},flags:{}}}track(e,t,r){this.eventQueue.push({distinct_id:e,event_name:t,properties:r,timestamp:new Date().toISOString()}),this.eventQueue.length>=this.flushSize&&this.flush().catch(()=>{})}async flush(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];try{(await fetch(`${this.ingestUrl}/ingest/batch`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.apiKey},body:JSON.stringify({events:e})})).ok||(this.eventQueue=e.concat(this.eventQueue))}catch{this.eventQueue=e.concat(this.eventQueue)}}async refresh(){try{let{config:e,etag:t,notModified:r}=await this.fetchConfig();if(r)return;this.serverConfig=e,this.lastEtag=t,this.onConfigUpdate&&this.onConfigUpdate()}catch{}}async fetchConfig(){let e={"Content-Type":"application/json"};this.lastEtag&&(e["If-None-Match"]=this.lastEtag);let t=await fetch(`${this.baseUrl}/api/sdk/config?key=${encodeURIComponent(this.apiKey)}`,{method:"GET",headers:e});if(t.status===304)return{config:this.serverConfig,etag:this.lastEtag,notModified:!0};if(!t.ok){let s=await t.text().catch(()=>"");throw new Error(`SplitLab API error ${t.status}: ${s}`)}let r=t.headers.get("etag");return{config:await t.json(),etag:r}}};export{f as SplitLabServer,b as hashToFloat,C as murmurhash3};
1
+ import{murmurhash3 as R,hashToFloat as b}from"@splitlab/core";import{murmurhash3 as h,localEvaluate as p,evaluateRules as f}from"@splitlab/core";var u=class{constructor(e){this.serverConfig=null;this.eventQueue=[];this.flushTimer=null;this.configRefreshTimer=null;this.lastEtag=null;this.ready=!1;this.apiKey=e.apiKey,this.baseUrl=e.baseUrl.replace(/\/$/,""),this.ingestUrl=(e.ingestUrl||e.baseUrl).replace(/\/$/,""),this.configRefreshInterval=e.configRefreshInterval??3e4,this.flushInterval=e.flushInterval??1e4,this.flushSize=e.flushSize??100,this.onConfigUpdate=e.onConfigUpdate??null,this.environment=e.environment??"production"}async initialize(){let{config:e,etag:i}=await this.fetchConfig();this.serverConfig=e,this.lastEtag=i,this.configRefreshTimer=setInterval(()=>{this.refresh().catch(()=>{})},this.configRefreshInterval),this.flushTimer=setInterval(()=>{this.flush().catch(()=>{})},this.flushInterval),this.ready=!0}isReady(){return this.ready}async destroy(){this.configRefreshTimer!==null&&(clearInterval(this.configRefreshTimer),this.configRefreshTimer=null),this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),await this.flush(),this.ready=!1}getVariant(e,i,n){if(!this.serverConfig)return null;let t=this.serverConfig.experiments.find(r=>r.key===e);if(!t)return null;let a=this.serverConfig.segments||[];if(t.targeting_rules&&!f(t.targeting_rules,n||{},a))return null;let s=h(t.key+":"+i);if(s%1e4/100>=t.traffic_percentage)return null;let o=t.variants.reduce((r,v)=>r+v.weight,0),c=s%o,l=0;for(let r of t.variants)if(l+=r.weight,c<l)return r.key;return t.variants[t.variants.length-1].key}isFeatureEnabled(e,i,n){if(!this.serverConfig)return!1;let t=this.serverConfig.flags.find(o=>o.key===e);if(!t)return!1;let a=this.serverConfig.segments||[];return t.rules&&!f(t.rules,n||{},a)?!1:h(t.key+":"+i)%100<t.rollout_percentage}evaluateAll(e,i){return this.serverConfig?p(this.serverConfig,e,i||{}):{experiments:{},flags:{}}}track(e,i,n){this.eventQueue.push({distinct_id:e,event_name:i,properties:n,timestamp:new Date().toISOString()}),this.eventQueue.length>=this.flushSize&&this.flush().catch(()=>{})}async flush(){if(this.eventQueue.length===0)return;let e=this.eventQueue;this.eventQueue=[];try{(await fetch(`${this.ingestUrl}/ingest/batch`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.apiKey},body:JSON.stringify({events:e})})).ok||(this.eventQueue=e.concat(this.eventQueue))}catch{this.eventQueue=e.concat(this.eventQueue)}}async refresh(){try{let{config:e,etag:i,notModified:n}=await this.fetchConfig();if(n)return;this.serverConfig=e,this.lastEtag=i,this.onConfigUpdate&&this.onConfigUpdate()}catch{}}async fetchConfig(){let e={"Content-Type":"application/json"};this.lastEtag&&(e["If-None-Match"]=this.lastEtag);let i=this.environment!=="production"?`&env=${encodeURIComponent(this.environment)}`:"",n=await fetch(`${this.baseUrl}/api/sdk/config?key=${encodeURIComponent(this.apiKey)}${i}`,{method:"GET",headers:e});if(n.status===304)return{config:this.serverConfig,etag:this.lastEtag,notModified:!0};if(!n.ok){let s=await n.text().catch(()=>"");throw new Error(`SplitLab API error ${n.status}: ${s}`)}let t=n.headers.get("etag");return{config:await n.json(),etag:t}}};export{u as SplitLabServer,b as hashToFloat,R as murmurhash3};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitlab/node",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Node.js server SDK for SplitLab A/B testing and feature flags",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -33,7 +33,7 @@
33
33
  "dev": "tsup --watch"
34
34
  },
35
35
  "dependencies": {
36
- "@splitlab/core": "^0.1.0"
36
+ "@splitlab/core": "^0.2.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "tsup": "^8.0.0",