{"version":3,"file":"esm.min.js","sources":["../../src/feature-repository.ts","../../src/util.ts","../../src/mongrule.ts","../../src/GrowthBook.ts"],"sourcesContent":["import {\n ApiHost,\n CacheSettings,\n ClientKey,\n FeatureApiResponse,\n Polyfills,\n RepositoryKey,\n} from \"./types/growthbook\";\nimport type { GrowthBook } from \".\";\n\ntype CacheEntry = {\n data: FeatureApiResponse;\n version: string;\n staleAt: Date;\n};\ntype ScopedChannel = {\n src: EventSource;\n cb: (event: MessageEvent) => void;\n errors: number;\n};\n\n// Config settings\nconst cacheSettings: CacheSettings = {\n // Consider a fetch stale after 1 minute\n staleTTL: 1000 * 60,\n cacheKey: \"gbFeaturesCache\",\n backgroundSync: true,\n};\nconst polyfills: Polyfills = {\n fetch: globalThis.fetch ? globalThis.fetch.bind(globalThis) : undefined,\n SubtleCrypto: globalThis.crypto ? globalThis.crypto.subtle : undefined,\n EventSource: globalThis.EventSource,\n localStorage: globalThis.localStorage,\n};\n\n// Global state\nconst subscribedInstances: Map> = new Map();\nlet cacheInitialized = false;\nconst cache: Map = new Map();\nconst activeFetches: Map<\n RepositoryKey,\n Promise\n> = new Map();\nconst streams: Map = new Map();\nconst supportsSSE: Set = new Set();\n\n// Public functions\nexport function setPolyfills(overrides: Partial): void {\n Object.assign(polyfills, overrides);\n}\nexport function configureCache(overrides: Partial): void {\n Object.assign(cacheSettings, overrides);\n if (!cacheSettings.backgroundSync) {\n clearAutoRefresh();\n }\n}\n\nexport async function clearCache(): Promise {\n cache.clear();\n activeFetches.clear();\n clearAutoRefresh();\n cacheInitialized = false;\n await updatePersistentCache();\n}\n\nexport async function refreshFeatures(\n instance: GrowthBook,\n timeout?: number,\n skipCache?: boolean,\n allowStale?: boolean,\n updateInstance?: boolean\n): Promise {\n const data = await fetchFeaturesWithCache(\n instance,\n allowStale,\n timeout,\n skipCache\n );\n updateInstance && data && (await setFeaturesOnInstance(instance, data));\n}\n\n// Subscribe a GrowthBook instance to feature changes\nexport function subscribe(instance: GrowthBook): void {\n const [key] = getKey(instance);\n const subs = subscribedInstances.get(key) || new Set();\n subs.add(instance);\n subscribedInstances.set(key, subs);\n}\nexport function unsubscribe(instance: GrowthBook): void {\n subscribedInstances.forEach((s) => s.delete(instance));\n}\n\n// Private functions\nasync function updatePersistentCache() {\n try {\n await polyfills.localStorage.setItem(\n cacheSettings.cacheKey,\n JSON.stringify(Array.from(cache.entries()))\n );\n } catch (e) {\n // Ignore localStorage errors\n }\n}\n\nasync function fetchFeaturesWithCache(\n instance: GrowthBook,\n allowStale?: boolean,\n timeout?: number,\n skipCache?: boolean\n): Promise {\n const [key] = getKey(instance);\n const now = new Date();\n await initializeCache();\n const existing = cache.get(key);\n if (existing && !skipCache && (allowStale || existing.staleAt > now)) {\n // Reload features in the backgroud if stale\n if (existing.staleAt < now) {\n fetchFeatures(instance);\n }\n // Otherwise, if we don't need to refresh now, start a background sync\n else {\n startAutoRefresh(instance);\n }\n return existing.data;\n } else {\n const data = await promiseTimeout(fetchFeatures(instance), timeout);\n return data;\n }\n}\n\nfunction getKey(instance: GrowthBook): [RepositoryKey, ApiHost, ClientKey] {\n const [apiHost, clientKey] = instance.getApiInfo();\n return [`${apiHost}||${clientKey}`, apiHost, clientKey];\n}\n\n// Guarantee the promise always resolves within {timeout} ms\n// Resolved value will be `null` when there's an error or it takes too long\n// Note: The promise will continue running in the background, even if the timeout is hit\nfunction promiseTimeout(\n promise: Promise,\n timeout?: number\n): Promise {\n return new Promise((resolve) => {\n let resolved = false;\n let timer: unknown;\n const finish = (data?: T) => {\n if (resolved) return;\n resolved = true;\n timer && clearTimeout(timer as NodeJS.Timer);\n resolve(data || null);\n };\n\n if (timeout) {\n timer = setTimeout(() => finish(), timeout);\n }\n\n promise.then((data) => finish(data)).catch(() => finish());\n });\n}\n\n// Populate cache from localStorage (if available)\nasync function initializeCache(): Promise {\n if (cacheInitialized) return;\n cacheInitialized = true;\n if (polyfills.localStorage) {\n try {\n const value = await polyfills.localStorage.getItem(\n cacheSettings.cacheKey\n );\n if (value) {\n const parsed: [RepositoryKey, CacheEntry][] = JSON.parse(value);\n if (parsed && Array.isArray(parsed)) {\n parsed.forEach(([key, data]) => {\n cache.set(key, {\n ...data,\n staleAt: new Date(data.staleAt),\n });\n });\n }\n }\n } catch (e) {\n // Ignore localStorage errors\n }\n }\n}\n\n// Called whenever new features are fetched from the API\nfunction onNewFeatureData(key: RepositoryKey, data: FeatureApiResponse): void {\n // If contents haven't changed, ignore the update, extend the stale TTL\n const version = data.dateUpdated || \"\";\n const staleAt = new Date(Date.now() + cacheSettings.staleTTL);\n const existing = cache.get(key);\n if (existing && version && existing.version === version) {\n existing.staleAt = staleAt;\n return;\n }\n\n // Update in-memory cache\n cache.set(key, {\n data,\n version,\n staleAt,\n });\n // Update local storage (don't await this, just update asynchronously)\n updatePersistentCache();\n\n // Update features for all subscribed GrowthBook instances\n const instances = subscribedInstances.get(key);\n instances &&\n instances.forEach((instance) => setFeaturesOnInstance(instance, data));\n}\n\nasync function setFeaturesOnInstance(\n instance: GrowthBook,\n data: FeatureApiResponse\n): Promise {\n await (data.encryptedFeatures\n ? instance.setEncryptedFeatures(\n data.encryptedFeatures,\n undefined,\n polyfills.SubtleCrypto\n )\n : instance.setFeatures(data.features || instance.getFeatures()));\n}\n\nasync function fetchFeatures(\n instance: GrowthBook\n): Promise {\n const [key, apiHost, clientKey] = getKey(instance);\n const endpoint = apiHost + \"/api/features/\" + clientKey;\n\n let promise = activeFetches.get(key);\n if (!promise) {\n promise = (polyfills.fetch as typeof globalThis.fetch)(endpoint)\n // TODO: auto-retry if status code indicates a temporary error\n .then((res) => {\n if (res.headers.get(\"x-sse-support\") === \"enabled\") {\n supportsSSE.add(key);\n }\n return res.json();\n })\n .then((data: FeatureApiResponse) => {\n onNewFeatureData(key, data);\n startAutoRefresh(instance);\n activeFetches.delete(key);\n return data;\n })\n .catch((e) => {\n process.env.NODE_ENV !== \"production\" &&\n instance.log(\"Error fetching features\", {\n apiHost,\n clientKey,\n error: e ? e.message : null,\n });\n activeFetches.delete(key);\n return Promise.resolve({});\n });\n activeFetches.set(key, promise);\n }\n return await promise;\n}\n\n// Watch a feature endpoint for changes\n// Will prefer SSE if enabled, otherwise fall back to cron\nfunction startAutoRefresh(instance: GrowthBook) {\n const [key, apiHost, clientKey] = getKey(instance);\n if (\n cacheSettings.backgroundSync &&\n supportsSSE.has(key) &&\n polyfills.EventSource\n ) {\n if (streams.has(key)) return;\n const channel: ScopedChannel = {\n src: new polyfills.EventSource(`${apiHost}/sub/${clientKey}`),\n cb: (event: MessageEvent) => {\n try {\n const json: FeatureApiResponse = JSON.parse(event.data);\n onNewFeatureData(key, json);\n // Reset error count on success\n channel.errors = 0;\n } catch (e) {\n process.env.NODE_ENV !== \"production\" &&\n instance.log(\"SSE Error\", {\n apiHost,\n clientKey,\n error: e ? (e as Error).message : null,\n });\n onSSEError(channel, key);\n }\n },\n errors: 0,\n };\n streams.set(key, channel);\n channel.src.addEventListener(\"features\", channel.cb);\n\n channel.src.onerror = () => {\n onSSEError(channel, key);\n };\n }\n}\n\nfunction onSSEError(channel: ScopedChannel, key: RepositoryKey) {\n channel.errors++;\n if (channel.errors > 3 || channel.src.readyState === 2) {\n destroyChannel(channel, key);\n }\n}\n\nfunction destroyChannel(channel: ScopedChannel, key: RepositoryKey) {\n channel.src.onerror = null;\n channel.src.close();\n streams.delete(key);\n}\n\nfunction clearAutoRefresh() {\n // Clear list of which keys are auto-updated\n supportsSSE.clear();\n\n // Stop listening for any SSE events\n streams.forEach(destroyChannel);\n\n // Remove all references to GrowthBook instances\n subscribedInstances.clear();\n}\n","import { VariationRange } from \"./types/growthbook\";\n\nfunction hashFnv32a(str: string): number {\n let hval = 0x811c9dc5;\n const l = str.length;\n\n for (let i = 0; i < l; i++) {\n hval ^= str.charCodeAt(i);\n hval +=\n (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);\n }\n return hval >>> 0;\n}\n\nexport function hash(str: string): number {\n return (hashFnv32a(str) % 1000) / 1000;\n}\n\nexport function getEqualWeights(n: number): number[] {\n if (n <= 0) return [];\n return new Array(n).fill(1 / n);\n}\n\nexport function inNamespace(\n hashValue: string,\n namespace: [string, number, number]\n): boolean {\n const n = hash(hashValue + \"__\" + namespace[0]);\n return n >= namespace[1] && n < namespace[2];\n}\n\nexport function chooseVariation(n: number, ranges: VariationRange[]): number {\n for (let i = 0; i < ranges.length; i++) {\n if (n >= ranges[i][0] && n < ranges[i][1]) {\n return i;\n }\n }\n return -1;\n}\n\nexport function getUrlRegExp(regexString: string): RegExp | undefined {\n try {\n const escaped = regexString.replace(/([^\\\\])\\//g, \"$1\\\\/\");\n return new RegExp(escaped);\n } catch (e) {\n console.error(e);\n return undefined;\n }\n}\n\nexport function getBucketRanges(\n numVariations: number,\n coverage: number = 1,\n weights?: number[]\n): VariationRange[] {\n // Make sure coverage is within bounds\n if (coverage < 0) {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(\"Experiment.coverage must be greater than or equal to 0\");\n }\n coverage = 0;\n } else if (coverage > 1) {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(\"Experiment.coverage must be less than or equal to 1\");\n }\n coverage = 1;\n }\n\n // Default to equal weights if missing or invalid\n const equal = getEqualWeights(numVariations);\n weights = weights || equal;\n if (weights.length !== numVariations) {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(\n \"Experiment.weights array must be the same length as Experiment.variations\"\n );\n }\n weights = equal;\n }\n\n // If weights don't add up to 1 (or close to it), default to equal weights\n const totalWeight = weights.reduce((w, sum) => sum + w, 0);\n if (totalWeight < 0.99 || totalWeight > 1.01) {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(\"Experiment.weights must add up to 1\");\n }\n weights = equal;\n }\n\n // Covert weights to ranges\n let cumulative = 0;\n return weights.map((w) => {\n const start = cumulative;\n cumulative += w;\n return [start, start + coverage * w];\n }) as VariationRange[];\n}\n\nexport function getQueryStringOverride(\n id: string,\n url: string,\n numVariations: number\n) {\n if (!url) {\n return null;\n }\n\n const search = url.split(\"?\")[1];\n if (!search) {\n return null;\n }\n\n const match = search\n .replace(/#.*/, \"\") // Get rid of anchor\n .split(\"&\") // Split into key/value pairs\n .map((kv) => kv.split(\"=\", 2))\n .filter(([k]) => k === id) // Look for key that matches the experiment id\n .map(([, v]) => parseInt(v)); // Parse the value into an integer\n\n if (match.length > 0 && match[0] >= 0 && match[0] < numVariations)\n return match[0];\n\n return null;\n}\n\nexport function isIncluded(include: () => boolean) {\n try {\n return include();\n } catch (e) {\n console.error(e);\n return false;\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport {\n ConditionInterface,\n TestedObj,\n ConditionValue,\n Operator,\n OperatorConditionValue,\n VarType,\n} from \"./types/mongrule\";\n\nconst _regexCache: { [key: string]: RegExp } = {};\n\n// The top-level condition evaluation function\nexport function evalCondition(\n obj: TestedObj,\n condition: ConditionInterface\n): boolean {\n // Recursive condition\n if (\"$or\" in condition) {\n return evalOr(obj, condition[\"$or\"] as ConditionInterface[]);\n }\n if (\"$nor\" in condition) {\n return !evalOr(obj, condition[\"$nor\"] as ConditionInterface[]);\n }\n if (\"$and\" in condition) {\n return evalAnd(obj, condition[\"$and\"] as ConditionInterface[]);\n }\n if (\"$not\" in condition) {\n return !evalCondition(obj, condition[\"$not\"] as ConditionInterface);\n }\n\n // Condition is an object, keys are object paths, values are the condition for that path\n for (const [k, v] of Object.entries(condition)) {\n if (!evalConditionValue(v, getPath(obj, k))) return false;\n }\n return true;\n}\n\n// Return value at dot-separated path of an object\nfunction getPath(obj: TestedObj, path: string) {\n const parts = path.split(\".\");\n let current: any = obj;\n for (let i = 0; i < parts.length; i++) {\n if (current && typeof current === \"object\" && parts[i] in current) {\n current = current[parts[i]];\n } else {\n return null;\n }\n }\n return current;\n}\n\n// Transform a regex string into a real RegExp object\nfunction getRegex(regex: string): RegExp {\n if (!_regexCache[regex]) {\n _regexCache[regex] = new RegExp(regex.replace(/([^\\\\])\\//g, \"$1\\\\/\"));\n }\n return _regexCache[regex];\n}\n\n// Evaluate a single value against a condition\nfunction evalConditionValue(condition: ConditionValue, value: any) {\n // Simple equality comparisons\n if (typeof condition === \"string\") {\n return value + \"\" === condition;\n }\n if (typeof condition === \"number\") {\n return value * 1 === condition;\n }\n if (typeof condition === \"boolean\") {\n return !!value === condition;\n }\n if (Array.isArray(condition) || !isOperatorObject(condition)) {\n return JSON.stringify(value) === JSON.stringify(condition);\n }\n\n // This is a special operator condition and we should evaluate each one separately\n for (const op in condition) {\n if (\n !evalOperatorCondition(\n op as Operator,\n value,\n condition[op as keyof OperatorConditionValue]\n )\n ) {\n return false;\n }\n }\n return true;\n}\n\n// If the object has only keys that start with '$'\nfunction isOperatorObject(obj: any): boolean {\n const keys = Object.keys(obj);\n return (\n keys.length > 0 && keys.filter((k) => k[0] === \"$\").length === keys.length\n );\n}\n\n// Return the data type of a value\nfunction getType(v: any): VarType | \"unknown\" {\n if (v === null) return \"null\";\n if (Array.isArray(v)) return \"array\";\n const t = typeof v;\n if ([\"string\", \"number\", \"boolean\", \"object\", \"undefined\"].includes(t)) {\n return t as VarType;\n }\n return \"unknown\";\n}\n\n// At least one element of actual must match the expected condition/value\nfunction elemMatch(actual: any, expected: any) {\n if (!Array.isArray(actual)) return false;\n const check = isOperatorObject(expected)\n ? (v: any) => evalConditionValue(expected, v)\n : (v: any) => evalCondition(v, expected);\n for (let i = 0; i < actual.length; i++) {\n if (actual[i] && check(actual[i])) {\n return true;\n }\n }\n return false;\n}\n\n// Evaluate a single operator condition\nfunction evalOperatorCondition(\n operator: Operator,\n actual: any,\n expected: any\n): boolean {\n switch (operator) {\n case \"$eq\":\n return actual === expected;\n case \"$ne\":\n return actual !== expected;\n case \"$lt\":\n return actual < expected;\n case \"$lte\":\n return actual <= expected;\n case \"$gt\":\n return actual > expected;\n case \"$gte\":\n return actual >= expected;\n case \"$exists\":\n return expected ? actual !== null : actual === null;\n case \"$in\":\n return expected.includes(actual);\n case \"$nin\":\n return !expected.includes(actual);\n case \"$not\":\n return !evalConditionValue(expected, actual);\n case \"$size\":\n if (!Array.isArray(actual)) return false;\n return evalConditionValue(expected, actual.length);\n case \"$elemMatch\":\n return elemMatch(actual, expected);\n case \"$all\":\n if (!Array.isArray(actual)) return false;\n for (let i = 0; i < expected.length; i++) {\n let passed = false;\n for (let j = 0; j < actual.length; j++) {\n if (evalConditionValue(expected[i], actual[j])) {\n passed = true;\n break;\n }\n }\n if (!passed) return false;\n }\n return true;\n case \"$regex\":\n try {\n return getRegex(expected).test(actual);\n } catch (e) {\n return false;\n }\n case \"$type\":\n return getType(actual) === expected;\n default:\n console.error(\"Unknown operator: \" + operator);\n return false;\n }\n}\n\n// Recursive $or rule\nfunction evalOr(obj: TestedObj, conditions: ConditionInterface[]): boolean {\n if (!conditions.length) return true;\n for (let i = 0; i < conditions.length; i++) {\n if (evalCondition(obj, conditions[i])) {\n return true;\n }\n }\n return false;\n}\n\n// Recursive $and rule\nfunction evalAnd(obj: TestedObj, conditions: ConditionInterface[]): boolean {\n for (let i = 0; i < conditions.length; i++) {\n if (!evalCondition(obj, conditions[i])) {\n return false;\n }\n }\n return true;\n}\n","import type {\n Context,\n Experiment,\n FeatureResult,\n Result,\n SubscriptionFunction,\n FeatureDefinition,\n FeatureResultSource,\n Attributes,\n JSONValue,\n WidenPrimitives,\n RealtimeUsageData,\n LoadFeaturesOptions,\n RefreshFeaturesOptions,\n ApiHost,\n ClientKey,\n} from \"./types/growthbook\";\nimport type { ConditionInterface } from \"./types/mongrule\";\nimport {\n getUrlRegExp,\n isIncluded,\n getBucketRanges,\n hash,\n chooseVariation,\n getQueryStringOverride,\n inNamespace,\n} from \"./util\";\nimport { evalCondition } from \"./mongrule\";\nimport { refreshFeatures, subscribe, unsubscribe } from \"./feature-repository\";\n\nconst isBrowser =\n typeof window !== \"undefined\" && typeof document !== \"undefined\";\n\nconst base64ToBuf = (b: string) =>\n Uint8Array.from(atob(b), (c) => c.charCodeAt(0));\n\nexport class GrowthBook {\n // context is technically private, but some tools depend on it so we can't mangle the name\n // _ctx below is a clone of this property that we use internally\n private context: Context;\n public debug: boolean;\n public ready: boolean;\n\n // Properties and methods that start with \"_\" are mangled by Terser (saves ~150 bytes)\n private _ctx: Context;\n private _renderer: null | (() => void);\n private _trackedExperiments: Set;\n private _trackedFeatures: Record;\n private _subscriptions: Set;\n private _rtQueue: RealtimeUsageData[];\n private _rtTimer: number;\n private _assigned: Map<\n string,\n {\n // eslint-disable-next-line\n experiment: Experiment;\n // eslint-disable-next-line\n result: Result;\n }\n >;\n // eslint-disable-next-line\n private _forcedFeatureValues: Map;\n private _attributeOverrides: Attributes;\n\n constructor(context?: Context) {\n context = context || {};\n // These properties are all initialized in the constructor instead of above\n // This saves ~80 bytes in the final output\n this._ctx = this.context = context;\n this._renderer = null;\n this._trackedExperiments = new Set();\n this._trackedFeatures = {};\n this.debug = false;\n this._subscriptions = new Set();\n this._rtQueue = [];\n this._rtTimer = 0;\n this.ready = false;\n this._assigned = new Map();\n this._forcedFeatureValues = new Map();\n this._attributeOverrides = {};\n\n if (context.features) {\n this.ready = true;\n }\n\n if (isBrowser && context.enableDevMode) {\n window._growthbook = this;\n document.dispatchEvent(new Event(\"gbloaded\"));\n }\n\n if (context.clientKey) {\n this._refresh({}, true, false);\n }\n }\n\n public async loadFeatures(options?: LoadFeaturesOptions): Promise {\n await this._refresh(options, true, true);\n if (options && options.autoRefresh) {\n subscribe(this);\n }\n }\n\n public async refreshFeatures(\n options?: RefreshFeaturesOptions\n ): Promise {\n await this._refresh(options, false, true);\n }\n\n public getApiInfo(): [ApiHost, ClientKey] {\n return [\n (this._ctx.apiHost || \"https://cdn.growthbook.io\").replace(/\\/*$/, \"\"),\n this._ctx.clientKey || \"\",\n ];\n }\n\n private async _refresh(\n options?: RefreshFeaturesOptions,\n allowStale?: boolean,\n updateInstance?: boolean\n ) {\n options = options || {};\n if (!this._ctx.clientKey) {\n throw new Error(\"Missing clientKey\");\n }\n await refreshFeatures(\n this,\n options.timeout,\n options.skipCache || this._ctx.enableDevMode,\n allowStale,\n updateInstance\n );\n }\n\n private _render() {\n if (this._renderer) {\n this._renderer();\n }\n }\n\n public setFeatures(features: Record) {\n this._ctx.features = features;\n this.ready = true;\n this._render();\n }\n\n public async setEncryptedFeatures(\n encryptedString: string,\n decryptionKey?: string,\n subtle?: SubtleCrypto\n ): Promise {\n decryptionKey = decryptionKey || this._ctx.decryptionKey || \"\";\n subtle = subtle || (globalThis.crypto && globalThis.crypto.subtle);\n if (!subtle) {\n throw new Error(\"No SubtleCrypto implementation found\");\n }\n try {\n const key = await subtle.importKey(\n \"raw\",\n base64ToBuf(decryptionKey),\n { name: \"AES-CBC\", length: 128 },\n true,\n [\"encrypt\", \"decrypt\"]\n );\n const [iv, cipherText] = encryptedString.split(\".\");\n const plainTextBuffer = await subtle.decrypt(\n { name: \"AES-CBC\", iv: base64ToBuf(iv) },\n key,\n base64ToBuf(cipherText)\n );\n\n this.setFeatures(JSON.parse(new TextDecoder().decode(plainTextBuffer)));\n } catch (e) {\n throw new Error(\"Failed to decrypt features\");\n }\n }\n\n public setAttributes(attributes: Attributes) {\n this._ctx.attributes = attributes;\n this._render();\n }\n\n public setAttributeOverrides(overrides: Attributes) {\n this._attributeOverrides = overrides;\n this._render();\n }\n public setForcedVariations(vars: Record) {\n this._ctx.forcedVariations = vars || {};\n this._render();\n }\n // eslint-disable-next-line\n public setForcedFeatures(map: Map) {\n this._forcedFeatureValues = map;\n this._render();\n }\n\n public getAttributes() {\n return { ...this._ctx.attributes, ...this._attributeOverrides };\n }\n\n public getFeatures() {\n return this._ctx.features || {};\n }\n\n public subscribe(cb: SubscriptionFunction): () => void {\n this._subscriptions.add(cb);\n\n return () => {\n this._subscriptions.delete(cb);\n };\n }\n\n public getAllResults() {\n return new Map(this._assigned);\n }\n\n public destroy() {\n // Release references to save memory\n this._subscriptions.clear();\n this._assigned.clear();\n this._trackedExperiments.clear();\n this._trackedFeatures = {};\n this._rtQueue = [];\n if (this._rtTimer) {\n clearTimeout(this._rtTimer);\n }\n unsubscribe(this);\n\n if (isBrowser && window._growthbook === this) {\n delete window._growthbook;\n }\n }\n\n public setRenderer(renderer: () => void) {\n this._renderer = renderer;\n }\n\n public forceVariation(key: string, variation: number) {\n this._ctx.forcedVariations = this._ctx.forcedVariations || {};\n this._ctx.forcedVariations[key] = variation;\n this._render();\n }\n\n public run(experiment: Experiment): Result {\n const result = this._run(experiment, null);\n this._fireSubscriptions(experiment, result);\n return result;\n }\n\n private _fireSubscriptions(experiment: Experiment, result: Result) {\n const key = experiment.key;\n\n // If assigned variation has changed, fire subscriptions\n const prev = this._assigned.get(key);\n // TODO: what if the experiment definition has changed?\n if (\n !prev ||\n prev.result.inExperiment !== result.inExperiment ||\n prev.result.variationId !== result.variationId\n ) {\n this._assigned.set(key, { experiment, result });\n this._subscriptions.forEach((cb) => {\n try {\n cb(experiment, result);\n } catch (e) {\n console.error(e);\n }\n });\n }\n }\n\n private _trackFeatureUsage(key: string, res: FeatureResult): void {\n // Don't track feature usage that was forced via an override\n if (res.source === \"override\") return;\n\n // Only track a feature once, unless the assigned value changed\n const stringifiedValue = JSON.stringify(res.value);\n if (this._trackedFeatures[key] === stringifiedValue) return;\n this._trackedFeatures[key] = stringifiedValue;\n\n // Fire user-supplied callback\n if (this._ctx.onFeatureUsage) {\n try {\n this._ctx.onFeatureUsage(key, res);\n } catch (e) {\n // Ignore feature usage callback errors\n }\n }\n\n // In browser environments, queue up feature usage to be tracked in batches\n if (!isBrowser || !window.fetch) return;\n this._rtQueue.push({\n key,\n on: res.on,\n });\n if (!this._rtTimer) {\n this._rtTimer = window.setTimeout(() => {\n // Reset the queue\n this._rtTimer = 0;\n const q = [...this._rtQueue];\n this._rtQueue = [];\n\n // Skip logging if a real-time usage key is not configured\n if (!this._ctx.realtimeKey) return;\n\n window\n .fetch(\n `https://rt.growthbook.io/?key=${\n this._ctx.realtimeKey\n }&events=${encodeURIComponent(JSON.stringify(q))}`,\n\n {\n cache: \"no-cache\",\n mode: \"no-cors\",\n }\n )\n .catch(() => {\n // TODO: retry in case of network errors?\n });\n }, this._ctx.realtimeInterval || 2000);\n }\n }\n\n private _getFeatureResult(\n key: string,\n value: T,\n source: FeatureResultSource,\n ruleId?: string,\n experiment?: Experiment,\n result?: Result\n ): FeatureResult {\n const ret: FeatureResult = {\n value,\n on: !!value,\n off: !value,\n source,\n ruleId: ruleId || \"\",\n };\n if (experiment) ret.experiment = experiment;\n if (result) ret.experimentResult = result;\n\n // Track the usage of this feature in real-time\n this._trackFeatureUsage(key, ret);\n\n return ret;\n }\n\n public isOn(key: string): boolean {\n return this.evalFeature(key).on;\n }\n public isOff(key: string): boolean {\n return this.evalFeature(key).off;\n }\n public getFeatureValue(\n key: string,\n defaultValue: T\n ): WidenPrimitives {\n return (\n this.evalFeature>(key).value ??\n (defaultValue as WidenPrimitives)\n );\n }\n\n // eslint-disable-next-line\n public feature(\n id: string\n ): FeatureResult {\n return this.evalFeature(id);\n }\n\n // eslint-disable-next-line\n public evalFeature(\n id: string\n ): FeatureResult {\n // Global override\n if (this._forcedFeatureValues.has(id)) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Global override\", {\n id,\n value: this._forcedFeatureValues.get(id),\n });\n return this._getFeatureResult(\n id,\n this._forcedFeatureValues.get(id),\n \"override\"\n );\n }\n\n // Unknown feature id\n if (!this._ctx.features || !this._ctx.features[id]) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Unknown feature\", { id });\n return this._getFeatureResult(id, null, \"unknownFeature\");\n }\n\n // Get the feature\n const feature: FeatureDefinition = this._ctx.features[id];\n\n // Loop through the rules\n if (feature.rules) {\n for (const rule of feature.rules) {\n // If it's a conditional rule, skip if the condition doesn't pass\n if (rule.condition && !this._conditionPasses(rule.condition)) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip rule because of condition\", {\n id,\n rule,\n });\n continue;\n }\n // Feature value is being forced\n if (\"force\" in rule) {\n // Skip if coverage is reduced and user not included\n if (\"coverage\" in rule) {\n const { hashValue } = this._getHashAttribute(rule.hashAttribute);\n if (!hashValue) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip rule because of missing hashAttribute\", {\n id,\n rule,\n });\n continue;\n }\n const n = hash(hashValue + id);\n if (n > (rule.coverage as number)) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip rule because of coverage\", {\n id,\n rule,\n });\n continue;\n }\n }\n\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Force value from rule\", {\n id,\n rule,\n });\n\n return this._getFeatureResult(id, rule.force as T, \"force\", rule.id);\n }\n if (!rule.variations) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip invalid rule\", {\n id,\n rule,\n });\n\n continue;\n }\n // For experiment rules, run an experiment\n const exp: Experiment = {\n variations: rule.variations as [T, T, ...T[]],\n key: rule.key || id,\n };\n if (\"coverage\" in rule) exp.coverage = rule.coverage;\n if (rule.weights) exp.weights = rule.weights;\n if (rule.hashAttribute) exp.hashAttribute = rule.hashAttribute;\n if (rule.namespace) exp.namespace = rule.namespace;\n\n // Only return a value if the user is part of the experiment\n const res = this._run(exp, id);\n this._fireSubscriptions(exp, res);\n if (res.inExperiment) {\n return this._getFeatureResult(\n id,\n res.value,\n \"experiment\",\n rule.id,\n exp,\n res\n );\n }\n }\n }\n\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Use default value\", {\n id,\n value: feature.defaultValue ?? null,\n });\n\n // Fall back to using the default value\n return this._getFeatureResult(\n id,\n feature.defaultValue ?? null,\n \"defaultValue\"\n );\n }\n\n private _conditionPasses(condition: ConditionInterface): boolean {\n return evalCondition(this.getAttributes(), condition);\n }\n\n private _run(\n experiment: Experiment,\n featureId: string | null\n ): Result {\n const key = experiment.key;\n const numVariations = experiment.variations.length;\n\n // 1. If experiment has less than 2 variations, return immediately\n if (numVariations < 2) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Invalid experiment\", { id: key });\n return this._getResult(experiment, -1, false, featureId);\n }\n\n // 2. If the context is disabled, return immediately\n if (this._ctx.enabled === false) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Context disabled\", { id: key });\n return this._getResult(experiment, -1, false, featureId);\n }\n\n // 2.5. Merge in experiment overrides from the context\n experiment = this._mergeOverrides(experiment);\n\n // 3. If a variation is forced from a querystring, return the forced variation\n const qsOverride = getQueryStringOverride(\n key,\n this._getContextUrl(),\n numVariations\n );\n if (qsOverride !== null) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Force via querystring\", {\n id: key,\n variation: qsOverride,\n });\n return this._getResult(experiment, qsOverride, false, featureId);\n }\n\n // 4. If a variation is forced in the context, return the forced variation\n if (this._ctx.forcedVariations && key in this._ctx.forcedVariations) {\n const variation = this._ctx.forcedVariations[key];\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Force via dev tools\", {\n id: key,\n variation,\n });\n return this._getResult(experiment, variation, false, featureId);\n }\n\n // 5. Exclude if a draft experiment or not active\n if (experiment.status === \"draft\" || experiment.active === false) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip because inactive\", {\n id: key,\n });\n return this._getResult(experiment, -1, false, featureId);\n }\n\n // 6. Get the hash attribute and return if empty\n const { hashValue } = this._getHashAttribute(experiment.hashAttribute);\n if (!hashValue) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip because missing hashAttribute\", {\n id: key,\n });\n return this._getResult(experiment, -1, false, featureId);\n }\n\n // 7. Exclude if user not in experiment.namespace\n if (experiment.namespace && !inNamespace(hashValue, experiment.namespace)) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip because of namespace\", {\n id: key,\n });\n return this._getResult(experiment, -1, false, featureId);\n }\n\n // 7.5. Exclude if experiment.include returns false or throws\n if (experiment.include && !isIncluded(experiment.include)) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip because of include function\", {\n id: key,\n });\n return this._getResult(experiment, -1, false, featureId);\n }\n\n // 8. Exclude if condition is false\n if (experiment.condition && !this._conditionPasses(experiment.condition)) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip because of condition\", {\n id: key,\n });\n return this._getResult(experiment, -1, false, featureId);\n }\n\n // 8.1. Exclude if user is not in a required group\n if (\n experiment.groups &&\n !this._hasGroupOverlap(experiment.groups as string[])\n ) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip because of groups\", {\n id: key,\n });\n return this._getResult(experiment, -1, false, featureId);\n }\n\n // 8.2. Exclude if not on a targeted url\n if (experiment.url && !this._urlIsValid(experiment.url as RegExp)) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip because of url\", {\n id: key,\n });\n return this._getResult(experiment, -1, false, featureId);\n }\n\n // 9. Get bucket ranges and choose variation\n const ranges = getBucketRanges(\n numVariations,\n experiment.coverage ?? 1,\n experiment.weights\n );\n const n = hash(hashValue + key);\n const assigned = chooseVariation(n, ranges);\n\n // 10. Return if not in experiment\n if (assigned < 0) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip because of coverage\", {\n id: key,\n });\n return this._getResult(experiment, -1, false, featureId);\n }\n\n // 11. Experiment has a forced variation\n if (\"force\" in experiment) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Force variation\", {\n id: key,\n variation: experiment.force,\n });\n return this._getResult(\n experiment,\n experiment.force ?? -1,\n false,\n featureId\n );\n }\n\n // 12. Exclude if in QA mode\n if (this._ctx.qaMode) {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip because QA mode\", {\n id: key,\n });\n return this._getResult(experiment, -1, false, featureId);\n }\n\n // 12.5. Exclude if experiment is stopped\n if (experiment.status === \"stopped\") {\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"Skip because stopped\", {\n id: key,\n });\n return this._getResult(experiment, -1, false, featureId);\n }\n\n // 13. Build the result object\n const result = this._getResult(experiment, assigned, true, featureId);\n\n // 14. Fire the tracking callback\n this._track(experiment, result);\n\n // 15. Return the result\n process.env.NODE_ENV !== \"production\" &&\n this.log(\"In experiment\", {\n id: key,\n variation: result.variationId,\n });\n return result;\n }\n\n log(msg: string, ctx: Record) {\n if (!this.debug) return;\n if (this._ctx.log) this._ctx.log(msg, ctx);\n else console.log(msg, ctx);\n }\n\n private _track(experiment: Experiment, result: Result) {\n if (!this._ctx.trackingCallback) return;\n\n const key = experiment.key;\n\n // Make sure a tracking callback is only fired once per unique experiment\n const k =\n result.hashAttribute + result.hashValue + key + result.variationId;\n if (this._trackedExperiments.has(k)) return;\n this._trackedExperiments.add(k);\n\n try {\n this._ctx.trackingCallback(experiment, result);\n } catch (e) {\n console.error(e);\n }\n }\n\n private _mergeOverrides(experiment: Experiment): Experiment {\n const key = experiment.key;\n const o = this._ctx.overrides;\n if (o && o[key]) {\n experiment = Object.assign({}, experiment, o[key]);\n if (typeof experiment.url === \"string\") {\n experiment.url = getUrlRegExp(\n // eslint-disable-next-line\n experiment.url as any\n );\n }\n }\n\n return experiment;\n }\n\n private _getHashAttribute(attr?: string) {\n const hashAttribute = attr || \"id\";\n\n let hashValue = \"\";\n if (this._attributeOverrides[hashAttribute]) {\n hashValue = this._attributeOverrides[hashAttribute];\n } else if (this._ctx.attributes) {\n hashValue = this._ctx.attributes[hashAttribute] || \"\";\n } else if (this._ctx.user) {\n hashValue = this._ctx.user[hashAttribute] || \"\";\n }\n\n return { hashAttribute, hashValue };\n }\n\n private _getResult(\n experiment: Experiment,\n variationIndex: number,\n hashUsed: boolean,\n featureId: string | null\n ): Result {\n let inExperiment = true;\n // If assigned variation is not valid, use the baseline and mark the user as not in the experiment\n if (variationIndex < 0 || variationIndex >= experiment.variations.length) {\n variationIndex = 0;\n inExperiment = false;\n }\n\n const { hashAttribute, hashValue } = this._getHashAttribute(\n experiment.hashAttribute\n );\n\n return {\n featureId,\n inExperiment,\n hashUsed,\n variationId: variationIndex,\n value: experiment.variations[variationIndex],\n hashAttribute,\n hashValue,\n };\n }\n\n private _getContextUrl() {\n return this._ctx.url || (isBrowser ? window.location.href : \"\");\n }\n\n private _urlIsValid(urlRegex: RegExp): boolean {\n const url = this._getContextUrl();\n if (!url) return false;\n\n const pathOnly = url.replace(/^https?:\\/\\//, \"\").replace(/^[^/]*\\//, \"/\");\n\n if (urlRegex.test(url)) return true;\n if (urlRegex.test(pathOnly)) return true;\n return false;\n }\n\n private _hasGroupOverlap(expGroups: string[]): boolean {\n const groups = this._ctx.groups || {};\n for (let i = 0; i < expGroups.length; i++) {\n if (groups[expGroups[i]]) return true;\n }\n return false;\n }\n}\n"],"names":["cacheSettings","staleTTL","cacheKey","backgroundSync","polyfills","fetch","globalThis","bind","undefined","SubtleCrypto","crypto","subtle","EventSource","localStorage","subscribedInstances","Map","cacheInitialized","cache","activeFetches","streams","supportsSSE","Set","setPolyfills","overrides","Object","assign","configureCache","clearAutoRefresh","async","clearCache","clear","updatePersistentCache","setItem","JSON","stringify","Array","from","entries","e","getKey","instance","apiHost","clientKey","getApiInfo","concat","onNewFeatureData","key","data","version","dateUpdated","staleAt","Date","now","existing","get","set","instances","forEach","setFeaturesOnInstance","encryptedFeatures","setEncryptedFeatures","setFeatures","features","getFeatures","fetchFeatures","endpoint","promise","then","res","headers","add","json","startAutoRefresh","delete","catch","Promise","resolve","has","channel","src","cb","event","parse","errors","onSSEError","addEventListener","onerror","readyState","destroyChannel","close","hash","str","hval","l","length","i","charCodeAt","hashFnv32a","getEqualWeights","n","fill","_regexCache","evalCondition","obj","condition","evalOr","conditions","evalAnd","k","v","evalConditionValue","getPath","path","parts","split","current","value","isArray","isOperatorObject","op","evalOperatorCondition","keys","filter","operator","actual","expected","includes","check","elemMatch","passed","j","regex","RegExp","replace","test","t","getType","console","error","isBrowser","window","document","base64ToBuf","b","Uint8Array","atob","c","GrowthBook","constructor","context","this","_ctx","_renderer","_trackedExperiments","_trackedFeatures","debug","_subscriptions","_rtQueue","_rtTimer","ready","_assigned","_forcedFeatureValues","_attributeOverrides","enableDevMode","_growthbook","dispatchEvent","Event","_refresh","options","autoRefresh","subs","subscribe","allowStale","updateInstance","Error","timeout","skipCache","getItem","parsed","_ref","initializeCache","timer","resolved","finish","clearTimeout","setTimeout","promiseTimeout","fetchFeaturesWithCache","refreshFeatures","_render","encryptedString","decryptionKey","importKey","name","iv","cipherText","plainTextBuffer","decrypt","TextDecoder","decode","setAttributes","attributes","setAttributeOverrides","setForcedVariations","vars","forcedVariations","setForcedFeatures","map","getAttributes","getAllResults","destroy","s","setRenderer","renderer","forceVariation","variation","run","experiment","result","_run","_fireSubscriptions","prev","inExperiment","variationId","_trackFeatureUsage","source","stringifiedValue","onFeatureUsage","push","on","q","realtimeKey","encodeURIComponent","mode","realtimeInterval","_getFeatureResult","ruleId","ret","off","experimentResult","isOn","evalFeature","isOff","getFeatureValue","defaultValue","_this$evalFeature$val","feature","id","_feature$defaultValue2","rules","rule","_conditionPasses","hashValue","_getHashAttribute","hashAttribute","coverage","force","variations","exp","weights","namespace","featureId","_experiment$coverage","numVariations","_getResult","enabled","_mergeOverrides","qsOverride","url","search","match","kv","_ref2","parseInt","getQueryStringOverride","_getContextUrl","status","active","inNamespace","include","isIncluded","groups","_hasGroupOverlap","_urlIsValid","ranges","arguments","equal","totalWeight","reduce","w","sum","cumulative","start","getBucketRanges","assigned","chooseVariation","_experiment$force","qaMode","_track","log","msg","ctx","trackingCallback","o","regexString","escaped","getUrlRegExp","attr","user","variationIndex","hashUsed","location","href","urlRegex","pathOnly","expGroups"],"mappings":"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"}