@featurevisor/sdk 1.27.4 → 1.27.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/coverage/clover.xml +2 -2
- package/coverage/coverage-final.json +8 -8
- package/coverage/lcov-report/bucket.ts.html +1 -1
- package/coverage/lcov-report/conditions.ts.html +1 -1
- package/coverage/lcov-report/datafileReader.ts.html +1 -1
- package/coverage/lcov-report/emitter.ts.html +1 -1
- package/coverage/lcov-report/feature.ts.html +1 -1
- package/coverage/lcov-report/index.html +1 -1
- package/coverage/lcov-report/instance.ts.html +1 -1
- package/coverage/lcov-report/logger.ts.html +1 -1
- package/coverage/lcov-report/segments.ts.html +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.gz +0 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -8
- package/src/logger.spec.ts +1 -3
- package/.eslintcache +0 -1
- package/.eslintrc.js +0 -18
- package/.prettierignore +0 -5
- package/prettier.config.js +0 -8
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e={77:e=>{!function(){const t=e=>(new TextEncoder).encode(e);function r(e,r){let i,a,s,n,o,u,l,c;for("string"==typeof e&&(e=t(e)),i=3&e.length,a=e.length-i,s=r,o=3432918353,u=461845907,c=0;c<a;)l=255&e[c]|(255&e[++c])<<8|(255&e[++c])<<16|(255&e[++c])<<24,++c,l=(65535&l)*o+(((l>>>16)*o&65535)<<16)&4294967295,l=l<<15|l>>>17,l=(65535&l)*u+(((l>>>16)*u&65535)<<16)&4294967295,s^=l,s=s<<13|s>>>19,n=5*(65535&s)+((5*(s>>>16)&65535)<<16)&4294967295,s=27492+(65535&n)+((58964+(n>>>16)&65535)<<16);switch(l=0,i){case 3:l^=(255&e[c+2])<<16;case 2:l^=(255&e[c+1])<<8;case 1:l^=255&e[c],l=(65535&l)*o+(((l>>>16)*o&65535)<<16)&4294967295,l=l<<15|l>>>17,l=(65535&l)*u+(((l>>>16)*u&65535)<<16)&4294967295,s^=l}return s^=e.length,s^=s>>>16,s=2246822507*(65535&s)+((2246822507*(s>>>16)&65535)<<16)&4294967295,s^=s>>>13,s=3266489909*(65535&s)+((3266489909*(s>>>16)&65535)<<16)&4294967295,s^=s>>>16,s>>>0}const i=r;i.v2=function(e,r){"string"==typeof e&&(e=t(e));let i,a=e.length,s=r^a,n=0;for(;a>=4;)i=255&e[n]|(255&e[++n])<<8|(255&e[++n])<<16|(255&e[++n])<<24,i=1540483477*(65535&i)+((1540483477*(i>>>16)&65535)<<16),i^=i>>>24,i=1540483477*(65535&i)+((1540483477*(i>>>16)&65535)<<16),s=1540483477*(65535&s)+((1540483477*(s>>>16)&65535)<<16)^i,a-=4,++n;switch(a){case 3:s^=(255&e[n+2])<<16;case 2:s^=(255&e[n+1])<<8;case 1:s^=255&e[n],s=1540483477*(65535&s)+((1540483477*(s>>>16)&65535)<<16)}return s^=s>>>13,s=1540483477*(65535&s)+((1540483477*(s>>>16)&65535)<<16),s^=s>>>15,s>>>0},i.v3=r,e.exports=i}()}},t={};function r(i){var a=t[i];if(void 0!==a)return a.exports;var s=t[i]={exports:{}};return e[i](s,s.exports,r),s.exports}r.d=(e,t)=>{for(var i in t)r.o(t,i)&&!r.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var i={};(()=>{r.d(i,{Q5:()=>d,p0:()=>E,d7:()=>T,Yd:()=>c,so:()=>s,zW:()=>V,iR:()=>K,Fs:()=>w,hu:()=>f,OH:()=>l,L3:()=>u,GU:()=>n,mC:()=>D,Uj:()=>o});var e=r(77);const t=1,a=Math.pow(2,32),s=1e5;function n(r){const i=e.v3(r,t)/a;return Math.floor(i*s)}const o="[Featurevisor]",u=["warn","error"],l=function(e,t,r={}){switch(e){case"debug":console.log(o,t,r);break;case"info":console.info(o,t,r);break;case"warn":console.warn(o,t,r);break;case"error":console.error(o,t,r)}};class c{constructor(e){this.levels=e.levels,this.handle=e.handler}setLevels(e){this.levels=e}log(e,t,r){-1!==this.levels.indexOf(e)&&this.handle(e,t,r)}debug(e,t){this.log("debug",e,t)}info(e,t){this.log("info",e,t)}warn(e,t){this.log("warn",e,t)}error(e,t){this.log("error",e,t)}}function f(e={}){const t=e.levels||u,r=e.handler||l;return new c({levels:t,handler:r})}class h{constructor(e){this.schemaVersion=e.schemaVersion,this.revision=e.revision,this.segments=e.segments,this.attributes=e.attributes,this.features=e.features}getRevision(){return this.revision}getSchemaVersion(){return this.schemaVersion}getAllAttributes(){return this.attributes}getAttribute(e){return this.attributes.find((t=>t.key===e))}getSegment(e){const t=this.segments.find((t=>t.key===e));if(t)return function(e,t){if("string"==typeof e[t]&&"*"!==e[t])try{e[t]=JSON.parse(e[t])}catch(e){console.error("Error parsing JSON",e)}return e}(t,"conditions")}getFeature(e){const t=this.features.find((t=>t.key===e));if(t)return t}}class d{constructor(){this._listeners={}}addListener(e,t){void 0===this._listeners[e]&&(this._listeners[e]=[]),this._listeners[e].push(t)}removeListener(e,t){if(void 0===this._listeners[e])return;const r=this._listeners[e].indexOf(t);-1!==r&&this._listeners[e].splice(r,1)}removeAllListeners(e){e?this._listeners[e]=[]:Object.keys(this._listeners).forEach((e=>{this._listeners[e]=[]}))}emit(e,...t){void 0!==this._listeners[e]&&this._listeners[e].forEach((e=>{e(...t)}))}}const g=(e,t)=>{const r=v(e),i=v(t),a=r.pop(),s=i.pop(),n=p(r,i);return 0!==n?n:a&&s?p(a.split("."),s.split(".")):a||s?a?-1:1:0},y=/^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i,v=e=>{if("string"!=typeof e)throw new TypeError("Invalid argument expected string");const t=e.match(y);if(!t)throw new Error(`Invalid argument not valid semver ('${e}' received)`);return t.shift(),t},b=e=>"*"===e||"x"===e||"X"===e,k=e=>{const t=parseInt(e,10);return isNaN(t)?e:t},m=(e,t)=>{if(b(e)||b(t))return 0;const[r,i]=((e,t)=>typeof e!=typeof t?[String(e),String(t)]:[e,t])(k(e),k(t));return r>i?1:r<i?-1:0},p=(e,t)=>{for(let r=0;r<Math.max(e.length,t.length);r++){const i=m(e[r]||"0",t[r]||"0");if(0!==i)return i}return 0};function K(e,t){const{attribute:r,operator:i,value:a}=e;if("equals"===i)return t[r]===a;if("notEquals"===i)return t[r]!==a;if("before"===i||"after"===i){const e=t[r],s=e instanceof Date?e:new Date(e),n=a instanceof Date?a:new Date(a);return"before"===i?s<n:s>n}if(Array.isArray(a)){const e=t[r];if("in"===i)return-1!==a.indexOf(e);if("notIn"===i)return-1===a.indexOf(e)}else if("string"==typeof t[r]&&"string"==typeof a){const e=t[r];if("contains"===i)return-1!==e.indexOf(a);if("notContains"===i)return-1===e.indexOf(a);if("startsWith"===i)return e.startsWith(a);if("endsWith"===i)return e.endsWith(a);if("semverEquals"===i)return 0===g(e,a);if("semverNotEquals"===i)return 0!==g(e,a);if("semverGreaterThan"===i)return 1===g(e,a);if("semverGreaterThanOrEquals"===i)return g(e,a)>=0;if("semverLessThan"===i)return-1===g(e,a);if("semverLessThanOrEquals"===i)return g(e,a)<=0}else if("number"==typeof t[r]&&"number"==typeof a){const e=t[r];if("greaterThan"===i)return e>a;if("greaterThanOrEquals"===i)return e>=a;if("lessThan"===i)return e<a;if("lessThanOrEquals"===i)return e<=a}return!1}function V(e,t,r){if("attribute"in e)try{return K(e,t)}catch(i){return r.warn(i.message,{error:i,details:{condition:e,context:t}}),!1}return"and"in e&&Array.isArray(e.and)?e.and.every((e=>V(e,t,r))):"or"in e&&Array.isArray(e.or)?e.or.some((e=>V(e,t,r))):"not"in e&&Array.isArray(e.not)?e.not.every((()=>!1===V({and:e.not},t,r))):!!Array.isArray(e)&&e.every((e=>V(e,t,r)))}function A(e,t,r,i){if("*"===e)return!0;if("string"==typeof e){const a=r.getSegment(e);return!!a&&function(e,t,r){return V(e.conditions,t,r)}(a,t,i)}if("object"==typeof e){if("and"in e&&Array.isArray(e.and))return e.and.every((e=>A(e,t,r,i)));if("or"in e&&Array.isArray(e.or))return e.or.some((e=>A(e,t,r,i)));if("not"in e&&Array.isArray(e.not))return e.not.every((e=>!1===A(e,t,r,i)))}return!!Array.isArray(e)&&e.every((e=>A(e,t,r,i)))}function I(e){return"string"==typeof e&&(e.startsWith("{")||e.startsWith("["))?JSON.parse(e):e}function F(e,t,r,i,a){const s=e.find((e=>A(I(e.segments),t,i,a)));if(!s)return{matchedTraffic:void 0,matchedAllocation:void 0};const n=function(e,t){for(const r of e.allocation){const[e,i]=r.range;if(r.range&&e<=t&&i>=t)return r}}(s,r);return{matchedTraffic:s,matchedAllocation:n}}function R(e,t,r,i){const a={force:void 0,forceIndex:void 0};if(!e.force)return a;for(let s=0;s<e.force.length;s++){const n=e.force[s];if(n.conditions&&V(n.conditions,t,i)){a.force=n,a.forceIndex=s;break}if(n.segments&&A(n.segments,t,r,i)){a.force=n,a.forceIndex=s;break}}return a}Object.keys({">":[1],">=":[0,1],"=":[0],"<=":[-1,0],"<":[-1]});const O={schemaVersion:"1",revision:"unknown",attributes:[],segments:[],features:[]};var E;function L(e,t){return t?t(e):fetch(e).then((e=>e.json()))}function D(e,t){try{if(void 0===e)return;switch(t){case"string":return"string"==typeof e?e:void 0;case"integer":return parseInt(e,10);case"double":return parseFloat(e);case"boolean":return!0===e;case"array":return Array.isArray(e)?e:void 0;case"object":return"object"==typeof e?e:void 0;default:return e}}catch(e){return}}!function(e){e.NOT_FOUND="not_found",e.NO_VARIATIONS="no_variations",e.NO_MATCH="no_match",e.DISABLED="disabled",e.REQUIRED="required",e.OUT_OF_RANGE="out_of_range",e.FORCED="forced",e.INITIAL="initial",e.STICKY="sticky",e.RULE="rule",e.ALLOCATED="allocated",e.DEFAULTED="defaulted",e.OVERRIDE="override",e.ERROR="error"}(E||(E={}));class T{constructor(e){this.bucketKeySeparator=e.bucketKeySeparator||".",this.configureBucketKey=e.configureBucketKey,this.configureBucketValue=e.configureBucketValue,this.datafileUrl=e.datafileUrl,this.handleDatafileFetch=e.handleDatafileFetch,this.initialFeatures=e.initialFeatures,this.interceptContext=e.interceptContext,this.logger=e.logger||f(),this.refreshInterval=e.refreshInterval,this.stickyFeatures=e.stickyFeatures,this.emitter=new d,this.statuses={ready:!1,refreshInProgress:!1},e.onReady&&this.emitter.addListener("ready",e.onReady),e.onRefresh&&this.emitter.addListener("refresh",e.onRefresh),e.onUpdate&&this.emitter.addListener("update",e.onUpdate),e.onActivation&&this.emitter.addListener("activation",e.onActivation);const t=this.emitter.addListener.bind(this.emitter);this.on=t,this.addListener=t;const r=this.emitter.removeListener.bind(this.emitter);if(this.off=r,this.removeListener=r,this.removeAllListeners=this.emitter.removeAllListeners.bind(this.emitter),e.datafileUrl)this.setDatafile(e.datafile||O),L(e.datafileUrl,e.handleDatafileFetch).then((e=>{this.setDatafile(e),this.statuses.ready=!0,this.emitter.emit("ready"),this.refreshInterval&&this.startRefreshing()})).catch((e=>{this.logger.error("failed to fetch datafile",{error:e})}));else{if(!e.datafile)throw new Error("Featurevisor SDK instance cannot be created without both `datafile` and `datafileUrl` options");this.setDatafile(e.datafile),this.statuses.ready=!0,setTimeout((()=>{this.emitter.emit("ready")}),0)}}setLogLevels(e){this.logger.setLevels(e)}onReady(){return new Promise((e=>{if(this.statuses.ready)return e(this);const t=()=>{this.emitter.removeListener("ready",t),e(this)};this.emitter.addListener("ready",t)}))}setDatafile(e){try{this.datafileReader=new h("string"==typeof e?JSON.parse(e):e)}catch(e){this.logger.error("could not parse datafile",{error:e})}}setStickyFeatures(e){this.stickyFeatures=e}getRevision(){return this.datafileReader.getRevision()}getFeature(e){return"string"==typeof e?this.datafileReader.getFeature(e):e}getBucketKey(e,t){const r=e.key;let i,a;if("string"==typeof e.bucketBy)i="plain",a=[e.bucketBy];else if(Array.isArray(e.bucketBy))i="and",a=e.bucketBy;else{if("object"!=typeof e.bucketBy||!Array.isArray(e.bucketBy.or))throw this.logger.error("invalid bucketBy",{featureKey:r,bucketBy:e.bucketBy}),new Error("invalid bucketBy");i="or",a=e.bucketBy.or}const s=[];a.forEach((e=>{const r=t[e];void 0!==r&&("plain"===i||"and"===i||0===s.length)&&s.push(r)})),s.push(r);const n=s.join(this.bucketKeySeparator);return this.configureBucketKey?this.configureBucketKey(e,t,n):n}getBucketValue(e,t){const r=this.getBucketKey(e,t),i=n(r);return this.configureBucketValue?{bucketKey:r,bucketValue:this.configureBucketValue(e,t,i)}:{bucketKey:r,bucketValue:i}}isReady(){return this.statuses.ready}refresh(){return this.logger.debug("refreshing datafile"),this.statuses.refreshInProgress?this.logger.warn("refresh in progress, skipping"):this.datafileUrl?(this.statuses.refreshInProgress=!0,void L(this.datafileUrl,this.handleDatafileFetch).then((e=>{const t=this.getRevision()!==e.revision;this.setDatafile(e),this.logger.info("refreshed datafile"),this.emitter.emit("refresh"),t&&this.emitter.emit("update"),this.statuses.refreshInProgress=!1})).catch((e=>{this.logger.error("failed to refresh datafile",{error:e}),this.statuses.refreshInProgress=!1}))):this.logger.error("cannot refresh since `datafileUrl` is not provided")}startRefreshing(){return this.datafileUrl?this.intervalId?this.logger.warn("refreshing has already started"):this.refreshInterval?void(this.intervalId=setInterval((()=>{this.refresh()}),1e3*this.refreshInterval)):this.logger.warn("no `refreshInterval` option provided"):this.logger.error("cannot start refreshing since `datafileUrl` is not provided")}stopRefreshing(){if(!this.intervalId)return this.logger.warn("refreshing has not started yet");clearInterval(this.intervalId)}evaluateFlag(e,t={}){let r;try{const i="string"==typeof e?e:e.key;if(this.stickyFeatures&&this.stickyFeatures[i]&&void 0!==this.stickyFeatures[i].enabled)return r={featureKey:i,reason:E.STICKY,sticky:this.stickyFeatures[i],enabled:this.stickyFeatures[i].enabled},this.logger.debug("using sticky enabled",r),r;if(this.statuses&&!this.statuses.ready&&this.initialFeatures&&this.initialFeatures[i]&&void 0!==this.initialFeatures[i].enabled)return r={featureKey:i,reason:E.INITIAL,initial:this.initialFeatures[i],enabled:this.initialFeatures[i].enabled},this.logger.debug("using initial enabled",r),r;const a=this.getFeature(e);if(!a)return r={featureKey:i,reason:E.NOT_FOUND},this.logger.warn("feature not found",r),r;a.deprecated&&this.logger.warn("feature is deprecated",{featureKey:a.key});const s=this.interceptContext?this.interceptContext(t):t,{force:n,forceIndex:o}=R(a,t,this.datafileReader,this.logger);if(n&&void 0!==n.enabled)return r={featureKey:a.key,reason:E.FORCED,forceIndex:o,force:n,enabled:n.enabled},this.logger.debug("forced enabled found",r),r;if(a.required&&a.required.length>0){const e=a.required.every((e=>{let t,r;return"string"==typeof e?t=e:(t=e.key,r=e.variation),!!this.isEnabled(t,s)&&(void 0===r||this.getVariation(t,s)===r)}));if(!e)return r={featureKey:a.key,reason:E.REQUIRED,required:a.required,enabled:e},this.logger.debug("required features not enabled",r),r}const{bucketKey:u,bucketValue:l}=this.getBucketValue(a,s),c=function(e,t,r,i){return e.find((e=>!!A(I(e.segments),t,r,i)))}(a.traffic,s,this.datafileReader,this.logger);if(c){if(a.ranges&&a.ranges.length>0)return a.ranges.find((e=>l>=e[0]&&l<e[1]))?(r={featureKey:a.key,reason:E.ALLOCATED,bucketKey:u,bucketValue:l,ruleKey:c.key,traffic:c,enabled:void 0===c.enabled||c.enabled},this.logger.debug("matched",r),r):(r={featureKey:a.key,reason:E.OUT_OF_RANGE,bucketKey:u,bucketValue:l,enabled:!1},this.logger.debug("not matched",r),r);if(void 0!==c.enabled)return r={featureKey:a.key,reason:E.OVERRIDE,bucketKey:u,bucketValue:l,ruleKey:c.key,traffic:c,enabled:c.enabled},this.logger.debug("override from rule",r),r;if(l<=c.percentage)return r={featureKey:a.key,reason:E.RULE,bucketKey:u,bucketValue:l,ruleKey:c.key,traffic:c,enabled:!0},this.logger.debug("matched traffic",r),r}return r={featureKey:a.key,reason:E.NO_MATCH,bucketKey:u,bucketValue:l,enabled:!1},this.logger.debug("nothing matched",r),r}catch(t){return r={featureKey:"string"==typeof e?e:e.key,reason:E.ERROR,error:t},this.logger.error("error",r),r}}isEnabled(e,t={}){try{return!0===this.evaluateFlag(e,t).enabled}catch(t){return this.logger.error("isEnabled",{featureKey:e,error:t}),!1}}evaluateVariation(e,t={}){let r;try{const i="string"==typeof e?e:e.key;if(!1===this.evaluateFlag(e,t).enabled)return r={featureKey:i,reason:E.DISABLED},this.logger.debug("feature is disabled",r),r;if(this.stickyFeatures&&this.stickyFeatures[i]){const e=this.stickyFeatures[i].variation;if(void 0!==e)return r={featureKey:i,reason:E.STICKY,variationValue:e},this.logger.debug("using sticky variation",r),r}if(this.statuses&&!this.statuses.ready&&this.initialFeatures&&this.initialFeatures[i]&&void 0!==this.initialFeatures[i].variation){const e=this.initialFeatures[i].variation;return r={featureKey:i,reason:E.INITIAL,variationValue:e},this.logger.debug("using initial variation",r),r}const a=this.getFeature(e);if(!a)return r={featureKey:i,reason:E.NOT_FOUND},this.logger.warn("feature not found",r),r;if(!a.variations||0===a.variations.length)return r={featureKey:i,reason:E.NO_VARIATIONS},this.logger.warn("no variations",r),r;const s=this.interceptContext?this.interceptContext(t):t,{force:n,forceIndex:o}=R(a,t,this.datafileReader,this.logger);if(n&&n.variation){const e=a.variations.find((e=>e.value===n.variation));if(e)return r={featureKey:a.key,reason:E.FORCED,forceIndex:o,force:n,variation:e},this.logger.debug("forced variation found",r),r}const{bucketKey:u,bucketValue:l}=this.getBucketValue(a,s),{matchedTraffic:c,matchedAllocation:f}=F(a.traffic,s,l,this.datafileReader,this.logger);if(c){if(c.variation){const e=a.variations.find((e=>e.value===c.variation));if(e)return r={featureKey:a.key,reason:E.RULE,bucketKey:u,bucketValue:l,ruleKey:c.key,traffic:c,variation:e},this.logger.debug("override from rule",r),r}if(f&&f.variation){const e=a.variations.find((e=>e.value===f.variation));if(e)return r={featureKey:a.key,reason:E.ALLOCATED,bucketKey:u,bucketValue:l,ruleKey:c.key,traffic:c,variation:e},this.logger.debug("allocated variation",r),r}}return r={featureKey:a.key,reason:E.NO_MATCH,bucketKey:u,bucketValue:l},this.logger.debug("no matched variation",r),r}catch(t){return r={featureKey:"string"==typeof e?e:e.key,reason:E.ERROR,error:t},this.logger.error("error",r),r}}getVariation(e,t={}){try{const r=this.evaluateVariation(e,t);return void 0!==r.variationValue?r.variationValue:r.variation?r.variation.value:void 0}catch(t){return void this.logger.error("getVariation",{featureKey:e,error:t})}}activate(e,t={}){try{const r=this.evaluateVariation(e,t),i=r.variation?r.variation.value:r.variationValue;if(void 0===i)return;const a=this.interceptContext?this.interceptContext(t):t,s={};return this.datafileReader.getAllAttributes().filter((e=>!0===e.capture)).forEach((e=>{void 0!==a[e.key]&&(s[e.key]=t[e.key])})),this.emitter.emit("activation",e,i,a,s,r),i}catch(t){return void this.logger.error("activate",{featureKey:e,error:t})}}evaluateVariable(e,t,r={}){let i;try{const a="string"==typeof e?e:e.key;if(!1===this.evaluateFlag(e,r).enabled)return i={featureKey:a,reason:E.DISABLED},this.logger.debug("feature is disabled",i),i;if(this.stickyFeatures&&this.stickyFeatures[a]){const e=this.stickyFeatures[a].variables;if(e){const r=e[t];if(void 0!==r)return i={featureKey:a,reason:E.STICKY,variableKey:t,variableValue:r},this.logger.debug("using sticky variable",i),i}}if(this.statuses&&!this.statuses.ready&&this.initialFeatures&&this.initialFeatures[a]){const e=this.initialFeatures[a].variables;if(e&&void 0!==e[t])return i={featureKey:a,reason:E.INITIAL,variableKey:t,variableValue:e[t]},this.logger.debug("using initial variable",i),i}const s=this.getFeature(e);if(!s)return i={featureKey:a,reason:E.NOT_FOUND,variableKey:t},this.logger.warn("feature not found in datafile",i),i;const n=Array.isArray(s.variablesSchema)?s.variablesSchema.find((e=>e.key===t)):void 0;if(!n)return i={featureKey:a,reason:E.NOT_FOUND,variableKey:t},this.logger.warn("variable schema not found",i),i;const o=this.interceptContext?this.interceptContext(r):r,{force:u,forceIndex:l}=R(s,r,this.datafileReader,this.logger);if(u&&u.variables&&void 0!==u.variables[t])return i={featureKey:s.key,reason:E.FORCED,forceIndex:l,force:u,variableKey:t,variableSchema:n,variableValue:u.variables[t]},this.logger.debug("forced variable",i),i;const{bucketKey:c,bucketValue:f}=this.getBucketValue(s,o),{matchedTraffic:h,matchedAllocation:d}=F(s.traffic,o,f,this.datafileReader,this.logger);if(h){if(h.variables&&void 0!==h.variables[t])return i={featureKey:s.key,reason:E.RULE,bucketKey:c,bucketValue:f,ruleKey:h.key,traffic:h,variableKey:t,variableSchema:n,variableValue:h.variables[t]},this.logger.debug("override from rule",i),i;let e;if(u&&u.variation?e=u.variation:d&&d.variation&&(e=d.variation),e&&Array.isArray(s.variations)){const r=s.variations.find((t=>t.value===e));if(r&&r.variables){const e=r.variables.find((e=>e.key===t));if(e){if(e.overrides){const r=e.overrides.find((e=>e.conditions?V("string"==typeof e.conditions?JSON.parse(e.conditions):e.conditions,o,this.logger):!!e.segments&&A(I(e.segments),o,this.datafileReader,this.logger)));if(r)return i={featureKey:s.key,reason:E.OVERRIDE,bucketKey:c,bucketValue:f,ruleKey:h.key,traffic:h,variableKey:t,variableSchema:n,variableValue:r.value},this.logger.debug("variable override",i),i}if(void 0!==e.value)return i={featureKey:s.key,reason:E.ALLOCATED,bucketKey:c,bucketValue:f,ruleKey:h.key,traffic:h,variableKey:t,variableSchema:n,variableValue:e.value},this.logger.debug("allocated variable",i),i}}}}return i={featureKey:s.key,reason:E.DEFAULTED,bucketKey:c,bucketValue:f,variableKey:t,variableSchema:n,variableValue:n.defaultValue},this.logger.debug("using default value",i),i}catch(r){return i={featureKey:"string"==typeof e?e:e.key,reason:E.ERROR,variableKey:t,error:r},this.logger.error("error",i),i}}getVariable(e,t,r={}){try{const i=this.evaluateVariable(e,t,r);return void 0!==i.variableValue?i.variableSchema&&"json"===i.variableSchema.type&&"string"==typeof i.variableValue?JSON.parse(i.variableValue):i.variableValue:void 0}catch(r){return void this.logger.error("getVariable",{featureKey:e,variableKey:t,error:r})}}getVariableBoolean(e,t,r={}){return D(this.getVariable(e,t,r),"boolean")}getVariableString(e,t,r={}){return D(this.getVariable(e,t,r),"string")}getVariableInteger(e,t,r={}){return D(this.getVariable(e,t,r),"integer")}getVariableDouble(e,t,r={}){return D(this.getVariable(e,t,r),"double")}getVariableArray(e,t,r={}){return D(this.getVariable(e,t,r),"array")}getVariableObject(e,t,r={}){return D(this.getVariable(e,t,r),"object")}getVariableJSON(e,t,r={}){return D(this.getVariable(e,t,r),"json")}}function w(e){return new T(e)}})();var a=i.Q5,s=i.p0,n=i.d7,o=i.Yd,u=i.so,l=i.zW,c=i.iR,f=i.Fs,h=i.hu,d=i.OH,g=i.L3,y=i.GU,v=i.mC,b=i.Uj;export{a as Emitter,s as EvaluationReason,n as FeaturevisorInstance,o as Logger,u as MAX_BUCKETED_NUMBER,l as allConditionsAreMatched,c as conditionIsMatched,f as createInstance,h as createLogger,d as defaultLogHandler,g as defaultLogLevels,y as getBucketedNumber,v as getValueByType,b as loggerPrefix};
|
|
1
|
+
var e={784:e=>{!function(){const t=e=>(new TextEncoder).encode(e);function r(e,r){let i,a,s,n,o,u,l,c;for("string"==typeof e&&(e=t(e)),i=3&e.length,a=e.length-i,s=r,o=3432918353,u=461845907,c=0;c<a;)l=255&e[c]|(255&e[++c])<<8|(255&e[++c])<<16|(255&e[++c])<<24,++c,l=(65535&l)*o+(((l>>>16)*o&65535)<<16)&4294967295,l=l<<15|l>>>17,l=(65535&l)*u+(((l>>>16)*u&65535)<<16)&4294967295,s^=l,s=s<<13|s>>>19,n=5*(65535&s)+((5*(s>>>16)&65535)<<16)&4294967295,s=27492+(65535&n)+((58964+(n>>>16)&65535)<<16);switch(l=0,i){case 3:l^=(255&e[c+2])<<16;case 2:l^=(255&e[c+1])<<8;case 1:l^=255&e[c],l=(65535&l)*o+(((l>>>16)*o&65535)<<16)&4294967295,l=l<<15|l>>>17,l=(65535&l)*u+(((l>>>16)*u&65535)<<16)&4294967295,s^=l}return s^=e.length,s^=s>>>16,s=2246822507*(65535&s)+((2246822507*(s>>>16)&65535)<<16)&4294967295,s^=s>>>13,s=3266489909*(65535&s)+((3266489909*(s>>>16)&65535)<<16)&4294967295,s^=s>>>16,s>>>0}const i=r;i.v2=function(e,r){"string"==typeof e&&(e=t(e));let i,a=e.length,s=r^a,n=0;for(;a>=4;)i=255&e[n]|(255&e[++n])<<8|(255&e[++n])<<16|(255&e[++n])<<24,i=1540483477*(65535&i)+((1540483477*(i>>>16)&65535)<<16),i^=i>>>24,i=1540483477*(65535&i)+((1540483477*(i>>>16)&65535)<<16),s=1540483477*(65535&s)+((1540483477*(s>>>16)&65535)<<16)^i,a-=4,++n;switch(a){case 3:s^=(255&e[n+2])<<16;case 2:s^=(255&e[n+1])<<8;case 1:s^=255&e[n],s=1540483477*(65535&s)+((1540483477*(s>>>16)&65535)<<16)}return s^=s>>>13,s=1540483477*(65535&s)+((1540483477*(s>>>16)&65535)<<16),s^=s>>>15,s>>>0},i.v3=r,e.exports=i}()}},t={};function r(i){var a=t[i];if(void 0!==a)return a.exports;var s=t[i]={exports:{}};return e[i](s,s.exports,r),s.exports}r.d=(e,t)=>{for(var i in t)r.o(t,i)&&!r.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var i={};r.d(i,{vl:()=>y,f6:()=>D,Jr:()=>w,Vy:()=>h,lb:()=>o,i4:()=>I,mx:()=>A,Q_:()=>_,h:()=>d,K_:()=>f,DU:()=>c,dg:()=>u,Zy:()=>T,xE:()=>l});var a=r(784);const s=1,n=Math.pow(2,32),o=1e5;function u(e){const t=a.v3(e,s)/n;return Math.floor(t*o)}const l="[Featurevisor]",c=["warn","error"],f=function(e,t,r={}){switch(e){case"debug":console.log(l,t,r);break;case"info":console.info(l,t,r);break;case"warn":console.warn(l,t,r);break;case"error":console.error(l,t,r)}};class h{constructor(e){this.levels=e.levels,this.handle=e.handler}setLevels(e){this.levels=e}log(e,t,r){-1!==this.levels.indexOf(e)&&this.handle(e,t,r)}debug(e,t){this.log("debug",e,t)}info(e,t){this.log("info",e,t)}warn(e,t){this.log("warn",e,t)}error(e,t){this.log("error",e,t)}}function d(e={}){const t=e.levels||c,r=e.handler||f;return new h({levels:t,handler:r})}class g{constructor(e){this.schemaVersion=e.schemaVersion,this.revision=e.revision,this.segments=e.segments,this.attributes=e.attributes,this.features=e.features}getRevision(){return this.revision}getSchemaVersion(){return this.schemaVersion}getAllAttributes(){return this.attributes}getAttribute(e){return this.attributes.find((t=>t.key===e))}getSegment(e){const t=this.segments.find((t=>t.key===e));if(t)return function(e,t){if("string"==typeof e[t]&&"*"!==e[t])try{e[t]=JSON.parse(e[t])}catch(e){console.error("Error parsing JSON",e)}return e}(t,"conditions")}getFeature(e){const t=this.features.find((t=>t.key===e));if(t)return t}}class y{constructor(){this._listeners={}}addListener(e,t){void 0===this._listeners[e]&&(this._listeners[e]=[]),this._listeners[e].push(t)}removeListener(e,t){if(void 0===this._listeners[e])return;const r=this._listeners[e].indexOf(t);-1!==r&&this._listeners[e].splice(r,1)}removeAllListeners(e){e?this._listeners[e]=[]:Object.keys(this._listeners).forEach((e=>{this._listeners[e]=[]}))}emit(e,...t){void 0!==this._listeners[e]&&this._listeners[e].forEach((e=>{e(...t)}))}}const v=(e,t)=>{const r=k(e),i=k(t),a=r.pop(),s=i.pop(),n=V(r,i);return 0!==n?n:a&&s?V(a.split("."),s.split(".")):a||s?a?-1:1:0},b=/^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i,k=e=>{if("string"!=typeof e)throw new TypeError("Invalid argument expected string");const t=e.match(b);if(!t)throw new Error(`Invalid argument not valid semver ('${e}' received)`);return t.shift(),t},m=e=>"*"===e||"x"===e||"X"===e,p=e=>{const t=parseInt(e,10);return isNaN(t)?e:t},K=(e,t)=>{if(m(e)||m(t))return 0;const[r,i]=((e,t)=>typeof e!=typeof t?[String(e),String(t)]:[e,t])(p(e),p(t));return r>i?1:r<i?-1:0},V=(e,t)=>{for(let r=0;r<Math.max(e.length,t.length);r++){const i=K(e[r]||"0",t[r]||"0");if(0!==i)return i}return 0};function A(e,t){const{attribute:r,operator:i,value:a}=e;if("equals"===i)return t[r]===a;if("notEquals"===i)return t[r]!==a;if("before"===i||"after"===i){const e=t[r],s=e instanceof Date?e:new Date(e),n=a instanceof Date?a:new Date(a);return"before"===i?s<n:s>n}if(Array.isArray(a)){const e=t[r];if("in"===i)return-1!==a.indexOf(e);if("notIn"===i)return-1===a.indexOf(e)}else if("string"==typeof t[r]&&"string"==typeof a){const e=t[r];if("contains"===i)return-1!==e.indexOf(a);if("notContains"===i)return-1===e.indexOf(a);if("startsWith"===i)return e.startsWith(a);if("endsWith"===i)return e.endsWith(a);if("semverEquals"===i)return 0===v(e,a);if("semverNotEquals"===i)return 0!==v(e,a);if("semverGreaterThan"===i)return 1===v(e,a);if("semverGreaterThanOrEquals"===i)return v(e,a)>=0;if("semverLessThan"===i)return-1===v(e,a);if("semverLessThanOrEquals"===i)return v(e,a)<=0}else if("number"==typeof t[r]&&"number"==typeof a){const e=t[r];if("greaterThan"===i)return e>a;if("greaterThanOrEquals"===i)return e>=a;if("lessThan"===i)return e<a;if("lessThanOrEquals"===i)return e<=a}return!1}function I(e,t,r){if("attribute"in e)try{return A(e,t)}catch(i){return r.warn(i.message,{error:i,details:{condition:e,context:t}}),!1}return"and"in e&&Array.isArray(e.and)?e.and.every((e=>I(e,t,r))):"or"in e&&Array.isArray(e.or)?e.or.some((e=>I(e,t,r))):"not"in e&&Array.isArray(e.not)?e.not.every((()=>!1===I({and:e.not},t,r))):!!Array.isArray(e)&&e.every((e=>I(e,t,r)))}function E(e,t,r,i){if("*"===e)return!0;if("string"==typeof e){const a=r.getSegment(e);return!!a&&function(e,t,r){return I(e.conditions,t,r)}(a,t,i)}if("object"==typeof e){if("and"in e&&Array.isArray(e.and))return e.and.every((e=>E(e,t,r,i)));if("or"in e&&Array.isArray(e.or))return e.or.some((e=>E(e,t,r,i)));if("not"in e&&Array.isArray(e.not))return e.not.every((e=>!1===E(e,t,r,i)))}return!!Array.isArray(e)&&e.every((e=>E(e,t,r,i)))}function F(e){return"string"==typeof e&&(e.startsWith("{")||e.startsWith("["))?JSON.parse(e):e}function R(e,t,r,i,a){const s=e.find((e=>E(F(e.segments),t,i,a)));if(!s)return{matchedTraffic:void 0,matchedAllocation:void 0};const n=function(e,t){for(const r of e.allocation){const[e,i]=r.range;if(r.range&&e<=t&&i>=t)return r}}(s,r);return{matchedTraffic:s,matchedAllocation:n}}function O(e,t,r,i){const a={force:void 0,forceIndex:void 0};if(!e.force)return a;for(let s=0;s<e.force.length;s++){const n=e.force[s];if(n.conditions&&I(n.conditions,t,i)){a.force=n,a.forceIndex=s;break}if(n.segments&&E(n.segments,t,r,i)){a.force=n,a.forceIndex=s;break}}return a}Object.keys({">":[1],">=":[0,1],"=":[0],"<=":[-1,0],"<":[-1]});const L={schemaVersion:"1",revision:"unknown",attributes:[],segments:[],features:[]};var D;function x(e,t){return t?t(e):fetch(e).then((e=>e.json()))}function T(e,t){try{if(void 0===e)return;switch(t){case"string":return"string"==typeof e?e:void 0;case"integer":return parseInt(e,10);case"double":return parseFloat(e);case"boolean":return!0===e;case"array":return Array.isArray(e)?e:void 0;case"object":return"object"==typeof e?e:void 0;default:return e}}catch(e){return}}!function(e){e.NOT_FOUND="not_found",e.NO_VARIATIONS="no_variations",e.NO_MATCH="no_match",e.DISABLED="disabled",e.REQUIRED="required",e.OUT_OF_RANGE="out_of_range",e.FORCED="forced",e.INITIAL="initial",e.STICKY="sticky",e.RULE="rule",e.ALLOCATED="allocated",e.DEFAULTED="defaulted",e.OVERRIDE="override",e.ERROR="error"}(D||(D={}));class w{constructor(e){this.bucketKeySeparator=e.bucketKeySeparator||".",this.configureBucketKey=e.configureBucketKey,this.configureBucketValue=e.configureBucketValue,this.datafileUrl=e.datafileUrl,this.handleDatafileFetch=e.handleDatafileFetch,this.initialFeatures=e.initialFeatures,this.interceptContext=e.interceptContext,this.logger=e.logger||d(),this.refreshInterval=e.refreshInterval,this.stickyFeatures=e.stickyFeatures,this.emitter=new y,this.statuses={ready:!1,refreshInProgress:!1},e.onReady&&this.emitter.addListener("ready",e.onReady),e.onRefresh&&this.emitter.addListener("refresh",e.onRefresh),e.onUpdate&&this.emitter.addListener("update",e.onUpdate),e.onActivation&&this.emitter.addListener("activation",e.onActivation);const t=this.emitter.addListener.bind(this.emitter);this.on=t,this.addListener=t;const r=this.emitter.removeListener.bind(this.emitter);if(this.off=r,this.removeListener=r,this.removeAllListeners=this.emitter.removeAllListeners.bind(this.emitter),e.datafileUrl)this.setDatafile(e.datafile||L),x(e.datafileUrl,e.handleDatafileFetch).then((e=>{this.setDatafile(e),this.statuses.ready=!0,this.emitter.emit("ready"),this.refreshInterval&&this.startRefreshing()})).catch((e=>{this.logger.error("failed to fetch datafile",{error:e})}));else{if(!e.datafile)throw new Error("Featurevisor SDK instance cannot be created without both `datafile` and `datafileUrl` options");this.setDatafile(e.datafile),this.statuses.ready=!0,setTimeout((()=>{this.emitter.emit("ready")}),0)}}setLogLevels(e){this.logger.setLevels(e)}onReady(){return new Promise((e=>{if(this.statuses.ready)return e(this);const t=()=>{this.emitter.removeListener("ready",t),e(this)};this.emitter.addListener("ready",t)}))}setDatafile(e){try{this.datafileReader=new g("string"==typeof e?JSON.parse(e):e)}catch(e){this.logger.error("could not parse datafile",{error:e})}}setStickyFeatures(e){this.stickyFeatures=e}getRevision(){return this.datafileReader.getRevision()}getFeature(e){return"string"==typeof e?this.datafileReader.getFeature(e):e}getBucketKey(e,t){const r=e.key;let i,a;if("string"==typeof e.bucketBy)i="plain",a=[e.bucketBy];else if(Array.isArray(e.bucketBy))i="and",a=e.bucketBy;else{if("object"!=typeof e.bucketBy||!Array.isArray(e.bucketBy.or))throw this.logger.error("invalid bucketBy",{featureKey:r,bucketBy:e.bucketBy}),new Error("invalid bucketBy");i="or",a=e.bucketBy.or}const s=[];a.forEach((e=>{const r=t[e];void 0!==r&&("plain"===i||"and"===i||0===s.length)&&s.push(r)})),s.push(r);const n=s.join(this.bucketKeySeparator);return this.configureBucketKey?this.configureBucketKey(e,t,n):n}getBucketValue(e,t){const r=this.getBucketKey(e,t),i=u(r);return this.configureBucketValue?{bucketKey:r,bucketValue:this.configureBucketValue(e,t,i)}:{bucketKey:r,bucketValue:i}}isReady(){return this.statuses.ready}refresh(){return this.logger.debug("refreshing datafile"),this.statuses.refreshInProgress?this.logger.warn("refresh in progress, skipping"):this.datafileUrl?(this.statuses.refreshInProgress=!0,void x(this.datafileUrl,this.handleDatafileFetch).then((e=>{const t=this.getRevision()!==e.revision;this.setDatafile(e),this.logger.info("refreshed datafile"),this.emitter.emit("refresh"),t&&this.emitter.emit("update"),this.statuses.refreshInProgress=!1})).catch((e=>{this.logger.error("failed to refresh datafile",{error:e}),this.statuses.refreshInProgress=!1}))):this.logger.error("cannot refresh since `datafileUrl` is not provided")}startRefreshing(){return this.datafileUrl?this.intervalId?this.logger.warn("refreshing has already started"):this.refreshInterval?void(this.intervalId=setInterval((()=>{this.refresh()}),1e3*this.refreshInterval)):this.logger.warn("no `refreshInterval` option provided"):this.logger.error("cannot start refreshing since `datafileUrl` is not provided")}stopRefreshing(){if(!this.intervalId)return this.logger.warn("refreshing has not started yet");clearInterval(this.intervalId)}evaluateFlag(e,t={}){let r;try{const i="string"==typeof e?e:e.key;if(this.stickyFeatures&&this.stickyFeatures[i]&&void 0!==this.stickyFeatures[i].enabled)return r={featureKey:i,reason:D.STICKY,sticky:this.stickyFeatures[i],enabled:this.stickyFeatures[i].enabled},this.logger.debug("using sticky enabled",r),r;if(this.statuses&&!this.statuses.ready&&this.initialFeatures&&this.initialFeatures[i]&&void 0!==this.initialFeatures[i].enabled)return r={featureKey:i,reason:D.INITIAL,initial:this.initialFeatures[i],enabled:this.initialFeatures[i].enabled},this.logger.debug("using initial enabled",r),r;const a=this.getFeature(e);if(!a)return r={featureKey:i,reason:D.NOT_FOUND},this.logger.warn("feature not found",r),r;a.deprecated&&this.logger.warn("feature is deprecated",{featureKey:a.key});const s=this.interceptContext?this.interceptContext(t):t,{force:n,forceIndex:o}=O(a,t,this.datafileReader,this.logger);if(n&&void 0!==n.enabled)return r={featureKey:a.key,reason:D.FORCED,forceIndex:o,force:n,enabled:n.enabled},this.logger.debug("forced enabled found",r),r;if(a.required&&a.required.length>0){const e=a.required.every((e=>{let t,r;return"string"==typeof e?t=e:(t=e.key,r=e.variation),!!this.isEnabled(t,s)&&(void 0===r||this.getVariation(t,s)===r)}));if(!e)return r={featureKey:a.key,reason:D.REQUIRED,required:a.required,enabled:e},this.logger.debug("required features not enabled",r),r}const{bucketKey:u,bucketValue:l}=this.getBucketValue(a,s),c=function(e,t,r,i){return e.find((e=>!!E(F(e.segments),t,r,i)))}(a.traffic,s,this.datafileReader,this.logger);if(c){if(a.ranges&&a.ranges.length>0)return a.ranges.find((e=>l>=e[0]&&l<e[1]))?(r={featureKey:a.key,reason:D.ALLOCATED,bucketKey:u,bucketValue:l,ruleKey:c.key,traffic:c,enabled:void 0===c.enabled||c.enabled},this.logger.debug("matched",r),r):(r={featureKey:a.key,reason:D.OUT_OF_RANGE,bucketKey:u,bucketValue:l,enabled:!1},this.logger.debug("not matched",r),r);if(void 0!==c.enabled)return r={featureKey:a.key,reason:D.OVERRIDE,bucketKey:u,bucketValue:l,ruleKey:c.key,traffic:c,enabled:c.enabled},this.logger.debug("override from rule",r),r;if(l<=c.percentage)return r={featureKey:a.key,reason:D.RULE,bucketKey:u,bucketValue:l,ruleKey:c.key,traffic:c,enabled:!0},this.logger.debug("matched traffic",r),r}return r={featureKey:a.key,reason:D.NO_MATCH,bucketKey:u,bucketValue:l,enabled:!1},this.logger.debug("nothing matched",r),r}catch(t){return r={featureKey:"string"==typeof e?e:e.key,reason:D.ERROR,error:t},this.logger.error("error",r),r}}isEnabled(e,t={}){try{return!0===this.evaluateFlag(e,t).enabled}catch(t){return this.logger.error("isEnabled",{featureKey:e,error:t}),!1}}evaluateVariation(e,t={}){let r;try{const i="string"==typeof e?e:e.key;if(!1===this.evaluateFlag(e,t).enabled)return r={featureKey:i,reason:D.DISABLED},this.logger.debug("feature is disabled",r),r;if(this.stickyFeatures&&this.stickyFeatures[i]){const e=this.stickyFeatures[i].variation;if(void 0!==e)return r={featureKey:i,reason:D.STICKY,variationValue:e},this.logger.debug("using sticky variation",r),r}if(this.statuses&&!this.statuses.ready&&this.initialFeatures&&this.initialFeatures[i]&&void 0!==this.initialFeatures[i].variation){const e=this.initialFeatures[i].variation;return r={featureKey:i,reason:D.INITIAL,variationValue:e},this.logger.debug("using initial variation",r),r}const a=this.getFeature(e);if(!a)return r={featureKey:i,reason:D.NOT_FOUND},this.logger.warn("feature not found",r),r;if(!a.variations||0===a.variations.length)return r={featureKey:i,reason:D.NO_VARIATIONS},this.logger.warn("no variations",r),r;const s=this.interceptContext?this.interceptContext(t):t,{force:n,forceIndex:o}=O(a,t,this.datafileReader,this.logger);if(n&&n.variation){const e=a.variations.find((e=>e.value===n.variation));if(e)return r={featureKey:a.key,reason:D.FORCED,forceIndex:o,force:n,variation:e},this.logger.debug("forced variation found",r),r}const{bucketKey:u,bucketValue:l}=this.getBucketValue(a,s),{matchedTraffic:c,matchedAllocation:f}=R(a.traffic,s,l,this.datafileReader,this.logger);if(c){if(c.variation){const e=a.variations.find((e=>e.value===c.variation));if(e)return r={featureKey:a.key,reason:D.RULE,bucketKey:u,bucketValue:l,ruleKey:c.key,traffic:c,variation:e},this.logger.debug("override from rule",r),r}if(f&&f.variation){const e=a.variations.find((e=>e.value===f.variation));if(e)return r={featureKey:a.key,reason:D.ALLOCATED,bucketKey:u,bucketValue:l,ruleKey:c.key,traffic:c,variation:e},this.logger.debug("allocated variation",r),r}}return r={featureKey:a.key,reason:D.NO_MATCH,bucketKey:u,bucketValue:l},this.logger.debug("no matched variation",r),r}catch(t){return r={featureKey:"string"==typeof e?e:e.key,reason:D.ERROR,error:t},this.logger.error("error",r),r}}getVariation(e,t={}){try{const r=this.evaluateVariation(e,t);return void 0!==r.variationValue?r.variationValue:r.variation?r.variation.value:void 0}catch(t){return void this.logger.error("getVariation",{featureKey:e,error:t})}}activate(e,t={}){try{const r=this.evaluateVariation(e,t),i=r.variation?r.variation.value:r.variationValue;if(void 0===i)return;const a=this.interceptContext?this.interceptContext(t):t,s={};return this.datafileReader.getAllAttributes().filter((e=>!0===e.capture)).forEach((e=>{void 0!==a[e.key]&&(s[e.key]=t[e.key])})),this.emitter.emit("activation",e,i,a,s,r),i}catch(t){return void this.logger.error("activate",{featureKey:e,error:t})}}evaluateVariable(e,t,r={}){let i;try{const a="string"==typeof e?e:e.key;if(!1===this.evaluateFlag(e,r).enabled)return i={featureKey:a,reason:D.DISABLED},this.logger.debug("feature is disabled",i),i;if(this.stickyFeatures&&this.stickyFeatures[a]){const e=this.stickyFeatures[a].variables;if(e){const r=e[t];if(void 0!==r)return i={featureKey:a,reason:D.STICKY,variableKey:t,variableValue:r},this.logger.debug("using sticky variable",i),i}}if(this.statuses&&!this.statuses.ready&&this.initialFeatures&&this.initialFeatures[a]){const e=this.initialFeatures[a].variables;if(e&&void 0!==e[t])return i={featureKey:a,reason:D.INITIAL,variableKey:t,variableValue:e[t]},this.logger.debug("using initial variable",i),i}const s=this.getFeature(e);if(!s)return i={featureKey:a,reason:D.NOT_FOUND,variableKey:t},this.logger.warn("feature not found in datafile",i),i;const n=Array.isArray(s.variablesSchema)?s.variablesSchema.find((e=>e.key===t)):void 0;if(!n)return i={featureKey:a,reason:D.NOT_FOUND,variableKey:t},this.logger.warn("variable schema not found",i),i;const o=this.interceptContext?this.interceptContext(r):r,{force:u,forceIndex:l}=O(s,r,this.datafileReader,this.logger);if(u&&u.variables&&void 0!==u.variables[t])return i={featureKey:s.key,reason:D.FORCED,forceIndex:l,force:u,variableKey:t,variableSchema:n,variableValue:u.variables[t]},this.logger.debug("forced variable",i),i;const{bucketKey:c,bucketValue:f}=this.getBucketValue(s,o),{matchedTraffic:h,matchedAllocation:d}=R(s.traffic,o,f,this.datafileReader,this.logger);if(h){if(h.variables&&void 0!==h.variables[t])return i={featureKey:s.key,reason:D.RULE,bucketKey:c,bucketValue:f,ruleKey:h.key,traffic:h,variableKey:t,variableSchema:n,variableValue:h.variables[t]},this.logger.debug("override from rule",i),i;let e;if(u&&u.variation?e=u.variation:d&&d.variation&&(e=d.variation),e&&Array.isArray(s.variations)){const r=s.variations.find((t=>t.value===e));if(r&&r.variables){const e=r.variables.find((e=>e.key===t));if(e){if(e.overrides){const r=e.overrides.find((e=>e.conditions?I("string"==typeof e.conditions?JSON.parse(e.conditions):e.conditions,o,this.logger):!!e.segments&&E(F(e.segments),o,this.datafileReader,this.logger)));if(r)return i={featureKey:s.key,reason:D.OVERRIDE,bucketKey:c,bucketValue:f,ruleKey:h.key,traffic:h,variableKey:t,variableSchema:n,variableValue:r.value},this.logger.debug("variable override",i),i}if(void 0!==e.value)return i={featureKey:s.key,reason:D.ALLOCATED,bucketKey:c,bucketValue:f,ruleKey:h.key,traffic:h,variableKey:t,variableSchema:n,variableValue:e.value},this.logger.debug("allocated variable",i),i}}}}return i={featureKey:s.key,reason:D.DEFAULTED,bucketKey:c,bucketValue:f,variableKey:t,variableSchema:n,variableValue:n.defaultValue},this.logger.debug("using default value",i),i}catch(r){return i={featureKey:"string"==typeof e?e:e.key,reason:D.ERROR,variableKey:t,error:r},this.logger.error("error",i),i}}getVariable(e,t,r={}){try{const i=this.evaluateVariable(e,t,r);return void 0!==i.variableValue?i.variableSchema&&"json"===i.variableSchema.type&&"string"==typeof i.variableValue?JSON.parse(i.variableValue):i.variableValue:void 0}catch(r){return void this.logger.error("getVariable",{featureKey:e,variableKey:t,error:r})}}getVariableBoolean(e,t,r={}){return T(this.getVariable(e,t,r),"boolean")}getVariableString(e,t,r={}){return T(this.getVariable(e,t,r),"string")}getVariableInteger(e,t,r={}){return T(this.getVariable(e,t,r),"integer")}getVariableDouble(e,t,r={}){return T(this.getVariable(e,t,r),"double")}getVariableArray(e,t,r={}){return T(this.getVariable(e,t,r),"array")}getVariableObject(e,t,r={}){return T(this.getVariable(e,t,r),"object")}getVariableJSON(e,t,r={}){return T(this.getVariable(e,t,r),"json")}}function _(e){return new w(e)}var S=i.vl,N=i.f6,B=i.Jr,U=i.Vy,C=i.lb,q=i.i4,j=i.mx,M=i.Q_,J=i.h,P=i.K_,W=i.DU,z=i.dg,G=i.Zy,H=i.xE;export{S as Emitter,N as EvaluationReason,B as FeaturevisorInstance,U as Logger,C as MAX_BUCKETED_NUMBER,q as allConditionsAreMatched,j as conditionIsMatched,M as createInstance,J as createLogger,P as defaultLogHandler,W as defaultLogLevels,z as getBucketedNumber,G as getValueByType,H as loggerPrefix};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.gz
CHANGED
|
Binary file
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","mappings":"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","sources":["webpack://@featurevisor/sdk/../../node_modules/murmurhash/murmurhash.js","webpack://@featurevisor/sdk/webpack/bootstrap","webpack://@featurevisor/sdk/webpack/runtime/define property getters","webpack://@featurevisor/sdk/webpack/runtime/hasOwnProperty shorthand","webpack://@featurevisor/sdk/./src/bucket.ts","webpack://@featurevisor/sdk/./src/logger.ts","webpack://@featurevisor/sdk/./src/datafileReader.ts","webpack://@featurevisor/sdk/./src/emitter.ts","webpack://@featurevisor/sdk/../../node_modules/compare-versions/lib/esm/index.js","webpack://@featurevisor/sdk/./src/conditions.ts","webpack://@featurevisor/sdk/./src/segments.ts","webpack://@featurevisor/sdk/./src/feature.ts","webpack://@featurevisor/sdk/./src/instance.ts"],"sourcesContent":["(function(){\n const _global = this;\n\n const createBuffer = (val) => new TextEncoder().encode(val)\n\n /**\n * JS Implementation of MurmurHash2\n *\n * @author <a href=\"mailto:gary.court@gmail.com\">Gary Court</a>\n * @see http://github.com/garycourt/murmurhash-js\n * @author <a href=\"mailto:aappleby@gmail.com\">Austin Appleby</a>\n * @see http://sites.google.com/site/murmurhash/\n *\n * @param {Uint8Array | string} str ASCII only\n * @param {number} seed Positive integer only\n * @return {number} 32-bit positive integer hash\n */\n function MurmurHashV2(str, seed) {\n if (typeof str === 'string') str = createBuffer(str);\n let\n l = str.length,\n h = seed ^ l,\n i = 0,\n k;\n\n while (l >= 4) {\n k =\n ((str[i] & 0xff)) |\n ((str[++i] & 0xff) << 8) |\n ((str[++i] & 0xff) << 16) |\n ((str[++i] & 0xff) << 24);\n\n k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n k ^= k >>> 24;\n k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n\n h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k;\n\n l -= 4;\n ++i;\n }\n\n switch (l) {\n case 3: h ^= (str[i + 2] & 0xff) << 16;\n case 2: h ^= (str[i + 1] & 0xff) << 8;\n case 1: h ^= (str[i] & 0xff);\n h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n }\n\n h ^= h >>> 13;\n h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n h ^= h >>> 15;\n\n return h >>> 0;\n };\n\n /*\n * JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)\n *\n * @author <a href=\"mailto:gary.court@gmail.com\">Gary Court</a>\n * @see http://github.com/garycourt/murmurhash-js\n * @author <a href=\"mailto:aappleby@gmail.com\">Austin Appleby</a>\n * @see http://sites.google.com/site/murmurhash/\n *\n * @param {Uint8Array | string} key ASCII only\n * @param {number} seed Positive integer only\n * @return {number} 32-bit positive integer hash\n */\n function MurmurHashV3(key, seed) {\n if (typeof key === 'string') key = createBuffer(key);\n\n let remainder, bytes, h1, h1b, c1, c1b, c2, c2b, k1, i;\n\n remainder = key.length & 3; // key.length % 4\n bytes = key.length - remainder;\n h1 = seed;\n c1 = 0xcc9e2d51;\n c2 = 0x1b873593;\n i = 0;\n\n while (i < bytes) {\n k1 =\n ((key[i] & 0xff)) |\n ((key[++i] & 0xff) << 8) |\n ((key[++i] & 0xff) << 16) |\n ((key[++i] & 0xff) << 24);\n ++i;\n\n k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;\n k1 = (k1 << 15) | (k1 >>> 17);\n k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;\n\n h1 ^= k1;\n h1 = (h1 << 13) | (h1 >>> 19);\n h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;\n h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));\n }\n\n k1 = 0;\n\n switch (remainder) {\n case 3: k1 ^= (key[i + 2] & 0xff) << 16;\n case 2: k1 ^= (key[i + 1] & 0xff) << 8;\n case 1: k1 ^= (key[i] & 0xff);\n\n k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;\n k1 = (k1 << 15) | (k1 >>> 17);\n k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;\n h1 ^= k1;\n }\n\n h1 ^= key.length;\n\n h1 ^= h1 >>> 16;\n h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;\n h1 ^= h1 >>> 13;\n h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;\n h1 ^= h1 >>> 16;\n\n return h1 >>> 0;\n }\n\n const murmur = MurmurHashV3;\n murmur.v2 = MurmurHashV2;\n murmur.v3 = MurmurHashV3;\n\n if (typeof(module) != 'undefined') {\n module.exports = murmur;\n } else {\n const _previousRoot = _global.murmur;\n murmur.noConflict = function() {\n _global.murmur = _previousRoot;\n return murmur;\n }\n _global.murmur = murmur;\n }\n}());\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","import * as murmurhash from \"murmurhash\";\n\nconst HASH_SEED = 1;\nconst MAX_HASH_VALUE = Math.pow(2, 32);\n\nexport const MAX_BUCKETED_NUMBER = 100000; // 100% * 1000 to include three decimal places in the same integer value\n\nexport function getBucketedNumber(bucketKey: string): number {\n const hashValue = murmurhash.v3(bucketKey, HASH_SEED);\n const ratio = hashValue / MAX_HASH_VALUE;\n\n return Math.floor(ratio * MAX_BUCKETED_NUMBER);\n}\n","export type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport type LogMessage = string;\n\nexport interface LogDetails {\n [key: string]: any;\n}\n\nexport type LogHandler = (level: LogLevel, message: LogMessage, details?: LogDetails) => void;\n\nexport interface CreateLoggerOptions {\n levels?: LogLevel[];\n handler?: LogHandler;\n}\n\nexport const loggerPrefix = \"[Featurevisor]\";\n\nexport const defaultLogLevels: LogLevel[] = [\n // supported, but not enabled by default\n // \"debug\",\n // \"info\",\n\n // enabled by default\n \"warn\",\n \"error\",\n];\n\nexport const defaultLogHandler: LogHandler = function defaultLogHandler(\n level,\n message,\n details = {},\n) {\n switch (level) {\n case \"debug\":\n console.log(loggerPrefix, message, details);\n break;\n case \"info\":\n console.info(loggerPrefix, message, details);\n break;\n case \"warn\":\n console.warn(loggerPrefix, message, details);\n break;\n case \"error\":\n console.error(loggerPrefix, message, details);\n break;\n }\n};\n\nexport class Logger {\n private levels: LogLevel[];\n private handle: LogHandler;\n\n constructor(options: CreateLoggerOptions) {\n this.levels = options.levels as LogLevel[];\n this.handle = options.handler as LogHandler;\n }\n\n setLevels(levels: LogLevel[]) {\n this.levels = levels;\n }\n\n log(level: LogLevel, message: LogMessage, details?: LogDetails) {\n if (this.levels.indexOf(level) !== -1) {\n this.handle(level, message, details);\n }\n }\n\n debug(message: LogMessage, details?: LogDetails) {\n this.log(\"debug\", message, details);\n }\n\n info(message: LogMessage, details?: LogDetails) {\n this.log(\"info\", message, details);\n }\n\n warn(message: LogMessage, details?: LogDetails) {\n this.log(\"warn\", message, details);\n }\n\n error(message: LogMessage, details?: LogDetails) {\n this.log(\"error\", message, details);\n }\n}\n\nexport function createLogger(options: CreateLoggerOptions = {}): Logger {\n const levels = options.levels || defaultLogLevels;\n const logHandler = options.handler || defaultLogHandler;\n\n return new Logger({ levels, handler: logHandler });\n}\n","import {\n Feature,\n Segment,\n DatafileContent,\n Attribute,\n AttributeKey,\n SegmentKey,\n FeatureKey,\n} from \"@featurevisor/types\";\n\nexport function parseJsonConditionsIfStringified<T>(record: T, key: string): T {\n if (typeof record[key] === \"string\" && record[key] !== \"*\") {\n try {\n record[key] = JSON.parse(record[key]);\n } catch (e) {\n console.error(\"Error parsing JSON\", e);\n }\n }\n\n return record;\n}\n\nexport class DatafileReader {\n private schemaVersion: string;\n private revision: string;\n private attributes: Attribute[];\n private segments: Segment[];\n private features: Feature[];\n\n constructor(datafileJson: DatafileContent) {\n this.schemaVersion = datafileJson.schemaVersion;\n this.revision = datafileJson.revision;\n this.segments = datafileJson.segments;\n this.attributes = datafileJson.attributes;\n this.features = datafileJson.features;\n }\n\n getRevision(): string {\n return this.revision;\n }\n\n getSchemaVersion(): string {\n return this.schemaVersion;\n }\n\n getAllAttributes(): Attribute[] {\n return this.attributes;\n }\n\n getAttribute(attributeKey: AttributeKey): Attribute | undefined {\n return this.attributes.find((a) => a.key === attributeKey);\n }\n\n getSegment(segmentKey: SegmentKey): Segment | undefined {\n const segment = this.segments.find((s) => s.key === segmentKey);\n\n if (!segment) {\n return undefined;\n }\n\n return parseJsonConditionsIfStringified(segment, \"conditions\");\n }\n\n getFeature(featureKey: FeatureKey): Feature | undefined {\n const feature = this.features.find((s) => s.key === featureKey);\n\n if (!feature) {\n return undefined;\n }\n\n return feature;\n }\n}\n","export type EventName = \"ready\" | \"refresh\" | \"update\" | \"activation\";\n\nexport interface Listeners {\n [key: string]: Function[];\n}\n\nexport class Emitter {\n private _listeners: Listeners;\n\n constructor() {\n this._listeners = {};\n }\n\n public addListener(eventName: EventName, fn: Function): void {\n if (typeof this._listeners[eventName] === \"undefined\") {\n this._listeners[eventName] = [];\n }\n\n this._listeners[eventName].push(fn);\n }\n\n public removeListener(eventName: EventName, fn: Function): void {\n if (typeof this._listeners[eventName] === \"undefined\") {\n return;\n }\n\n const index = this._listeners[eventName].indexOf(fn);\n\n if (index !== -1) {\n this._listeners[eventName].splice(index, 1);\n }\n }\n\n public removeAllListeners(eventName?: EventName): void {\n if (eventName) {\n this._listeners[eventName] = [];\n } else {\n Object.keys(this._listeners).forEach((key) => {\n this._listeners[key] = [];\n });\n }\n }\n\n public emit(eventName: EventName, ...args: any[]): void {\n if (typeof this._listeners[eventName] === \"undefined\") {\n return;\n }\n\n this._listeners[eventName].forEach((fn) => {\n fn(...args);\n });\n }\n}\n","/**\n * Compare [semver](https://semver.org/) version strings to find greater, equal or lesser.\n * This library supports the full semver specification, including comparing versions with different number of digits like `1.0.0`, `1.0`, `1`, and pre-release versions like `1.0.0-alpha`.\n * @param v1 - First version to compare\n * @param v2 - Second version to compare\n * @returns Numeric value compatible with the [Array.sort(fn) interface](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Parameters).\n */\nexport const compareVersions = (v1, v2) => {\n // validate input and split into segments\n const n1 = validateAndParse(v1);\n const n2 = validateAndParse(v2);\n // pop off the patch\n const p1 = n1.pop();\n const p2 = n2.pop();\n // validate numbers\n const r = compareSegments(n1, n2);\n if (r !== 0)\n return r;\n // validate pre-release\n if (p1 && p2) {\n return compareSegments(p1.split('.'), p2.split('.'));\n }\n else if (p1 || p2) {\n return p1 ? -1 : 1;\n }\n return 0;\n};\n/**\n * Validate [semver](https://semver.org/) version strings.\n *\n * @param version Version number to validate\n * @returns `true` if the version number is a valid semver version number, `false` otherwise.\n *\n * @example\n * ```\n * validate('1.0.0-rc.1'); // return true\n * validate('1.0-rc.1'); // return false\n * validate('foo'); // return false\n * ```\n */\nexport const validate = (version) => typeof version === 'string' && /^[v\\d]/.test(version) && semver.test(version);\n/**\n * Compare [semver](https://semver.org/) version strings using the specified operator.\n *\n * @param v1 First version to compare\n * @param v2 Second version to compare\n * @param operator Allowed arithmetic operator to use\n * @returns `true` if the comparison between the firstVersion and the secondVersion satisfies the operator, `false` otherwise.\n *\n * @example\n * ```\n * compare('10.1.8', '10.0.4', '>'); // return true\n * compare('10.0.1', '10.0.1', '='); // return true\n * compare('10.1.1', '10.2.2', '<'); // return true\n * compare('10.1.1', '10.2.2', '<='); // return true\n * compare('10.1.1', '10.2.2', '>='); // return false\n * ```\n */\nexport const compare = (v1, v2, operator) => {\n // validate input operator\n assertValidOperator(operator);\n // since result of compareVersions can only be -1 or 0 or 1\n // a simple map can be used to replace switch\n const res = compareVersions(v1, v2);\n return operatorResMap[operator].includes(res);\n};\n/**\n * Match [npm semver](https://docs.npmjs.com/cli/v6/using-npm/semver) version range.\n *\n * @param version Version number to match\n * @param range Range pattern for version\n * @returns `true` if the version number is within the range, `false` otherwise.\n *\n * @example\n * ```\n * satisfies('1.1.0', '^1.0.0'); // return true\n * satisfies('1.1.0', '~1.0.0'); // return false\n * ```\n */\nexport const satisfies = (version, range) => {\n // handle multiple comparators\n if (range.includes('||')) {\n return range.split('||').some((r) => satisfies(version, r));\n }\n else if (range.includes(' ')) {\n return range\n .trim()\n .replace(/\\s{2,}/g, ' ')\n .split(' ')\n .every((r) => satisfies(version, r));\n }\n // if no range operator then \"=\"\n const m = range.match(/^([<>=~^]+)/);\n const op = m ? m[1] : '=';\n // if gt/lt/eq then operator compare\n if (op !== '^' && op !== '~')\n return compare(version, range, op);\n // else range of either \"~\" or \"^\" is assumed\n const [v1, v2, v3, , vp] = validateAndParse(version);\n const [r1, r2, r3, , rp] = validateAndParse(range);\n const v = [v1, v2, v3];\n const r = [r1, r2 !== null && r2 !== void 0 ? r2 : 'x', r3 !== null && r3 !== void 0 ? r3 : 'x'];\n // validate pre-release\n if (rp) {\n if (!vp)\n return false;\n if (compareSegments(v, r) !== 0)\n return false;\n if (compareSegments(vp.split('.'), rp.split('.')) === -1)\n return false;\n }\n // first non-zero number\n const nonZero = r.findIndex((v) => v !== '0') + 1;\n // pointer to where segments can be >=\n const i = op === '~' ? 2 : nonZero > 1 ? nonZero : 1;\n // before pointer must be equal\n if (compareSegments(v.slice(0, i), r.slice(0, i)) !== 0)\n return false;\n // after pointer must be >=\n if (compareSegments(v.slice(i), r.slice(i)) === -1)\n return false;\n return true;\n};\nconst semver = /^[v^~<>=]*?(\\d+)(?:\\.([x*]|\\d+)(?:\\.([x*]|\\d+)(?:\\.([x*]|\\d+))?(?:-([\\da-z\\-]+(?:\\.[\\da-z\\-]+)*))?(?:\\+[\\da-z\\-]+(?:\\.[\\da-z\\-]+)*)?)?)?$/i;\nconst validateAndParse = (version) => {\n if (typeof version !== 'string') {\n throw new TypeError('Invalid argument expected string');\n }\n const match = version.match(semver);\n if (!match) {\n throw new Error(`Invalid argument not valid semver ('${version}' received)`);\n }\n match.shift();\n return match;\n};\nconst isWildcard = (s) => s === '*' || s === 'x' || s === 'X';\nconst tryParse = (v) => {\n const n = parseInt(v, 10);\n return isNaN(n) ? v : n;\n};\nconst forceType = (a, b) => typeof a !== typeof b ? [String(a), String(b)] : [a, b];\nconst compareStrings = (a, b) => {\n if (isWildcard(a) || isWildcard(b))\n return 0;\n const [ap, bp] = forceType(tryParse(a), tryParse(b));\n if (ap > bp)\n return 1;\n if (ap < bp)\n return -1;\n return 0;\n};\nconst compareSegments = (a, b) => {\n for (let i = 0; i < Math.max(a.length, b.length); i++) {\n const r = compareStrings(a[i] || '0', b[i] || '0');\n if (r !== 0)\n return r;\n }\n return 0;\n};\nconst operatorResMap = {\n '>': [1],\n '>=': [0, 1],\n '=': [0],\n '<=': [-1, 0],\n '<': [-1],\n};\nconst allowedOperators = Object.keys(operatorResMap);\nconst assertValidOperator = (op) => {\n if (typeof op !== 'string') {\n throw new TypeError(`Invalid operator type, expected string but got ${typeof op}`);\n }\n if (allowedOperators.indexOf(op) === -1) {\n throw new Error(`Invalid operator, expected one of ${allowedOperators.join('|')}`);\n }\n};\n//# sourceMappingURL=index.js.map","import { compareVersions } from \"compare-versions\";\n\nimport { Context, Condition, PlainCondition } from \"@featurevisor/types\";\n\nimport { Logger } from \"./logger\";\n\nexport function conditionIsMatched(condition: PlainCondition, context: Context): boolean {\n const { attribute, operator, value } = condition;\n\n if (operator === \"equals\") {\n return context[attribute] === value;\n } else if (operator === \"notEquals\") {\n return context[attribute] !== value;\n } else if (operator === \"before\" || operator === \"after\") {\n // date comparisons\n const valueInContext = context[attribute] as string | Date;\n\n const dateInContext =\n valueInContext instanceof Date ? valueInContext : new Date(valueInContext);\n const dateInCondition = value instanceof Date ? value : new Date(value as string);\n\n return operator === \"before\"\n ? dateInContext < dateInCondition\n : dateInContext > dateInCondition;\n } else if (Array.isArray(value)) {\n // array\n const valueInContext = context[attribute] as string;\n\n if (operator === \"in\") {\n return value.indexOf(valueInContext) !== -1;\n } else if (operator === \"notIn\") {\n return value.indexOf(valueInContext) === -1;\n }\n } else if (typeof context[attribute] === \"string\" && typeof value === \"string\") {\n // string\n const valueInContext = context[attribute] as string;\n\n if (operator === \"contains\") {\n return valueInContext.indexOf(value) !== -1;\n } else if (operator === \"notContains\") {\n return valueInContext.indexOf(value) === -1;\n } else if (operator === \"startsWith\") {\n return valueInContext.startsWith(value);\n } else if (operator === \"endsWith\") {\n return valueInContext.endsWith(value);\n } else if (operator === \"semverEquals\") {\n return compareVersions(valueInContext, value) === 0;\n } else if (operator === \"semverNotEquals\") {\n return compareVersions(valueInContext, value) !== 0;\n } else if (operator === \"semverGreaterThan\") {\n return compareVersions(valueInContext, value) === 1;\n } else if (operator === \"semverGreaterThanOrEquals\") {\n return compareVersions(valueInContext, value) >= 0;\n } else if (operator === \"semverLessThan\") {\n return compareVersions(valueInContext, value) === -1;\n } else if (operator === \"semverLessThanOrEquals\") {\n return compareVersions(valueInContext, value) <= 0;\n }\n } else if (typeof context[attribute] === \"number\" && typeof value === \"number\") {\n // numeric\n const valueInContext = context[attribute] as number;\n\n if (operator === \"greaterThan\") {\n return valueInContext > value;\n } else if (operator === \"greaterThanOrEquals\") {\n return valueInContext >= value;\n } else if (operator === \"lessThan\") {\n return valueInContext < value;\n } else if (operator === \"lessThanOrEquals\") {\n return valueInContext <= value;\n }\n }\n\n return false;\n}\n\nexport function allConditionsAreMatched(\n conditions: Condition[] | Condition,\n context: Context,\n logger: Logger,\n): boolean {\n if (\"attribute\" in conditions) {\n try {\n return conditionIsMatched(conditions, context);\n } catch (e) {\n logger.warn(e.message, {\n error: e,\n details: {\n condition: conditions,\n context,\n },\n });\n\n return false;\n }\n }\n\n if (\"and\" in conditions && Array.isArray(conditions.and)) {\n return conditions.and.every((c) => allConditionsAreMatched(c, context, logger));\n }\n\n if (\"or\" in conditions && Array.isArray(conditions.or)) {\n return conditions.or.some((c) => allConditionsAreMatched(c, context, logger));\n }\n\n if (\"not\" in conditions && Array.isArray(conditions.not)) {\n return conditions.not.every(\n () =>\n allConditionsAreMatched(\n {\n and: conditions.not,\n },\n context,\n logger,\n ) === false,\n );\n }\n\n if (Array.isArray(conditions)) {\n return conditions.every((c) => allConditionsAreMatched(c, context, logger));\n }\n\n return false;\n}\n","import { Context, GroupSegment, Segment, Condition } from \"@featurevisor/types\";\nimport { allConditionsAreMatched } from \"./conditions\";\nimport { DatafileReader } from \"./datafileReader\";\nimport { Logger } from \"./logger\";\n\nexport function segmentIsMatched(segment: Segment, context: Context, logger: Logger): boolean {\n return allConditionsAreMatched(segment.conditions as Condition | Condition[], context, logger);\n}\n\nexport function allGroupSegmentsAreMatched(\n groupSegments: GroupSegment | GroupSegment[] | \"*\",\n context: Context,\n datafileReader: DatafileReader,\n logger: Logger,\n): boolean {\n if (groupSegments === \"*\") {\n return true;\n }\n\n if (typeof groupSegments === \"string\") {\n const segment = datafileReader.getSegment(groupSegments);\n\n if (segment) {\n return segmentIsMatched(segment, context, logger);\n }\n\n return false;\n }\n\n if (typeof groupSegments === \"object\") {\n if (\"and\" in groupSegments && Array.isArray(groupSegments.and)) {\n return groupSegments.and.every((groupSegment) =>\n allGroupSegmentsAreMatched(groupSegment, context, datafileReader, logger),\n );\n }\n\n if (\"or\" in groupSegments && Array.isArray(groupSegments.or)) {\n return groupSegments.or.some((groupSegment) =>\n allGroupSegmentsAreMatched(groupSegment, context, datafileReader, logger),\n );\n }\n\n if (\"not\" in groupSegments && Array.isArray(groupSegments.not)) {\n return groupSegments.not.every(\n (groupSegment) =>\n allGroupSegmentsAreMatched(groupSegment, context, datafileReader, logger) === false,\n );\n }\n }\n\n if (Array.isArray(groupSegments)) {\n return groupSegments.every((groupSegment) =>\n allGroupSegmentsAreMatched(groupSegment, context, datafileReader, logger),\n );\n }\n\n return false;\n}\n","import { Allocation, Context, Traffic, Feature, Force } from \"@featurevisor/types\";\nimport { DatafileReader } from \"./datafileReader\";\nimport { allGroupSegmentsAreMatched } from \"./segments\";\nimport { allConditionsAreMatched } from \"./conditions\";\nimport { Logger } from \"./logger\";\n\nexport function getMatchedAllocation(\n traffic: Traffic,\n bucketValue: number,\n): Allocation | undefined {\n for (const allocation of traffic.allocation) {\n const [start, end] = allocation.range;\n\n if (allocation.range && start <= bucketValue && end >= bucketValue) {\n return allocation;\n }\n }\n\n return undefined;\n}\n\nexport function parseFromStringifiedSegments(value) {\n if (typeof value === \"string\" && (value.startsWith(\"{\") || value.startsWith(\"[\"))) {\n return JSON.parse(value);\n }\n\n return value;\n}\n\nexport function getMatchedTraffic(\n traffic: Traffic[],\n context: Context,\n datafileReader: DatafileReader,\n logger: Logger,\n): Traffic | undefined {\n return traffic.find((t) => {\n if (\n !allGroupSegmentsAreMatched(\n parseFromStringifiedSegments(t.segments),\n context,\n datafileReader,\n logger,\n )\n ) {\n return false;\n }\n\n return true;\n });\n}\n\nexport interface MatchedTrafficAndAllocation {\n matchedTraffic: Traffic | undefined;\n matchedAllocation: Allocation | undefined;\n}\n\nexport function getMatchedTrafficAndAllocation(\n traffic: Traffic[],\n context: Context,\n bucketValue: number,\n datafileReader: DatafileReader,\n logger: Logger,\n): MatchedTrafficAndAllocation {\n const matchedTraffic = traffic.find((t) => {\n return allGroupSegmentsAreMatched(\n parseFromStringifiedSegments(t.segments),\n context,\n datafileReader,\n logger,\n );\n });\n\n if (!matchedTraffic) {\n return {\n matchedTraffic: undefined,\n matchedAllocation: undefined,\n };\n }\n\n const matchedAllocation = getMatchedAllocation(matchedTraffic, bucketValue);\n\n return {\n matchedTraffic,\n matchedAllocation,\n };\n}\n\nexport interface ForceResult {\n force?: Force;\n forceIndex?: number;\n}\n\nexport function findForceFromFeature(\n feature: Feature,\n context: Context,\n datafileReader: DatafileReader,\n logger: Logger,\n): ForceResult {\n const result: ForceResult = {\n force: undefined,\n forceIndex: undefined,\n };\n\n if (!feature.force) {\n return result;\n }\n\n for (let i = 0; i < feature.force.length; i++) {\n const currentForce = feature.force[i];\n\n if (\n currentForce.conditions &&\n allConditionsAreMatched(currentForce.conditions, context, logger)\n ) {\n result.force = currentForce;\n result.forceIndex = i;\n break;\n }\n\n if (\n currentForce.segments &&\n allGroupSegmentsAreMatched(currentForce.segments, context, datafileReader, logger)\n ) {\n result.force = currentForce;\n result.forceIndex = i;\n break;\n }\n }\n\n return result;\n}\n","import {\n Context,\n AttributeValue,\n BucketKey,\n BucketValue,\n DatafileContent,\n Feature,\n FeatureKey,\n InitialFeatures,\n OverrideFeature,\n StickyFeatures,\n Traffic,\n VariableType,\n VariableValue,\n VariationValue,\n Variation,\n RuleKey,\n VariableKey,\n VariableSchema,\n Force,\n Required,\n} from \"@featurevisor/types\";\n\nimport { createLogger, Logger, LogLevel } from \"./logger\";\nimport { DatafileReader } from \"./datafileReader\";\nimport { Emitter } from \"./emitter\";\nimport { getBucketedNumber } from \"./bucket\";\nimport {\n findForceFromFeature,\n getMatchedTraffic,\n getMatchedTrafficAndAllocation,\n parseFromStringifiedSegments,\n} from \"./feature\";\nimport { allConditionsAreMatched } from \"./conditions\";\nimport { allGroupSegmentsAreMatched } from \"./segments\";\n\nexport type ReadyCallback = () => void;\n\nexport type ActivationCallback = (\n featureName: string,\n variation: VariationValue,\n context: Context,\n captureContext: Context,\n) => void;\n\nexport type ConfigureBucketKey = (feature, context, bucketKey: BucketKey) => BucketKey;\n\nexport type ConfigureBucketValue = (feature, context, bucketValue: BucketValue) => BucketValue;\n\nexport interface Statuses {\n ready: boolean;\n refreshInProgress: boolean;\n}\n\nconst DEFAULT_BUCKET_KEY_SEPARATOR = \".\";\n\nexport type InterceptContext = (context: Context) => Context;\n\nexport interface InstanceOptions {\n bucketKeySeparator?: string;\n configureBucketKey?: ConfigureBucketKey;\n configureBucketValue?: ConfigureBucketValue;\n datafile?: DatafileContent | string;\n datafileUrl?: string;\n handleDatafileFetch?: (datafileUrl: string) => Promise<DatafileContent>;\n initialFeatures?: InitialFeatures;\n interceptContext?: InterceptContext;\n logger?: Logger;\n onActivation?: ActivationCallback;\n onReady?: ReadyCallback;\n onRefresh?: () => void;\n onUpdate?: () => void;\n refreshInterval?: number; // seconds\n stickyFeatures?: StickyFeatures;\n}\n\nconst emptyDatafile: DatafileContent = {\n schemaVersion: \"1\",\n revision: \"unknown\",\n attributes: [],\n segments: [],\n features: [],\n};\n\nexport type DatafileFetchHandler = (datafileUrl: string) => Promise<DatafileContent>;\n\nexport enum EvaluationReason {\n NOT_FOUND = \"not_found\",\n NO_VARIATIONS = \"no_variations\",\n NO_MATCH = \"no_match\",\n DISABLED = \"disabled\",\n REQUIRED = \"required\",\n OUT_OF_RANGE = \"out_of_range\",\n FORCED = \"forced\",\n INITIAL = \"initial\",\n STICKY = \"sticky\",\n RULE = \"rule\",\n ALLOCATED = \"allocated\",\n DEFAULTED = \"defaulted\",\n OVERRIDE = \"override\",\n ERROR = \"error\",\n}\n\nexport interface Evaluation {\n // required\n featureKey: FeatureKey;\n reason: EvaluationReason;\n\n // common\n bucketKey?: BucketKey;\n bucketValue?: BucketValue;\n ruleKey?: RuleKey;\n error?: Error;\n enabled?: boolean;\n traffic?: Traffic;\n forceIndex?: number;\n force?: Force;\n required?: Required[];\n sticky?: OverrideFeature;\n initial?: OverrideFeature;\n\n // variation\n variation?: Variation;\n variationValue?: VariationValue;\n\n // variable\n variableKey?: VariableKey;\n variableValue?: VariableValue;\n variableSchema?: VariableSchema;\n}\n\nfunction fetchDatafileContent(\n datafileUrl,\n handleDatafileFetch?: DatafileFetchHandler,\n): Promise<DatafileContent> {\n if (handleDatafileFetch) {\n return handleDatafileFetch(datafileUrl);\n }\n\n return fetch(datafileUrl).then((res) => res.json());\n}\n\ntype FieldType = string | VariableType;\ntype ValueType = VariableValue;\n\nexport function getValueByType(value: ValueType, fieldType: FieldType): ValueType {\n try {\n if (value === undefined) {\n return undefined;\n }\n\n switch (fieldType) {\n case \"string\":\n return typeof value === \"string\" ? value : undefined;\n case \"integer\":\n return parseInt(value as string, 10);\n case \"double\":\n return parseFloat(value as string);\n case \"boolean\":\n return value === true;\n case \"array\":\n return Array.isArray(value) ? value : undefined;\n case \"object\":\n return typeof value === \"object\" ? value : undefined;\n // @NOTE: `json` is not handled here intentionally\n default:\n return value;\n }\n } catch (e) {\n return undefined;\n }\n}\n\nexport class FeaturevisorInstance {\n // from options\n private bucketKeySeparator: string;\n private configureBucketKey?: ConfigureBucketKey;\n private configureBucketValue?: ConfigureBucketValue;\n private datafileUrl?: string;\n private handleDatafileFetch?: DatafileFetchHandler;\n private initialFeatures?: InitialFeatures;\n private interceptContext?: InterceptContext;\n private logger: Logger;\n private refreshInterval?: number; // seconds\n private stickyFeatures?: StickyFeatures;\n\n // internally created\n private datafileReader: DatafileReader;\n private emitter: Emitter;\n private statuses: Statuses;\n private intervalId?: ReturnType<typeof setInterval>;\n\n // exposed from emitter\n public on: Emitter[\"addListener\"];\n public addListener: Emitter[\"addListener\"];\n public off: Emitter[\"removeListener\"];\n public removeListener: Emitter[\"removeListener\"];\n public removeAllListeners: Emitter[\"removeAllListeners\"];\n\n constructor(options: InstanceOptions) {\n // from options\n this.bucketKeySeparator = options.bucketKeySeparator || DEFAULT_BUCKET_KEY_SEPARATOR;\n this.configureBucketKey = options.configureBucketKey;\n this.configureBucketValue = options.configureBucketValue;\n this.datafileUrl = options.datafileUrl;\n this.handleDatafileFetch = options.handleDatafileFetch;\n this.initialFeatures = options.initialFeatures;\n this.interceptContext = options.interceptContext;\n this.logger = options.logger || createLogger();\n this.refreshInterval = options.refreshInterval;\n this.stickyFeatures = options.stickyFeatures;\n\n // internal\n this.emitter = new Emitter();\n this.statuses = {\n ready: false,\n refreshInProgress: false,\n };\n\n // register events\n if (options.onReady) {\n this.emitter.addListener(\"ready\", options.onReady);\n }\n\n if (options.onRefresh) {\n this.emitter.addListener(\"refresh\", options.onRefresh);\n }\n\n if (options.onUpdate) {\n this.emitter.addListener(\"update\", options.onUpdate);\n }\n\n if (options.onActivation) {\n this.emitter.addListener(\"activation\", options.onActivation);\n }\n\n // expose emitter methods\n const on = this.emitter.addListener.bind(this.emitter);\n this.on = on;\n this.addListener = on;\n\n const off = this.emitter.removeListener.bind(this.emitter);\n this.off = off;\n this.removeListener = off;\n\n this.removeAllListeners = this.emitter.removeAllListeners.bind(this.emitter);\n\n // datafile\n if (options.datafileUrl) {\n this.setDatafile(options.datafile || emptyDatafile);\n\n fetchDatafileContent(options.datafileUrl, options.handleDatafileFetch)\n .then((datafile) => {\n this.setDatafile(datafile);\n\n this.statuses.ready = true;\n this.emitter.emit(\"ready\");\n\n if (this.refreshInterval) {\n this.startRefreshing();\n }\n })\n .catch((e) => {\n this.logger.error(\"failed to fetch datafile\", { error: e });\n });\n } else if (options.datafile) {\n this.setDatafile(options.datafile);\n this.statuses.ready = true;\n\n setTimeout(() => {\n this.emitter.emit(\"ready\");\n }, 0);\n } else {\n throw new Error(\n \"Featurevisor SDK instance cannot be created without both `datafile` and `datafileUrl` options\",\n );\n }\n }\n\n setLogLevels(levels: LogLevel[]) {\n this.logger.setLevels(levels);\n }\n\n onReady(): Promise<FeaturevisorInstance> {\n return new Promise((resolve) => {\n if (this.statuses.ready) {\n return resolve(this);\n }\n\n const cb = () => {\n this.emitter.removeListener(\"ready\", cb);\n\n resolve(this);\n };\n\n this.emitter.addListener(\"ready\", cb);\n });\n }\n\n setDatafile(datafile: DatafileContent | string) {\n try {\n this.datafileReader = new DatafileReader(\n typeof datafile === \"string\" ? JSON.parse(datafile) : datafile,\n );\n } catch (e) {\n this.logger.error(\"could not parse datafile\", { error: e });\n }\n }\n\n setStickyFeatures(stickyFeatures: StickyFeatures | undefined) {\n this.stickyFeatures = stickyFeatures;\n }\n\n getRevision(): string {\n return this.datafileReader.getRevision();\n }\n\n getFeature(featureKey: string | Feature): Feature | undefined {\n return typeof featureKey === \"string\"\n ? this.datafileReader.getFeature(featureKey) // only key provided\n : featureKey; // full feature provided\n }\n\n /**\n * Bucketing\n */\n private getBucketKey(feature: Feature, context: Context): BucketKey {\n const featureKey = feature.key;\n\n let type;\n let attributeKeys;\n\n if (typeof feature.bucketBy === \"string\") {\n type = \"plain\";\n attributeKeys = [feature.bucketBy];\n } else if (Array.isArray(feature.bucketBy)) {\n type = \"and\";\n attributeKeys = feature.bucketBy;\n } else if (typeof feature.bucketBy === \"object\" && Array.isArray(feature.bucketBy.or)) {\n type = \"or\";\n attributeKeys = feature.bucketBy.or;\n } else {\n this.logger.error(\"invalid bucketBy\", { featureKey, bucketBy: feature.bucketBy });\n\n throw new Error(\"invalid bucketBy\");\n }\n\n const bucketKey: AttributeValue[] = [];\n\n attributeKeys.forEach((attributeKey) => {\n const attributeValue = context[attributeKey];\n\n if (typeof attributeValue === \"undefined\") {\n return;\n }\n\n if (type === \"plain\" || type === \"and\") {\n bucketKey.push(attributeValue);\n } else {\n // or\n if (bucketKey.length === 0) {\n bucketKey.push(attributeValue);\n }\n }\n });\n\n bucketKey.push(featureKey);\n\n const result = bucketKey.join(this.bucketKeySeparator);\n\n if (this.configureBucketKey) {\n return this.configureBucketKey(feature, context, result);\n }\n\n return result;\n }\n\n private getBucketValue(\n feature: Feature,\n context: Context,\n ): { bucketKey: BucketKey; bucketValue: BucketValue } {\n const bucketKey = this.getBucketKey(feature, context);\n\n const value = getBucketedNumber(bucketKey);\n\n if (this.configureBucketValue) {\n const configuredValue = this.configureBucketValue(feature, context, value);\n\n return {\n bucketKey,\n bucketValue: configuredValue,\n };\n }\n\n return {\n bucketKey,\n bucketValue: value,\n };\n }\n\n /**\n * Statuses\n */\n isReady(): boolean {\n return this.statuses.ready;\n }\n\n /**\n * Refresh\n */\n refresh() {\n this.logger.debug(\"refreshing datafile\");\n\n if (this.statuses.refreshInProgress) {\n return this.logger.warn(\"refresh in progress, skipping\");\n }\n\n if (!this.datafileUrl) {\n return this.logger.error(\"cannot refresh since `datafileUrl` is not provided\");\n }\n\n this.statuses.refreshInProgress = true;\n\n fetchDatafileContent(this.datafileUrl, this.handleDatafileFetch)\n .then((datafile) => {\n const currentRevision = this.getRevision();\n const newRevision = datafile.revision;\n const isNotSameRevision = currentRevision !== newRevision;\n\n this.setDatafile(datafile);\n this.logger.info(\"refreshed datafile\");\n\n this.emitter.emit(\"refresh\");\n\n if (isNotSameRevision) {\n this.emitter.emit(\"update\");\n }\n\n this.statuses.refreshInProgress = false;\n })\n .catch((e) => {\n this.logger.error(\"failed to refresh datafile\", { error: e });\n this.statuses.refreshInProgress = false;\n });\n }\n\n startRefreshing() {\n if (!this.datafileUrl) {\n return this.logger.error(\"cannot start refreshing since `datafileUrl` is not provided\");\n }\n\n if (this.intervalId) {\n return this.logger.warn(\"refreshing has already started\");\n }\n\n if (!this.refreshInterval) {\n return this.logger.warn(\"no `refreshInterval` option provided\");\n }\n\n this.intervalId = setInterval(() => {\n this.refresh();\n }, this.refreshInterval * 1000);\n }\n\n stopRefreshing() {\n if (!this.intervalId) {\n return this.logger.warn(\"refreshing has not started yet\");\n }\n\n clearInterval(this.intervalId);\n }\n\n /**\n * Flag\n */\n evaluateFlag(featureKey: FeatureKey | Feature, context: Context = {}): Evaluation {\n let evaluation: Evaluation;\n\n try {\n const key = typeof featureKey === \"string\" ? featureKey : featureKey.key;\n\n // sticky\n if (\n this.stickyFeatures &&\n this.stickyFeatures[key] &&\n typeof this.stickyFeatures[key].enabled !== \"undefined\"\n ) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.STICKY,\n sticky: this.stickyFeatures[key],\n enabled: this.stickyFeatures[key].enabled,\n };\n\n this.logger.debug(\"using sticky enabled\", evaluation);\n\n return evaluation;\n }\n\n // initial\n if (\n this.statuses &&\n !this.statuses.ready &&\n this.initialFeatures &&\n this.initialFeatures[key] &&\n typeof this.initialFeatures[key].enabled !== \"undefined\"\n ) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.INITIAL,\n initial: this.initialFeatures[key],\n enabled: this.initialFeatures[key].enabled,\n };\n\n this.logger.debug(\"using initial enabled\", evaluation);\n\n return evaluation;\n }\n\n const feature = this.getFeature(featureKey);\n\n // not found\n if (!feature) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.NOT_FOUND,\n };\n\n this.logger.warn(\"feature not found\", evaluation);\n\n return evaluation;\n }\n\n // deprecated\n if (feature.deprecated) {\n this.logger.warn(\"feature is deprecated\", { featureKey: feature.key });\n }\n\n const finalContext = this.interceptContext ? this.interceptContext(context) : context;\n\n // forced\n const { force, forceIndex } = findForceFromFeature(\n feature,\n context,\n this.datafileReader,\n this.logger,\n );\n\n if (force && typeof force.enabled !== \"undefined\") {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.FORCED,\n forceIndex,\n force,\n enabled: force.enabled,\n };\n\n this.logger.debug(\"forced enabled found\", evaluation);\n\n return evaluation;\n }\n\n // required\n if (feature.required && feature.required.length > 0) {\n const requiredFeaturesAreEnabled = feature.required.every((required) => {\n let requiredKey;\n let requiredVariation;\n\n if (typeof required === \"string\") {\n requiredKey = required;\n } else {\n requiredKey = required.key;\n requiredVariation = required.variation;\n }\n\n const requiredIsEnabled = this.isEnabled(requiredKey, finalContext);\n\n if (!requiredIsEnabled) {\n return false;\n }\n\n if (typeof requiredVariation !== \"undefined\") {\n const requiredVariationValue = this.getVariation(requiredKey, finalContext);\n\n return requiredVariationValue === requiredVariation;\n }\n\n return true;\n });\n\n if (!requiredFeaturesAreEnabled) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.REQUIRED,\n required: feature.required,\n enabled: requiredFeaturesAreEnabled,\n };\n\n this.logger.debug(\"required features not enabled\", evaluation);\n\n return evaluation;\n }\n }\n\n // bucketing\n const { bucketKey, bucketValue } = this.getBucketValue(feature, finalContext);\n\n const matchedTraffic = getMatchedTraffic(\n feature.traffic,\n finalContext,\n this.datafileReader,\n this.logger,\n );\n\n if (matchedTraffic) {\n // check if mutually exclusive\n if (feature.ranges && feature.ranges.length > 0) {\n const matchedRange = feature.ranges.find((range) => {\n return bucketValue >= range[0] && bucketValue < range[1];\n });\n\n // matched\n if (matchedRange) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.ALLOCATED,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n enabled:\n typeof matchedTraffic.enabled === \"undefined\" ? true : matchedTraffic.enabled,\n };\n\n this.logger.debug(\"matched\", evaluation);\n\n return evaluation;\n }\n\n // no match\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.OUT_OF_RANGE,\n bucketKey,\n bucketValue,\n enabled: false,\n };\n\n this.logger.debug(\"not matched\", evaluation);\n\n return evaluation;\n }\n\n // override from rule\n if (typeof matchedTraffic.enabled !== \"undefined\") {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.OVERRIDE,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n enabled: matchedTraffic.enabled,\n };\n\n this.logger.debug(\"override from rule\", evaluation);\n\n return evaluation;\n }\n\n // treated as enabled because of matched traffic\n if (bucketValue <= matchedTraffic.percentage) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.RULE,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n enabled: true,\n };\n\n this.logger.debug(\"matched traffic\", evaluation);\n\n return evaluation;\n }\n }\n\n // nothing matched\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.NO_MATCH,\n bucketKey,\n bucketValue,\n enabled: false,\n };\n\n this.logger.debug(\"nothing matched\", evaluation);\n\n return evaluation;\n } catch (e) {\n evaluation = {\n featureKey: typeof featureKey === \"string\" ? featureKey : featureKey.key,\n reason: EvaluationReason.ERROR,\n error: e,\n };\n\n this.logger.error(\"error\", evaluation);\n\n return evaluation;\n }\n }\n\n isEnabled(featureKey: FeatureKey | Feature, context: Context = {}): boolean {\n try {\n const evaluation = this.evaluateFlag(featureKey, context);\n\n return evaluation.enabled === true;\n } catch (e) {\n this.logger.error(\"isEnabled\", { featureKey, error: e });\n\n return false;\n }\n }\n\n /**\n * Variation\n */\n evaluateVariation(featureKey: FeatureKey | Feature, context: Context = {}): Evaluation {\n let evaluation: Evaluation;\n\n try {\n const key = typeof featureKey === \"string\" ? featureKey : featureKey.key;\n\n const flag = this.evaluateFlag(featureKey, context);\n\n if (flag.enabled === false) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.DISABLED,\n };\n\n this.logger.debug(\"feature is disabled\", evaluation);\n\n return evaluation;\n }\n\n // sticky\n if (this.stickyFeatures && this.stickyFeatures[key]) {\n const variationValue = this.stickyFeatures[key].variation;\n\n if (typeof variationValue !== \"undefined\") {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.STICKY,\n variationValue,\n };\n\n this.logger.debug(\"using sticky variation\", evaluation);\n\n return evaluation;\n }\n }\n\n // initial\n if (\n this.statuses &&\n !this.statuses.ready &&\n this.initialFeatures &&\n this.initialFeatures[key] &&\n typeof this.initialFeatures[key].variation !== \"undefined\"\n ) {\n const variationValue = this.initialFeatures[key].variation;\n\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.INITIAL,\n variationValue,\n };\n\n this.logger.debug(\"using initial variation\", evaluation);\n\n return evaluation;\n }\n\n const feature = this.getFeature(featureKey);\n\n // not found\n if (!feature) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.NOT_FOUND,\n };\n\n this.logger.warn(\"feature not found\", evaluation);\n\n return evaluation;\n }\n\n // no variations\n if (!feature.variations || feature.variations.length === 0) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.NO_VARIATIONS,\n };\n\n this.logger.warn(\"no variations\", evaluation);\n\n return evaluation;\n }\n\n const finalContext = this.interceptContext ? this.interceptContext(context) : context;\n\n // forced\n const { force, forceIndex } = findForceFromFeature(\n feature,\n context,\n this.datafileReader,\n this.logger,\n );\n\n if (force && force.variation) {\n const variation = feature.variations.find((v) => v.value === force.variation);\n\n if (variation) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.FORCED,\n forceIndex,\n force,\n variation,\n };\n\n this.logger.debug(\"forced variation found\", evaluation);\n\n return evaluation;\n }\n }\n\n // bucketing\n const { bucketKey, bucketValue } = this.getBucketValue(feature, finalContext);\n\n const { matchedTraffic, matchedAllocation } = getMatchedTrafficAndAllocation(\n feature.traffic,\n finalContext,\n bucketValue,\n this.datafileReader,\n this.logger,\n );\n\n if (matchedTraffic) {\n // override from rule\n if (matchedTraffic.variation) {\n const variation = feature.variations.find((v) => v.value === matchedTraffic.variation);\n\n if (variation) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.RULE,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n variation,\n };\n\n this.logger.debug(\"override from rule\", evaluation);\n\n return evaluation;\n }\n }\n\n // regular allocation\n if (matchedAllocation && matchedAllocation.variation) {\n const variation = feature.variations.find((v) => v.value === matchedAllocation.variation);\n\n if (variation) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.ALLOCATED,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n variation,\n };\n\n this.logger.debug(\"allocated variation\", evaluation);\n\n return evaluation;\n }\n }\n }\n\n // nothing matched\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.NO_MATCH,\n bucketKey,\n bucketValue,\n };\n\n this.logger.debug(\"no matched variation\", evaluation);\n\n return evaluation;\n } catch (e) {\n evaluation = {\n featureKey: typeof featureKey === \"string\" ? featureKey : featureKey.key,\n reason: EvaluationReason.ERROR,\n error: e,\n };\n\n this.logger.error(\"error\", evaluation);\n\n return evaluation;\n }\n }\n\n getVariation(\n featureKey: FeatureKey | Feature,\n context: Context = {},\n ): VariationValue | undefined {\n try {\n const evaluation = this.evaluateVariation(featureKey, context);\n\n if (typeof evaluation.variationValue !== \"undefined\") {\n return evaluation.variationValue;\n }\n\n if (evaluation.variation) {\n return evaluation.variation.value;\n }\n\n return undefined;\n } catch (e) {\n this.logger.error(\"getVariation\", { featureKey, error: e });\n\n return undefined;\n }\n }\n\n /**\n * Activate\n */\n activate(featureKey: FeatureKey, context: Context = {}): VariationValue | undefined {\n try {\n const evaluation = this.evaluateVariation(featureKey, context);\n const variationValue = evaluation.variation\n ? evaluation.variation.value\n : evaluation.variationValue;\n\n if (typeof variationValue === \"undefined\") {\n return undefined;\n }\n\n const finalContext = this.interceptContext ? this.interceptContext(context) : context;\n\n const captureContext: Context = {};\n\n const attributesForCapturing = this.datafileReader\n .getAllAttributes()\n .filter((a) => a.capture === true);\n\n attributesForCapturing.forEach((a) => {\n if (typeof finalContext[a.key] !== \"undefined\") {\n captureContext[a.key] = context[a.key];\n }\n });\n\n this.emitter.emit(\n \"activation\",\n featureKey,\n variationValue,\n finalContext,\n captureContext,\n evaluation,\n );\n\n return variationValue;\n } catch (e) {\n this.logger.error(\"activate\", { featureKey, error: e });\n\n return undefined;\n }\n }\n\n /**\n * Variable\n */\n evaluateVariable(\n featureKey: FeatureKey | Feature,\n variableKey: VariableKey,\n context: Context = {},\n ): Evaluation {\n let evaluation: Evaluation;\n\n try {\n const key = typeof featureKey === \"string\" ? featureKey : featureKey.key;\n\n const flag = this.evaluateFlag(featureKey, context);\n\n if (flag.enabled === false) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.DISABLED,\n };\n\n this.logger.debug(\"feature is disabled\", evaluation);\n\n return evaluation;\n }\n\n // sticky\n if (this.stickyFeatures && this.stickyFeatures[key]) {\n const variables = this.stickyFeatures[key].variables;\n\n if (variables) {\n const result = variables[variableKey];\n\n if (typeof result !== \"undefined\") {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.STICKY,\n variableKey,\n variableValue: result,\n };\n\n this.logger.debug(\"using sticky variable\", evaluation);\n\n return evaluation;\n }\n }\n }\n\n // initial\n if (\n this.statuses &&\n !this.statuses.ready &&\n this.initialFeatures &&\n this.initialFeatures[key]\n ) {\n const variables = this.initialFeatures[key].variables;\n\n if (variables) {\n if (typeof variables[variableKey] !== \"undefined\") {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.INITIAL,\n variableKey,\n variableValue: variables[variableKey],\n };\n\n this.logger.debug(\"using initial variable\", evaluation);\n\n return evaluation;\n }\n }\n }\n\n const feature = this.getFeature(featureKey);\n\n // not found\n if (!feature) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.NOT_FOUND,\n variableKey,\n };\n\n this.logger.warn(\"feature not found in datafile\", evaluation);\n\n return evaluation;\n }\n\n const variableSchema = Array.isArray(feature.variablesSchema)\n ? feature.variablesSchema.find((v) => v.key === variableKey)\n : undefined;\n\n // variable schema not found\n if (!variableSchema) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.NOT_FOUND,\n variableKey,\n };\n\n this.logger.warn(\"variable schema not found\", evaluation);\n\n return evaluation;\n }\n\n const finalContext = this.interceptContext ? this.interceptContext(context) : context;\n\n // forced\n const { force, forceIndex } = findForceFromFeature(\n feature,\n context,\n this.datafileReader,\n this.logger,\n );\n\n if (force && force.variables && typeof force.variables[variableKey] !== \"undefined\") {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.FORCED,\n forceIndex,\n force,\n variableKey,\n variableSchema,\n variableValue: force.variables[variableKey],\n };\n\n this.logger.debug(\"forced variable\", evaluation);\n\n return evaluation;\n }\n\n // bucketing\n const { bucketKey, bucketValue } = this.getBucketValue(feature, finalContext);\n\n const { matchedTraffic, matchedAllocation } = getMatchedTrafficAndAllocation(\n feature.traffic,\n finalContext,\n bucketValue,\n this.datafileReader,\n this.logger,\n );\n\n if (matchedTraffic) {\n // override from rule\n if (\n matchedTraffic.variables &&\n typeof matchedTraffic.variables[variableKey] !== \"undefined\"\n ) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.RULE,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n variableKey,\n variableSchema,\n variableValue: matchedTraffic.variables[variableKey],\n };\n\n this.logger.debug(\"override from rule\", evaluation);\n\n return evaluation;\n }\n\n // regular allocation\n let variationValue;\n\n if (force && force.variation) {\n variationValue = force.variation;\n } else if (matchedAllocation && matchedAllocation.variation) {\n variationValue = matchedAllocation.variation;\n }\n\n if (variationValue && Array.isArray(feature.variations)) {\n const variation = feature.variations.find((v) => v.value === variationValue);\n\n if (variation && variation.variables) {\n const variableFromVariation = variation.variables.find((v) => v.key === variableKey);\n\n if (variableFromVariation) {\n if (variableFromVariation.overrides) {\n const override = variableFromVariation.overrides.find((o) => {\n if (o.conditions) {\n return allConditionsAreMatched(\n typeof o.conditions === \"string\" ? JSON.parse(o.conditions) : o.conditions,\n finalContext,\n this.logger,\n );\n }\n\n if (o.segments) {\n return allGroupSegmentsAreMatched(\n parseFromStringifiedSegments(o.segments),\n finalContext,\n this.datafileReader,\n this.logger,\n );\n }\n\n return false;\n });\n\n if (override) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.OVERRIDE,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n variableKey,\n variableSchema,\n variableValue: override.value,\n };\n\n this.logger.debug(\"variable override\", evaluation);\n\n return evaluation;\n }\n }\n\n if (typeof variableFromVariation.value !== \"undefined\") {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.ALLOCATED,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n variableKey,\n variableSchema,\n variableValue: variableFromVariation.value,\n };\n\n this.logger.debug(\"allocated variable\", evaluation);\n\n return evaluation;\n }\n }\n }\n }\n }\n\n // fall back to default\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.DEFAULTED,\n bucketKey,\n bucketValue,\n variableKey,\n variableSchema,\n variableValue: variableSchema.defaultValue,\n };\n\n this.logger.debug(\"using default value\", evaluation);\n\n return evaluation;\n } catch (e) {\n evaluation = {\n featureKey: typeof featureKey === \"string\" ? featureKey : featureKey.key,\n reason: EvaluationReason.ERROR,\n variableKey,\n error: e,\n };\n\n this.logger.error(\"error\", evaluation);\n\n return evaluation;\n }\n }\n\n getVariable(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): VariableValue | undefined {\n try {\n const evaluation = this.evaluateVariable(featureKey, variableKey, context);\n\n if (typeof evaluation.variableValue !== \"undefined\") {\n if (\n evaluation.variableSchema &&\n evaluation.variableSchema.type === \"json\" &&\n typeof evaluation.variableValue === \"string\"\n ) {\n return JSON.parse(evaluation.variableValue);\n }\n\n return evaluation.variableValue;\n }\n\n return undefined;\n } catch (e) {\n this.logger.error(\"getVariable\", { featureKey, variableKey, error: e });\n\n return undefined;\n }\n }\n\n getVariableBoolean(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): boolean | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"boolean\") as boolean | undefined;\n }\n\n getVariableString(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): string | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"string\") as string | undefined;\n }\n\n getVariableInteger(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): number | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"integer\") as number | undefined;\n }\n\n getVariableDouble(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): number | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"double\") as number | undefined;\n }\n\n getVariableArray(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): string[] | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"array\") as string[] | undefined;\n }\n\n getVariableObject<T>(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): T | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"object\") as T | undefined;\n }\n\n getVariableJSON<T>(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): T | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"json\") as T | undefined;\n }\n}\n\nexport function createInstance(options: InstanceOptions): FeaturevisorInstance {\n return new FeaturevisorInstance(options);\n}\n"],"names":["createBuffer","val","TextEncoder","encode","MurmurHashV3","key","seed","remainder","bytes","h1","h1b","c1","c2","k1","i","length","murmur","v2","str","k","l","h","v3","module","exports","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","d","definition","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","HASH_SEED","MAX_HASH_VALUE","Math","pow","MAX_BUCKETED_NUMBER","getBucketedNumber","bucketKey","ratio","murmurhash","floor","loggerPrefix","defaultLogLevels","defaultLogHandler","level","message","details","console","log","info","warn","error","Logger","constructor","options","this","levels","handle","handler","setLevels","indexOf","debug","createLogger","logHandler","DatafileReader","datafileJson","schemaVersion","revision","segments","attributes","features","getRevision","getSchemaVersion","getAllAttributes","getAttribute","attributeKey","find","a","getSegment","segmentKey","segment","s","record","JSON","parse","e","parseJsonConditionsIfStringified","getFeature","featureKey","feature","Emitter","_listeners","addListener","eventName","fn","push","removeListener","index","splice","removeAllListeners","keys","forEach","emit","args","compareVersions","v1","n1","validateAndParse","n2","p1","pop","p2","r","compareSegments","split","semver","version","TypeError","match","Error","shift","isWildcard","tryParse","v","n","parseInt","isNaN","compareStrings","b","ap","bp","String","forceType","max","conditionIsMatched","condition","context","attribute","operator","value","valueInContext","dateInContext","Date","dateInCondition","Array","isArray","startsWith","endsWith","allConditionsAreMatched","conditions","logger","and","every","c","or","some","not","allGroupSegmentsAreMatched","groupSegments","datafileReader","segmentIsMatched","groupSegment","parseFromStringifiedSegments","getMatchedTrafficAndAllocation","traffic","bucketValue","matchedTraffic","t","matchedAllocation","allocation","start","end","range","getMatchedAllocation","findForceFromFeature","result","force","forceIndex","currentForce","emptyDatafile","EvaluationReason","fetchDatafileContent","datafileUrl","handleDatafileFetch","fetch","then","res","json","getValueByType","fieldType","parseFloat","FeaturevisorInstance","bucketKeySeparator","configureBucketKey","configureBucketValue","initialFeatures","interceptContext","refreshInterval","stickyFeatures","emitter","statuses","ready","refreshInProgress","onReady","onRefresh","onUpdate","onActivation","on","bind","off","setDatafile","datafile","startRefreshing","catch","setTimeout","setLogLevels","Promise","resolve","cb","setStickyFeatures","getBucketKey","type","attributeKeys","bucketBy","attributeValue","join","getBucketValue","isReady","refresh","isNotSameRevision","intervalId","setInterval","stopRefreshing","clearInterval","evaluateFlag","evaluation","enabled","reason","STICKY","sticky","INITIAL","initial","NOT_FOUND","deprecated","finalContext","FORCED","required","requiredFeaturesAreEnabled","requiredKey","requiredVariation","variation","isEnabled","getVariation","REQUIRED","getMatchedTraffic","ranges","ALLOCATED","ruleKey","OUT_OF_RANGE","OVERRIDE","percentage","RULE","NO_MATCH","ERROR","evaluateVariation","DISABLED","variationValue","variations","NO_VARIATIONS","activate","captureContext","filter","capture","evaluateVariable","variableKey","variables","variableValue","variableSchema","variablesSchema","variableFromVariation","overrides","override","DEFAULTED","defaultValue","getVariable","getVariableBoolean","getVariableString","getVariableInteger","getVariableDouble","getVariableArray","getVariableObject","getVariableJSON","createInstance"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"index.mjs","mappings":"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","sources":["webpack://@featurevisor/sdk/../../node_modules/murmurhash/murmurhash.js","webpack://@featurevisor/sdk/webpack/bootstrap","webpack://@featurevisor/sdk/webpack/runtime/define property getters","webpack://@featurevisor/sdk/webpack/runtime/hasOwnProperty shorthand","webpack://@featurevisor/sdk/./src/bucket.ts","webpack://@featurevisor/sdk/./src/logger.ts","webpack://@featurevisor/sdk/./src/datafileReader.ts","webpack://@featurevisor/sdk/./src/emitter.ts","webpack://@featurevisor/sdk/../../node_modules/compare-versions/lib/esm/index.js","webpack://@featurevisor/sdk/./src/conditions.ts","webpack://@featurevisor/sdk/./src/segments.ts","webpack://@featurevisor/sdk/./src/feature.ts","webpack://@featurevisor/sdk/./src/instance.ts"],"sourcesContent":["(function(){\n const _global = this;\n\n const createBuffer = (val) => new TextEncoder().encode(val)\n\n /**\n * JS Implementation of MurmurHash2\n *\n * @author <a href=\"mailto:gary.court@gmail.com\">Gary Court</a>\n * @see http://github.com/garycourt/murmurhash-js\n * @author <a href=\"mailto:aappleby@gmail.com\">Austin Appleby</a>\n * @see http://sites.google.com/site/murmurhash/\n *\n * @param {Uint8Array | string} str ASCII only\n * @param {number} seed Positive integer only\n * @return {number} 32-bit positive integer hash\n */\n function MurmurHashV2(str, seed) {\n if (typeof str === 'string') str = createBuffer(str);\n let\n l = str.length,\n h = seed ^ l,\n i = 0,\n k;\n\n while (l >= 4) {\n k =\n ((str[i] & 0xff)) |\n ((str[++i] & 0xff) << 8) |\n ((str[++i] & 0xff) << 16) |\n ((str[++i] & 0xff) << 24);\n\n k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n k ^= k >>> 24;\n k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n\n h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k;\n\n l -= 4;\n ++i;\n }\n\n switch (l) {\n case 3: h ^= (str[i + 2] & 0xff) << 16;\n case 2: h ^= (str[i + 1] & 0xff) << 8;\n case 1: h ^= (str[i] & 0xff);\n h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n }\n\n h ^= h >>> 13;\n h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n h ^= h >>> 15;\n\n return h >>> 0;\n };\n\n /*\n * JS Implementation of MurmurHash3 (r136) (as of May 20, 2011)\n *\n * @author <a href=\"mailto:gary.court@gmail.com\">Gary Court</a>\n * @see http://github.com/garycourt/murmurhash-js\n * @author <a href=\"mailto:aappleby@gmail.com\">Austin Appleby</a>\n * @see http://sites.google.com/site/murmurhash/\n *\n * @param {Uint8Array | string} key ASCII only\n * @param {number} seed Positive integer only\n * @return {number} 32-bit positive integer hash\n */\n function MurmurHashV3(key, seed) {\n if (typeof key === 'string') key = createBuffer(key);\n\n let remainder, bytes, h1, h1b, c1, c1b, c2, c2b, k1, i;\n\n remainder = key.length & 3; // key.length % 4\n bytes = key.length - remainder;\n h1 = seed;\n c1 = 0xcc9e2d51;\n c2 = 0x1b873593;\n i = 0;\n\n while (i < bytes) {\n k1 =\n ((key[i] & 0xff)) |\n ((key[++i] & 0xff) << 8) |\n ((key[++i] & 0xff) << 16) |\n ((key[++i] & 0xff) << 24);\n ++i;\n\n k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;\n k1 = (k1 << 15) | (k1 >>> 17);\n k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;\n\n h1 ^= k1;\n h1 = (h1 << 13) | (h1 >>> 19);\n h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;\n h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));\n }\n\n k1 = 0;\n\n switch (remainder) {\n case 3: k1 ^= (key[i + 2] & 0xff) << 16;\n case 2: k1 ^= (key[i + 1] & 0xff) << 8;\n case 1: k1 ^= (key[i] & 0xff);\n\n k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;\n k1 = (k1 << 15) | (k1 >>> 17);\n k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;\n h1 ^= k1;\n }\n\n h1 ^= key.length;\n\n h1 ^= h1 >>> 16;\n h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;\n h1 ^= h1 >>> 13;\n h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;\n h1 ^= h1 >>> 16;\n\n return h1 >>> 0;\n }\n\n const murmur = MurmurHashV3;\n murmur.v2 = MurmurHashV2;\n murmur.v3 = MurmurHashV3;\n\n if (typeof(module) != 'undefined') {\n module.exports = murmur;\n } else {\n const _previousRoot = _global.murmur;\n murmur.noConflict = function() {\n _global.murmur = _previousRoot;\n return murmur;\n }\n _global.murmur = murmur;\n }\n}());\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","import * as murmurhash from \"murmurhash\";\n\nconst HASH_SEED = 1;\nconst MAX_HASH_VALUE = Math.pow(2, 32);\n\nexport const MAX_BUCKETED_NUMBER = 100000; // 100% * 1000 to include three decimal places in the same integer value\n\nexport function getBucketedNumber(bucketKey: string): number {\n const hashValue = murmurhash.v3(bucketKey, HASH_SEED);\n const ratio = hashValue / MAX_HASH_VALUE;\n\n return Math.floor(ratio * MAX_BUCKETED_NUMBER);\n}\n","export type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport type LogMessage = string;\n\nexport interface LogDetails {\n [key: string]: any;\n}\n\nexport type LogHandler = (level: LogLevel, message: LogMessage, details?: LogDetails) => void;\n\nexport interface CreateLoggerOptions {\n levels?: LogLevel[];\n handler?: LogHandler;\n}\n\nexport const loggerPrefix = \"[Featurevisor]\";\n\nexport const defaultLogLevels: LogLevel[] = [\n // supported, but not enabled by default\n // \"debug\",\n // \"info\",\n\n // enabled by default\n \"warn\",\n \"error\",\n];\n\nexport const defaultLogHandler: LogHandler = function defaultLogHandler(\n level,\n message,\n details = {},\n) {\n switch (level) {\n case \"debug\":\n console.log(loggerPrefix, message, details);\n break;\n case \"info\":\n console.info(loggerPrefix, message, details);\n break;\n case \"warn\":\n console.warn(loggerPrefix, message, details);\n break;\n case \"error\":\n console.error(loggerPrefix, message, details);\n break;\n }\n};\n\nexport class Logger {\n private levels: LogLevel[];\n private handle: LogHandler;\n\n constructor(options: CreateLoggerOptions) {\n this.levels = options.levels as LogLevel[];\n this.handle = options.handler as LogHandler;\n }\n\n setLevels(levels: LogLevel[]) {\n this.levels = levels;\n }\n\n log(level: LogLevel, message: LogMessage, details?: LogDetails) {\n if (this.levels.indexOf(level) !== -1) {\n this.handle(level, message, details);\n }\n }\n\n debug(message: LogMessage, details?: LogDetails) {\n this.log(\"debug\", message, details);\n }\n\n info(message: LogMessage, details?: LogDetails) {\n this.log(\"info\", message, details);\n }\n\n warn(message: LogMessage, details?: LogDetails) {\n this.log(\"warn\", message, details);\n }\n\n error(message: LogMessage, details?: LogDetails) {\n this.log(\"error\", message, details);\n }\n}\n\nexport function createLogger(options: CreateLoggerOptions = {}): Logger {\n const levels = options.levels || defaultLogLevels;\n const logHandler = options.handler || defaultLogHandler;\n\n return new Logger({ levels, handler: logHandler });\n}\n","import {\n Feature,\n Segment,\n DatafileContent,\n Attribute,\n AttributeKey,\n SegmentKey,\n FeatureKey,\n} from \"@featurevisor/types\";\n\nexport function parseJsonConditionsIfStringified<T>(record: T, key: string): T {\n if (typeof record[key] === \"string\" && record[key] !== \"*\") {\n try {\n record[key] = JSON.parse(record[key]);\n } catch (e) {\n console.error(\"Error parsing JSON\", e);\n }\n }\n\n return record;\n}\n\nexport class DatafileReader {\n private schemaVersion: string;\n private revision: string;\n private attributes: Attribute[];\n private segments: Segment[];\n private features: Feature[];\n\n constructor(datafileJson: DatafileContent) {\n this.schemaVersion = datafileJson.schemaVersion;\n this.revision = datafileJson.revision;\n this.segments = datafileJson.segments;\n this.attributes = datafileJson.attributes;\n this.features = datafileJson.features;\n }\n\n getRevision(): string {\n return this.revision;\n }\n\n getSchemaVersion(): string {\n return this.schemaVersion;\n }\n\n getAllAttributes(): Attribute[] {\n return this.attributes;\n }\n\n getAttribute(attributeKey: AttributeKey): Attribute | undefined {\n return this.attributes.find((a) => a.key === attributeKey);\n }\n\n getSegment(segmentKey: SegmentKey): Segment | undefined {\n const segment = this.segments.find((s) => s.key === segmentKey);\n\n if (!segment) {\n return undefined;\n }\n\n return parseJsonConditionsIfStringified(segment, \"conditions\");\n }\n\n getFeature(featureKey: FeatureKey): Feature | undefined {\n const feature = this.features.find((s) => s.key === featureKey);\n\n if (!feature) {\n return undefined;\n }\n\n return feature;\n }\n}\n","export type EventName = \"ready\" | \"refresh\" | \"update\" | \"activation\";\n\nexport interface Listeners {\n [key: string]: Function[];\n}\n\nexport class Emitter {\n private _listeners: Listeners;\n\n constructor() {\n this._listeners = {};\n }\n\n public addListener(eventName: EventName, fn: Function): void {\n if (typeof this._listeners[eventName] === \"undefined\") {\n this._listeners[eventName] = [];\n }\n\n this._listeners[eventName].push(fn);\n }\n\n public removeListener(eventName: EventName, fn: Function): void {\n if (typeof this._listeners[eventName] === \"undefined\") {\n return;\n }\n\n const index = this._listeners[eventName].indexOf(fn);\n\n if (index !== -1) {\n this._listeners[eventName].splice(index, 1);\n }\n }\n\n public removeAllListeners(eventName?: EventName): void {\n if (eventName) {\n this._listeners[eventName] = [];\n } else {\n Object.keys(this._listeners).forEach((key) => {\n this._listeners[key] = [];\n });\n }\n }\n\n public emit(eventName: EventName, ...args: any[]): void {\n if (typeof this._listeners[eventName] === \"undefined\") {\n return;\n }\n\n this._listeners[eventName].forEach((fn) => {\n fn(...args);\n });\n }\n}\n","/**\n * Compare [semver](https://semver.org/) version strings to find greater, equal or lesser.\n * This library supports the full semver specification, including comparing versions with different number of digits like `1.0.0`, `1.0`, `1`, and pre-release versions like `1.0.0-alpha`.\n * @param v1 - First version to compare\n * @param v2 - Second version to compare\n * @returns Numeric value compatible with the [Array.sort(fn) interface](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Parameters).\n */\nexport const compareVersions = (v1, v2) => {\n // validate input and split into segments\n const n1 = validateAndParse(v1);\n const n2 = validateAndParse(v2);\n // pop off the patch\n const p1 = n1.pop();\n const p2 = n2.pop();\n // validate numbers\n const r = compareSegments(n1, n2);\n if (r !== 0)\n return r;\n // validate pre-release\n if (p1 && p2) {\n return compareSegments(p1.split('.'), p2.split('.'));\n }\n else if (p1 || p2) {\n return p1 ? -1 : 1;\n }\n return 0;\n};\n/**\n * Validate [semver](https://semver.org/) version strings.\n *\n * @param version Version number to validate\n * @returns `true` if the version number is a valid semver version number, `false` otherwise.\n *\n * @example\n * ```\n * validate('1.0.0-rc.1'); // return true\n * validate('1.0-rc.1'); // return false\n * validate('foo'); // return false\n * ```\n */\nexport const validate = (version) => typeof version === 'string' && /^[v\\d]/.test(version) && semver.test(version);\n/**\n * Compare [semver](https://semver.org/) version strings using the specified operator.\n *\n * @param v1 First version to compare\n * @param v2 Second version to compare\n * @param operator Allowed arithmetic operator to use\n * @returns `true` if the comparison between the firstVersion and the secondVersion satisfies the operator, `false` otherwise.\n *\n * @example\n * ```\n * compare('10.1.8', '10.0.4', '>'); // return true\n * compare('10.0.1', '10.0.1', '='); // return true\n * compare('10.1.1', '10.2.2', '<'); // return true\n * compare('10.1.1', '10.2.2', '<='); // return true\n * compare('10.1.1', '10.2.2', '>='); // return false\n * ```\n */\nexport const compare = (v1, v2, operator) => {\n // validate input operator\n assertValidOperator(operator);\n // since result of compareVersions can only be -1 or 0 or 1\n // a simple map can be used to replace switch\n const res = compareVersions(v1, v2);\n return operatorResMap[operator].includes(res);\n};\n/**\n * Match [npm semver](https://docs.npmjs.com/cli/v6/using-npm/semver) version range.\n *\n * @param version Version number to match\n * @param range Range pattern for version\n * @returns `true` if the version number is within the range, `false` otherwise.\n *\n * @example\n * ```\n * satisfies('1.1.0', '^1.0.0'); // return true\n * satisfies('1.1.0', '~1.0.0'); // return false\n * ```\n */\nexport const satisfies = (version, range) => {\n // handle multiple comparators\n if (range.includes('||')) {\n return range.split('||').some((r) => satisfies(version, r));\n }\n else if (range.includes(' ')) {\n return range\n .trim()\n .replace(/\\s{2,}/g, ' ')\n .split(' ')\n .every((r) => satisfies(version, r));\n }\n // if no range operator then \"=\"\n const m = range.match(/^([<>=~^]+)/);\n const op = m ? m[1] : '=';\n // if gt/lt/eq then operator compare\n if (op !== '^' && op !== '~')\n return compare(version, range, op);\n // else range of either \"~\" or \"^\" is assumed\n const [v1, v2, v3, , vp] = validateAndParse(version);\n const [r1, r2, r3, , rp] = validateAndParse(range);\n const v = [v1, v2, v3];\n const r = [r1, r2 !== null && r2 !== void 0 ? r2 : 'x', r3 !== null && r3 !== void 0 ? r3 : 'x'];\n // validate pre-release\n if (rp) {\n if (!vp)\n return false;\n if (compareSegments(v, r) !== 0)\n return false;\n if (compareSegments(vp.split('.'), rp.split('.')) === -1)\n return false;\n }\n // first non-zero number\n const nonZero = r.findIndex((v) => v !== '0') + 1;\n // pointer to where segments can be >=\n const i = op === '~' ? 2 : nonZero > 1 ? nonZero : 1;\n // before pointer must be equal\n if (compareSegments(v.slice(0, i), r.slice(0, i)) !== 0)\n return false;\n // after pointer must be >=\n if (compareSegments(v.slice(i), r.slice(i)) === -1)\n return false;\n return true;\n};\nconst semver = /^[v^~<>=]*?(\\d+)(?:\\.([x*]|\\d+)(?:\\.([x*]|\\d+)(?:\\.([x*]|\\d+))?(?:-([\\da-z\\-]+(?:\\.[\\da-z\\-]+)*))?(?:\\+[\\da-z\\-]+(?:\\.[\\da-z\\-]+)*)?)?)?$/i;\nconst validateAndParse = (version) => {\n if (typeof version !== 'string') {\n throw new TypeError('Invalid argument expected string');\n }\n const match = version.match(semver);\n if (!match) {\n throw new Error(`Invalid argument not valid semver ('${version}' received)`);\n }\n match.shift();\n return match;\n};\nconst isWildcard = (s) => s === '*' || s === 'x' || s === 'X';\nconst tryParse = (v) => {\n const n = parseInt(v, 10);\n return isNaN(n) ? v : n;\n};\nconst forceType = (a, b) => typeof a !== typeof b ? [String(a), String(b)] : [a, b];\nconst compareStrings = (a, b) => {\n if (isWildcard(a) || isWildcard(b))\n return 0;\n const [ap, bp] = forceType(tryParse(a), tryParse(b));\n if (ap > bp)\n return 1;\n if (ap < bp)\n return -1;\n return 0;\n};\nconst compareSegments = (a, b) => {\n for (let i = 0; i < Math.max(a.length, b.length); i++) {\n const r = compareStrings(a[i] || '0', b[i] || '0');\n if (r !== 0)\n return r;\n }\n return 0;\n};\nconst operatorResMap = {\n '>': [1],\n '>=': [0, 1],\n '=': [0],\n '<=': [-1, 0],\n '<': [-1],\n};\nconst allowedOperators = Object.keys(operatorResMap);\nconst assertValidOperator = (op) => {\n if (typeof op !== 'string') {\n throw new TypeError(`Invalid operator type, expected string but got ${typeof op}`);\n }\n if (allowedOperators.indexOf(op) === -1) {\n throw new Error(`Invalid operator, expected one of ${allowedOperators.join('|')}`);\n }\n};\n//# sourceMappingURL=index.js.map","import { compareVersions } from \"compare-versions\";\n\nimport { Context, Condition, PlainCondition } from \"@featurevisor/types\";\n\nimport { Logger } from \"./logger\";\n\nexport function conditionIsMatched(condition: PlainCondition, context: Context): boolean {\n const { attribute, operator, value } = condition;\n\n if (operator === \"equals\") {\n return context[attribute] === value;\n } else if (operator === \"notEquals\") {\n return context[attribute] !== value;\n } else if (operator === \"before\" || operator === \"after\") {\n // date comparisons\n const valueInContext = context[attribute] as string | Date;\n\n const dateInContext =\n valueInContext instanceof Date ? valueInContext : new Date(valueInContext);\n const dateInCondition = value instanceof Date ? value : new Date(value as string);\n\n return operator === \"before\"\n ? dateInContext < dateInCondition\n : dateInContext > dateInCondition;\n } else if (Array.isArray(value)) {\n // array\n const valueInContext = context[attribute] as string;\n\n if (operator === \"in\") {\n return value.indexOf(valueInContext) !== -1;\n } else if (operator === \"notIn\") {\n return value.indexOf(valueInContext) === -1;\n }\n } else if (typeof context[attribute] === \"string\" && typeof value === \"string\") {\n // string\n const valueInContext = context[attribute] as string;\n\n if (operator === \"contains\") {\n return valueInContext.indexOf(value) !== -1;\n } else if (operator === \"notContains\") {\n return valueInContext.indexOf(value) === -1;\n } else if (operator === \"startsWith\") {\n return valueInContext.startsWith(value);\n } else if (operator === \"endsWith\") {\n return valueInContext.endsWith(value);\n } else if (operator === \"semverEquals\") {\n return compareVersions(valueInContext, value) === 0;\n } else if (operator === \"semverNotEquals\") {\n return compareVersions(valueInContext, value) !== 0;\n } else if (operator === \"semverGreaterThan\") {\n return compareVersions(valueInContext, value) === 1;\n } else if (operator === \"semverGreaterThanOrEquals\") {\n return compareVersions(valueInContext, value) >= 0;\n } else if (operator === \"semverLessThan\") {\n return compareVersions(valueInContext, value) === -1;\n } else if (operator === \"semverLessThanOrEquals\") {\n return compareVersions(valueInContext, value) <= 0;\n }\n } else if (typeof context[attribute] === \"number\" && typeof value === \"number\") {\n // numeric\n const valueInContext = context[attribute] as number;\n\n if (operator === \"greaterThan\") {\n return valueInContext > value;\n } else if (operator === \"greaterThanOrEquals\") {\n return valueInContext >= value;\n } else if (operator === \"lessThan\") {\n return valueInContext < value;\n } else if (operator === \"lessThanOrEquals\") {\n return valueInContext <= value;\n }\n }\n\n return false;\n}\n\nexport function allConditionsAreMatched(\n conditions: Condition[] | Condition,\n context: Context,\n logger: Logger,\n): boolean {\n if (\"attribute\" in conditions) {\n try {\n return conditionIsMatched(conditions, context);\n } catch (e) {\n logger.warn(e.message, {\n error: e,\n details: {\n condition: conditions,\n context,\n },\n });\n\n return false;\n }\n }\n\n if (\"and\" in conditions && Array.isArray(conditions.and)) {\n return conditions.and.every((c) => allConditionsAreMatched(c, context, logger));\n }\n\n if (\"or\" in conditions && Array.isArray(conditions.or)) {\n return conditions.or.some((c) => allConditionsAreMatched(c, context, logger));\n }\n\n if (\"not\" in conditions && Array.isArray(conditions.not)) {\n return conditions.not.every(\n () =>\n allConditionsAreMatched(\n {\n and: conditions.not,\n },\n context,\n logger,\n ) === false,\n );\n }\n\n if (Array.isArray(conditions)) {\n return conditions.every((c) => allConditionsAreMatched(c, context, logger));\n }\n\n return false;\n}\n","import { Context, GroupSegment, Segment, Condition } from \"@featurevisor/types\";\nimport { allConditionsAreMatched } from \"./conditions\";\nimport { DatafileReader } from \"./datafileReader\";\nimport { Logger } from \"./logger\";\n\nexport function segmentIsMatched(segment: Segment, context: Context, logger: Logger): boolean {\n return allConditionsAreMatched(segment.conditions as Condition | Condition[], context, logger);\n}\n\nexport function allGroupSegmentsAreMatched(\n groupSegments: GroupSegment | GroupSegment[] | \"*\",\n context: Context,\n datafileReader: DatafileReader,\n logger: Logger,\n): boolean {\n if (groupSegments === \"*\") {\n return true;\n }\n\n if (typeof groupSegments === \"string\") {\n const segment = datafileReader.getSegment(groupSegments);\n\n if (segment) {\n return segmentIsMatched(segment, context, logger);\n }\n\n return false;\n }\n\n if (typeof groupSegments === \"object\") {\n if (\"and\" in groupSegments && Array.isArray(groupSegments.and)) {\n return groupSegments.and.every((groupSegment) =>\n allGroupSegmentsAreMatched(groupSegment, context, datafileReader, logger),\n );\n }\n\n if (\"or\" in groupSegments && Array.isArray(groupSegments.or)) {\n return groupSegments.or.some((groupSegment) =>\n allGroupSegmentsAreMatched(groupSegment, context, datafileReader, logger),\n );\n }\n\n if (\"not\" in groupSegments && Array.isArray(groupSegments.not)) {\n return groupSegments.not.every(\n (groupSegment) =>\n allGroupSegmentsAreMatched(groupSegment, context, datafileReader, logger) === false,\n );\n }\n }\n\n if (Array.isArray(groupSegments)) {\n return groupSegments.every((groupSegment) =>\n allGroupSegmentsAreMatched(groupSegment, context, datafileReader, logger),\n );\n }\n\n return false;\n}\n","import { Allocation, Context, Traffic, Feature, Force } from \"@featurevisor/types\";\nimport { DatafileReader } from \"./datafileReader\";\nimport { allGroupSegmentsAreMatched } from \"./segments\";\nimport { allConditionsAreMatched } from \"./conditions\";\nimport { Logger } from \"./logger\";\n\nexport function getMatchedAllocation(\n traffic: Traffic,\n bucketValue: number,\n): Allocation | undefined {\n for (const allocation of traffic.allocation) {\n const [start, end] = allocation.range;\n\n if (allocation.range && start <= bucketValue && end >= bucketValue) {\n return allocation;\n }\n }\n\n return undefined;\n}\n\nexport function parseFromStringifiedSegments(value) {\n if (typeof value === \"string\" && (value.startsWith(\"{\") || value.startsWith(\"[\"))) {\n return JSON.parse(value);\n }\n\n return value;\n}\n\nexport function getMatchedTraffic(\n traffic: Traffic[],\n context: Context,\n datafileReader: DatafileReader,\n logger: Logger,\n): Traffic | undefined {\n return traffic.find((t) => {\n if (\n !allGroupSegmentsAreMatched(\n parseFromStringifiedSegments(t.segments),\n context,\n datafileReader,\n logger,\n )\n ) {\n return false;\n }\n\n return true;\n });\n}\n\nexport interface MatchedTrafficAndAllocation {\n matchedTraffic: Traffic | undefined;\n matchedAllocation: Allocation | undefined;\n}\n\nexport function getMatchedTrafficAndAllocation(\n traffic: Traffic[],\n context: Context,\n bucketValue: number,\n datafileReader: DatafileReader,\n logger: Logger,\n): MatchedTrafficAndAllocation {\n const matchedTraffic = traffic.find((t) => {\n return allGroupSegmentsAreMatched(\n parseFromStringifiedSegments(t.segments),\n context,\n datafileReader,\n logger,\n );\n });\n\n if (!matchedTraffic) {\n return {\n matchedTraffic: undefined,\n matchedAllocation: undefined,\n };\n }\n\n const matchedAllocation = getMatchedAllocation(matchedTraffic, bucketValue);\n\n return {\n matchedTraffic,\n matchedAllocation,\n };\n}\n\nexport interface ForceResult {\n force?: Force;\n forceIndex?: number;\n}\n\nexport function findForceFromFeature(\n feature: Feature,\n context: Context,\n datafileReader: DatafileReader,\n logger: Logger,\n): ForceResult {\n const result: ForceResult = {\n force: undefined,\n forceIndex: undefined,\n };\n\n if (!feature.force) {\n return result;\n }\n\n for (let i = 0; i < feature.force.length; i++) {\n const currentForce = feature.force[i];\n\n if (\n currentForce.conditions &&\n allConditionsAreMatched(currentForce.conditions, context, logger)\n ) {\n result.force = currentForce;\n result.forceIndex = i;\n break;\n }\n\n if (\n currentForce.segments &&\n allGroupSegmentsAreMatched(currentForce.segments, context, datafileReader, logger)\n ) {\n result.force = currentForce;\n result.forceIndex = i;\n break;\n }\n }\n\n return result;\n}\n","import {\n Context,\n AttributeValue,\n BucketKey,\n BucketValue,\n DatafileContent,\n Feature,\n FeatureKey,\n InitialFeatures,\n OverrideFeature,\n StickyFeatures,\n Traffic,\n VariableType,\n VariableValue,\n VariationValue,\n Variation,\n RuleKey,\n VariableKey,\n VariableSchema,\n Force,\n Required,\n} from \"@featurevisor/types\";\n\nimport { createLogger, Logger, LogLevel } from \"./logger\";\nimport { DatafileReader } from \"./datafileReader\";\nimport { Emitter } from \"./emitter\";\nimport { getBucketedNumber } from \"./bucket\";\nimport {\n findForceFromFeature,\n getMatchedTraffic,\n getMatchedTrafficAndAllocation,\n parseFromStringifiedSegments,\n} from \"./feature\";\nimport { allConditionsAreMatched } from \"./conditions\";\nimport { allGroupSegmentsAreMatched } from \"./segments\";\n\nexport type ReadyCallback = () => void;\n\nexport type ActivationCallback = (\n featureName: string,\n variation: VariationValue,\n context: Context,\n captureContext: Context,\n) => void;\n\nexport type ConfigureBucketKey = (feature, context, bucketKey: BucketKey) => BucketKey;\n\nexport type ConfigureBucketValue = (feature, context, bucketValue: BucketValue) => BucketValue;\n\nexport interface Statuses {\n ready: boolean;\n refreshInProgress: boolean;\n}\n\nconst DEFAULT_BUCKET_KEY_SEPARATOR = \".\";\n\nexport type InterceptContext = (context: Context) => Context;\n\nexport interface InstanceOptions {\n bucketKeySeparator?: string;\n configureBucketKey?: ConfigureBucketKey;\n configureBucketValue?: ConfigureBucketValue;\n datafile?: DatafileContent | string;\n datafileUrl?: string;\n handleDatafileFetch?: (datafileUrl: string) => Promise<DatafileContent>;\n initialFeatures?: InitialFeatures;\n interceptContext?: InterceptContext;\n logger?: Logger;\n onActivation?: ActivationCallback;\n onReady?: ReadyCallback;\n onRefresh?: () => void;\n onUpdate?: () => void;\n refreshInterval?: number; // seconds\n stickyFeatures?: StickyFeatures;\n}\n\nconst emptyDatafile: DatafileContent = {\n schemaVersion: \"1\",\n revision: \"unknown\",\n attributes: [],\n segments: [],\n features: [],\n};\n\nexport type DatafileFetchHandler = (datafileUrl: string) => Promise<DatafileContent>;\n\nexport enum EvaluationReason {\n NOT_FOUND = \"not_found\",\n NO_VARIATIONS = \"no_variations\",\n NO_MATCH = \"no_match\",\n DISABLED = \"disabled\",\n REQUIRED = \"required\",\n OUT_OF_RANGE = \"out_of_range\",\n FORCED = \"forced\",\n INITIAL = \"initial\",\n STICKY = \"sticky\",\n RULE = \"rule\",\n ALLOCATED = \"allocated\",\n DEFAULTED = \"defaulted\",\n OVERRIDE = \"override\",\n ERROR = \"error\",\n}\n\nexport interface Evaluation {\n // required\n featureKey: FeatureKey;\n reason: EvaluationReason;\n\n // common\n bucketKey?: BucketKey;\n bucketValue?: BucketValue;\n ruleKey?: RuleKey;\n error?: Error;\n enabled?: boolean;\n traffic?: Traffic;\n forceIndex?: number;\n force?: Force;\n required?: Required[];\n sticky?: OverrideFeature;\n initial?: OverrideFeature;\n\n // variation\n variation?: Variation;\n variationValue?: VariationValue;\n\n // variable\n variableKey?: VariableKey;\n variableValue?: VariableValue;\n variableSchema?: VariableSchema;\n}\n\nfunction fetchDatafileContent(\n datafileUrl,\n handleDatafileFetch?: DatafileFetchHandler,\n): Promise<DatafileContent> {\n if (handleDatafileFetch) {\n return handleDatafileFetch(datafileUrl);\n }\n\n return fetch(datafileUrl).then((res) => res.json());\n}\n\ntype FieldType = string | VariableType;\ntype ValueType = VariableValue;\n\nexport function getValueByType(value: ValueType, fieldType: FieldType): ValueType {\n try {\n if (value === undefined) {\n return undefined;\n }\n\n switch (fieldType) {\n case \"string\":\n return typeof value === \"string\" ? value : undefined;\n case \"integer\":\n return parseInt(value as string, 10);\n case \"double\":\n return parseFloat(value as string);\n case \"boolean\":\n return value === true;\n case \"array\":\n return Array.isArray(value) ? value : undefined;\n case \"object\":\n return typeof value === \"object\" ? value : undefined;\n // @NOTE: `json` is not handled here intentionally\n default:\n return value;\n }\n } catch (e) {\n return undefined;\n }\n}\n\nexport class FeaturevisorInstance {\n // from options\n private bucketKeySeparator: string;\n private configureBucketKey?: ConfigureBucketKey;\n private configureBucketValue?: ConfigureBucketValue;\n private datafileUrl?: string;\n private handleDatafileFetch?: DatafileFetchHandler;\n private initialFeatures?: InitialFeatures;\n private interceptContext?: InterceptContext;\n private logger: Logger;\n private refreshInterval?: number; // seconds\n private stickyFeatures?: StickyFeatures;\n\n // internally created\n private datafileReader: DatafileReader;\n private emitter: Emitter;\n private statuses: Statuses;\n private intervalId?: ReturnType<typeof setInterval>;\n\n // exposed from emitter\n public on: Emitter[\"addListener\"];\n public addListener: Emitter[\"addListener\"];\n public off: Emitter[\"removeListener\"];\n public removeListener: Emitter[\"removeListener\"];\n public removeAllListeners: Emitter[\"removeAllListeners\"];\n\n constructor(options: InstanceOptions) {\n // from options\n this.bucketKeySeparator = options.bucketKeySeparator || DEFAULT_BUCKET_KEY_SEPARATOR;\n this.configureBucketKey = options.configureBucketKey;\n this.configureBucketValue = options.configureBucketValue;\n this.datafileUrl = options.datafileUrl;\n this.handleDatafileFetch = options.handleDatafileFetch;\n this.initialFeatures = options.initialFeatures;\n this.interceptContext = options.interceptContext;\n this.logger = options.logger || createLogger();\n this.refreshInterval = options.refreshInterval;\n this.stickyFeatures = options.stickyFeatures;\n\n // internal\n this.emitter = new Emitter();\n this.statuses = {\n ready: false,\n refreshInProgress: false,\n };\n\n // register events\n if (options.onReady) {\n this.emitter.addListener(\"ready\", options.onReady);\n }\n\n if (options.onRefresh) {\n this.emitter.addListener(\"refresh\", options.onRefresh);\n }\n\n if (options.onUpdate) {\n this.emitter.addListener(\"update\", options.onUpdate);\n }\n\n if (options.onActivation) {\n this.emitter.addListener(\"activation\", options.onActivation);\n }\n\n // expose emitter methods\n const on = this.emitter.addListener.bind(this.emitter);\n this.on = on;\n this.addListener = on;\n\n const off = this.emitter.removeListener.bind(this.emitter);\n this.off = off;\n this.removeListener = off;\n\n this.removeAllListeners = this.emitter.removeAllListeners.bind(this.emitter);\n\n // datafile\n if (options.datafileUrl) {\n this.setDatafile(options.datafile || emptyDatafile);\n\n fetchDatafileContent(options.datafileUrl, options.handleDatafileFetch)\n .then((datafile) => {\n this.setDatafile(datafile);\n\n this.statuses.ready = true;\n this.emitter.emit(\"ready\");\n\n if (this.refreshInterval) {\n this.startRefreshing();\n }\n })\n .catch((e) => {\n this.logger.error(\"failed to fetch datafile\", { error: e });\n });\n } else if (options.datafile) {\n this.setDatafile(options.datafile);\n this.statuses.ready = true;\n\n setTimeout(() => {\n this.emitter.emit(\"ready\");\n }, 0);\n } else {\n throw new Error(\n \"Featurevisor SDK instance cannot be created without both `datafile` and `datafileUrl` options\",\n );\n }\n }\n\n setLogLevels(levels: LogLevel[]) {\n this.logger.setLevels(levels);\n }\n\n onReady(): Promise<FeaturevisorInstance> {\n return new Promise((resolve) => {\n if (this.statuses.ready) {\n return resolve(this);\n }\n\n const cb = () => {\n this.emitter.removeListener(\"ready\", cb);\n\n resolve(this);\n };\n\n this.emitter.addListener(\"ready\", cb);\n });\n }\n\n setDatafile(datafile: DatafileContent | string) {\n try {\n this.datafileReader = new DatafileReader(\n typeof datafile === \"string\" ? JSON.parse(datafile) : datafile,\n );\n } catch (e) {\n this.logger.error(\"could not parse datafile\", { error: e });\n }\n }\n\n setStickyFeatures(stickyFeatures: StickyFeatures | undefined) {\n this.stickyFeatures = stickyFeatures;\n }\n\n getRevision(): string {\n return this.datafileReader.getRevision();\n }\n\n getFeature(featureKey: string | Feature): Feature | undefined {\n return typeof featureKey === \"string\"\n ? this.datafileReader.getFeature(featureKey) // only key provided\n : featureKey; // full feature provided\n }\n\n /**\n * Bucketing\n */\n private getBucketKey(feature: Feature, context: Context): BucketKey {\n const featureKey = feature.key;\n\n let type;\n let attributeKeys;\n\n if (typeof feature.bucketBy === \"string\") {\n type = \"plain\";\n attributeKeys = [feature.bucketBy];\n } else if (Array.isArray(feature.bucketBy)) {\n type = \"and\";\n attributeKeys = feature.bucketBy;\n } else if (typeof feature.bucketBy === \"object\" && Array.isArray(feature.bucketBy.or)) {\n type = \"or\";\n attributeKeys = feature.bucketBy.or;\n } else {\n this.logger.error(\"invalid bucketBy\", { featureKey, bucketBy: feature.bucketBy });\n\n throw new Error(\"invalid bucketBy\");\n }\n\n const bucketKey: AttributeValue[] = [];\n\n attributeKeys.forEach((attributeKey) => {\n const attributeValue = context[attributeKey];\n\n if (typeof attributeValue === \"undefined\") {\n return;\n }\n\n if (type === \"plain\" || type === \"and\") {\n bucketKey.push(attributeValue);\n } else {\n // or\n if (bucketKey.length === 0) {\n bucketKey.push(attributeValue);\n }\n }\n });\n\n bucketKey.push(featureKey);\n\n const result = bucketKey.join(this.bucketKeySeparator);\n\n if (this.configureBucketKey) {\n return this.configureBucketKey(feature, context, result);\n }\n\n return result;\n }\n\n private getBucketValue(\n feature: Feature,\n context: Context,\n ): { bucketKey: BucketKey; bucketValue: BucketValue } {\n const bucketKey = this.getBucketKey(feature, context);\n\n const value = getBucketedNumber(bucketKey);\n\n if (this.configureBucketValue) {\n const configuredValue = this.configureBucketValue(feature, context, value);\n\n return {\n bucketKey,\n bucketValue: configuredValue,\n };\n }\n\n return {\n bucketKey,\n bucketValue: value,\n };\n }\n\n /**\n * Statuses\n */\n isReady(): boolean {\n return this.statuses.ready;\n }\n\n /**\n * Refresh\n */\n refresh() {\n this.logger.debug(\"refreshing datafile\");\n\n if (this.statuses.refreshInProgress) {\n return this.logger.warn(\"refresh in progress, skipping\");\n }\n\n if (!this.datafileUrl) {\n return this.logger.error(\"cannot refresh since `datafileUrl` is not provided\");\n }\n\n this.statuses.refreshInProgress = true;\n\n fetchDatafileContent(this.datafileUrl, this.handleDatafileFetch)\n .then((datafile) => {\n const currentRevision = this.getRevision();\n const newRevision = datafile.revision;\n const isNotSameRevision = currentRevision !== newRevision;\n\n this.setDatafile(datafile);\n this.logger.info(\"refreshed datafile\");\n\n this.emitter.emit(\"refresh\");\n\n if (isNotSameRevision) {\n this.emitter.emit(\"update\");\n }\n\n this.statuses.refreshInProgress = false;\n })\n .catch((e) => {\n this.logger.error(\"failed to refresh datafile\", { error: e });\n this.statuses.refreshInProgress = false;\n });\n }\n\n startRefreshing() {\n if (!this.datafileUrl) {\n return this.logger.error(\"cannot start refreshing since `datafileUrl` is not provided\");\n }\n\n if (this.intervalId) {\n return this.logger.warn(\"refreshing has already started\");\n }\n\n if (!this.refreshInterval) {\n return this.logger.warn(\"no `refreshInterval` option provided\");\n }\n\n this.intervalId = setInterval(() => {\n this.refresh();\n }, this.refreshInterval * 1000);\n }\n\n stopRefreshing() {\n if (!this.intervalId) {\n return this.logger.warn(\"refreshing has not started yet\");\n }\n\n clearInterval(this.intervalId);\n }\n\n /**\n * Flag\n */\n evaluateFlag(featureKey: FeatureKey | Feature, context: Context = {}): Evaluation {\n let evaluation: Evaluation;\n\n try {\n const key = typeof featureKey === \"string\" ? featureKey : featureKey.key;\n\n // sticky\n if (\n this.stickyFeatures &&\n this.stickyFeatures[key] &&\n typeof this.stickyFeatures[key].enabled !== \"undefined\"\n ) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.STICKY,\n sticky: this.stickyFeatures[key],\n enabled: this.stickyFeatures[key].enabled,\n };\n\n this.logger.debug(\"using sticky enabled\", evaluation);\n\n return evaluation;\n }\n\n // initial\n if (\n this.statuses &&\n !this.statuses.ready &&\n this.initialFeatures &&\n this.initialFeatures[key] &&\n typeof this.initialFeatures[key].enabled !== \"undefined\"\n ) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.INITIAL,\n initial: this.initialFeatures[key],\n enabled: this.initialFeatures[key].enabled,\n };\n\n this.logger.debug(\"using initial enabled\", evaluation);\n\n return evaluation;\n }\n\n const feature = this.getFeature(featureKey);\n\n // not found\n if (!feature) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.NOT_FOUND,\n };\n\n this.logger.warn(\"feature not found\", evaluation);\n\n return evaluation;\n }\n\n // deprecated\n if (feature.deprecated) {\n this.logger.warn(\"feature is deprecated\", { featureKey: feature.key });\n }\n\n const finalContext = this.interceptContext ? this.interceptContext(context) : context;\n\n // forced\n const { force, forceIndex } = findForceFromFeature(\n feature,\n context,\n this.datafileReader,\n this.logger,\n );\n\n if (force && typeof force.enabled !== \"undefined\") {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.FORCED,\n forceIndex,\n force,\n enabled: force.enabled,\n };\n\n this.logger.debug(\"forced enabled found\", evaluation);\n\n return evaluation;\n }\n\n // required\n if (feature.required && feature.required.length > 0) {\n const requiredFeaturesAreEnabled = feature.required.every((required) => {\n let requiredKey;\n let requiredVariation;\n\n if (typeof required === \"string\") {\n requiredKey = required;\n } else {\n requiredKey = required.key;\n requiredVariation = required.variation;\n }\n\n const requiredIsEnabled = this.isEnabled(requiredKey, finalContext);\n\n if (!requiredIsEnabled) {\n return false;\n }\n\n if (typeof requiredVariation !== \"undefined\") {\n const requiredVariationValue = this.getVariation(requiredKey, finalContext);\n\n return requiredVariationValue === requiredVariation;\n }\n\n return true;\n });\n\n if (!requiredFeaturesAreEnabled) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.REQUIRED,\n required: feature.required,\n enabled: requiredFeaturesAreEnabled,\n };\n\n this.logger.debug(\"required features not enabled\", evaluation);\n\n return evaluation;\n }\n }\n\n // bucketing\n const { bucketKey, bucketValue } = this.getBucketValue(feature, finalContext);\n\n const matchedTraffic = getMatchedTraffic(\n feature.traffic,\n finalContext,\n this.datafileReader,\n this.logger,\n );\n\n if (matchedTraffic) {\n // check if mutually exclusive\n if (feature.ranges && feature.ranges.length > 0) {\n const matchedRange = feature.ranges.find((range) => {\n return bucketValue >= range[0] && bucketValue < range[1];\n });\n\n // matched\n if (matchedRange) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.ALLOCATED,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n enabled:\n typeof matchedTraffic.enabled === \"undefined\" ? true : matchedTraffic.enabled,\n };\n\n this.logger.debug(\"matched\", evaluation);\n\n return evaluation;\n }\n\n // no match\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.OUT_OF_RANGE,\n bucketKey,\n bucketValue,\n enabled: false,\n };\n\n this.logger.debug(\"not matched\", evaluation);\n\n return evaluation;\n }\n\n // override from rule\n if (typeof matchedTraffic.enabled !== \"undefined\") {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.OVERRIDE,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n enabled: matchedTraffic.enabled,\n };\n\n this.logger.debug(\"override from rule\", evaluation);\n\n return evaluation;\n }\n\n // treated as enabled because of matched traffic\n if (bucketValue <= matchedTraffic.percentage) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.RULE,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n enabled: true,\n };\n\n this.logger.debug(\"matched traffic\", evaluation);\n\n return evaluation;\n }\n }\n\n // nothing matched\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.NO_MATCH,\n bucketKey,\n bucketValue,\n enabled: false,\n };\n\n this.logger.debug(\"nothing matched\", evaluation);\n\n return evaluation;\n } catch (e) {\n evaluation = {\n featureKey: typeof featureKey === \"string\" ? featureKey : featureKey.key,\n reason: EvaluationReason.ERROR,\n error: e,\n };\n\n this.logger.error(\"error\", evaluation);\n\n return evaluation;\n }\n }\n\n isEnabled(featureKey: FeatureKey | Feature, context: Context = {}): boolean {\n try {\n const evaluation = this.evaluateFlag(featureKey, context);\n\n return evaluation.enabled === true;\n } catch (e) {\n this.logger.error(\"isEnabled\", { featureKey, error: e });\n\n return false;\n }\n }\n\n /**\n * Variation\n */\n evaluateVariation(featureKey: FeatureKey | Feature, context: Context = {}): Evaluation {\n let evaluation: Evaluation;\n\n try {\n const key = typeof featureKey === \"string\" ? featureKey : featureKey.key;\n\n const flag = this.evaluateFlag(featureKey, context);\n\n if (flag.enabled === false) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.DISABLED,\n };\n\n this.logger.debug(\"feature is disabled\", evaluation);\n\n return evaluation;\n }\n\n // sticky\n if (this.stickyFeatures && this.stickyFeatures[key]) {\n const variationValue = this.stickyFeatures[key].variation;\n\n if (typeof variationValue !== \"undefined\") {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.STICKY,\n variationValue,\n };\n\n this.logger.debug(\"using sticky variation\", evaluation);\n\n return evaluation;\n }\n }\n\n // initial\n if (\n this.statuses &&\n !this.statuses.ready &&\n this.initialFeatures &&\n this.initialFeatures[key] &&\n typeof this.initialFeatures[key].variation !== \"undefined\"\n ) {\n const variationValue = this.initialFeatures[key].variation;\n\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.INITIAL,\n variationValue,\n };\n\n this.logger.debug(\"using initial variation\", evaluation);\n\n return evaluation;\n }\n\n const feature = this.getFeature(featureKey);\n\n // not found\n if (!feature) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.NOT_FOUND,\n };\n\n this.logger.warn(\"feature not found\", evaluation);\n\n return evaluation;\n }\n\n // no variations\n if (!feature.variations || feature.variations.length === 0) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.NO_VARIATIONS,\n };\n\n this.logger.warn(\"no variations\", evaluation);\n\n return evaluation;\n }\n\n const finalContext = this.interceptContext ? this.interceptContext(context) : context;\n\n // forced\n const { force, forceIndex } = findForceFromFeature(\n feature,\n context,\n this.datafileReader,\n this.logger,\n );\n\n if (force && force.variation) {\n const variation = feature.variations.find((v) => v.value === force.variation);\n\n if (variation) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.FORCED,\n forceIndex,\n force,\n variation,\n };\n\n this.logger.debug(\"forced variation found\", evaluation);\n\n return evaluation;\n }\n }\n\n // bucketing\n const { bucketKey, bucketValue } = this.getBucketValue(feature, finalContext);\n\n const { matchedTraffic, matchedAllocation } = getMatchedTrafficAndAllocation(\n feature.traffic,\n finalContext,\n bucketValue,\n this.datafileReader,\n this.logger,\n );\n\n if (matchedTraffic) {\n // override from rule\n if (matchedTraffic.variation) {\n const variation = feature.variations.find((v) => v.value === matchedTraffic.variation);\n\n if (variation) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.RULE,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n variation,\n };\n\n this.logger.debug(\"override from rule\", evaluation);\n\n return evaluation;\n }\n }\n\n // regular allocation\n if (matchedAllocation && matchedAllocation.variation) {\n const variation = feature.variations.find((v) => v.value === matchedAllocation.variation);\n\n if (variation) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.ALLOCATED,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n variation,\n };\n\n this.logger.debug(\"allocated variation\", evaluation);\n\n return evaluation;\n }\n }\n }\n\n // nothing matched\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.NO_MATCH,\n bucketKey,\n bucketValue,\n };\n\n this.logger.debug(\"no matched variation\", evaluation);\n\n return evaluation;\n } catch (e) {\n evaluation = {\n featureKey: typeof featureKey === \"string\" ? featureKey : featureKey.key,\n reason: EvaluationReason.ERROR,\n error: e,\n };\n\n this.logger.error(\"error\", evaluation);\n\n return evaluation;\n }\n }\n\n getVariation(\n featureKey: FeatureKey | Feature,\n context: Context = {},\n ): VariationValue | undefined {\n try {\n const evaluation = this.evaluateVariation(featureKey, context);\n\n if (typeof evaluation.variationValue !== \"undefined\") {\n return evaluation.variationValue;\n }\n\n if (evaluation.variation) {\n return evaluation.variation.value;\n }\n\n return undefined;\n } catch (e) {\n this.logger.error(\"getVariation\", { featureKey, error: e });\n\n return undefined;\n }\n }\n\n /**\n * Activate\n */\n activate(featureKey: FeatureKey, context: Context = {}): VariationValue | undefined {\n try {\n const evaluation = this.evaluateVariation(featureKey, context);\n const variationValue = evaluation.variation\n ? evaluation.variation.value\n : evaluation.variationValue;\n\n if (typeof variationValue === \"undefined\") {\n return undefined;\n }\n\n const finalContext = this.interceptContext ? this.interceptContext(context) : context;\n\n const captureContext: Context = {};\n\n const attributesForCapturing = this.datafileReader\n .getAllAttributes()\n .filter((a) => a.capture === true);\n\n attributesForCapturing.forEach((a) => {\n if (typeof finalContext[a.key] !== \"undefined\") {\n captureContext[a.key] = context[a.key];\n }\n });\n\n this.emitter.emit(\n \"activation\",\n featureKey,\n variationValue,\n finalContext,\n captureContext,\n evaluation,\n );\n\n return variationValue;\n } catch (e) {\n this.logger.error(\"activate\", { featureKey, error: e });\n\n return undefined;\n }\n }\n\n /**\n * Variable\n */\n evaluateVariable(\n featureKey: FeatureKey | Feature,\n variableKey: VariableKey,\n context: Context = {},\n ): Evaluation {\n let evaluation: Evaluation;\n\n try {\n const key = typeof featureKey === \"string\" ? featureKey : featureKey.key;\n\n const flag = this.evaluateFlag(featureKey, context);\n\n if (flag.enabled === false) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.DISABLED,\n };\n\n this.logger.debug(\"feature is disabled\", evaluation);\n\n return evaluation;\n }\n\n // sticky\n if (this.stickyFeatures && this.stickyFeatures[key]) {\n const variables = this.stickyFeatures[key].variables;\n\n if (variables) {\n const result = variables[variableKey];\n\n if (typeof result !== \"undefined\") {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.STICKY,\n variableKey,\n variableValue: result,\n };\n\n this.logger.debug(\"using sticky variable\", evaluation);\n\n return evaluation;\n }\n }\n }\n\n // initial\n if (\n this.statuses &&\n !this.statuses.ready &&\n this.initialFeatures &&\n this.initialFeatures[key]\n ) {\n const variables = this.initialFeatures[key].variables;\n\n if (variables) {\n if (typeof variables[variableKey] !== \"undefined\") {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.INITIAL,\n variableKey,\n variableValue: variables[variableKey],\n };\n\n this.logger.debug(\"using initial variable\", evaluation);\n\n return evaluation;\n }\n }\n }\n\n const feature = this.getFeature(featureKey);\n\n // not found\n if (!feature) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.NOT_FOUND,\n variableKey,\n };\n\n this.logger.warn(\"feature not found in datafile\", evaluation);\n\n return evaluation;\n }\n\n const variableSchema = Array.isArray(feature.variablesSchema)\n ? feature.variablesSchema.find((v) => v.key === variableKey)\n : undefined;\n\n // variable schema not found\n if (!variableSchema) {\n evaluation = {\n featureKey: key,\n reason: EvaluationReason.NOT_FOUND,\n variableKey,\n };\n\n this.logger.warn(\"variable schema not found\", evaluation);\n\n return evaluation;\n }\n\n const finalContext = this.interceptContext ? this.interceptContext(context) : context;\n\n // forced\n const { force, forceIndex } = findForceFromFeature(\n feature,\n context,\n this.datafileReader,\n this.logger,\n );\n\n if (force && force.variables && typeof force.variables[variableKey] !== \"undefined\") {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.FORCED,\n forceIndex,\n force,\n variableKey,\n variableSchema,\n variableValue: force.variables[variableKey],\n };\n\n this.logger.debug(\"forced variable\", evaluation);\n\n return evaluation;\n }\n\n // bucketing\n const { bucketKey, bucketValue } = this.getBucketValue(feature, finalContext);\n\n const { matchedTraffic, matchedAllocation } = getMatchedTrafficAndAllocation(\n feature.traffic,\n finalContext,\n bucketValue,\n this.datafileReader,\n this.logger,\n );\n\n if (matchedTraffic) {\n // override from rule\n if (\n matchedTraffic.variables &&\n typeof matchedTraffic.variables[variableKey] !== \"undefined\"\n ) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.RULE,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n variableKey,\n variableSchema,\n variableValue: matchedTraffic.variables[variableKey],\n };\n\n this.logger.debug(\"override from rule\", evaluation);\n\n return evaluation;\n }\n\n // regular allocation\n let variationValue;\n\n if (force && force.variation) {\n variationValue = force.variation;\n } else if (matchedAllocation && matchedAllocation.variation) {\n variationValue = matchedAllocation.variation;\n }\n\n if (variationValue && Array.isArray(feature.variations)) {\n const variation = feature.variations.find((v) => v.value === variationValue);\n\n if (variation && variation.variables) {\n const variableFromVariation = variation.variables.find((v) => v.key === variableKey);\n\n if (variableFromVariation) {\n if (variableFromVariation.overrides) {\n const override = variableFromVariation.overrides.find((o) => {\n if (o.conditions) {\n return allConditionsAreMatched(\n typeof o.conditions === \"string\" ? JSON.parse(o.conditions) : o.conditions,\n finalContext,\n this.logger,\n );\n }\n\n if (o.segments) {\n return allGroupSegmentsAreMatched(\n parseFromStringifiedSegments(o.segments),\n finalContext,\n this.datafileReader,\n this.logger,\n );\n }\n\n return false;\n });\n\n if (override) {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.OVERRIDE,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n variableKey,\n variableSchema,\n variableValue: override.value,\n };\n\n this.logger.debug(\"variable override\", evaluation);\n\n return evaluation;\n }\n }\n\n if (typeof variableFromVariation.value !== \"undefined\") {\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.ALLOCATED,\n bucketKey,\n bucketValue,\n ruleKey: matchedTraffic.key,\n traffic: matchedTraffic,\n variableKey,\n variableSchema,\n variableValue: variableFromVariation.value,\n };\n\n this.logger.debug(\"allocated variable\", evaluation);\n\n return evaluation;\n }\n }\n }\n }\n }\n\n // fall back to default\n evaluation = {\n featureKey: feature.key,\n reason: EvaluationReason.DEFAULTED,\n bucketKey,\n bucketValue,\n variableKey,\n variableSchema,\n variableValue: variableSchema.defaultValue,\n };\n\n this.logger.debug(\"using default value\", evaluation);\n\n return evaluation;\n } catch (e) {\n evaluation = {\n featureKey: typeof featureKey === \"string\" ? featureKey : featureKey.key,\n reason: EvaluationReason.ERROR,\n variableKey,\n error: e,\n };\n\n this.logger.error(\"error\", evaluation);\n\n return evaluation;\n }\n }\n\n getVariable(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): VariableValue | undefined {\n try {\n const evaluation = this.evaluateVariable(featureKey, variableKey, context);\n\n if (typeof evaluation.variableValue !== \"undefined\") {\n if (\n evaluation.variableSchema &&\n evaluation.variableSchema.type === \"json\" &&\n typeof evaluation.variableValue === \"string\"\n ) {\n return JSON.parse(evaluation.variableValue);\n }\n\n return evaluation.variableValue;\n }\n\n return undefined;\n } catch (e) {\n this.logger.error(\"getVariable\", { featureKey, variableKey, error: e });\n\n return undefined;\n }\n }\n\n getVariableBoolean(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): boolean | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"boolean\") as boolean | undefined;\n }\n\n getVariableString(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): string | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"string\") as string | undefined;\n }\n\n getVariableInteger(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): number | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"integer\") as number | undefined;\n }\n\n getVariableDouble(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): number | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"double\") as number | undefined;\n }\n\n getVariableArray(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): string[] | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"array\") as string[] | undefined;\n }\n\n getVariableObject<T>(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): T | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"object\") as T | undefined;\n }\n\n getVariableJSON<T>(\n featureKey: FeatureKey | Feature,\n variableKey: string,\n context: Context = {},\n ): T | undefined {\n const variableValue = this.getVariable(featureKey, variableKey, context);\n\n return getValueByType(variableValue, \"json\") as T | undefined;\n }\n}\n\nexport function createInstance(options: InstanceOptions): FeaturevisorInstance {\n return new FeaturevisorInstance(options);\n}\n"],"names":["createBuffer","val","TextEncoder","encode","MurmurHashV3","key","seed","remainder","bytes","h1","h1b","c1","c2","k1","i","length","murmur","v2","str","k","l","h","v3","module","exports","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","d","definition","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","HASH_SEED","MAX_HASH_VALUE","Math","pow","MAX_BUCKETED_NUMBER","getBucketedNumber","bucketKey","ratio","murmurhash","floor","loggerPrefix","defaultLogLevels","defaultLogHandler","level","message","details","console","log","info","warn","error","Logger","constructor","options","this","levels","handle","handler","setLevels","indexOf","debug","createLogger","logHandler","DatafileReader","datafileJson","schemaVersion","revision","segments","attributes","features","getRevision","getSchemaVersion","getAllAttributes","getAttribute","attributeKey","find","a","getSegment","segmentKey","segment","s","record","JSON","parse","e","parseJsonConditionsIfStringified","getFeature","featureKey","feature","Emitter","_listeners","addListener","eventName","fn","push","removeListener","index","splice","removeAllListeners","keys","forEach","emit","args","compareVersions","v1","n1","validateAndParse","n2","p1","pop","p2","r","compareSegments","split","semver","version","TypeError","match","Error","shift","isWildcard","tryParse","v","n","parseInt","isNaN","compareStrings","b","ap","bp","String","forceType","max","conditionIsMatched","condition","context","attribute","operator","value","valueInContext","dateInContext","Date","dateInCondition","Array","isArray","startsWith","endsWith","allConditionsAreMatched","conditions","logger","and","every","c","or","some","not","allGroupSegmentsAreMatched","groupSegments","datafileReader","segmentIsMatched","groupSegment","parseFromStringifiedSegments","getMatchedTrafficAndAllocation","traffic","bucketValue","matchedTraffic","t","matchedAllocation","allocation","start","end","range","getMatchedAllocation","findForceFromFeature","result","force","forceIndex","currentForce","emptyDatafile","EvaluationReason","fetchDatafileContent","datafileUrl","handleDatafileFetch","fetch","then","res","json","getValueByType","fieldType","parseFloat","FeaturevisorInstance","bucketKeySeparator","configureBucketKey","configureBucketValue","initialFeatures","interceptContext","refreshInterval","stickyFeatures","emitter","statuses","ready","refreshInProgress","onReady","onRefresh","onUpdate","onActivation","on","bind","off","setDatafile","datafile","startRefreshing","catch","setTimeout","setLogLevels","Promise","resolve","cb","setStickyFeatures","getBucketKey","type","attributeKeys","bucketBy","attributeValue","join","getBucketValue","isReady","refresh","isNotSameRevision","intervalId","setInterval","stopRefreshing","clearInterval","evaluateFlag","evaluation","enabled","reason","STICKY","sticky","INITIAL","initial","NOT_FOUND","deprecated","finalContext","FORCED","required","requiredFeaturesAreEnabled","requiredKey","requiredVariation","variation","isEnabled","getVariation","REQUIRED","getMatchedTraffic","ranges","ALLOCATED","ruleKey","OUT_OF_RANGE","OVERRIDE","percentage","RULE","NO_MATCH","ERROR","evaluateVariation","DISABLED","variationValue","variations","NO_VARIATIONS","activate","captureContext","filter","capture","evaluateVariable","variableKey","variables","variableValue","variableSchema","variablesSchema","variableFromVariation","overrides","override","DEFAULTED","defaultValue","getVariable","getVariableBoolean","getVariableString","getVariableInteger","getVariableDouble","getVariableArray","getVariableObject","getVariableJSON","createInstance"],"sourceRoot":""}
|