@obelism/improve-sdk 0.2.0 → 0.3.1

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/README.md CHANGED
@@ -1 +1,183 @@
1
1
  # Obelism Improve JS SDK
2
+
3
+ ## Install
4
+
5
+ ```bash
6
+ npm i @obelism/improve-sdk
7
+ ```
8
+
9
+ ## Class
10
+
11
+ The Improve JS SDK exposes two classes;
12
+
13
+ - [ImproveServerSDK](https://improve.obelism.studio/docs/sdk/javascript#server)
14
+ - [ImproveClientSDK](https://improve.obelism.studio/docs/sdk/javascript#client)
15
+ - [Types](https://improve.obelism.studio/docs/sdk/javascript#types)
16
+
17
+ While similar they both work slightly different but are based on the same base. This base defines the constructor and three methods;
18
+
19
+ ### constructor
20
+
21
+ ```ts
22
+ constructor({
23
+ organizationId: string
24
+ environment: 'develop' | 'staging' | 'production'
25
+ config?: Configuration
26
+ fetchTimeout?: number
27
+ }) => void
28
+ ```
29
+
30
+ - **organizationId** - Unique identifier of your Organization, available from your dashboard
31
+ - **environment** - Application environment, can be one of three values
32
+ - **config** - (optional) Configuration file, this can be either fetched or provided on initialization
33
+ - **fetchTimeout** - (optional) When fetching the config after what amount of ms should it abort, default; 3000ms
34
+
35
+ ### fetchConfig
36
+
37
+ ```ts
38
+ async fetchConfig() => void
39
+ ```
40
+
41
+ Asynchronous function that fetches the config from Improve. Either provide the config on initialization or use this function to get started.
42
+
43
+ ### loadConfig
44
+
45
+ ```ts
46
+ loadConfig = (config: ImproveConfiguration) => void
47
+ ```
48
+
49
+ When loading an Improve config file from a different source you can either pass it directly into the class constructor or load it with the `loadConfig` method.
50
+
51
+ ### generateVisitorId
52
+
53
+ ```ts
54
+ generateVisitorId() => string
55
+ ```
56
+
57
+ Method to get a unique identifier for a visitor. Recommended to save the generated visitor ID in a cookie with a max-age so that between visits you'll be able to keep serving the same version to this visitor.
58
+
59
+ ### getVisitorCookieName
60
+
61
+ ```ts
62
+ getVisitorCookieName() => string
63
+ ```
64
+
65
+ Helper method that gives you the name for the visitorID cookie name. If this name is used on the server, the client will be able to pick up and send events to Improve.
66
+
67
+ ### validateTestValue
68
+
69
+ ```ts
70
+ validateTestValue = (testName: string, testValue: string) => boolean
71
+ ```
72
+
73
+ Validate if a test name and test value are a valid combination. Requires a config to be loaded by either passing it in the constructor, using [loadConfig](/docs/sdk/javascript#loadconfig) or [fetchConfig](/docs/sdk/javascript#fetchconfig).
74
+
75
+ ## Server
76
+
77
+ The server class is setup that it can run on either serverless or serverfull environments. When running in a serverfull envrionment it will use memory to keep track of recent visitors decisions. However it is recommend to always store the made decision in a cookie in case the memory has been purged between visits of a visitor.
78
+
79
+ ### getFlagConfig
80
+
81
+ ```ts
82
+ getFlagConfig(flagSlug: string) => {
83
+ id: string
84
+ name: string
85
+ audience: string
86
+ options: {
87
+ name: string
88
+ slug: string
89
+ value: string | undefined
90
+ split: number
91
+ }[]
92
+ } | undefined
93
+ ```
94
+
95
+ Exposed for when needed but in most cases it's recommended to use the [getFlagValue](/docs/sdk/javascript#getflagvalue) directly.
96
+
97
+ ### getTestConfig
98
+
99
+ ```ts
100
+ getTestConfig(testSlug: string) => {
101
+ id: string
102
+ name: string
103
+ defaultValue: string
104
+ audience: string
105
+ allocation: number
106
+ options: {
107
+ name: string
108
+ slug: string
109
+ value: string | undefined
110
+ split: number
111
+ }[]
112
+ events: {
113
+ start: string
114
+ metrics: string[]
115
+ conversion: string
116
+ }
117
+ } | undefined
118
+ ```
119
+
120
+ Exposed for when needed but in most cases it's recommended to use the [getTestValue](/docs/sdk/javascript#gettestvalue) directly.
121
+
122
+ ### getFlagValue
123
+
124
+ ```ts
125
+ getFlagValue = (flagSlug: string, visitorId: string, userAgent: string) =>
126
+ string | null
127
+ ```
128
+
129
+ Based on the slug, visitorId and userAgent this method gives you back what version of the flag this visitor should get. If no config is loaded yet or no flag with the given slug is found it returns `null`. When the userAgent of the visitor doesn't match the audience of the Flag it will always return the control value. If the visitor does match the audience it will receive the control or variation based on the randomization using the odds setup in the split.
130
+
131
+ ### getTestValue
132
+
133
+ ```ts
134
+ getTestValue = (testSlug: string, visitorId: string, userAgent: string) =>
135
+ string | null
136
+ ```
137
+
138
+ Based on the slug, visitorId and userAgent this method gives you back what version of the AB test this visitor should get. If no config is loaded yet or no AB test with the given slug is found it returns `null`. When the userAgent of the visitor doesn't match the audience of the Test it will always return the control value. If the visitor does match the audience it will then check the allocation. If that's lower than 100% it will based on randomization check if this visitor should get the AB test. After that it will receive a random version of the test based on the randomization using the odds setup in the split.
139
+
140
+ ## Client
141
+
142
+ ### setupVisitor
143
+
144
+ ```ts
145
+ setupVisitor(userAgent: string = window.navigator.userAgent) => string | null
146
+ ```
147
+
148
+ Optional method to setup the visitor, if this is not called before using any of the other Client methods it will be called automatically. You only have to call this yourself if you want to make sure it gets the `userAgent` from somewhere else.
149
+
150
+ This method will automatically save the visitorID to the class and cookie + parse the userAgent to be used in the postAnalytic.
151
+
152
+ ### getFlagValue
153
+
154
+ ```ts
155
+ getFlagValue = (flagSlug: string) => string | null
156
+ ```
157
+
158
+ Same as [getFlagValue](/docs/sdk/javascript#getflagvalue) on the server class this generates and give the unique value. However on the client it also saves the value to a cookie that's stored for one month.
159
+
160
+ ### getTestValue
161
+
162
+ ```ts
163
+ getTestValue = (testSlug: string) => string | null
164
+ ```
165
+
166
+ Same as [getTestValue](/docs/sdk/javascript#gettestvalue) on the server class this generates and give the unique value. However on the client it also saves the value to a cookie that's stored for one month.
167
+
168
+ ### setAnalyticsUrls
169
+
170
+ ```ts
171
+ setAnalyticsUrls = (url: string) => void
172
+ ```
173
+
174
+ Configure the analytics url to post message towards. Convenient in case add blockers block the direct post requests you can proxy them through your domain and pathname.
175
+
176
+ ### postAnalytic
177
+
178
+ ```ts
179
+ postAnalytic = (testSlug: string, event: string, message?: string) =>
180
+ Promise<Response> | null
181
+ ```
182
+
183
+ Posts an analytics message to Improve or the url configured with [setAnalyticsUrls](/docs/sdk/javascript#setanalyticsurls)
package/dist/client.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,"__esModule",{value:!0});var i=require("ua-parser-js"),t=i&&i.__esModule?i:{default:i};const e={device:["wearable","mobile","tablet","console","smarttv","embedded","desktop"],browser:["chrome","safari","firefox","edge","ie","samsung internet","social","other"],os:["mac os","ios","android","windows","unix"]},s=i=>i&&e.device.includes(i)?i:"desktop",r=["tiktok","wechat","weibo","snapchat","klarna","Line","instagram","facebook","alipay","Baidu"],o=(i="")=>{if(!i)return"other";let t=i.toLowerCase();return e.browser.find(i=>t.includes(i))||(r.includes(t)?"social":"other")},n=["wearable","mobile","tablet"],l=i=>n.includes(i)?"coarse":"fine",a=(i="")=>{if(!i)return"unix";let t=i.toLowerCase();return e.os.find(i=>t.includes(i))||"unix"},u=i=>{if(!i||"string"!=typeof i)return null;let e=new t.default(i).getResult(),r=s(e.device.type);return{pointer:l(r),device:r,browser:o(e.browser.name),os:a(e.os.name)}},h=(i,t)=>!i||Object.entries(i).every(([i,e])=>t[i]===e),c=i=>{if(0===i.length)return null;if(1===i.length)return i[0].slug;let t=Math.random()*i.reduce((i,{split:t})=>i+t,0);return(i.find(({split:i})=>(t-=i)<=0)||i[0]).slug},d="visi",f="https://improve.obelism.studio",g=`${f}/config`,v=`${f}/api/log`,p="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",m=i=>new Promise(t=>setTimeout(t,i)),w=async(i=1e3,t)=>(await m(i),t?.abort(),null),b=(i=3e3,t,e)=>{let s=new AbortController;return Promise.race([fetch(t,{...e,signal:s.signal}),w(i,s)])};class y{#i;constructor({organizationId:i,environment:t,state:e,config:s,fetchTimeout:r}){this.organizationId="",this.environment="develop",this.#i=null,this.config=null,this.fetchConfig=async i=>{if(this.config)return;if(!this.#i)throw Error("No config fetch setup provided");let t=await b(this.#i.timeout,this.#i.url,i);if(!t||!t.ok)throw Error("Configuration fetch timed-out");this.config=await t.json()},this.loadConfig=i=>{this.config=i},this.generateVisitorId=()=>[d,(function(i=5){return i&&"number"==typeof i?Array(i).fill("").reduce(i=>i+=p.charAt(Math.floor(Math.random()*p.length)),""):""})(26).toUpperCase()].join("_"),this.getVisitorCookieName=()=>"visitorId",this.validateTestValue=(i,t)=>{if(!this.config)throw Error("Config is required before validating, either use `.fetchConfig()`, .loadConfig(config) or provide it during setup");let e=this.config.tests[i];if(!e)throw Error(`No config found for ${i}`);return!!e.options.find(i=>i.slug===t)},this.validateVisitorId=i=>{let t=i.split("_");if(2!==t.length)return!1;let[e,s]=t;return e===d&&26===s.length},this.organizationId=i,this.environment=t,s?this.config=s:this.#i={url:[g,i,t,e||"active"].join("/"),timeout:r||3e3}}}const I=i=>{if(!i)return!1;let t=document.cookie.split("; ").find(t=>{let[e]=t.split("=");return i===e});return!!t&&t.split("=")[1]},V=(i,t)=>{let e=new Date;e.setMonth(e.getMonth()+1),document.cookie=`${i}=${t};path=/;expires=${e.toUTCString()}`},C=()=>{let i=window.innerWidth;return i<=768?"small":i<=1024?"medium":i<=1200?"large":"huge"};exports.ImproveClientSDK=class extends y{#t;#e;#s;#r;#o;constructor(...i){super(...i),this.#e=!1,this.#s="",this.#r={},this.#o=v,this.setupVisitor=(i=window.navigator.userAgent)=>{let t=I(this.getVisitorCookieName()),e=t&&this.validateVisitorId(t);this.#e=e,this.#s=e?t:this.generateVisitorId();let s=u(i);return s?(this.#t=s,V(this.getVisitorCookieName(),this.#s),this.#s):null},this.getFlagValue=i=>{if(!this.config)return null;let t=this.config.flags[i];if(!t||!t.options[0])return null;if(this.#t||this.setupVisitor(),!this.#s||!this.#t)return t.options[0].slug;if(this.#t?.[i])return this.#t[i];if(!h(this.config.audience[t.audience],this.#t))return t.options[0].slug;let e=I(i)||c(t.options);return e?(this.#t[i]=e,V(i,e),e):null},this.getTestValue=i=>{if(!this.config)return null;let t=this.config.tests[i];if(!t)return null;if(this.#t||this.setupVisitor(),!this.#s||!this.#t)return t.defaultValue;if(this.#t?.[i])return this.#t[i];if(!h(this.config.audience[t.audience],this.#t))return t.defaultValue;if(t.allocation<100&&100*Math.random()>t.allocation)return this.#t[i]=t.defaultValue,this.#t?.[i];let e=I(i),s=e&&this.validateTestValue(i,e)?e:c(t.options);return s?(this.#t[i]=s,V(i,s),s):null},this.setAnalyticsUrls=i=>{this.#o=i},this.postAnalytic=(i,t,e)=>{if(!this.config)return null;let s=this.config.tests[i];if(this.#t||this.setupVisitor(),!s||!this.#t||this.#r?.[i]?.[t])return null;let r=this.#r[i]||{};r[t]=!0,this.#r[i]=r;let o=this.#t?.[i]||null;if(o||(o=this.getTestValue(i)||null),!o)return;let n={organizationId:this.organizationId,environment:this.environment,testId:s.id,testValue:o,visitorId:this.#s,pointer:this.#t.pointer,device:this.#t.device,screen:C(),browser:this.#t.browser,os:this.#t.os,visitor:this.#e?"recurring":"new",event:t,message:e||""};return fetch(this.#o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)})}}};
1
+ Object.defineProperty(exports,"__esModule",{value:!0});var i=require("ua-parser-js"),t=i&&i.__esModule?i:{default:i};const e={device:["wearable","mobile","tablet","console","smarttv","embedded","desktop"],browser:["chrome","safari","firefox","edge","ie","samsung internet","social","other"],os:["mac os","ios","android","windows","unix"]},s=i=>i&&e.device.includes(i)?i:"desktop",r=["tiktok","wechat","weibo","snapchat","klarna","Line","instagram","facebook","alipay","Baidu"],o=(i="")=>{if(!i)return"other";let t=i.toLowerCase();return e.browser.find(i=>t.includes(i))||(r.includes(t)?"social":"other")},n=["wearable","mobile","tablet"],l=i=>n.includes(i)?"coarse":"fine",a=(i="")=>{if(!i)return"unix";let t=i.toLowerCase();return e.os.find(i=>t.includes(i))||"unix"},h=i=>{if(!i||"string"!=typeof i)return null;let e=new t.default(i).getResult(),r=s(e.device.type);return{pointer:l(r),device:r,browser:o(e.browser.name),os:a(e.os.name)}},u=(i,t)=>!i||Object.entries(i).every(([i,e])=>t[i]===e),c=i=>{if(0===i.length)return null;if(1===i.length)return i[0].slug;let t=Math.random()*i.reduce((i,{split:t})=>i+t,0);return(i.find(({split:i})=>(t-=i)<=0)||i[0]).slug},f="visi",d="https://improve.obelism.studio",g="/api/log",v="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",p=i=>new Promise(t=>setTimeout(t,i)),m=async(i=1e3,t)=>(await p(i),t?.abort(),null),w=(i=3e3,t,e)=>{let s=new AbortController;return Promise.race([fetch(t,{...e,signal:s.signal}),m(i,s)])};class b{#i;constructor({organizationId:i,environment:t,state:e,config:s,fetchTimeout:r,baseUrl:o}){this.organizationId="",this.environment="develop",this.#i=null,this.config=null,this._fetchConfig=async i=>{if(this.config)return;if(!this.#i)throw Error("No config fetch setup provided");let t=await w(this.#i.timeout,this.#i.url,i);if(!t||!t.ok)throw Error("Configuration fetch timed-out");this.config=await t.json()},this.loadConfig=i=>{this.config=i},this.generateVisitorId=()=>[f,(function(i=5){return i&&"number"==typeof i?Array(i).fill("").reduce(i=>i+=v.charAt(Math.floor(Math.random()*v.length)),""):""})(26).toUpperCase()].join("_"),this.getVisitorCookieName=()=>"visitorId",this.validateTestValue=(i,t)=>{if(!this.config)throw Error("Config is required before validating, either use `.fetchConfig()`, .loadConfig(config) or provide it during setup");let e=this.config.tests[i];if(!e)throw Error(`No config found for ${i}`);return!!e.options.find(i=>i.slug===t)},this.validateVisitorId=i=>{let t=i.split("_");if(2!==t.length)return!1;let[e,s]=t;return e===f&&26===s.length},this.organizationId=i,this.environment=t,this._baseUrl=o||d,s?this.config=s:this.#i={url:[`${this._baseUrl}/config`,i,t,e||"active"].join("/"),timeout:r||3e3}}}const y=i=>{if(!i)return!1;let t=document.cookie.split("; ").find(t=>{let[e]=t.split("=");return i===e});return!!t&&t.split("=")[1]},I=(i,t)=>{let e=new Date;e.setMonth(e.getMonth()+1),document.cookie=`${i}=${t};path=/;expires=${e.toUTCString()}`},V=()=>{let i=window.innerWidth;return i<=768?"small":i<=1024?"medium":i<=1200?"large":"huge"};exports.ImproveClientSDK=class extends b{#t;#e;#s;#r;#o;constructor(i){super(i),this.#e=!1,this.#s="",this.#r={},this.#o=`${d}${g}`,this.fetchConfig=this._fetchConfig,this.setupVisitor=(i=window.navigator.userAgent)=>{let t=y(this.getVisitorCookieName()),e=t&&this.validateVisitorId(t);this.#e=e,this.#s=e?t:this.generateVisitorId();let s=h(i);return s?(this.#t=s,I(this.getVisitorCookieName(),this.#s),this.#s):null},this.getFlagValue=i=>{if(!this.config)return null;let t=this.config.flags[i];if(!t||!t.options[0])return null;if(this.#t||this.setupVisitor(),!this.#s||!this.#t)return t.options[0].slug;if(this.#t?.[i])return this.#t[i];if(!u(this.config.audience[t.audience],this.#t))return t.options[0].slug;let e=y(i)||c(t.options);return e?(this.#t[i]=e,I(i,e),e):null},this.getTestValue=i=>{if(!this.config)return null;let t=this.config.tests[i];if(!t)return null;if(this.#t||this.setupVisitor(),!this.#s||!this.#t)return t.defaultValue;if(this.#t?.[i])return this.#t[i];if(!u(this.config.audience[t.audience],this.#t))return t.defaultValue;if(t.allocation<100&&100*Math.random()>t.allocation)return this.#t[i]=t.defaultValue,this.#t?.[i];let e=y(i),s=e&&this.validateTestValue(i,e)?e:c(t.options);return s?(this.#t[i]=s,I(i,s),s):null},this.setAnalyticsUrls=i=>{this.#o=i},this.postAnalytic=(i,t,e)=>{if(!this.config)return null;let s=this.config.tests[i];if(this.#t||this.setupVisitor(),!s||!this.#t||this.#r?.[i]?.[t])return null;let r=this.#r[i]||{};r[t]=!0,this.#r[i]=r;let o=this.#t?.[i]||null;if(o||(o=this.getTestValue(i)||null),!o)return;let n={organizationId:this.organizationId,environment:this.environment,testId:s.id,testValue:o,visitorId:this.#s,pointer:this.#t.pointer,device:this.#t.device,screen:V(),browser:this.#t.browser,os:this.#t.os,visitor:this.#e?"recurring":"new",event:t,message:e||""};return fetch(this.#o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)})},this.#o=`${this._baseUrl}${g}`}};
package/dist/client.d.ts CHANGED
@@ -5,8 +5,9 @@ declare class BaseImproveSDK {
5
5
  organizationId: string;
6
6
  environment: ImproveEnvironmentOption;
7
7
  config: ImproveConfiguration | null;
8
- constructor({ organizationId, environment, state, config, fetchTimeout, }: ImproveSetupArgs);
9
- fetchConfig: (config?: RequestInit) => Promise<void>;
8
+ _baseUrl: undefined | string;
9
+ constructor({ organizationId, environment, state, config, fetchTimeout, baseUrl, }: ImproveSetupArgs);
10
+ _fetchConfig: (config?: RequestInit) => Promise<void>;
10
11
  loadConfig: (config: ImproveConfiguration) => void;
11
12
  generateVisitorId: () => string;
12
13
  getVisitorCookieName: () => string;
@@ -31,6 +32,8 @@ type CreateAnalytic = {
31
32
  };
32
33
  declare class ImproveClientSDK extends BaseImproveSDK {
33
34
  #private;
35
+ fetchConfig: (config?: RequestInit) => Promise<void>;
36
+ constructor(args: ImproveSetupArgs);
34
37
  setupVisitor: (userAgent?: string) => string;
35
38
  getFlagValue: (flagSlug: string) => string;
36
39
  getTestValue: (testSlug: string) => string;
package/dist/client.mjs CHANGED
@@ -1 +1 @@
1
- import i from"ua-parser-js";let t={device:["wearable","mobile","tablet","console","smarttv","embedded","desktop"],browser:["chrome","safari","firefox","edge","ie","samsung internet","social","other"],os:["mac os","ios","android","windows","unix"]},e=i=>i&&t.device.includes(i)?i:"desktop",s=["tiktok","wechat","weibo","snapchat","klarna","Line","instagram","facebook","alipay","Baidu"],r=(i="")=>{if(!i)return"other";let e=i.toLowerCase();return t.browser.find(i=>e.includes(i))||(s.includes(e)?"social":"other")},o=["wearable","mobile","tablet"],n=i=>o.includes(i)?"coarse":"fine",l=(i="")=>{if(!i)return"unix";let e=i.toLowerCase();return t.os.find(i=>e.includes(i))||"unix"},a=t=>{if(!t||"string"!=typeof t)return null;let s=new i(t).getResult(),o=e(s.device.type);return{pointer:n(o),device:o,browser:r(s.browser.name),os:l(s.os.name)}},h=(i,t)=>!i||Object.entries(i).every(([i,e])=>t[i]===e),u=i=>{if(0===i.length)return null;if(1===i.length)return i[0].slug;let t=Math.random()*i.reduce((i,{split:t})=>i+t,0);return(i.find(({split:i})=>(t-=i)<=0)||i[0]).slug},c="visi",f="https://improve.obelism.studio",d=`${f}/config`,g=`${f}/api/log`,v="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",p=i=>new Promise(t=>setTimeout(t,i)),m=async(i=1e3,t)=>(await p(i),t?.abort(),null),w=(i=3e3,t,e)=>{let s=new AbortController;return Promise.race([fetch(t,{...e,signal:s.signal}),m(i,s)])};class b{#i;constructor({organizationId:i,environment:t,state:e,config:s,fetchTimeout:r}){this.organizationId="",this.environment="develop",this.#i=null,this.config=null,this.fetchConfig=async i=>{if(this.config)return;if(!this.#i)throw Error("No config fetch setup provided");let t=await w(this.#i.timeout,this.#i.url,i);if(!t||!t.ok)throw Error("Configuration fetch timed-out");this.config=await t.json()},this.loadConfig=i=>{this.config=i},this.generateVisitorId=()=>[c,(function(i=5){return i&&"number"==typeof i?Array(i).fill("").reduce(i=>i+=v.charAt(Math.floor(Math.random()*v.length)),""):""})(26).toUpperCase()].join("_"),this.getVisitorCookieName=()=>"visitorId",this.validateTestValue=(i,t)=>{if(!this.config)throw Error("Config is required before validating, either use `.fetchConfig()`, .loadConfig(config) or provide it during setup");let e=this.config.tests[i];if(!e)throw Error(`No config found for ${i}`);return!!e.options.find(i=>i.slug===t)},this.validateVisitorId=i=>{let t=i.split("_");if(2!==t.length)return!1;let[e,s]=t;return e===c&&26===s.length},this.organizationId=i,this.environment=t,s?this.config=s:this.#i={url:[d,i,t,e||"active"].join("/"),timeout:r||3e3}}}let y=i=>{if(!i)return!1;let t=document.cookie.split("; ").find(t=>{let[e]=t.split("=");return i===e});return!!t&&t.split("=")[1]},I=(i,t)=>{let e=new Date;e.setMonth(e.getMonth()+1),document.cookie=`${i}=${t};path=/;expires=${e.toUTCString()}`},V=()=>{let i=window.innerWidth;return i<=768?"small":i<=1024?"medium":i<=1200?"large":"huge"};class C extends b{#t;#e;#s;#r;#o;constructor(...i){super(...i),this.#e=!1,this.#s="",this.#r={},this.#o=g,this.setupVisitor=(i=window.navigator.userAgent)=>{let t=y(this.getVisitorCookieName()),e=t&&this.validateVisitorId(t);this.#e=e,this.#s=e?t:this.generateVisitorId();let s=a(i);return s?(this.#t=s,I(this.getVisitorCookieName(),this.#s),this.#s):null},this.getFlagValue=i=>{if(!this.config)return null;let t=this.config.flags[i];if(!t||!t.options[0])return null;if(this.#t||this.setupVisitor(),!this.#s||!this.#t)return t.options[0].slug;if(this.#t?.[i])return this.#t[i];if(!h(this.config.audience[t.audience],this.#t))return t.options[0].slug;let e=y(i)||u(t.options);return e?(this.#t[i]=e,I(i,e),e):null},this.getTestValue=i=>{if(!this.config)return null;let t=this.config.tests[i];if(!t)return null;if(this.#t||this.setupVisitor(),!this.#s||!this.#t)return t.defaultValue;if(this.#t?.[i])return this.#t[i];if(!h(this.config.audience[t.audience],this.#t))return t.defaultValue;if(t.allocation<100&&100*Math.random()>t.allocation)return this.#t[i]=t.defaultValue,this.#t?.[i];let e=y(i),s=e&&this.validateTestValue(i,e)?e:u(t.options);return s?(this.#t[i]=s,I(i,s),s):null},this.setAnalyticsUrls=i=>{this.#o=i},this.postAnalytic=(i,t,e)=>{if(!this.config)return null;let s=this.config.tests[i];if(this.#t||this.setupVisitor(),!s||!this.#t||this.#r?.[i]?.[t])return null;let r=this.#r[i]||{};r[t]=!0,this.#r[i]=r;let o=this.#t?.[i]||null;if(o||(o=this.getTestValue(i)||null),!o)return;let n={organizationId:this.organizationId,environment:this.environment,testId:s.id,testValue:o,visitorId:this.#s,pointer:this.#t.pointer,device:this.#t.device,screen:V(),browser:this.#t.browser,os:this.#t.os,visitor:this.#e?"recurring":"new",event:t,message:e||""};return fetch(this.#o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)})}}}export{C as ImproveClientSDK};
1
+ import i from"ua-parser-js";let t={device:["wearable","mobile","tablet","console","smarttv","embedded","desktop"],browser:["chrome","safari","firefox","edge","ie","samsung internet","social","other"],os:["mac os","ios","android","windows","unix"]},e=i=>i&&t.device.includes(i)?i:"desktop",s=["tiktok","wechat","weibo","snapchat","klarna","Line","instagram","facebook","alipay","Baidu"],r=(i="")=>{if(!i)return"other";let e=i.toLowerCase();return t.browser.find(i=>e.includes(i))||(s.includes(e)?"social":"other")},o=["wearable","mobile","tablet"],n=i=>o.includes(i)?"coarse":"fine",l=(i="")=>{if(!i)return"unix";let e=i.toLowerCase();return t.os.find(i=>e.includes(i))||"unix"},a=t=>{if(!t||"string"!=typeof t)return null;let s=new i(t).getResult(),o=e(s.device.type);return{pointer:n(o),device:o,browser:r(s.browser.name),os:l(s.os.name)}},h=(i,t)=>!i||Object.entries(i).every(([i,e])=>t[i]===e),u=i=>{if(0===i.length)return null;if(1===i.length)return i[0].slug;let t=Math.random()*i.reduce((i,{split:t})=>i+t,0);return(i.find(({split:i})=>(t-=i)<=0)||i[0]).slug},c="visi",f="https://improve.obelism.studio",d="/api/log",g="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",v=i=>new Promise(t=>setTimeout(t,i)),p=async(i=1e3,t)=>(await v(i),t?.abort(),null),m=(i=3e3,t,e)=>{let s=new AbortController;return Promise.race([fetch(t,{...e,signal:s.signal}),p(i,s)])};class w{#i;constructor({organizationId:i,environment:t,state:e,config:s,fetchTimeout:r,baseUrl:o}){this.organizationId="",this.environment="develop",this.#i=null,this.config=null,this._fetchConfig=async i=>{if(this.config)return;if(!this.#i)throw Error("No config fetch setup provided");let t=await m(this.#i.timeout,this.#i.url,i);if(!t||!t.ok)throw Error("Configuration fetch timed-out");this.config=await t.json()},this.loadConfig=i=>{this.config=i},this.generateVisitorId=()=>[c,(function(i=5){return i&&"number"==typeof i?Array(i).fill("").reduce(i=>i+=g.charAt(Math.floor(Math.random()*g.length)),""):""})(26).toUpperCase()].join("_"),this.getVisitorCookieName=()=>"visitorId",this.validateTestValue=(i,t)=>{if(!this.config)throw Error("Config is required before validating, either use `.fetchConfig()`, .loadConfig(config) or provide it during setup");let e=this.config.tests[i];if(!e)throw Error(`No config found for ${i}`);return!!e.options.find(i=>i.slug===t)},this.validateVisitorId=i=>{let t=i.split("_");if(2!==t.length)return!1;let[e,s]=t;return e===c&&26===s.length},this.organizationId=i,this.environment=t,this._baseUrl=o||f,s?this.config=s:this.#i={url:[`${this._baseUrl}/config`,i,t,e||"active"].join("/"),timeout:r||3e3}}}let b=i=>{if(!i)return!1;let t=document.cookie.split("; ").find(t=>{let[e]=t.split("=");return i===e});return!!t&&t.split("=")[1]},y=(i,t)=>{let e=new Date;e.setMonth(e.getMonth()+1),document.cookie=`${i}=${t};path=/;expires=${e.toUTCString()}`},I=()=>{let i=window.innerWidth;return i<=768?"small":i<=1024?"medium":i<=1200?"large":"huge"};class V extends w{#t;#e;#s;#r;#o;constructor(i){super(i),this.#e=!1,this.#s="",this.#r={},this.#o=`${f}${d}`,this.fetchConfig=this._fetchConfig,this.setupVisitor=(i=window.navigator.userAgent)=>{let t=b(this.getVisitorCookieName()),e=t&&this.validateVisitorId(t);this.#e=e,this.#s=e?t:this.generateVisitorId();let s=a(i);return s?(this.#t=s,y(this.getVisitorCookieName(),this.#s),this.#s):null},this.getFlagValue=i=>{if(!this.config)return null;let t=this.config.flags[i];if(!t||!t.options[0])return null;if(this.#t||this.setupVisitor(),!this.#s||!this.#t)return t.options[0].slug;if(this.#t?.[i])return this.#t[i];if(!h(this.config.audience[t.audience],this.#t))return t.options[0].slug;let e=b(i)||u(t.options);return e?(this.#t[i]=e,y(i,e),e):null},this.getTestValue=i=>{if(!this.config)return null;let t=this.config.tests[i];if(!t)return null;if(this.#t||this.setupVisitor(),!this.#s||!this.#t)return t.defaultValue;if(this.#t?.[i])return this.#t[i];if(!h(this.config.audience[t.audience],this.#t))return t.defaultValue;if(t.allocation<100&&100*Math.random()>t.allocation)return this.#t[i]=t.defaultValue,this.#t?.[i];let e=b(i),s=e&&this.validateTestValue(i,e)?e:u(t.options);return s?(this.#t[i]=s,y(i,s),s):null},this.setAnalyticsUrls=i=>{this.#o=i},this.postAnalytic=(i,t,e)=>{if(!this.config)return null;let s=this.config.tests[i];if(this.#t||this.setupVisitor(),!s||!this.#t||this.#r?.[i]?.[t])return null;let r=this.#r[i]||{};r[t]=!0,this.#r[i]=r;let o=this.#t?.[i]||null;if(o||(o=this.getTestValue(i)||null),!o)return;let n={organizationId:this.organizationId,environment:this.environment,testId:s.id,testValue:o,visitorId:this.#s,pointer:this.#t.pointer,device:this.#t.device,screen:I(),browser:this.#t.browser,os:this.#t.os,visitor:this.#e?"recurring":"new",event:t,message:e||""};return fetch(this.#o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)})},this.#o=`${this._baseUrl}${d}`}}export{V as ImproveClientSDK};
package/dist/server.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,"__esModule",{value:!0});var i=require("ua-parser-js"),t=i&&i.__esModule?i:{default:i};const e={device:["wearable","mobile","tablet","console","smarttv","embedded","desktop"],browser:["chrome","safari","firefox","edge","ie","samsung internet","social","other"],os:["mac os","ios","android","windows","unix"]},s=i=>i&&e.device.includes(i)?i:"desktop",r=["tiktok","wechat","weibo","snapchat","klarna","Line","instagram","facebook","alipay","Baidu"],o=(i="")=>{if(!i)return"other";let t=i.toLowerCase();return e.browser.find(i=>t.includes(i))||(r.includes(t)?"social":"other")},n=["wearable","mobile","tablet"],l=i=>n.includes(i)?"coarse":"fine",a=(i="")=>{if(!i)return"unix";let t=i.toLowerCase();return e.os.find(i=>t.includes(i))||"unix"},u=i=>{if(!i||"string"!=typeof i)return null;let e=new t.default(i).getResult(),r=s(e.device.type);return{pointer:l(r),device:r,browser:o(e.browser.name),os:a(e.os.name)}},h=(i,t)=>!i||Object.entries(i).every(([i,e])=>t[i]===e),f=i=>{if(0===i.length)return null;if(1===i.length)return i[0].slug;let t=Math.random()*i.reduce((i,{split:t})=>i+t,0);return(i.find(({split:i})=>(t-=i)<=0)||i[0]).slug},c="visi",g="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",d=i=>new Promise(t=>setTimeout(t,i)),v=async(i=1e3,t)=>(await d(i),t?.abort(),null),p=(i=3e3,t,e)=>{let s=new AbortController;return Promise.race([fetch(t,{...e,signal:s.signal}),v(i,s)])};class m{#i;constructor({organizationId:i,environment:t,state:e,config:s,fetchTimeout:r}){this.organizationId="",this.environment="develop",this.#i=null,this.config=null,this.fetchConfig=async i=>{if(this.config)return;if(!this.#i)throw Error("No config fetch setup provided");let t=await p(this.#i.timeout,this.#i.url,i);if(!t||!t.ok)throw Error("Configuration fetch timed-out");this.config=await t.json()},this.loadConfig=i=>{this.config=i},this.generateVisitorId=()=>[c,(function(i=5){return i&&"number"==typeof i?Array(i).fill("").reduce(i=>i+=g.charAt(Math.floor(Math.random()*g.length)),""):""})(26).toUpperCase()].join("_"),this.getVisitorCookieName=()=>"visitorId",this.validateTestValue=(i,t)=>{if(!this.config)throw Error("Config is required before validating, either use `.fetchConfig()`, .loadConfig(config) or provide it during setup");let e=this.config.tests[i];if(!e)throw Error(`No config found for ${i}`);return!!e.options.find(i=>i.slug===t)},this.validateVisitorId=i=>{let t=i.split("_");if(2!==t.length)return!1;let[e,s]=t;return e===c&&26===s.length},this.organizationId=i,this.environment=t,s?this.config=s:this.#i={url:["https://improve.obelism.studio/config",i,t,e||"active"].join("/"),timeout:r||3e3}}}exports.ImproveServerSDK=class extends m{#t;constructor(...i){super(...i),this.#t={},this.getFlagConfig=i=>this.config?.flags?.[i],this.getTestConfig=i=>this.config?.tests?.[i],this.getFlagValue=(i,t,e)=>{let s=this.getFlagConfig(i);if(!s||!this.config)return null;if(!t)return s.options[0].slug;if(this.#t?.[t]?.[e]?.[i])return this.#t[t][e][i];if(this.#t[t]=this.#t[t]||{},this.#t[t][e]=this.#t[t][e]||u(e),!h(this.config.audience[s.audience],this.#t[t][e]))return s.options[0].slug;let r=f(s.options);return r?(this.#t[t][e][i]=r,r):null},this.getTestValue=(i,t,e)=>{let s=this.getTestConfig(i);if(!s||!this.config)return null;if(!t||!e)return s.defaultValue;if(this.#t?.[t]?.[e]?.[i])return this.#t[t][e][i];if(this.#t[t]=this.#t[t]||{},this.#t[t][e]=this.#t[t][e]||u(e),!h(this.config.audience[s.audience],this.#t[t][e]))return s.defaultValue;if(s.allocation<100&&100*Math.random()>s.allocation)return this.#t[t][e][i]=s.defaultValue,this.#t[t][e][i];let r=f(s.options);return r?(this.#t[t][e][i]=r,r):null}}};
1
+ Object.defineProperty(exports,"__esModule",{value:!0});var i=require("ua-parser-js"),t=i&&i.__esModule?i:{default:i};const e={device:["wearable","mobile","tablet","console","smarttv","embedded","desktop"],browser:["chrome","safari","firefox","edge","ie","samsung internet","social","other"],os:["mac os","ios","android","windows","unix"]},s=i=>i&&e.device.includes(i)?i:"desktop",o=["tiktok","wechat","weibo","snapchat","klarna","Line","instagram","facebook","alipay","Baidu"],r=(i="")=>{if(!i)return"other";let t=i.toLowerCase();return e.browser.find(i=>t.includes(i))||(o.includes(t)?"social":"other")},n=["wearable","mobile","tablet"],a=i=>n.includes(i)?"coarse":"fine",l=(i="")=>{if(!i)return"unix";let t=i.toLowerCase();return e.os.find(i=>t.includes(i))||"unix"},h=i=>{if(!i||"string"!=typeof i)return null;let e=new t.default(i).getResult(),o=s(e.device.type);return{pointer:a(o),device:o,browser:r(e.browser.name),os:l(e.os.name)}},u=(i,t)=>!i||Object.entries(i).every(([i,e])=>t[i]===e),f=i=>{if(0===i.length)return null;if(1===i.length)return i[0].slug;let t=Math.random()*i.reduce((i,{split:t})=>i+t,0);return(i.find(({split:i})=>(t-=i)<=0)||i[0]).slug},c="visi",g="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",d=i=>new Promise(t=>setTimeout(t,i)),v=async(i=1e3,t)=>(await d(i),t?.abort(),null),p=(i=3e3,t,e)=>{let s=new AbortController;return Promise.race([fetch(t,{...e,signal:s.signal}),v(i,s)])};class m{#i;constructor({organizationId:i,environment:t,state:e,config:s,fetchTimeout:o,baseUrl:r}){this.organizationId="",this.environment="develop",this.#i=null,this.config=null,this._fetchConfig=async i=>{if(this.config)return;if(!this.#i)throw Error("No config fetch setup provided");let t=await p(this.#i.timeout,this.#i.url,i);if(!t||!t.ok)throw Error("Configuration fetch timed-out");this.config=await t.json()},this.loadConfig=i=>{this.config=i},this.generateVisitorId=()=>[c,(function(i=5){return i&&"number"==typeof i?Array(i).fill("").reduce(i=>i+=g.charAt(Math.floor(Math.random()*g.length)),""):""})(26).toUpperCase()].join("_"),this.getVisitorCookieName=()=>"visitorId",this.validateTestValue=(i,t)=>{if(!this.config)throw Error("Config is required before validating, either use `.fetchConfig()`, .loadConfig(config) or provide it during setup");let e=this.config.tests[i];if(!e)throw Error(`No config found for ${i}`);return!!e.options.find(i=>i.slug===t)},this.validateVisitorId=i=>{let t=i.split("_");if(2!==t.length)return!1;let[e,s]=t;return e===c&&26===s.length},this.organizationId=i,this.environment=t,this._baseUrl=r||"https://improve.obelism.studio",s?this.config=s:this.#i={url:[`${this._baseUrl}/config`,i,t,e||"active"].join("/"),timeout:o||3e3}}}exports.ImproveServerSDK=class extends m{#t;#e;constructor({token:i,...t}){super(t),this.#t={},this.fetchConfig=async i=>this._fetchConfig({...i,headers:{...i?.headers,token:this.#e}}),this.getFlagConfig=i=>this.config?.flags?.[i],this.getTestConfig=i=>this.config?.tests?.[i],this.getFlagValue=(i,t,e)=>{let s=this.getFlagConfig(i);if(!s||!this.config)return null;if(!t)return s.options[0].slug;if(this.#t?.[t]?.[e]?.[i])return this.#t[t][e][i];if(this.#t[t]=this.#t[t]||{},this.#t[t][e]=this.#t[t][e]||h(e),!u(this.config.audience[s.audience],this.#t[t][e]))return s.options[0].slug;let o=f(s.options);return o?(this.#t[t][e][i]=o,o):null},this.getTestValue=(i,t,e)=>{let s=this.getTestConfig(i);if(!s||!this.config)return null;if(!t||!e)return s.defaultValue;if(this.#t?.[t]?.[e]?.[i])return this.#t[t][e][i];if(this.#t[t]=this.#t[t]||{},this.#t[t][e]=this.#t[t][e]||h(e),!u(this.config.audience[s.audience],this.#t[t][e]))return s.defaultValue;if(s.allocation<100&&100*Math.random()>s.allocation)return this.#t[t][e][i]=s.defaultValue,this.#t[t][e][i];let o=f(s.options);return o?(this.#t[t][e][i]=o,o):null},this.#e=i}};
package/dist/server.d.ts CHANGED
@@ -6,8 +6,9 @@ declare class BaseImproveSDK {
6
6
  organizationId: string;
7
7
  environment: ImproveEnvironmentOption;
8
8
  config: ImproveConfiguration | null;
9
- constructor({ organizationId, environment, state, config, fetchTimeout, }: ImproveSetupArgs);
10
- fetchConfig: (config?: RequestInit) => Promise<void>;
9
+ _baseUrl: undefined | string;
10
+ constructor({ organizationId, environment, state, config, fetchTimeout, baseUrl, }: ImproveSetupArgs);
11
+ _fetchConfig: (config?: RequestInit) => Promise<void>;
11
12
  loadConfig: (config: ImproveConfiguration) => void;
12
13
  generateVisitorId: () => string;
13
14
  getVisitorCookieName: () => string;
@@ -15,8 +16,15 @@ declare class BaseImproveSDK {
15
16
  validateVisitorId: (possibleVisitorId: string) => boolean;
16
17
  }
17
18
 
19
+ type ImproveServerSetupArgs = (Omit<ImproveSetupArgs, 'config' | 'baseUrl'> & {
20
+ config: ImproveConfiguration;
21
+ }) | (Omit<ImproveSetupArgs, 'config'> & {
22
+ token: string;
23
+ });
18
24
  declare class ImproveServerSDK extends BaseImproveSDK {
19
25
  #private;
26
+ constructor({ token, ...args }: ImproveServerSetupArgs);
27
+ fetchConfig: (config?: RequestInit) => Promise<void>;
20
28
  getFlagConfig: (flagSlug: string) => __types.ImproveFlag;
21
29
  getTestConfig: (testSlug: string) => __types.ImproveTest;
22
30
  getFlagValue: (flagSlug: string, visitorId: string, userAgent: string) => string;
package/dist/server.mjs CHANGED
@@ -1 +1 @@
1
- import i from"ua-parser-js";let t={device:["wearable","mobile","tablet","console","smarttv","embedded","desktop"],browser:["chrome","safari","firefox","edge","ie","samsung internet","social","other"],os:["mac os","ios","android","windows","unix"]},e=i=>i&&t.device.includes(i)?i:"desktop",s=["tiktok","wechat","weibo","snapchat","klarna","Line","instagram","facebook","alipay","Baidu"],r=(i="")=>{if(!i)return"other";let e=i.toLowerCase();return t.browser.find(i=>e.includes(i))||(s.includes(e)?"social":"other")},o=["wearable","mobile","tablet"],n=i=>o.includes(i)?"coarse":"fine",l=(i="")=>{if(!i)return"unix";let e=i.toLowerCase();return t.os.find(i=>e.includes(i))||"unix"},a=t=>{if(!t||"string"!=typeof t)return null;let s=new i(t).getResult(),o=e(s.device.type);return{pointer:n(o),device:o,browser:r(s.browser.name),os:l(s.os.name)}},h=(i,t)=>!i||Object.entries(i).every(([i,e])=>t[i]===e),u=i=>{if(0===i.length)return null;if(1===i.length)return i[0].slug;let t=Math.random()*i.reduce((i,{split:t})=>i+t,0);return(i.find(({split:i})=>(t-=i)<=0)||i[0]).slug},f="visi",c="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",g=i=>new Promise(t=>setTimeout(t,i)),d=async(i=1e3,t)=>(await g(i),t?.abort(),null),v=(i=3e3,t,e)=>{let s=new AbortController;return Promise.race([fetch(t,{...e,signal:s.signal}),d(i,s)])};class m{#i;constructor({organizationId:i,environment:t,state:e,config:s,fetchTimeout:r}){this.organizationId="",this.environment="develop",this.#i=null,this.config=null,this.fetchConfig=async i=>{if(this.config)return;if(!this.#i)throw Error("No config fetch setup provided");let t=await v(this.#i.timeout,this.#i.url,i);if(!t||!t.ok)throw Error("Configuration fetch timed-out");this.config=await t.json()},this.loadConfig=i=>{this.config=i},this.generateVisitorId=()=>[f,(function(i=5){return i&&"number"==typeof i?Array(i).fill("").reduce(i=>i+=c.charAt(Math.floor(Math.random()*c.length)),""):""})(26).toUpperCase()].join("_"),this.getVisitorCookieName=()=>"visitorId",this.validateTestValue=(i,t)=>{if(!this.config)throw Error("Config is required before validating, either use `.fetchConfig()`, .loadConfig(config) or provide it during setup");let e=this.config.tests[i];if(!e)throw Error(`No config found for ${i}`);return!!e.options.find(i=>i.slug===t)},this.validateVisitorId=i=>{let t=i.split("_");if(2!==t.length)return!1;let[e,s]=t;return e===f&&26===s.length},this.organizationId=i,this.environment=t,s?this.config=s:this.#i={url:["https://improve.obelism.studio/config",i,t,e||"active"].join("/"),timeout:r||3e3}}}class p extends m{#t;constructor(...i){super(...i),this.#t={},this.getFlagConfig=i=>this.config?.flags?.[i],this.getTestConfig=i=>this.config?.tests?.[i],this.getFlagValue=(i,t,e)=>{let s=this.getFlagConfig(i);if(!s||!this.config)return null;if(!t)return s.options[0].slug;if(this.#t?.[t]?.[e]?.[i])return this.#t[t][e][i];if(this.#t[t]=this.#t[t]||{},this.#t[t][e]=this.#t[t][e]||a(e),!h(this.config.audience[s.audience],this.#t[t][e]))return s.options[0].slug;let r=u(s.options);return r?(this.#t[t][e][i]=r,r):null},this.getTestValue=(i,t,e)=>{let s=this.getTestConfig(i);if(!s||!this.config)return null;if(!t||!e)return s.defaultValue;if(this.#t?.[t]?.[e]?.[i])return this.#t[t][e][i];if(this.#t[t]=this.#t[t]||{},this.#t[t][e]=this.#t[t][e]||a(e),!h(this.config.audience[s.audience],this.#t[t][e]))return s.defaultValue;if(s.allocation<100&&100*Math.random()>s.allocation)return this.#t[t][e][i]=s.defaultValue,this.#t[t][e][i];let r=u(s.options);return r?(this.#t[t][e][i]=r,r):null}}}export{p as ImproveServerSDK};
1
+ import i from"ua-parser-js";let t={device:["wearable","mobile","tablet","console","smarttv","embedded","desktop"],browser:["chrome","safari","firefox","edge","ie","samsung internet","social","other"],os:["mac os","ios","android","windows","unix"]},e=i=>i&&t.device.includes(i)?i:"desktop",s=["tiktok","wechat","weibo","snapchat","klarna","Line","instagram","facebook","alipay","Baidu"],o=(i="")=>{if(!i)return"other";let e=i.toLowerCase();return t.browser.find(i=>e.includes(i))||(s.includes(e)?"social":"other")},r=["wearable","mobile","tablet"],n=i=>r.includes(i)?"coarse":"fine",a=(i="")=>{if(!i)return"unix";let e=i.toLowerCase();return t.os.find(i=>e.includes(i))||"unix"},l=t=>{if(!t||"string"!=typeof t)return null;let s=new i(t).getResult(),r=e(s.device.type);return{pointer:n(r),device:r,browser:o(s.browser.name),os:a(s.os.name)}},h=(i,t)=>!i||Object.entries(i).every(([i,e])=>t[i]===e),u=i=>{if(0===i.length)return null;if(1===i.length)return i[0].slug;let t=Math.random()*i.reduce((i,{split:t})=>i+t,0);return(i.find(({split:i})=>(t-=i)<=0)||i[0]).slug},f="visi",c="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",g=i=>new Promise(t=>setTimeout(t,i)),d=async(i=1e3,t)=>(await g(i),t?.abort(),null),v=(i=3e3,t,e)=>{let s=new AbortController;return Promise.race([fetch(t,{...e,signal:s.signal}),d(i,s)])};class m{#i;constructor({organizationId:i,environment:t,state:e,config:s,fetchTimeout:o,baseUrl:r}){this.organizationId="",this.environment="develop",this.#i=null,this.config=null,this._fetchConfig=async i=>{if(this.config)return;if(!this.#i)throw Error("No config fetch setup provided");let t=await v(this.#i.timeout,this.#i.url,i);if(!t||!t.ok)throw Error("Configuration fetch timed-out");this.config=await t.json()},this.loadConfig=i=>{this.config=i},this.generateVisitorId=()=>[f,(function(i=5){return i&&"number"==typeof i?Array(i).fill("").reduce(i=>i+=c.charAt(Math.floor(Math.random()*c.length)),""):""})(26).toUpperCase()].join("_"),this.getVisitorCookieName=()=>"visitorId",this.validateTestValue=(i,t)=>{if(!this.config)throw Error("Config is required before validating, either use `.fetchConfig()`, .loadConfig(config) or provide it during setup");let e=this.config.tests[i];if(!e)throw Error(`No config found for ${i}`);return!!e.options.find(i=>i.slug===t)},this.validateVisitorId=i=>{let t=i.split("_");if(2!==t.length)return!1;let[e,s]=t;return e===f&&26===s.length},this.organizationId=i,this.environment=t,this._baseUrl=r||"https://improve.obelism.studio",s?this.config=s:this.#i={url:[`${this._baseUrl}/config`,i,t,e||"active"].join("/"),timeout:o||3e3}}}class p extends m{#t;#e;constructor({token:i,...t}){super(t),this.#t={},this.fetchConfig=async i=>this._fetchConfig({...i,headers:{...i?.headers,token:this.#e}}),this.getFlagConfig=i=>this.config?.flags?.[i],this.getTestConfig=i=>this.config?.tests?.[i],this.getFlagValue=(i,t,e)=>{let s=this.getFlagConfig(i);if(!s||!this.config)return null;if(!t)return s.options[0].slug;if(this.#t?.[t]?.[e]?.[i])return this.#t[t][e][i];if(this.#t[t]=this.#t[t]||{},this.#t[t][e]=this.#t[t][e]||l(e),!h(this.config.audience[s.audience],this.#t[t][e]))return s.options[0].slug;let o=u(s.options);return o?(this.#t[t][e][i]=o,o):null},this.getTestValue=(i,t,e)=>{let s=this.getTestConfig(i);if(!s||!this.config)return null;if(!t||!e)return s.defaultValue;if(this.#t?.[t]?.[e]?.[i])return this.#t[t][e][i];if(this.#t[t]=this.#t[t]||{},this.#t[t][e]=this.#t[t][e]||l(e),!h(this.config.audience[s.audience],this.#t[t][e]))return s.defaultValue;if(s.allocation<100&&100*Math.random()>s.allocation)return this.#t[t][e][i]=s.defaultValue,this.#t[t][e][i];let o=u(s.options);return o?(this.#t[t][e][i]=o,o):null},this.#e=i}}export{p as ImproveServerSDK};
package/dist/types.d.ts CHANGED
@@ -17,6 +17,7 @@ type ImproveSetupArgs = {
17
17
  environment: ImproveEnvironmentOption;
18
18
  state?: ImproveTestState;
19
19
  config?: ImproveConfiguration;
20
+ baseUrl?: string;
20
21
  fetchTimeout?: number;
21
22
  };
22
23
  type ImproveFlagOption = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@obelism/improve-sdk",
3
3
  "description": "Obelism Improve SDK",
4
- "version": "0.2.0",
4
+ "version": "0.3.1",
5
5
  "keywords": [
6
6
  "ab-tests",
7
7
  "feature-flags",