rox-serverless
Version:
CloudBees Feature Management ROX JS SDK for serverless
1,448 lines (1,384 loc) • 62.2 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const levels = {
debug: 0,
info: 1,
warn: 2,
error: 3
};
let level = 'error';
class Logger {
constructor() {
this.debug = (data, ...args) => {
if (levels[level] <= levels.debug && console /* console not present on old IEs */) {
console.log(data, ...args); // eslint-disable-line no-console
}
};
this.info = (data, ...args) => {
if (levels[level] <= levels.info && console /* console not present on old IEs */) {
console.info(data, ...args); // eslint-disable-line no-console
}
};
this.warn = (data, ...args) => {
if (levels[level] <= levels.warn && console /* console not present on old IEs */) {
console.warn(data, ...args); // eslint-disable-line no-console
}
};
this.error = (data, ...args) => {
if (console /* console not present on old IEs */) {
console.error(data, ...args); // eslint-disable-line no-console
}
};
this.setVerboseMode = debugLevel => {
if (debugLevel === 'verbose') {
level = 'debug';
this.debug('Active verbose mode');
}
else {
level = 'error';
}
};
this.setLogger = (newLogger) => {
logger = newLogger;
};
}
}
let logger = new Logger();
var RoxLogger = logger;
const ExceptionTrigger = {
DYNAMIC_PROPERTIES_RULE: 'DYNAMIC_PROPERTIES_RULE',
CONFIGURATION_FETCHED_HANDLER: 'CONFIGURATION_FETCHED_HANDLER',
IMPRESSION_HANDLER: 'IMPRESSION_HANDLER',
CUSTOM_PROPERTY_GENERATOR: 'CUSTOM_PROPERTY_GENERATOR'
};
class UserspaceUnhandledErrorInvoker {
invoke(exceptionTrigger, error) {
if (!this.userUnhandledErrorHandler) {
RoxLogger.error('User Unhandled Error Occured, no fallback handler was set, exception ignored.', error);
return;
}
try {
this.userUnhandledErrorHandler(exceptionTrigger, error);
}
catch (err) {
RoxLogger.error('User Unhandled Error Handler itself threw an exception. original exception:' + error, err);
}
}
setHandler(handler) {
if (!(handler instanceof Function)) {
RoxLogger.warn('UserspaceUnhandledErrorHandler must be a function. default will be used.');
return;
}
this.userUnhandledErrorHandler = handler;
}
}
// wanted to create with new on client.js and pass it as an object, but 'new RoxParser()' appears in too many places :(
var globalUserUnhandledErrorInvoker = new UserspaceUnhandledErrorInvoker();
class DeploymentConfiguration {
constructor(condition) {
this.condition = condition;
}
}
class Experiment {
constructor(identifier, name, archived, sticky, deploymentConfiguration, flags, labels, stickinessProperty) {
this.identifier = identifier;
this.name = name;
this.archived = archived;
this.sticky = sticky;
this.deploymentConfiguration = deploymentConfiguration;
this.flags = flags;
this.labels = labels;
this.stickinessProperty = stickinessProperty;
}
}
class TargetGroup {
constructor(identifier, condition) {
this.identifier = identifier;
this.condition = condition;
}
}
class StringTokenizer {
constructor(string, delimiters, returnDelim) {
this._string = string;
this._delimiters = delimiters;
this._returnDelim = returnDelim;
this._position = 0;
}
countTokens() {
let count = 0;
let inToken = false;
for (let i = this._position, length = this._string.length; i < length; i++) {
if (this._delimiters.indexOf(this._string.charAt(i)) != -1) {
if (this._returnDelim)
count++;
if (inToken) {
count++;
inToken = false;
}
}
else {
inToken = true;
}
}
if (inToken)
count++;
return count;
}
hasMoreElements() {
return this.hasMoreTokens();
}
hasMoreTokens() {
if (!this._delimiters) {
return false;
}
const length = this._string.length;
if (this._position < length) {
if (this._returnDelim)
return true;
for (let i = this._position; i < length; i++) {
if (this._delimiters.indexOf(this._string.charAt(i)) == -1) {
return true;
}
}
}
return false;
}
nextElement() {
return this.nextToken();
}
nextToken() {
if (!this._delimiters) {
return undefined;
}
let i = this._position;
const length = this._string.length;
if (i < length) {
if (this._returnDelim) {
if (this._delimiters.indexOf(this._string.charAt(this._position)) != -1)
return this._string.charAt(this._position++);
for (this._position++; this._position < length; this._position++)
if (this._delimiters.indexOf(this._string.charAt(this._position)) != -1)
return this._string.substr(i, this._position - i);
return this._string.substr(i);
}
while (i < length &&
this._delimiters.indexOf(this._string.charAt(this._position)) != -1)
i++;
this._position = i;
if (i < length) {
for (this._position++; this._position < length; this._position++)
if (this._delimiters.indexOf(this._string.charAt(this._position)) != -1)
return this._string.substr(i, this._position - i);
return this._string.substr(i);
}
}
return undefined;
}
nextTokenWithDelimiters(delimiters) {
this._delimiters = delimiters;
return this.nextToken();
}
}
class TargetGroupRepository {
constructor() {
this.map = {};
}
addTargetGroup(targetGroup) {
this.map[targetGroup.identifier] = targetGroup;
}
setTargetGroups(targetGroups) {
this.map = {};
targetGroups = targetGroups || [];
targetGroups.forEach(function (element) {
this.map[element.identifier] = element;
}, this);
}
targetGroupWithName(name) {
return this.map[name];
}
get targetGroups() {
return Object.keys(this.map).map(t => this.map[t]);
}
}
const instance$1 = new TargetGroupRepository();
class CustomPropertyRepository {
constructor() {
this.store = new Map();
}
has(property) {
return this.store.has(property.name);
}
get(name) {
return this.store.get(name);
}
set(property) {
this.store.set(property.name, property);
}
setIfNotExists(property) {
if (this.has(property)) {
return;
}
this.set(property);
}
clear() {
this.store.clear();
}
get items() {
return Array.from(this.store.values());
}
}
var customPropsRepository = new CustomPropertyRepository();
class FlagsSetter {
constructor(flagRepo, experimentsRepo) {
this.flagRepo = flagRepo;
this.experimentsRepo = experimentsRepo;
}
prepareFlagsWithExperiments() {
const experiments = this.experimentsRepo.experiments || [];
RoxLogger.debug(`Set experiments ${JSON.stringify(experiments)}`);
const flagsWithCondition = [];
experiments.forEach((experiment) => {
if (!experiment) {
return;
}
experiment.flags.forEach((flag) => {
if (!flag) {
return;
}
const flagObject = this.flagRepo.flagWithName(flag.name);
if (flagObject) {
flagsWithCondition.push(flagObject);
this.connectExperimentToFlag(flagObject, experiment.deploymentConfiguration.condition);
}
});
});
this.flagRepo.flags.forEach((flagToSet) => {
if (!flagsWithCondition.some((f) => f === flagToSet)) {
this.connectExperimentToFlag(flagToSet, undefined);
}
});
}
setAddedFlag(addedFlag) {
const experiment = this.experimentsRepo.experimentForFlag(addedFlag);
if (experiment) {
this.connectExperimentToFlag(addedFlag, experiment.deploymentConfiguration.condition);
}
}
connectExperimentToFlag(flag, condition) {
flag.condition = condition;
}
}
class ExperimentsRepository {
constructor() {
this.map = {};
}
setExperiments(experiments) {
this.map = {};
experiments = experiments || [];
experiments.forEach(function (element) {
this.map[element.identifier] = element;
}, this);
}
experimentWithName(name) {
return this.map[name];
}
get experiments() {
return Object.keys(this.map).map(t => this.map[t]);
}
experimentForFlagName(flagName) {
return this.experiments.find(e => e.flags && e.flags.some(f => f.name === flagName));
}
experimentForFlag(flag) {
return this.experimentForFlagName(flag.name);
}
}
const instance = new ExperimentsRepository();
class RoxFlagRepository {
constructor() {
this.map = {};
}
addFlag(name, flag) {
flag.name = name;
this.map[name] = flag;
new FlagsSetter(this, instance).setAddedFlag(flag);
}
flagWithName(name) {
return this.map[name];
}
get flags() {
return Object.keys(this.map).map(t => this.map[t]);
}
get items() {
return this.flags;
}
}
var FlagsRepository = new RoxFlagRepository();
var md5$1 = {exports: {}};
var crypt = {exports: {}};
(function() {
var base64map
= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
crypt$1 = {
// Bit-wise rotation left
rotl: function(n, b) {
return (n << b) | (n >>> (32 - b));
},
// Bit-wise rotation right
rotr: function(n, b) {
return (n << (32 - b)) | (n >>> b);
},
// Swap big-endian to little-endian and vice versa
endian: function(n) {
// If number given, swap endian
if (n.constructor == Number) {
return crypt$1.rotl(n, 8) & 0x00FF00FF | crypt$1.rotl(n, 24) & 0xFF00FF00;
}
// Else, assume array and swap all items
for (var i = 0; i < n.length; i++)
n[i] = crypt$1.endian(n[i]);
return n;
},
// Generate an array of any length of random bytes
randomBytes: function(n) {
for (var bytes = []; n > 0; n--)
bytes.push(Math.floor(Math.random() * 256));
return bytes;
},
// Convert a byte array to big-endian 32-bit words
bytesToWords: function(bytes) {
for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8)
words[b >>> 5] |= bytes[i] << (24 - b % 32);
return words;
},
// Convert big-endian 32-bit words to a byte array
wordsToBytes: function(words) {
for (var bytes = [], b = 0; b < words.length * 32; b += 8)
bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);
return bytes;
},
// Convert a byte array to a hex string
bytesToHex: function(bytes) {
for (var hex = [], i = 0; i < bytes.length; i++) {
hex.push((bytes[i] >>> 4).toString(16));
hex.push((bytes[i] & 0xF).toString(16));
}
return hex.join('');
},
// Convert a hex string to a byte array
hexToBytes: function(hex) {
for (var bytes = [], c = 0; c < hex.length; c += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return bytes;
},
// Convert a byte array to a base-64 string
bytesToBase64: function(bytes) {
for (var base64 = [], i = 0; i < bytes.length; i += 3) {
var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
for (var j = 0; j < 4; j++)
if (i * 8 + j * 6 <= bytes.length * 8)
base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F));
else
base64.push('=');
}
return base64.join('');
},
// Convert a base-64 string to a byte array
base64ToBytes: function(base64) {
// Remove non-base-64 characters
base64 = base64.replace(/[^A-Z0-9+\/]/ig, '');
for (var bytes = [], i = 0, imod4 = 0; i < base64.length;
imod4 = ++i % 4) {
if (imod4 == 0) continue;
bytes.push(((base64map.indexOf(base64.charAt(i - 1))
& (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2))
| (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2)));
}
return bytes;
}
};
crypt.exports = crypt$1;
})();
var charenc = {
// UTF-8 encoding
utf8: {
// Convert a string to a byte array
stringToBytes: function(str) {
return charenc.bin.stringToBytes(unescape(encodeURIComponent(str)));
},
// Convert a byte array to a string
bytesToString: function(bytes) {
return decodeURIComponent(escape(charenc.bin.bytesToString(bytes)));
}
},
// Binary encoding
bin: {
// Convert a string to a byte array
stringToBytes: function(str) {
for (var bytes = [], i = 0; i < str.length; i++)
bytes.push(str.charCodeAt(i) & 0xFF);
return bytes;
},
// Convert a byte array to a string
bytesToString: function(bytes) {
for (var str = [], i = 0; i < bytes.length; i++)
str.push(String.fromCharCode(bytes[i]));
return str.join('');
}
}
};
var charenc_1 = charenc;
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
// The _isBuffer check is for Safari 5-7 support, because it's missing
// Object.prototype.constructor. Remove this eventually
var isBuffer_1 = function (obj) {
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
};
function isBuffer (obj) {
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
}
// For Node v0.10 support. Remove this eventually.
function isSlowBuffer (obj) {
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}
(function(){
var crypt$1 = crypt.exports,
utf8 = charenc_1.utf8,
isBuffer = isBuffer_1,
bin = charenc_1.bin,
// The core
md5 = function (message, options) {
// Convert to byte array
if (message.constructor == String)
if (options && options.encoding === 'binary')
message = bin.stringToBytes(message);
else
message = utf8.stringToBytes(message);
else if (isBuffer(message))
message = Array.prototype.slice.call(message, 0);
else if (!Array.isArray(message) && message.constructor !== Uint8Array)
message = message.toString();
// else, assume byte array already
var m = crypt$1.bytesToWords(message),
l = message.length * 8,
a = 1732584193,
b = -271733879,
c = -1732584194,
d = 271733878;
// Swap endian
for (var i = 0; i < m.length; i++) {
m[i] = ((m[i] << 8) | (m[i] >>> 24)) & 0x00FF00FF |
((m[i] << 24) | (m[i] >>> 8)) & 0xFF00FF00;
}
// Padding
m[l >>> 5] |= 0x80 << (l % 32);
m[(((l + 64) >>> 9) << 4) + 14] = l;
// Method shortcuts
var FF = md5._ff,
GG = md5._gg,
HH = md5._hh,
II = md5._ii;
for (var i = 0; i < m.length; i += 16) {
var aa = a,
bb = b,
cc = c,
dd = d;
a = FF(a, b, c, d, m[i+ 0], 7, -680876936);
d = FF(d, a, b, c, m[i+ 1], 12, -389564586);
c = FF(c, d, a, b, m[i+ 2], 17, 606105819);
b = FF(b, c, d, a, m[i+ 3], 22, -1044525330);
a = FF(a, b, c, d, m[i+ 4], 7, -176418897);
d = FF(d, a, b, c, m[i+ 5], 12, 1200080426);
c = FF(c, d, a, b, m[i+ 6], 17, -1473231341);
b = FF(b, c, d, a, m[i+ 7], 22, -45705983);
a = FF(a, b, c, d, m[i+ 8], 7, 1770035416);
d = FF(d, a, b, c, m[i+ 9], 12, -1958414417);
c = FF(c, d, a, b, m[i+10], 17, -42063);
b = FF(b, c, d, a, m[i+11], 22, -1990404162);
a = FF(a, b, c, d, m[i+12], 7, 1804603682);
d = FF(d, a, b, c, m[i+13], 12, -40341101);
c = FF(c, d, a, b, m[i+14], 17, -1502002290);
b = FF(b, c, d, a, m[i+15], 22, 1236535329);
a = GG(a, b, c, d, m[i+ 1], 5, -165796510);
d = GG(d, a, b, c, m[i+ 6], 9, -1069501632);
c = GG(c, d, a, b, m[i+11], 14, 643717713);
b = GG(b, c, d, a, m[i+ 0], 20, -373897302);
a = GG(a, b, c, d, m[i+ 5], 5, -701558691);
d = GG(d, a, b, c, m[i+10], 9, 38016083);
c = GG(c, d, a, b, m[i+15], 14, -660478335);
b = GG(b, c, d, a, m[i+ 4], 20, -405537848);
a = GG(a, b, c, d, m[i+ 9], 5, 568446438);
d = GG(d, a, b, c, m[i+14], 9, -1019803690);
c = GG(c, d, a, b, m[i+ 3], 14, -187363961);
b = GG(b, c, d, a, m[i+ 8], 20, 1163531501);
a = GG(a, b, c, d, m[i+13], 5, -1444681467);
d = GG(d, a, b, c, m[i+ 2], 9, -51403784);
c = GG(c, d, a, b, m[i+ 7], 14, 1735328473);
b = GG(b, c, d, a, m[i+12], 20, -1926607734);
a = HH(a, b, c, d, m[i+ 5], 4, -378558);
d = HH(d, a, b, c, m[i+ 8], 11, -2022574463);
c = HH(c, d, a, b, m[i+11], 16, 1839030562);
b = HH(b, c, d, a, m[i+14], 23, -35309556);
a = HH(a, b, c, d, m[i+ 1], 4, -1530992060);
d = HH(d, a, b, c, m[i+ 4], 11, 1272893353);
c = HH(c, d, a, b, m[i+ 7], 16, -155497632);
b = HH(b, c, d, a, m[i+10], 23, -1094730640);
a = HH(a, b, c, d, m[i+13], 4, 681279174);
d = HH(d, a, b, c, m[i+ 0], 11, -358537222);
c = HH(c, d, a, b, m[i+ 3], 16, -722521979);
b = HH(b, c, d, a, m[i+ 6], 23, 76029189);
a = HH(a, b, c, d, m[i+ 9], 4, -640364487);
d = HH(d, a, b, c, m[i+12], 11, -421815835);
c = HH(c, d, a, b, m[i+15], 16, 530742520);
b = HH(b, c, d, a, m[i+ 2], 23, -995338651);
a = II(a, b, c, d, m[i+ 0], 6, -198630844);
d = II(d, a, b, c, m[i+ 7], 10, 1126891415);
c = II(c, d, a, b, m[i+14], 15, -1416354905);
b = II(b, c, d, a, m[i+ 5], 21, -57434055);
a = II(a, b, c, d, m[i+12], 6, 1700485571);
d = II(d, a, b, c, m[i+ 3], 10, -1894986606);
c = II(c, d, a, b, m[i+10], 15, -1051523);
b = II(b, c, d, a, m[i+ 1], 21, -2054922799);
a = II(a, b, c, d, m[i+ 8], 6, 1873313359);
d = II(d, a, b, c, m[i+15], 10, -30611744);
c = II(c, d, a, b, m[i+ 6], 15, -1560198380);
b = II(b, c, d, a, m[i+13], 21, 1309151649);
a = II(a, b, c, d, m[i+ 4], 6, -145523070);
d = II(d, a, b, c, m[i+11], 10, -1120210379);
c = II(c, d, a, b, m[i+ 2], 15, 718787259);
b = II(b, c, d, a, m[i+ 9], 21, -343485551);
a = (a + aa) >>> 0;
b = (b + bb) >>> 0;
c = (c + cc) >>> 0;
d = (d + dd) >>> 0;
}
return crypt$1.endian([a, b, c, d]);
};
// Auxiliary functions
md5._ff = function (a, b, c, d, x, s, t) {
var n = a + (b & c | ~b & d) + (x >>> 0) + t;
return ((n << s) | (n >>> (32 - s))) + b;
};
md5._gg = function (a, b, c, d, x, s, t) {
var n = a + (b & d | c & ~d) + (x >>> 0) + t;
return ((n << s) | (n >>> (32 - s))) + b;
};
md5._hh = function (a, b, c, d, x, s, t) {
var n = a + (b ^ c ^ d) + (x >>> 0) + t;
return ((n << s) | (n >>> (32 - s))) + b;
};
md5._ii = function (a, b, c, d, x, s, t) {
var n = a + (c ^ (b | ~d)) + (x >>> 0) + t;
return ((n << s) | (n >>> (32 - s))) + b;
};
// Package private blocksize
md5._blocksize = 16;
md5._digestsize = 16;
md5$1.exports = function (message, options) {
if (message === undefined || message === null)
throw new Error('Illegal argument ' + message);
var digestbytes = crypt$1.wordsToBytes(md5(message, options));
return options && options.asBytes ? digestbytes :
options && options.asString ? bin.bytesToString(digestbytes) :
crypt$1.bytesToHex(digestbytes);
};
})();
/**
* base64.ts
*
* Licensed under the BSD 3-Clause License.
* http://opensource.org/licenses/BSD-3-Clause
*
* References:
* http://en.wikipedia.org/wiki/Base64
*
* @author Dan Kogai (https://github.com/dankogai)
*/
const _hasatob = typeof atob === 'function';
const _hasbtoa = typeof btoa === 'function';
const _hasBuffer = typeof Buffer === 'function';
const _TD = typeof TextDecoder === 'function' ? new TextDecoder() : undefined;
const _TE = typeof TextEncoder === 'function' ? new TextEncoder() : undefined;
const b64ch = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const b64chs = Array.prototype.slice.call(b64ch);
const b64tab = ((a) => {
let tab = {};
a.forEach((c, i) => tab[c] = i);
return tab;
})(b64chs);
const b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
const _fromCC = String.fromCharCode.bind(String);
const _U8Afrom = typeof Uint8Array.from === 'function'
? Uint8Array.from.bind(Uint8Array)
: (it, fn = (x) => x) => new Uint8Array(Array.prototype.slice.call(it, 0).map(fn));
const _mkUriSafe = (src) => src
.replace(/=/g, '').replace(/[+\/]/g, (m0) => m0 == '+' ? '-' : '_');
const _tidyB64 = (s) => s.replace(/[^A-Za-z0-9\+\/]/g, '');
/**
* polyfill version of `btoa`
*/
const btoaPolyfill = (bin) => {
// console.log('polyfilled');
let u32, c0, c1, c2, asc = '';
const pad = bin.length % 3;
for (let i = 0; i < bin.length;) {
if ((c0 = bin.charCodeAt(i++)) > 255 ||
(c1 = bin.charCodeAt(i++)) > 255 ||
(c2 = bin.charCodeAt(i++)) > 255)
throw new TypeError('invalid character found');
u32 = (c0 << 16) | (c1 << 8) | c2;
asc += b64chs[u32 >> 18 & 63]
+ b64chs[u32 >> 12 & 63]
+ b64chs[u32 >> 6 & 63]
+ b64chs[u32 & 63];
}
return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc;
};
/**
* does what `window.btoa` of web browsers do.
* @param {String} bin binary string
* @returns {string} Base64-encoded string
*/
const _btoa = _hasbtoa ? (bin) => btoa(bin)
: _hasBuffer ? (bin) => Buffer.from(bin, 'binary').toString('base64')
: btoaPolyfill;
const _fromUint8Array = _hasBuffer
? (u8a) => Buffer.from(u8a).toString('base64')
: (u8a) => {
// cf. https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string/12713326#12713326
const maxargs = 0x1000;
let strs = [];
for (let i = 0, l = u8a.length; i < l; i += maxargs) {
strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs)));
}
return _btoa(strs.join(''));
};
// This trick is found broken https://github.com/dankogai/js-base64/issues/130
// const utob = (src: string) => unescape(encodeURIComponent(src));
// reverting good old fationed regexp
const cb_utob = (c) => {
if (c.length < 2) {
var cc = c.charCodeAt(0);
return cc < 0x80 ? c
: cc < 0x800 ? (_fromCC(0xc0 | (cc >>> 6))
+ _fromCC(0x80 | (cc & 0x3f)))
: (_fromCC(0xe0 | ((cc >>> 12) & 0x0f))
+ _fromCC(0x80 | ((cc >>> 6) & 0x3f))
+ _fromCC(0x80 | (cc & 0x3f)));
}
else {
var cc = 0x10000
+ (c.charCodeAt(0) - 0xD800) * 0x400
+ (c.charCodeAt(1) - 0xDC00);
return (_fromCC(0xf0 | ((cc >>> 18) & 0x07))
+ _fromCC(0x80 | ((cc >>> 12) & 0x3f))
+ _fromCC(0x80 | ((cc >>> 6) & 0x3f))
+ _fromCC(0x80 | (cc & 0x3f)));
}
};
const re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
/**
* @deprecated should have been internal use only.
* @param {string} src UTF-8 string
* @returns {string} UTF-16 string
*/
const utob = (u) => u.replace(re_utob, cb_utob);
//
const _encode = _hasBuffer
? (s) => Buffer.from(s, 'utf8').toString('base64')
: _TE
? (s) => _fromUint8Array(_TE.encode(s))
: (s) => _btoa(utob(s));
/**
* converts a UTF-8-encoded string to a Base64 string.
* @param {boolean} [urlsafe] if `true` make the result URL-safe
* @returns {string} Base64 string
*/
const encode = (src, urlsafe = false) => urlsafe
? _mkUriSafe(_encode(src))
: _encode(src);
// This trick is found broken https://github.com/dankogai/js-base64/issues/130
// const btou = (src: string) => decodeURIComponent(escape(src));
// reverting good old fationed regexp
const re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g;
const cb_btou = (cccc) => {
switch (cccc.length) {
case 4:
var cp = ((0x07 & cccc.charCodeAt(0)) << 18)
| ((0x3f & cccc.charCodeAt(1)) << 12)
| ((0x3f & cccc.charCodeAt(2)) << 6)
| (0x3f & cccc.charCodeAt(3)), offset = cp - 0x10000;
return (_fromCC((offset >>> 10) + 0xD800)
+ _fromCC((offset & 0x3FF) + 0xDC00));
case 3:
return _fromCC(((0x0f & cccc.charCodeAt(0)) << 12)
| ((0x3f & cccc.charCodeAt(1)) << 6)
| (0x3f & cccc.charCodeAt(2)));
default:
return _fromCC(((0x1f & cccc.charCodeAt(0)) << 6)
| (0x3f & cccc.charCodeAt(1)));
}
};
/**
* @deprecated should have been internal use only.
* @param {string} src UTF-16 string
* @returns {string} UTF-8 string
*/
const btou = (b) => b.replace(re_btou, cb_btou);
/**
* polyfill version of `atob`
*/
const atobPolyfill = (asc) => {
// console.log('polyfilled');
asc = asc.replace(/\s+/g, '');
if (!b64re.test(asc))
throw new TypeError('malformed base64.');
asc += '=='.slice(2 - (asc.length & 3));
let u24, bin = '', r1, r2;
for (let i = 0; i < asc.length;) {
u24 = b64tab[asc.charAt(i++)] << 18
| b64tab[asc.charAt(i++)] << 12
| (r1 = b64tab[asc.charAt(i++)]) << 6
| (r2 = b64tab[asc.charAt(i++)]);
bin += r1 === 64 ? _fromCC(u24 >> 16 & 255)
: r2 === 64 ? _fromCC(u24 >> 16 & 255, u24 >> 8 & 255)
: _fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255);
}
return bin;
};
/**
* does what `window.atob` of web browsers do.
* @param {String} asc Base64-encoded string
* @returns {string} binary string
*/
const _atob = _hasatob ? (asc) => atob(_tidyB64(asc))
: _hasBuffer ? (asc) => Buffer.from(asc, 'base64').toString('binary')
: atobPolyfill;
//
const _toUint8Array = _hasBuffer
? (a) => _U8Afrom(Buffer.from(a, 'base64'))
: (a) => _U8Afrom(_atob(a), c => c.charCodeAt(0));
//
const _decode = _hasBuffer
? (a) => Buffer.from(a, 'base64').toString('utf8')
: _TD
? (a) => _TD.decode(_toUint8Array(a))
: (a) => btou(_atob(a));
const _unURI = (a) => _tidyB64(a.replace(/[-_]/g, (m0) => m0 == '-' ? '+' : '/'));
/**
* converts a Base64 string to a UTF-8 string.
* @param {String} src Base64 string. Both normal and URL-safe are supported
* @returns {string} UTF-8 string
*/
const decode = (src) => _decode(_unURI(src));
const _defaultHandler = (propName, context) => (context ? context[propName] : undefined);
let _handler = _defaultHandler;
function DynamicPropertiesHandler() {
return _handler;
}
function _versionCompare(v1, v2, options = { zeroExtend: true, lexicographical: true }) {
const lexicographical = options && options.lexicographical;
const zeroExtend = options && options.zeroExtend;
let v1parts = v1.split('.');
let v2parts = v2.split('.');
function isValidPart(x) {
return (lexicographical ? /[0-9A-Za-z_-]+$/ : /^\d+$/).test(x);
}
if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) {
return NaN;
}
if (zeroExtend) {
while (v1parts.length < v2parts.length)
v1parts.push('0');
while (v2parts.length < v1parts.length)
v2parts.push('0');
}
if (!lexicographical) {
v1parts = v1parts.map(Number);
v2parts = v2parts.map(Number);
}
for (let i = 0; i < v1parts.length; ++i) {
if (v2parts.length == i) {
return 1;
}
if (v1parts[i] == v2parts[i]) {
continue;
}
else if (v1parts[i] > v2parts[i]) {
return 1;
}
else {
return -1;
}
}
if (v1parts.length != v2parts.length) {
return -1;
}
return 0;
}
const getBucket = (seed) => {
let hash = md5$1.exports(seed, { asBytes: true });
hash =
((hash[0] & 0xff) |
((hash[1] & 0xff) << 8) |
((hash[2] & 0xff) << 16) |
((hash[3] & 0xff) << 24)) >>>
0;
const bucket = hash / (Math.pow(2, 32) - 1);
return bucket;
};
const isUndefined = (op) => op === undefined;
const now = () => Date.now();
const and = (op1, op2) => op1 && op2;
const or = (op1, op2) => op1 || op2;
const ne = (op1, op2) => (isUndefined(op1) ? false : op1) !== (isUndefined(op2) ? false : op2);
const eq = (op1, op2) => (isUndefined(op1) ? false : op1) === (isUndefined(op2) ? false : op2);
const not = (op) => !op;
const ifThen = (conditionExpression, trueExpression, falseExpression) => conditionExpression ? trueExpression : falseExpression;
const lt = (op1, op2) => {
if (isUndefined(op1) || isUndefined(op2))
return false;
if (typeof op1 !== 'number') {
op1 = Number(op1);
if (isNaN(op1)) {
return false;
}
}
if (typeof op2 !== 'number') {
op2 = Number(op2);
if (isNaN(op2)) {
return false;
}
}
return op1 < op2;
};
const lte = (op1, op2) => {
if (isUndefined(op1) || isUndefined(op2))
return false;
if (typeof op1 !== 'number') {
op1 = Number(op1);
if (isNaN(op1)) {
return false;
}
}
if (typeof op2 !== 'number') {
op2 = Number(op2);
if (isNaN(op2)) {
return false;
}
}
return op1 <= op2;
};
const tsToNum = (op1) => {
if (isUndefined(op1))
return undefined;
if (op1 instanceof Date) {
return op1.getTime() / 1000; // epoc is in seconds, getTime in miliseconds
}
return undefined;
};
const gt = (op1, op2) => {
if (isUndefined(op1) || isUndefined(op2))
return false;
if (typeof op1 !== 'number') {
op1 = Number(op1);
if (isNaN(op1)) {
return false;
}
}
if (typeof op2 !== 'number') {
op2 = Number(op2);
if (isNaN(op2)) {
return false;
}
}
return op1 > op2;
};
const numne = (op1, op2) => {
if (isUndefined(op1) || isUndefined(op2))
return false;
if (typeof op1 !== 'number') {
op1 = Number(op1);
if (isNaN(op1)) {
return false;
}
}
if (typeof op2 !== 'number') {
op2 = Number(op2);
if (isNaN(op2)) {
return false;
}
}
return op1 !== op2;
};
const numeq = (op1, op2) => {
if (isUndefined(op1) || isUndefined(op2))
return false;
if (typeof op1 !== 'number') {
op1 = Number(op1);
if (isNaN(op1)) {
return false;
}
}
if (typeof op2 !== 'number') {
op2 = Number(op2);
if (isNaN(op2)) {
return false;
}
}
return op1 === op2;
};
const gte = (op1, op2) => {
if (isUndefined(op1) || isUndefined(op2))
return false;
if (typeof op1 !== 'number') {
op1 = Number(op1);
if (isNaN(op1)) {
return false;
}
}
if (typeof op2 !== 'number') {
op2 = Number(op2);
if (isNaN(op2)) {
return false;
}
}
return op1 >= op2;
};
const match = (op1, op2, op3) => {
const text = op1;
const regex = new RegExp(op2, op3);
const match = regex.exec(text);
if (match) {
return true;
}
return false;
};
const semverLt = (op1, op2) => {
if (isUndefined(op1) || isUndefined(op2))
return false;
if (typeof op1 !== 'string' || typeof op2 !== 'string')
return false;
return _versionCompare(op1, op2, { zeroExtend: true }) < 0;
};
const semverLte = (op1, op2) => {
if (isUndefined(op1) || isUndefined(op2))
return false;
if (typeof op1 !== 'string' || typeof op2 !== 'string')
return false;
return _versionCompare(op1, op2, { zeroExtend: true }) <= 0;
};
const semverGt = (op1, op2) => {
if (isUndefined(op1) || isUndefined(op2))
return false;
if (typeof op1 !== 'string' || typeof op2 !== 'string')
return false;
return _versionCompare(op1, op2, { zeroExtend: true }) > 0;
};
const semverGte = (op1, op2) => {
if (isUndefined(op1) || isUndefined(op2))
return false;
if (typeof op1 !== 'string' || typeof op2 !== 'string')
return false;
return _versionCompare(op1, op2, { zeroExtend: true }) >= 0;
};
const semverEq = (op1, op2) => {
if (isUndefined(op1) || isUndefined(op2))
return false;
if (typeof op1 !== 'string' || typeof op2 !== 'string')
return false;
return _versionCompare(op1, op2) == 0;
};
const semverNe = (op1, op2) => {
if (isUndefined(op1) || isUndefined(op2))
return false;
if (typeof op1 !== 'string' || typeof op2 !== 'string')
return false;
return _versionCompare(op1, op2) != 0;
};
const mergeSeed = (seed1, seed2) => seed1 + '.' + seed2;
const isInPercentage = (percentage, seed) => {
const bucket = getBucket(seed);
const isInPercentage = bucket <= percentage;
return isInPercentage;
};
const isInPercentageRange = (percentageLow, percentageHigh, seed) => {
const bucket = getBucket(seed);
const isInPercentage = bucket >= percentageLow && bucket <= percentageHigh;
return isInPercentage;
};
const flagValue = (flagName, context = {}, internalContext = {}) => {
const flag = FlagsRepository.flagWithName(flagName);
if (flag) {
const contextClone = Object.assign({}, internalContext);
flag.getInternalValue(contextClone, context);
if (!contextClone.isPeek &&
!contextClone.result.isOverride &&
!contextClone.result.isFreezed) {
flag._flagImpression(contextClone.result.value, contextClone.result.usedContext);
}
return contextClone.result.value;
}
const exp = instance.experimentForFlagName(flagName);
if (exp && exp.deploymentConfiguration) {
const expressionValue = new RoxxParser().evaluateExpression(exp.deploymentConfiguration.condition, internalContext, context);
return expressionValue || 'false';
}
return 'false';
};
const isInTargetGroup = (targetGroup, context = {}, callContext = {}) => {
const tg = instance$1.targetGroupWithName(targetGroup);
if (tg) {
return new RoxxParser().evaluateExpression(tg.condition, callContext, context);
}
else {
return false;
}
};
const isTargetGroupPaired = () => false;
const property = (propName, context = {}) => {
const prop = customPropsRepository.get(propName);
if (!prop) {
const handler = DynamicPropertiesHandler && DynamicPropertiesHandler();
let handlerResult;
if (handler) {
if (!handler._isUserDefined) {
handlerResult = handler(propName, context);
}
else {
try {
handlerResult = handler(propName, context);
}
catch (err) {
err.isUserError = true;
err.trigger = ExceptionTrigger.DYNAMIC_PROPERTIES_RULE;
throw err;
}
}
}
return handlerResult;
}
else {
return prop.getValue(context);
}
};
const inArray = (target, list) => (list ? list.includes(target) : false);
const md5 = (str) => {
if (typeof str !== 'string') {
return undefined;
}
return md5$1.exports(str);
};
const concat = (str1, str2) => {
if (typeof str1 !== 'string' || typeof str2 !== 'string') {
return undefined;
}
return `${str1}${str2}`;
};
const b64d = (value) => {
if (typeof value !== 'string') {
return undefined;
}
return decodeURIComponent(decode(value));
};
const operatorsWithContext = [isInTargetGroup, flagValue, property];
var RoxxOperatorsMap = /*#__PURE__*/Object.freeze({
__proto__: null,
isUndefined: isUndefined,
now: now,
and: and,
or: or,
ne: ne,
eq: eq,
not: not,
ifThen: ifThen,
lt: lt,
lte: lte,
tsToNum: tsToNum,
gt: gt,
numne: numne,
numeq: numeq,
gte: gte,
match: match,
semverLt: semverLt,
semverLte: semverLte,
semverGt: semverGt,
semverGte: semverGte,
semverEq: semverEq,
semverNe: semverNe,
mergeSeed: mergeSeed,
isInPercentage: isInPercentage,
isInPercentageRange: isInPercentageRange,
flagValue: flagValue,
isInTargetGroup: isInTargetGroup,
isTargetGroupPaired: isTargetGroupPaired,
property: property,
inArray: inArray,
md5: md5,
concat: concat,
b64d: b64d,
operatorsWithContext: operatorsWithContext
});
const operatorsList = Object.keys(RoxxOperatorsMap);
const RoxxEscapedQuote = '\\"';
const RoxxEscapedQuotePlaceholder = '\\RO_Q';
const RoxxStringDelimiter = '"';
const RoxxArrayStartDelimiter = '[';
const RoxxArrayEndDelimiter = ']';
const RoxxDictStartDelimiter = '{';
const RoxxDictEndDelimiter = '}';
const RoxxTokenDelimiters = '{}[]():, \t\r\n"';
/**
* Type identifier for ope*rator* tokens
*/
const RoxxTokenTypeRator = 'operator';
/**
* Type identifier for ope*rand* tokens
*/
const RoxxTokenTypeRand = 'operand';
/**
*
*/
class RoxxTokenizer {
constructor() {
this.tokenArray = [];
this.arrayAccumulator = undefined;
this.dictionaryAccumulator = undefined;
this.dictKey = undefined;
}
/**
* Converts a string token into a Roxx type object.
* @param {string} token - The token to convert into a Roxx type.
* @returns {object}
*/
_stringToRoxx(token) {
if (operatorsList.includes(token))
return { type: RoxxTokenTypeRator, value: token };
if (token == 'true')
return { type: RoxxTokenTypeRand, value: true };
if (token == 'false')
return { type: RoxxTokenTypeRand, value: false };
if (token == 'undefined')
return { type: RoxxTokenTypeRand, value: undefined };
if (token.charAt(0) == '"' && token.charAt(token.length - 1) == '"')
return { type: RoxxTokenTypeRand, value: token.substr(1, token.length - 2) };
if (!isNaN(token))
return { type: RoxxTokenTypeRand, value: +token };
// we will never write literal date, it will only come from a custom property (but if we want to, this suppose to work)
// const tokenAsDate = Date.parse(token)
// if (!isNaN(tokenAsDate)) return {type: RoxxTokenTypeRand, value: new Date(tokenAsDate)}
return { type: 'UNKNOWN' };
}
/**
* Pushes a token into either the arrayAccumulator or the tokenArray
* according to context.
* @param {*} token - the token to push
*/
push(token) {
if (this.dictionaryAccumulator && !this.dictKey) {
this.dictKey = token.value;
}
else if (this.dictionaryAccumulator && this.dictKey) {
this.dictionaryAccumulator[this.dictKey] = token.value;
this.dictKey = undefined;
}
else if (this.arrayAccumulator) {
this.arrayAccumulator.push(token.value);
}
else {
this.tokenArray.push(token);
}
}
/**
* Produces a token array from an expression string. This array is later consumed by RoxxParser
* @see RoxxParser
* @param {string} expr - Roxx expression to tokenize
* @returns {Array}
*/
tokenize(expr) {
this.tokenArray = [];
this.arrayAccumulator = undefined;
this.dictionaryAccumulator = undefined;
let delimitersToUse = RoxxTokenDelimiters;
const expression = expr.replace(RoxxEscapedQuote, RoxxEscapedQuotePlaceholder);
const tokenizer = new StringTokenizer(expression, delimitersToUse, true);
let token, prevToken;
while (tokenizer.hasMoreTokens()) {
prevToken = token;
token = tokenizer.nextTokenWithDelimiters(delimitersToUse);
switch (token) {
case RoxxDictStartDelimiter:
this.dictionaryAccumulator = {};
break;
case RoxxDictEndDelimiter:
this.tokenArray.push({
type: RoxxTokenTypeRand,
value: this.dictionaryAccumulator,
});
this.dictionaryAccumulator = undefined;
break;
case RoxxArrayStartDelimiter:
this.arrayAccumulator = [];
break;
case RoxxArrayEndDelimiter:
this.tokenArray.push({ type: RoxxTokenTypeRand, value: this.arrayAccumulator });
this.arrayAccumulator = undefined;
break;
case RoxxStringDelimiter:
if (prevToken == RoxxStringDelimiter) {
// if previous token was also a string delimiter it means we encounterd an emptry string.
this.push({ type: RoxxTokenTypeRand, value: '' });
}
// Swap delimiters to use if needed. we do this so we can have strings with chars that are normally used as delimiters.
delimitersToUse =
delimitersToUse == RoxxStringDelimiter
? RoxxTokenDelimiters
: RoxxStringDelimiter;
break;
default:
if (delimitersToUse == RoxxStringDelimiter) {
// If get a token that's not RoxxStringDelimiter while using RoxxStringDelimiter as delimiters It's the string value!
this.push({
type: RoxxTokenTypeRand,
value: token.replace(RoxxEscapedQuotePlaceholder, RoxxEscapedQuote),
});
}
else if (RoxxTokenDelimiters.indexOf(token) == -1) {
// Is this token a delimiter or something else? if it's something else convert it to a roxx type and push.
this.push(this._stringToRoxx(token));
}
break;
}
}
return this.tokenArray;
}
}
const TARGET_URL_QUERY_PARAM_NAME = 'roxTargetUrl';
const AUTH_QUERY_PARAM_NAME = 'roxAuth';
class ProxyConfig {
constructor(proxySettings) {
this._proxyUrl = '';
this._proxyAuthHeader = '';
this._proxySettings = false;
if (proxySettings) {
this._proxySettings = Object.assign({}, proxySettings);
// calculating constants
this._proxyUrl = `${this._proxySettings.protocol}://${this._proxySettings.host}${this._proxySettings.port ? `:${this._proxySettings.port}` : ''}`;
if (this._proxySettings.auth &&
this._proxySettings.auth.username &&
this._proxySettings.auth.password) {
this._proxyAuthHeader = `Basic ${encode(`${this._proxySettings.auth.username}:${this._proxySettings.auth.password}`)}`;
this._proxyAuthHeaderEncoded = encodeURIComponent(this._proxyAuthHeader);
}
}
}
applyProxyToRequest(request) {
if (this._proxySettings) {
request.options = request.options ? Object.assign({}, request.options) : {};
const options = request.options;
options.params = options.params || {};
options.params[TARGET_URL_QUERY_PARAM_NAME] = request.url;
if (this._proxyAuthHeader) {
options.params[AUTH_QUERY_PARAM_NAME] = this._proxyAuthHeader;
}
request.url = this._proxyUrl;
}
}
applyProxyToSseRequest(request) {
if (this._proxySettings) {
request.url = `${this._proxyUrl}?${TARGET_URL_QUERY_PARAM_NAME}=${encodeURIComponent(request.url)}`;
if (this._proxyAuthHeaderEncoded) {
request.url = `${request.url}&${AUTH_QUERY_PARAM_NAME}=${this._proxyAuthHeaderEncoded}`;
}
}
}
get proxyUrl() {
return this._proxyUrl;
}
}
var ApiProvider;
(function (ApiProvider) {
ApiProvider["RolloutEu"] = "eu";
ApiProvider["Platform"] = "platform";
})(ApiProvider || (ApiProvider = {}));
const API_HOST = 'x-api.rollout.io';
let _proxyConfig = new ProxyConfig();
const DEFAULT_CONFIGURATION = (hostProvider) => {
let apiHost = API_HOST;
if (hostProvider == ApiProvider.RolloutEu) {
apiHost = `${'eu-'}${API_HOST}`; // as this goes into the url, not using the roxOptions.hosting value. instead using RoxOptions.hosting === "eu" as indication to use "eu-x-api..."
}
const configuration = {
API_HOST: apiHost,
CD_API_ENDPOINT: `https://${apiHost}/device/get_configuration`,
CD_S3_ENDPOINT: `https://conf.rollout.io/`,
SS_API_ENDPOINT: `https://${apiHost}/device/update_state_store/`,
SS_S3_ENDPOINT: `https://statestore.rollout.io/`,
CLIENT_DATA_CACHE_KEY: 'client_data',
NOTIFICATIONS_ENDPOINT: `https://push.rollout.io/sse`,
ANALYTICS_ENDPOINT: `https://analytic.rollout.io`,
ERROR_REPORTER: undefined,
};
if (hostProvider == ApiProvider.Platform) {
configuration.API_HOST = 'api.cloudbees.io';
configuration.CD_API_ENDPOINT = 'https://api.cloudbees.io/device/get_configuration';
configuration.CD_S3_ENDPOINT = 'https://rox-conf.cloudbees.io/';
configuration.SS_API_ENDPOINT = 'https://api.cloudbees.io/device/update_state_store/';
configuration.SS_S3_ENDPOINT = 'https://rox-state.cloudbees.io/';
configuration.ANALYTICS_ENDPOINT = 'https://fm-analytics.cloudbees.io';
configuration.NOTIFICATIONS_ENDPOINT =
'https://sdk-notification-service.cloudbees.io/sse';
}
return configuration;
};
const SELFMANAGEDMODE_CONFIGURATION = ({ analyticsURL, serverURL, pushUpdateURL, configurationURL, stateURL, }) => ({
CD_API_ENDPOINT: `${serverURL}/device/get_configuration`,
SS_API_ENDPOINT: `${serverURL}/device/update_state_store/`,
CLIENT_DATA_CACHE_KEY: 'client_data',
ANALYTICS_ENDPOINT: analyticsURL,
NOTIFICATIONS_ENDPOINT: `${pushUpdateURL}/sse`,
CD_S3_ENDPOINT: configurationURL,
SS_S3_ENDPOINT: stateURL,
ERROR_REPORTER: undefined,
});
let _activeConfiguration = Object.assign({}, DEFAULT_CONFIGURATION());
var Config = {
get: (key) => _activeConfiguration[key],
set: (key, value) => {
_activeConfiguration[key] = value;
},
setActive: function (newConfiguration) {
_activeConfiguration = Object.assign({}, newConfiguration);
},
setProxy: function (proxySettings) {
_proxyConfig = new ProxyConfig(proxySettings);
},
getProxy: () => _proxyConfig,
setHosting: function (hosting) {
if (hosting === ApiProvider.RolloutEu) {
_activeConfiguration = Object.assign({}, DEFAULT_CONFIGURATION('eu-'));
}
if (hosting === ApiProvider.Platform) {
_activeConfiguration = Object.assign({}, DEFAULT_CONFIGURATION(hosting));
}
},
setSelfManagedMode: function (conf) {
_activeConfiguration = Object.assign({}, DEFAULT_CONFIGURATION(), SELFMANAGEDMODE_CONFIGURATION(conf));
},
setErrorReporter: function (errorReporter) {
_activeConfiguration.ERROR_REPORTER = errorReporter;
},
/**
* Get the error reporter, or undefined if there is none configured.
* Don't forget to check for undefined before using!
*/
getErrorReporter: () => _activeConfiguration.ERROR_REPORTER,
};
class RoxxParser {
/**
* A parser for Roxx expressions.
* Roxx expre