@botpress/adk-cli
Version:
Command-line interface for the Botpress Agent Development Kit (ADK)
4,959 lines • 172 kB
JavaScript
// @bun
import {
CLI_VERSION,
FATAL_SPOOL_FILE,
TELEMETRY_CONFIG_DIR,
TELEMETRY_CONFIG_FILE
} from "./chunk-nxy2ya5r.js";
import {
POSTHOG_API_KEY,
POSTHOG_HOST,
isAdkError,
toSanitizedError
} from "./chunk-wzj4dc7n.js";
import {
__export,
__require
} from "./chunk-dhs2bg35.js";
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/extensions/error-tracking/modifiers/module.node.mjs
import { dirname, posix, sep } from "path";
function createModulerModifier() {
const getModuleFromFileName = createGetModuleFromFilename();
return async (frames) => {
for (const frame of frames)
frame.module = getModuleFromFileName(frame.filename);
return frames;
};
}
function createGetModuleFromFilename(basePath = process.argv[1] ? dirname(process.argv[1]) : process.cwd(), isWindows = sep === "\\") {
const normalizedBase = isWindows ? normalizeWindowsPath(basePath) : basePath;
return (filename) => {
if (!filename)
return;
const normalizedFilename = isWindows ? normalizeWindowsPath(filename) : filename;
let { dir, base: file, ext } = posix.parse(normalizedFilename);
if (ext === ".js" || ext === ".mjs" || ext === ".cjs")
file = file.slice(0, -1 * ext.length);
const decodedFile = decodeURIComponent(file);
if (!dir)
dir = ".";
const n = dir.lastIndexOf("/node_modules");
if (n > -1)
return `${dir.slice(n + 14).replace(/\//g, ".")}:${decodedFile}`;
if (dir.startsWith(normalizedBase)) {
const moduleName = dir.slice(normalizedBase.length + 1).replace(/\//g, ".");
return moduleName ? `${moduleName}:${decodedFile}` : decodedFile;
}
return decodedFile;
};
}
function normalizeWindowsPath(path) {
return path.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/featureFlagUtils.mjs
var normalizeFlagsResponse = (flagsResponse) => {
if ("flags" in flagsResponse) {
const featureFlags = getFlagValuesFromFlags(flagsResponse.flags);
const featureFlagPayloads = getPayloadsFromFlags(flagsResponse.flags);
return {
...flagsResponse,
featureFlags,
featureFlagPayloads
};
}
{
const featureFlags = flagsResponse.featureFlags ?? {};
const featureFlagPayloads = Object.fromEntries(Object.entries(flagsResponse.featureFlagPayloads || {}).map(([k, v]) => [
k,
parsePayload(v)
]));
const flags = Object.fromEntries(Object.entries(featureFlags).map(([key, value]) => [
key,
getFlagDetailFromFlagAndPayload(key, value, featureFlagPayloads[key])
]));
return {
...flagsResponse,
featureFlags,
featureFlagPayloads,
flags
};
}
};
function getFlagDetailFromFlagAndPayload(key, value, payload) {
return {
key,
enabled: typeof value == "string" ? true : value,
variant: typeof value == "string" ? value : undefined,
reason: undefined,
metadata: {
id: undefined,
version: undefined,
payload: payload ? JSON.stringify(payload) : undefined,
description: undefined
}
};
}
var getFlagValuesFromFlags = (flags) => Object.fromEntries(Object.entries(flags ?? {}).map(([key, detail]) => [
key,
getFeatureFlagValue(detail)
]).filter(([, value]) => value !== undefined));
var getPayloadsFromFlags = (flags) => {
const safeFlags = flags ?? {};
return Object.fromEntries(Object.keys(safeFlags).filter((flag) => {
const details = safeFlags[flag];
return details.enabled && details.metadata && details.metadata.payload !== undefined;
}).map((flag) => {
const payload = safeFlags[flag].metadata?.payload;
return [
flag,
payload ? parsePayload(payload) : undefined
];
}));
};
var getFeatureFlagValue = (detail) => detail === undefined ? undefined : detail.variant ?? detail.enabled;
var parsePayload = (response) => {
if (typeof response != "string")
return response;
try {
return JSON.parse(response);
} catch {
return response;
}
};
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/gzip.mjs
function isGzipSupported() {
return "CompressionStream" in globalThis && "TextEncoder" in globalThis && "Response" in globalThis && typeof Response.prototype.blob == "function";
}
async function gzipCompress(input, isDebug = true, options) {
try {
const compressedStream = new CompressionStream("gzip");
const writer = compressedStream.writable.getWriter();
const writePromise = writer.write(new TextEncoder().encode(input)).then(() => writer.close()).catch(async (err) => {
try {
await writer.abort(err);
} catch {}
throw err;
});
const responsePromise = new Response(compressedStream.readable).blob();
const [compressed] = await Promise.all([
responsePromise,
writePromise
]);
return compressed;
} catch (error) {
if (options?.rethrow)
throw error;
if (isDebug)
console.error("Failed to gzip compress data", error);
return null;
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/utils/bot-detection.mjs
var DEFAULT_BLOCKED_UA_STRS = [
"amazonbot",
"amazonproductbot",
"app.hypefactors.com",
"applebot",
"archive.org_bot",
"awariobot",
"backlinksextendedbot",
"baiduspider",
"bingbot",
"bingpreview",
"chrome-lighthouse",
"dataforseobot",
"deepscan",
"duckduckbot",
"facebookexternal",
"facebookcatalog",
"http://yandex.com/bots",
"hubspot",
"ia_archiver",
"leikibot",
"linkedinbot",
"meta-externalagent",
"mj12bot",
"msnbot",
"nessus",
"petalbot",
"pinterest",
"prerender",
"rogerbot",
"screaming frog",
"sebot-wa",
"sitebulb",
"slackbot",
"slurp",
"trendictionbot",
"turnitin",
"twitterbot",
"vercel-screenshot",
"vercelbot",
"yahoo! slurp",
"yandexbot",
"zoombot",
"bot.htm",
"bot.php",
"(bot;",
"bot/",
"crawler",
"ahrefsbot",
"ahrefssiteaudit",
"semrushbot",
"siteauditbot",
"splitsignalbot",
"gptbot",
"oai-searchbot",
"chatgpt-user",
"perplexitybot",
"better uptime bot",
"sentryuptimebot",
"uptimerobot",
"headlesschrome",
"cypress",
"google-hoteladsverifier",
"adsbot-google",
"apis-google",
"duplexweb-google",
"feedfetcher-google",
"google favicon",
"google web preview",
"google-read-aloud",
"googlebot",
"googleother",
"google-cloudvertexbot",
"googleweblight",
"mediapartners-google",
"storebot-google",
"google-inspectiontool",
"bytespider"
];
var isBlockedUA = function(ua, customBlockedUserAgents = []) {
if (!ua)
return false;
const uaLower = ua.toLowerCase();
return DEFAULT_BLOCKED_UA_STRS.concat(customBlockedUserAgents).some((blockedUA) => {
const blockedUaLower = blockedUA.toLowerCase();
return uaLower.indexOf(blockedUaLower) !== -1;
});
};
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/types.mjs
var types_PostHogPersistedProperty = /* @__PURE__ */ function(PostHogPersistedProperty) {
PostHogPersistedProperty["AnonymousId"] = "anonymous_id";
PostHogPersistedProperty["DistinctId"] = "distinct_id";
PostHogPersistedProperty["Props"] = "props";
PostHogPersistedProperty["EnablePersonProcessing"] = "enable_person_processing";
PostHogPersistedProperty["PersonMode"] = "person_mode";
PostHogPersistedProperty["FeatureFlagDetails"] = "feature_flag_details";
PostHogPersistedProperty["FeatureFlags"] = "feature_flags";
PostHogPersistedProperty["FeatureFlagPayloads"] = "feature_flag_payloads";
PostHogPersistedProperty["BootstrapFeatureFlagDetails"] = "bootstrap_feature_flag_details";
PostHogPersistedProperty["BootstrapFeatureFlags"] = "bootstrap_feature_flags";
PostHogPersistedProperty["BootstrapFeatureFlagPayloads"] = "bootstrap_feature_flag_payloads";
PostHogPersistedProperty["OverrideFeatureFlags"] = "override_feature_flags";
PostHogPersistedProperty["Queue"] = "queue";
PostHogPersistedProperty["LogsQueue"] = "logs_queue";
PostHogPersistedProperty["OptedOut"] = "opted_out";
PostHogPersistedProperty["SessionId"] = "session_id";
PostHogPersistedProperty["SessionStartTimestamp"] = "session_start_timestamp";
PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
PostHogPersistedProperty["PersonProperties"] = "person_properties";
PostHogPersistedProperty["GroupProperties"] = "group_properties";
PostHogPersistedProperty["InstalledAppBuild"] = "installed_app_build";
PostHogPersistedProperty["InstalledAppVersion"] = "installed_app_version";
PostHogPersistedProperty["SessionReplay"] = "session_replay";
PostHogPersistedProperty["SurveyLastSeenDate"] = "survey_last_seen_date";
PostHogPersistedProperty["SurveysSeen"] = "surveys_seen";
PostHogPersistedProperty["Surveys"] = "surveys";
PostHogPersistedProperty["RemoteConfig"] = "remote_config";
PostHogPersistedProperty["FlagsEndpointWasHit"] = "flags_endpoint_was_hit";
PostHogPersistedProperty["DeviceId"] = "device_id";
return PostHogPersistedProperty;
}({});
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/utils/type-utils.mjs
var nativeIsArray = Array.isArray;
var ObjProto = Object.prototype;
var type_utils_hasOwnProperty = ObjProto.hasOwnProperty;
var type_utils_toString = ObjProto.toString;
var isArray = nativeIsArray || function(obj) {
return type_utils_toString.call(obj) === "[object Array]";
};
var isObject = (x) => x === Object(x) && !isArray(x);
var isUndefined = (x) => x === undefined;
var isString = (x) => type_utils_toString.call(x) == "[object String]";
var isEmptyString = (x) => isString(x) && x.trim().length === 0;
var isNumber = (x) => type_utils_toString.call(x) == "[object Number]" && x === x;
var isPlainError = (x) => x instanceof Error;
function isPrimitive(value) {
return value === null || typeof value != "object";
}
function isBuiltin(candidate, className) {
return Object.prototype.toString.call(candidate) === `[object ${className}]`;
}
function isErrorEvent(event) {
return isBuiltin(event, "ErrorEvent");
}
function isEvent(candidate) {
return typeof Event != "undefined" && isInstanceOf(candidate, Event);
}
function isPlainObject(candidate) {
return isBuiltin(candidate, "Object");
}
function isInstanceOf(candidate, base) {
try {
return candidate instanceof base;
} catch {
return false;
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/utils/number-utils.mjs
function clampToRange(value, min, max, logger, fallbackValue) {
if (min > max) {
logger.warn("min cannot be greater than max.");
min = max;
}
if (isNumber(value))
if (value > max) {
logger.warn(" cannot be greater than max: " + max + ". Using max value instead.");
return max;
} else {
if (!(value < min))
return value;
logger.warn(" cannot be less than min: " + min + ". Using min value instead.");
return min;
}
logger.warn(" must be a number. using max or fallback. max: " + max + ", fallback: " + fallbackValue);
return clampToRange(fallbackValue || max, min, max, logger);
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/utils/bucketed-rate-limiter.mjs
var ONE_DAY_IN_MS = 86400000;
class BucketedRateLimiter {
constructor(options) {
this._buckets = {};
this._onBucketRateLimited = options._onBucketRateLimited;
this._bucketSize = clampToRange(options.bucketSize, 0, 100, options._logger);
this._refillRate = clampToRange(options.refillRate, 0, this._bucketSize, options._logger);
this._refillInterval = clampToRange(options.refillInterval, 0, ONE_DAY_IN_MS, options._logger);
}
_applyRefill(bucket, now) {
const elapsedMs = now - bucket.lastAccess;
const refillIntervals = Math.floor(elapsedMs / this._refillInterval);
if (refillIntervals > 0) {
const tokensToAdd = refillIntervals * this._refillRate;
bucket.tokens = Math.min(bucket.tokens + tokensToAdd, this._bucketSize);
bucket.lastAccess = bucket.lastAccess + refillIntervals * this._refillInterval;
}
}
consumeRateLimit(key) {
const now = Date.now();
const keyStr = String(key);
let bucket = this._buckets[keyStr];
if (bucket)
this._applyRefill(bucket, now);
else {
bucket = {
tokens: this._bucketSize,
lastAccess: now
};
this._buckets[keyStr] = bucket;
}
if (bucket.tokens === 0)
return true;
bucket.tokens--;
if (bucket.tokens === 0)
this._onBucketRateLimited?.(key);
return bucket.tokens === 0;
}
stop() {
this._buckets = {};
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/vendor/uuidv7.mjs
/*! For license information please see uuidv7.mjs.LICENSE.txt */
var DIGITS = "0123456789abcdef";
class UUID {
constructor(bytes) {
this.bytes = bytes;
}
static ofInner(bytes) {
if (bytes.length === 16)
return new UUID(bytes);
throw new TypeError("not 128-bit length");
}
static fromFieldsV7(unixTsMs, randA, randBHi, randBLo) {
if (!Number.isInteger(unixTsMs) || !Number.isInteger(randA) || !Number.isInteger(randBHi) || !Number.isInteger(randBLo) || unixTsMs < 0 || randA < 0 || randBHi < 0 || randBLo < 0 || unixTsMs > 281474976710655 || randA > 4095 || randBHi > 1073741823 || randBLo > 4294967295)
throw new RangeError("invalid field value");
const bytes = new Uint8Array(16);
bytes[0] = unixTsMs / 2 ** 40;
bytes[1] = unixTsMs / 2 ** 32;
bytes[2] = unixTsMs / 2 ** 24;
bytes[3] = unixTsMs / 2 ** 16;
bytes[4] = unixTsMs / 256;
bytes[5] = unixTsMs;
bytes[6] = 112 | randA >>> 8;
bytes[7] = randA;
bytes[8] = 128 | randBHi >>> 24;
bytes[9] = randBHi >>> 16;
bytes[10] = randBHi >>> 8;
bytes[11] = randBHi;
bytes[12] = randBLo >>> 24;
bytes[13] = randBLo >>> 16;
bytes[14] = randBLo >>> 8;
bytes[15] = randBLo;
return new UUID(bytes);
}
static parse(uuid) {
let hex;
switch (uuid.length) {
case 32:
hex = /^[0-9a-f]{32}$/i.exec(uuid)?.[0];
break;
case 36:
hex = /^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})$/i.exec(uuid)?.slice(1, 6).join("");
break;
case 38:
hex = /^\{([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})\}$/i.exec(uuid)?.slice(1, 6).join("");
break;
case 45:
hex = /^urn:uuid:([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})$/i.exec(uuid)?.slice(1, 6).join("");
break;
default:
break;
}
if (hex) {
const inner = new Uint8Array(16);
for (let i = 0;i < 16; i += 4) {
const n = parseInt(hex.substring(2 * i, 2 * i + 8), 16);
inner[i + 0] = n >>> 24;
inner[i + 1] = n >>> 16;
inner[i + 2] = n >>> 8;
inner[i + 3] = n;
}
return new UUID(inner);
}
throw new SyntaxError("could not parse UUID string");
}
toString() {
let text = "";
for (let i = 0;i < this.bytes.length; i++) {
text += DIGITS.charAt(this.bytes[i] >>> 4);
text += DIGITS.charAt(15 & this.bytes[i]);
if (i === 3 || i === 5 || i === 7 || i === 9)
text += "-";
}
return text;
}
toHex() {
let text = "";
for (let i = 0;i < this.bytes.length; i++) {
text += DIGITS.charAt(this.bytes[i] >>> 4);
text += DIGITS.charAt(15 & this.bytes[i]);
}
return text;
}
toJSON() {
return this.toString();
}
getVariant() {
const n = this.bytes[8] >>> 4;
if (n < 0)
throw new Error("unreachable");
if (n <= 7)
return this.bytes.every((e) => e === 0) ? "NIL" : "VAR_0";
if (n <= 11)
return "VAR_10";
if (n <= 13)
return "VAR_110";
if (n <= 15)
return this.bytes.every((e) => e === 255) ? "MAX" : "VAR_RESERVED";
else
throw new Error("unreachable");
}
getVersion() {
return this.getVariant() === "VAR_10" ? this.bytes[6] >>> 4 : undefined;
}
clone() {
return new UUID(this.bytes.slice(0));
}
equals(other) {
return this.compareTo(other) === 0;
}
compareTo(other) {
for (let i = 0;i < 16; i++) {
const diff = this.bytes[i] - other.bytes[i];
if (diff !== 0)
return Math.sign(diff);
}
return 0;
}
}
class V7Generator {
constructor(randomNumberGenerator) {
this.timestamp = 0;
this.counter = 0;
this.random = randomNumberGenerator ?? getDefaultRandom();
}
generate() {
return this.generateOrResetCore(Date.now(), 1e4);
}
generateOrAbort() {
return this.generateOrAbortCore(Date.now(), 1e4);
}
generateOrResetCore(unixTsMs, rollbackAllowance) {
let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
if (value === undefined) {
this.timestamp = 0;
value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
}
return value;
}
generateOrAbortCore(unixTsMs, rollbackAllowance) {
const MAX_COUNTER = 4398046511103;
if (!Number.isInteger(unixTsMs) || unixTsMs < 1 || unixTsMs > 281474976710655)
throw new RangeError("`unixTsMs` must be a 48-bit positive integer");
if (rollbackAllowance < 0 || rollbackAllowance > 281474976710655)
throw new RangeError("`rollbackAllowance` out of reasonable range");
if (unixTsMs > this.timestamp) {
this.timestamp = unixTsMs;
this.resetCounter();
} else {
if (!(unixTsMs + rollbackAllowance >= this.timestamp))
return;
this.counter++;
if (this.counter > MAX_COUNTER) {
this.timestamp++;
this.resetCounter();
}
}
return UUID.fromFieldsV7(this.timestamp, Math.trunc(this.counter / 2 ** 30), this.counter & 2 ** 30 - 1, this.random.nextUint32());
}
resetCounter() {
this.counter = 1024 * this.random.nextUint32() + (1023 & this.random.nextUint32());
}
generateV4() {
const bytes = new Uint8Array(Uint32Array.of(this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32()).buffer);
bytes[6] = 64 | bytes[6] >>> 4;
bytes[8] = 128 | bytes[8] >>> 2;
return UUID.ofInner(bytes);
}
}
var getDefaultRandom = () => ({
nextUint32: () => 65536 * Math.trunc(65536 * Math.random()) + Math.trunc(65536 * Math.random())
});
var defaultGenerator;
var uuidv7 = () => uuidv7obj().toString();
var uuidv7obj = () => (defaultGenerator || (defaultGenerator = new V7Generator)).generate();
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/utils/promise-queue.mjs
class PromiseQueue {
add(promise) {
const promiseUUID = uuidv7();
this.promiseByIds[promiseUUID] = promise;
promise.catch(() => {}).finally(() => {
delete this.promiseByIds[promiseUUID];
});
return promise;
}
async join() {
let promises = Object.values(this.promiseByIds);
let length = promises.length;
while (length > 0) {
await Promise.all(promises);
promises = Object.values(this.promiseByIds);
length = promises.length;
}
}
get length() {
return Object.keys(this.promiseByIds).length;
}
constructor() {
this.promiseByIds = {};
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/utils/logger.mjs
function createConsole(consoleLike = console) {
const lockedMethods = {
log: consoleLike.log.bind(consoleLike),
warn: consoleLike.warn.bind(consoleLike),
error: consoleLike.error.bind(consoleLike),
debug: consoleLike.debug.bind(consoleLike)
};
return lockedMethods;
}
var _createLogger = (prefix, maybeCall, consoleLike) => {
function _log(level, ...args) {
maybeCall(() => {
const consoleMethod = consoleLike[level];
consoleMethod(prefix, ...args);
});
}
const logger = {
debug: (...args) => {
_log("debug", ...args);
},
info: (...args) => {
_log("log", ...args);
},
warn: (...args) => {
_log("warn", ...args);
},
error: (...args) => {
_log("error", ...args);
},
critical: (...args) => {
consoleLike["error"](prefix, ...args);
},
createLogger: (additionalPrefix) => _createLogger(`${prefix} ${additionalPrefix}`, maybeCall, consoleLike)
};
return logger;
};
var passThrough = (fn) => fn();
function createLogger(prefix, maybeCall = passThrough) {
return _createLogger(prefix, maybeCall, createConsole());
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/utils/user-agent-utils.mjs
var MOBILE = "Mobile";
var IOS = "iOS";
var ANDROID = "Android";
var TABLET = "Tablet";
var ANDROID_TABLET = ANDROID + " " + TABLET;
var APPLE = "Apple";
var APPLE_WATCH = APPLE + " Watch";
var SAFARI = "Safari";
var BLACKBERRY = "BlackBerry";
var SAMSUNG = "Samsung";
var SAMSUNG_BROWSER = SAMSUNG + "Browser";
var SAMSUNG_INTERNET = SAMSUNG + " Internet";
var CHROME = "Chrome";
var CHROME_OS = CHROME + " OS";
var CHROME_IOS = CHROME + " " + IOS;
var INTERNET_EXPLORER = "Internet Explorer";
var INTERNET_EXPLORER_MOBILE = INTERNET_EXPLORER + " " + MOBILE;
var OPERA = "Opera";
var OPERA_MINI = OPERA + " Mini";
var EDGE = "Edge";
var MICROSOFT_EDGE = "Microsoft " + EDGE;
var FIREFOX = "Firefox";
var FIREFOX_IOS = FIREFOX + " " + IOS;
var NINTENDO = "Nintendo";
var PLAYSTATION = "PlayStation";
var XBOX = "Xbox";
var ANDROID_MOBILE = ANDROID + " " + MOBILE;
var MOBILE_SAFARI = MOBILE + " " + SAFARI;
var WINDOWS = "Windows";
var WINDOWS_PHONE = WINDOWS + " Phone";
var GENERIC = "Generic";
var GENERIC_MOBILE = GENERIC + " " + MOBILE.toLowerCase();
var GENERIC_TABLET = GENERIC + " " + TABLET.toLowerCase();
var KONQUEROR = "Konqueror";
var BROWSER_VERSION_REGEX_SUFFIX = "(\\d+(\\.\\d+)?)";
var DEFAULT_BROWSER_VERSION_REGEX = new RegExp("Version/" + BROWSER_VERSION_REGEX_SUFFIX);
var XBOX_REGEX = new RegExp(XBOX, "i");
var PLAYSTATION_REGEX = new RegExp(PLAYSTATION + " \\w+", "i");
var NINTENDO_REGEX = new RegExp(NINTENDO + " \\w+", "i");
var BLACKBERRY_REGEX = new RegExp(BLACKBERRY + "|PlayBook|BB10", "i");
var windowsVersionMap = {
"NT3.51": "NT 3.11",
"NT4.0": "NT 4.0",
"5.0": "2000",
"5.1": "XP",
"5.2": "XP",
"6.0": "Vista",
"6.1": "7",
"6.2": "8",
"6.3": "8.1",
"6.4": "10",
"10.0": "10"
};
var versionRegexes = {
[INTERNET_EXPLORER_MOBILE]: [
new RegExp("rv:" + BROWSER_VERSION_REGEX_SUFFIX)
],
[MICROSOFT_EDGE]: [
new RegExp(EDGE + "?\\/" + BROWSER_VERSION_REGEX_SUFFIX)
],
[CHROME]: [
new RegExp("(" + CHROME + "|CrMo)\\/" + BROWSER_VERSION_REGEX_SUFFIX)
],
[CHROME_IOS]: [
new RegExp("CriOS\\/" + BROWSER_VERSION_REGEX_SUFFIX)
],
"UC Browser": [
new RegExp("(UCBrowser|UCWEB)\\/" + BROWSER_VERSION_REGEX_SUFFIX)
],
[SAFARI]: [
DEFAULT_BROWSER_VERSION_REGEX
],
[MOBILE_SAFARI]: [
DEFAULT_BROWSER_VERSION_REGEX
],
[OPERA]: [
new RegExp("(" + OPERA + "|OPR)\\/" + BROWSER_VERSION_REGEX_SUFFIX)
],
[FIREFOX]: [
new RegExp(FIREFOX + "\\/" + BROWSER_VERSION_REGEX_SUFFIX)
],
[FIREFOX_IOS]: [
new RegExp("FxiOS\\/" + BROWSER_VERSION_REGEX_SUFFIX)
],
[KONQUEROR]: [
new RegExp("Konqueror[:/]?" + BROWSER_VERSION_REGEX_SUFFIX, "i")
],
[BLACKBERRY]: [
new RegExp(BLACKBERRY + " " + BROWSER_VERSION_REGEX_SUFFIX),
DEFAULT_BROWSER_VERSION_REGEX
],
[ANDROID_MOBILE]: [
new RegExp("android\\s" + BROWSER_VERSION_REGEX_SUFFIX, "i")
],
[SAMSUNG_INTERNET]: [
new RegExp(SAMSUNG_BROWSER + "\\/" + BROWSER_VERSION_REGEX_SUFFIX)
],
[INTERNET_EXPLORER]: [
new RegExp("(rv:|MSIE )" + BROWSER_VERSION_REGEX_SUFFIX)
],
Mozilla: [
new RegExp("rv:" + BROWSER_VERSION_REGEX_SUFFIX)
]
};
var osMatchers = [
[
new RegExp(XBOX + "; " + XBOX + " (.*?)[);]", "i"),
(match) => [
XBOX,
match && match[1] || ""
]
],
[
new RegExp(NINTENDO, "i"),
[
NINTENDO,
""
]
],
[
new RegExp(PLAYSTATION, "i"),
[
PLAYSTATION,
""
]
],
[
BLACKBERRY_REGEX,
[
BLACKBERRY,
""
]
],
[
new RegExp(WINDOWS, "i"),
(_, user_agent) => {
if (/Phone/.test(user_agent) || /WPDesktop/.test(user_agent))
return [
WINDOWS_PHONE,
""
];
if (new RegExp(MOBILE).test(user_agent) && !/IEMobile\b/.test(user_agent))
return [
WINDOWS + " " + MOBILE,
""
];
const match = /Windows NT ([0-9.]+)/i.exec(user_agent);
if (match && match[1]) {
const version = match[1];
let osVersion = windowsVersionMap[version] || "";
if (/arm/i.test(user_agent))
osVersion = "RT";
return [
WINDOWS,
osVersion
];
}
return [
WINDOWS,
""
];
}
],
[
/((iPhone|iPad|iPod).*?OS (\d+)_(\d+)_?(\d+)?|iPhone)/,
(match) => {
if (match && match[3]) {
const versionParts = [
match[3],
match[4],
match[5] || "0"
];
return [
IOS,
versionParts.join(".")
];
}
return [
IOS,
""
];
}
],
[
/(watch.*\/(\d+\.\d+\.\d+)|watch os,(\d+\.\d+),)/i,
(match) => {
let version = "";
if (match && match.length >= 3)
version = isUndefined(match[2]) ? match[3] : match[2];
return [
"watchOS",
version
];
}
],
[
new RegExp("(" + ANDROID + " (\\d+)\\.(\\d+)\\.?(\\d+)?|" + ANDROID + ")", "i"),
(match) => {
if (match && match[2]) {
const versionParts = [
match[2],
match[3],
match[4] || "0"
];
return [
ANDROID,
versionParts.join(".")
];
}
return [
ANDROID,
""
];
}
],
[
/Mac OS X (\d+)[_.](\d+)[_.]?(\d+)?/i,
(match) => {
const result = [
"Mac OS X",
""
];
if (match && match[1]) {
const versionParts = [
match[1],
match[2],
match[3] || "0"
];
result[1] = versionParts.join(".");
}
return result;
}
],
[
/Mac/i,
[
"Mac OS X",
""
]
],
[
/CrOS/,
[
CHROME_OS,
""
]
],
[
/Linux|debian/i,
[
"Linux",
""
]
]
];
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/utils/index.mjs
var STRING_FORMAT = "utf8";
function removeTrailingSlash(url) {
return url?.replace(/\/+$/, "");
}
async function retriable(fn, props) {
let lastError = null;
for (let i = 0;i < props.retryCount + 1; i++) {
if (i > 0)
await new Promise((r) => setTimeout(r, props.retryDelay));
try {
const res = await fn();
return res;
} catch (e) {
lastError = e;
if (!props.retryCheck(e))
throw e;
}
}
throw lastError;
}
function currentISOTime() {
return new Date().toISOString();
}
function safeSetTimeout(fn, timeout) {
const t = setTimeout(fn, timeout);
t?.unref && t?.unref();
return t;
}
var isError = (x) => x instanceof Error;
function allSettled(promises) {
return Promise.all(promises.map((p) => (p ?? Promise.resolve()).then((value) => ({
status: "fulfilled",
value
}), (reason) => ({
status: "rejected",
reason
}))));
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/logs/logs-utils.mjs
var OTLP_SEVERITY_MAP = {
trace: {
text: "TRACE",
number: 1
},
debug: {
text: "DEBUG",
number: 5
},
info: {
text: "INFO",
number: 9
},
warn: {
text: "WARN",
number: 13
},
error: {
text: "ERROR",
number: 17
},
fatal: {
text: "FATAL",
number: 21
}
};
var DEFAULT_OTLP_SEVERITY = OTLP_SEVERITY_MAP.info;
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/eventemitter.mjs
class SimpleEventEmitter {
constructor() {
this.events = {};
this.events = {};
}
on(event, listener) {
if (!this.events[event])
this.events[event] = [];
this.events[event].push(listener);
return () => {
this.events[event] = this.events[event].filter((x) => x !== listener);
};
}
emit(event, payload) {
for (const listener of this.events[event] || [])
listener(payload);
for (const listener of this.events["*"] || [])
listener(event, payload);
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/posthog-core-stateless.mjs
class PostHogFetchHttpError extends Error {
constructor(response, reqByteLength) {
super("HTTP error while fetching PostHog: status=" + response.status + ", reqByteLength=" + reqByteLength), this.response = response, this.reqByteLength = reqByteLength, this.name = "PostHogFetchHttpError";
}
get status() {
return this.response.status;
}
get text() {
return this.response.text();
}
get json() {
return this.response.json();
}
}
class PostHogFetchNetworkError extends Error {
constructor(error) {
super("Network error while fetching PostHog", error instanceof Error ? {
cause: error
} : {}), this.error = error, this.name = "PostHogFetchNetworkError";
}
}
async function logFlushError(err) {
if (err instanceof PostHogFetchHttpError) {
let text = "";
try {
text = await err.text;
} catch {}
console.error(`Error while flushing PostHog: message=${err.message}, response body=${text}`, err);
} else
console.error("Error while flushing PostHog", err);
return Promise.resolve();
}
function isPostHogFetchError(err) {
return typeof err == "object" && (err instanceof PostHogFetchHttpError || err instanceof PostHogFetchNetworkError);
}
function isPostHogFetchContentTooLargeError(err) {
return typeof err == "object" && err instanceof PostHogFetchHttpError && err.status === 413;
}
class PostHogCoreStateless {
constructor(apiKey, options = {}) {
this.flushPromise = null;
this.shutdownPromise = null;
this.promiseQueue = new PromiseQueue;
this._events = new SimpleEventEmitter;
this._isInitialized = false;
const normalizedApiKey = typeof apiKey == "string" ? apiKey.trim() : "";
const normalizedHost = typeof options.host == "string" ? options.host.trim() : "";
const missingApiKey = !normalizedApiKey;
this._logger = createLogger("[PostHog]", this.logMsgIfDebug.bind(this));
if (missingApiKey)
this._logger.error("You must pass your PostHog project's api key. The client will be disabled.");
this.apiKey = normalizedApiKey;
this.host = removeTrailingSlash(normalizedHost || "https://us.i.posthog.com");
this.flushAt = options.flushAt ? Math.max(options.flushAt, 1) : 20;
this.maxBatchSize = Math.max(this.flushAt, options.maxBatchSize ?? 100);
this.maxQueueSize = Math.max(this.flushAt, options.maxQueueSize ?? 1000);
this.flushInterval = options.flushInterval ?? 1e4;
this.preloadFeatureFlags = options.preloadFeatureFlags ?? true;
this.defaultOptIn = options.defaultOptIn ?? true;
this.disableSurveys = options.disableSurveys ?? false;
this._retryOptions = {
retryCount: options.fetchRetryCount ?? 3,
retryDelay: options.fetchRetryDelay ?? 3000,
retryCheck: isPostHogFetchError
};
this.requestTimeout = options.requestTimeout ?? 1e4;
this.featureFlagsRequestTimeoutMs = options.featureFlagsRequestTimeoutMs ?? 3000;
this.remoteConfigRequestTimeoutMs = options.remoteConfigRequestTimeoutMs ?? 3000;
this.disableGeoip = options.disableGeoip ?? true;
this.disabled = (options.disabled ?? false) || missingApiKey;
this.historicalMigration = options?.historicalMigration ?? false;
this._initPromise = Promise.resolve();
this._isInitialized = true;
this.evaluationContexts = options?.evaluationContexts ?? options?.evaluationEnvironments;
if (options?.evaluationEnvironments && !options?.evaluationContexts)
this._logger.warn("evaluationEnvironments is deprecated. Use evaluationContexts instead. This property will be removed in a future version.");
this.disableCompression = !isGzipSupported() || (options?.disableCompression ?? false);
}
logMsgIfDebug(fn) {
if (this.isDebug)
fn();
}
wrap(fn) {
if (this.disabled)
return void this._logger.warn("The client is disabled");
if (this._isInitialized)
return fn();
this._initPromise.then(() => fn());
}
getCommonEventProperties() {
return {
$lib: this.getLibraryId(),
$lib_version: this.getLibraryVersion()
};
}
get optedOut() {
return this.getPersistedProperty(types_PostHogPersistedProperty.OptedOut) ?? !this.defaultOptIn;
}
async optIn() {
this.wrap(() => {
this.setPersistedProperty(types_PostHogPersistedProperty.OptedOut, false);
});
}
async optOut() {
this.wrap(() => {
this.setPersistedProperty(types_PostHogPersistedProperty.OptedOut, true);
});
}
on(event, cb) {
return this._events.on(event, cb);
}
debug(enabled = true) {
this.removeDebugCallback?.();
if (enabled) {
const removeDebugCallback = this.on("*", (event, payload) => this._logger.info(event, payload));
this.removeDebugCallback = () => {
removeDebugCallback();
this.removeDebugCallback = undefined;
};
}
}
get isDebug() {
return !!this.removeDebugCallback;
}
get isDisabled() {
return this.disabled;
}
buildPayload(payload) {
return {
distinct_id: payload.distinct_id,
event: payload.event,
properties: {
...payload.properties || {},
...this.getCommonEventProperties()
}
};
}
addPendingPromise(promise) {
return this.promiseQueue.add(promise);
}
identifyStateless(distinctId, properties, options) {
this.wrap(() => {
const payload = {
...this.buildPayload({
distinct_id: distinctId,
event: "$identify",
properties
})
};
this.enqueue("identify", payload, options);
});
}
async identifyStatelessImmediate(distinctId, properties, options) {
const payload = {
...this.buildPayload({
distinct_id: distinctId,
event: "$identify",
properties
})
};
await this.sendImmediate("identify", payload, options);
}
captureStateless(distinctId, event, properties, options) {
this.wrap(() => {
const payload = this.buildPayload({
distinct_id: distinctId,
event,
properties
});
this.enqueue("capture", payload, options);
});
}
async captureStatelessImmediate(distinctId, event, properties, options) {
const payload = this.buildPayload({
distinct_id: distinctId,
event,
properties
});
await this.sendImmediate("capture", payload, options);
}
aliasStateless(alias, distinctId, properties, options) {
this.wrap(() => {
const payload = this.buildPayload({
event: "$create_alias",
distinct_id: distinctId,
properties: {
...properties || {},
distinct_id: distinctId,
alias
}
});
this.enqueue("alias", payload, options);
});
}
async aliasStatelessImmediate(alias, distinctId, properties, options) {
const payload = this.buildPayload({
event: "$create_alias",
distinct_id: distinctId,
properties: {
...properties || {},
distinct_id: distinctId,
alias
}
});
await this.sendImmediate("alias", payload, options);
}
groupIdentifyStateless(groupType, groupKey, groupProperties, options, distinctId, eventProperties) {
this.wrap(() => {
const payload = this.buildPayload({
distinct_id: distinctId || `$${groupType}_${groupKey}`,
event: "$groupidentify",
properties: {
$group_type: groupType,
$group_key: groupKey,
$group_set: groupProperties || {},
...eventProperties || {}
}
});
this.enqueue("capture", payload, options);
});
}
async getRemoteConfig() {
await this._initPromise;
let host = this.host;
if (host === "https://us.i.posthog.com")
host = "https://us-assets.i.posthog.com";
else if (host === "https://eu.i.posthog.com")
host = "https://eu-assets.i.posthog.com";
const url = `${host}/array/${this.apiKey}/config`;
const fetchOptions = {
method: "GET",
headers: {
...this.getCustomHeaders(),
"Content-Type": "application/json"
}
};
return this.fetchWithRetry(url, fetchOptions, {
retryCount: 0
}, this.remoteConfigRequestTimeoutMs).then((response) => response.json()).catch((error) => {
this._logger.error("Remote config could not be loaded", error);
this._events.emit("error", error);
});
}
async getFlags(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}, fetchConfig = false) {
await this._initPromise;
const configParam = fetchConfig ? "&config=true" : "";
const url = `${this.host}/flags/?v=2${configParam}`;
const requestData = {
token: this.apiKey,
distinct_id: distinctId,
groups,
person_properties: personProperties,
group_properties: groupProperties,
...extraPayload
};
if (personProperties.$device_id)
requestData.$device_id = personProperties.$device_id;
if (this.evaluationContexts && this.evaluationContexts.length > 0)
requestData.evaluation_contexts = this.evaluationContexts;
const fetchOptions = {
method: "POST",
headers: {
...this.getCustomHeaders(),
"Content-Type": "application/json"
},
body: JSON.stringify(requestData)
};
this._logger.info("Flags URL", url);
return this.fetchWithRetry(url, fetchOptions, {
retryCount: 0
}, this.featureFlagsRequestTimeoutMs).then((response) => response.json()).then((response) => ({
success: true,
response: normalizeFlagsResponse(response)
})).catch((error) => {
this._events.emit("error", error);
return {
success: false,
error: this.categorizeRequestError(error)
};
});
}
categorizeRequestError(error) {
if (error instanceof PostHogFetchHttpError)
return {
type: "api_error",
statusCode: error.status
};
if (error instanceof PostHogFetchNetworkError) {
const cause = error.error;
if (cause instanceof Error && (cause.name === "AbortError" || cause.name === "TimeoutError"))
return {
type: "timeout"
};
return {
type: "connection_error"
};
}
return {
type: "unknown_error"
};
}
async getFeatureFlagStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
await this._initPromise;
const flagDetailResponse = await this.getFeatureFlagDetailStateless(key, distinctId, groups, personProperties, groupProperties, disableGeoip);
if (flagDetailResponse === undefined)
return {
response: undefined,
requestId: undefined
};
let response = getFeatureFlagValue(flagDetailResponse.response);
if (response === undefined)
response = false;
return {
response,
requestId: flagDetailResponse.requestId
};
}
async getFeatureFlagDetailStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
await this._initPromise;
const flagsResponse = await this.getFeatureFlagDetailsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, [
key
]);
if (flagsResponse === undefined)
return;
const featureFlags = flagsResponse.flags;
const flagDetail = featureFlags[key];
return {
response: flagDetail,
requestId: flagsResponse.requestId,
evaluatedAt: flagsResponse.evaluatedAt
};
}
async getFeatureFlagPayloadStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
await this._initPromise;
const payloads = await this.getFeatureFlagPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, [
key
]);
if (!payloads)
return;
const response = payloads[key];
if (response === undefined)
return null;
return response;
}
async getFeatureFlagPayloadsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip, flagKeysToEvaluate) {
await this._initPromise;
const payloads = (await this.getFeatureFlagsAndPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, flagKeysToEvaluate)).payloads;
return payloads;
}
async getFeatureFlagsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip, flagKeysToEvaluate) {
await this._initPromise;
return await this.getFeatureFlagsAndPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, flagKeysToEvaluate);
}
async getFeatureFlagsAndPayloadsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip, flagKeysToEvaluate) {
await this._initPromise;
const featureFlagDetails = await this.getFeatureFlagDetailsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, flagKeysToEvaluate);
if (!featureFlagDetails)
return {
flags: undefined,
payloads: undefined,
requestId: undefined
};
return {
flags: featureFlagDetails.featureFlags,
payloads: featureFlagDetails.featureFlagPayloads,
requestId: featureFlagDetails.requestId
};
}
async getFeatureFlagDetailsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip, flagKeysToEvaluate) {
await this._initPromise;
const extraPayload = {};
if (disableGeoip ?? this.disableGeoip)
extraPayload["geoip_disable"] = true;
if (flagKeysToEvaluate)
extraPayload["flag_keys_to_evaluate"] = flagKeysToEvaluate;
const result = await this.getFlags(distinctId, groups, personProperties, groupProperties, extraPayload);
if (!result.success)
return;
const flagsResponse = result.response;
if (flagsResponse.errorsWhileComputingFlags)
console.error("[FEATURE FLAGS] Error while computing feature flags, some flags may be missing or incorrect. Learn more at https://posthog.com/docs/feature-flags/best-practices");
if (flagsResponse.quotaLimited?.includes("feature_flags")) {
console.warn("[FEATURE FLAGS] Feature flags quota limit exceeded - feature flags unavailable. Learn more about billing limits at https://posthog.com/docs/billing/limits-alerts");
return {
flags: {},
featureFlags: {},
featureFlagPayloads: {},
requestId: flagsResponse?.requestId,
quotaLimited: flagsResponse.quotaLimited
};
}
return flagsResponse;
}
async getSurveysStateless() {
await this._initPromise;
if (this.disableSurveys === true) {
this._logger.info("Loading surveys is disabled.");
return [];
}
const url = `${this.host}/api/surveys/?token=${this.apiKey}`;
const fetchOptions = {
method: "GET",
headers: {
...this.getCustomHeaders(),
"Content-Type": "application/json"
}
};
const response = await this.fetchWithRetry(url, fetchOptions).then((response2) => {
if (response2.status !== 200 || !response2.json) {
const msg = `Surveys API could not be loaded: ${response2.status}`;
const error = new Error(msg);
this._logger.error(error);
this._events.emit("error", new Error(msg));
return;
}
return response2.json();
}).catch((error) => {
this._logger.error("Surveys API could not be loaded", error);
this._events.emit("error", error);
});
const newSurveys = response?.surveys;
if (newSurveys)
this._logger.info("Surveys fetched from API: ", JSON.stringify(newSurveys));
return newSurveys ?? [];
}
get props() {
if (!this._props)
this._props = this.getPersistedProperty(types_PostHogPersistedProperty.Props);
return this._props || {};
}
set props(val) {
this._props = val;
}
async register(properties) {
this.wrap(() => {
this.props = {
...this.props,
...properties
};
this.setPersistedProperty(types_PostHogPersistedProperty.Props, this.props);
});
}
async unregister(property) {
this.wrap(() => {
delete this.props[property];
this.setPersistedProperty(types_PostHogPersistedProperty.Props, this.props);
});
}
processBeforeEnqueue(message) {
return message;
}
async flushStorage() {}
enqueue(type, _message, options) {
this.wrap(() => {
if (this.optedOut)
return void this._events.emit(type, "Library is disabled. Not sending event. To re-enable, call posthog.optIn()");
let message = this.prepareMessage(type, _message, options);
message = this.processBeforeEnqueue(message);
if (message === null)
return;
const queue = this.getPersistedProperty(types_PostHogPersistedProperty.Queue) || [];
if (queue.length >= this.maxQueueSize) {
queue.shift();
this._logger.info("Queue is full, the oldest event is dropped.");
}
queue.push({
message
});
this.setPersistedProperty(types_PostHogPersistedProperty.Queue, queue);
this._events.emit(type, message);
if (queue.length >= this.flushAt)
this.flushBackground();
if (this.flushInterval && !this._flushTimer)
this._flushTimer = safeSetTimeout(() => this.flushBackground(), this.flushInterval);
});
}
async sendImmediate(type, _message, options) {
if (this.disabled)
return void this._logger.warn("The client is disabled");
if (!this._isInitialized)
await this._initPromise;
if (this.optedOut)
return void this._events.emit(type, "Library is disabled. Not sending event. To re-enable, call posthog.optIn()");
let message = this.prepareMessage(type, _message, options);
message = this.processBeforeEnqueue(message);
if (message === null)
return;
const data = {
api_key: this.apiKey,
batch: [
message
],
sent_at: currentISOTime()
};
if (this.historicalMigration)
data.historical_migration = true;
const payload = JSON.stringify(data);
const url = `${this.host}/batch/`;
const gzippedPayload = this.disableCompression ? null : await gzipCompress(payload, this.isDebug);
const fetchOptions = {
method: "POST",
headers: {
...this.getCustomHeaders(),
"Content-Type": "application/json",
...gzippedPayload !== null && {
"Content-Encoding": "gzip"
}
},
body: gzippedPayload || payload
};
try {
await this.fetchWithRetry(url, fetchOptions);
} catch (err) {
this._events.emit("error", err);
}
}
prepareMessage(type, _message, options) {
const message = {
..._message,
type,
library: this.getLibraryId(),
library_version: this.getLibraryVersion(),
timestamp: options?.timestamp ? options?.timestamp : currentISOTime(),
uuid: options?.uuid ? options.uuid : uuidv7()
};
const addGeoipDisableProperty = options?.disableGeoip ?? this.disableGeoip;
if (addGeoipDisableProperty) {
if (!message.properties)
message.properties = {};
message["properties"]["$geoip_disable"] = true;
}
if (message.distinctId) {
message.distinct_id = message.distinctId;
delete message.distinctId;
}
return message;
}
clearFlushTimer() {
if (this._flushTimer) {
clearTimeout(this._flushTimer);
this._flushTimer = undefined;
}
}
flushBackground() {
this.flush().catch(async (err) => {
await logFlushError(err);
});
}
async flush() {
const nextFlushPromise = allSettled([
this.flushPromise
]).then(() => this._flush());
this.flushPromise = nextFlushPromise;
this.addPendingPromise(nextFlushPromise);
allSettled([
nextFlushPromise
]).then(() => {
if (this.flushPromise === nextFlushPromise)
this.flushPromise = null;
});
return nextFlushPromise;
}
getCustomHeaders() {
const customUserAgent = this.getCustomUserAgent();
const headers = {};
if (customUserAgent && customUserAgent !== "")
headers["User-Agent"] = customUserAgent;
return headers;
}
async _flush() {
this.clearFlushTimer();
await this._initPromise;
let queue = this.getPersistedProperty(types_PostHogPersistedProperty.Queue) || [];
if (!queue.length)
return;
const sentMessages = [];
const originalQueueLength = queue.length;
while (queue.length > 0 && sentMessages.length < originalQueueLength) {
const batchItems = queue.slice(0, this.maxBatchSize);
const batchMessages = batchItems.map((item) => item.message);
const persistQueueChange = async () => {
const refreshedQueue = this.getPersistedProperty(types_PostHogPersistedProperty.Queue) || [];
const newQueue = refreshedQueue.slice(batchItems.length);
this.setPersistedProperty(types_PostHogPersistedProperty.Queue, newQueue);
queue = newQueue;
await this.flushStorage();
};
const data = {
api_key: this.apiKey,
batch: batchMessages,
sent_at: currentISOTime()
};
if (this.historicalMigration)
data.historical_migration = true;
const payload = JSON.stringify(data);
const url = `${this.host}/batch/`;
const gzippedPayload = this.disableCompression ? null : await gzipCompress(payload, this.isDebug);
const fetchOptions = {
method: "POST",
headers: {
...this.getCustomHeaders(),
"Content-Type": "application/json",
...gzippedPayload !== null && {
"Content-Encoding": "gzip"
}
},
body: gzippedPayload || payload
};
const retryOptions = {
retryCheck: (err) => {
if (isPostHogFetchContentTooLargeError(err))
return false;
return isPostHogFetchError(err);
}
};
try {
await this.fetchWithRetry(url, fetchOptions, retryOptions);
} catch (err) {
if (isPostHogFetchContentTooLargeError(err) && batchMessages.length > 1) {
this.maxBatchSize = Math.max(1, Math.floor(batchMessages.length / 2));
this._logger.warn(`Received 413 when sending batch of size ${batchMessages.length}, reducing batch size to ${this.maxBatchSize}`);
continue;
}
if (!(err instanceof PostHogFetchNetworkError))
await persistQueueChange();
this._events.emit("error", err);
throw err;
}
await persistQueueChange();
sentMessages.push(...batchMessages);
}
this._events.emit("flush", sentMessages);
}
async _sendLogsBatch(payload) {
const serialized = JSON.stringify(payload);
const url = `${this.host}/i/v1/logs?token=${encodeURIComponent(this.apiKey)}`;
const gzippedPayload = this.disableCompression ? null : await gzipCompress(serialized, this.isDebug);
const fetchOptions = {
method: "POST",
headers: {
...this.getCustomHeaders(),
"Content-Type": "application/json",
...gzippedPayload !== null && {
"Content-Encoding": "gzip"
}
},
body: gzippedPayload || serialized
};
try {
await this.fetchWithRetry(url, fetchOptions, {
retryCheck: (err) => {
if (isPostHogFetchContentTooLargeError(err))
return false;
return isPostHogFetchError(err);
}
});
return {
kind: "ok"
};
} catch (err) {
if (isPostHogFetchContentTooLargeError(err))
return {
kind: "too-large"
};
if (err instanceof PostHogFetchNetworkError)
return {
kind: "retry-later",
error: err
};
return {
kind: "fatal",
error: err
};
}
}
async fetchWithRetry(url, options, retryOptions, requestTimeout) {
const body = options.body ? options.body : "";
let reqByteLength = -1;
try {
reqByteLength = body instanceof Blob ? body.size : Buffer.byteLength(body, STRING_FORMAT);
} catch {
if (body instanceof Blob)
reqByteLength = body.size;
else {
const encoded = new TextEncoder().encode(body);
reqByteLength = encoded.length;
}
}
return await retriable(async () => {
const ctrl = new AbortController;
const timeoutMs = requestTimeout ?? this.requestTimeout;
const timer = safeSetTimeout(() => ctrl.abort(), timeoutMs);
let res = null;
try {
res = await this.fetch(url, {
signal: ctrl.signal,
...options
});
} catch (e) {
throw new PostHogFetchNetworkError(e);
} finally {
clearTimeout(timer);
}
const isNoCors = options.mode === "no-cors";
if (!isNoCors && (res.status < 200 || res.status >= 400))
throw new PostHogFetchHttpError(res, reqByteLength);
return res;
}, {
...this._retryOptions,
...retryOptions
});
}
async _shutdown(shutdownTimeoutMs = 30000) {
await this._initPromise;
let hasTimedOut = false;
this.clearFlushTimer();
const doShutdown = async () => {
try {
await this.promiseQueue.join();
while (true) {
const queue = this.getPersistedProperty(types_PostHogPersistedProperty.Queue) || [];
if (queue.length === 0)
break;
await this.flush();
if (hasTimedOut)
break;
}
} catch (e) {
if (!isPostHogFetchError(e))
throw e;
await logFlushError(e);
}
};
let timeoutHandle;
try {
return await Promise.race([
new Promise((_, reject) => {
timeoutHandle = safeSetTimeout(() => {
this._logger.error("Timed out while shutting down PostHog");
hasTimedOut = true;
reject("Timeout while shutting down PostHog. Some events may not have been sent.");
}, shutdownTimeoutMs);
}),
doShutdown()
]);
} finally {
clearTimeout(timeoutHandle);
}
}
async shutdown(shutdownTimeoutMs = 30000) {
if (this.shutdownPromise)
this._logger.warn("shutdown() called while already shutting down. shutdown() is meant to be called once before process exit - use flush() for per-request cleanup");
else
this.shutdownPromise = this._shutdown(shutdownTimeoutMs).finally(() => {
this.shutdownPromise = null;
});
return this.shutdownPromise;
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/index.mjs
var exports_error_tracking = {};
__export(exports_error_tracking, {
winjsStackLineParser: () => winjsStackLineParser,
stripReservedExceptionStepFields: () => stripReservedExceptionStepFields,
reverseAndStripFrames: () => reverseAndStripFrames,
resolveExceptionStepsConfig: () => resolveExceptionStepsConfig,
opera11StackLineParser: () => opera11StackLineParser,
opera10StackLineParser: () => opera10StackLineParser,
nodeStackLineParser: () => nodeStackLineParser,
getUtf8ByteLength: () => getUtf8ByteLength,
geckoStackLineParser: () => geckoStackLineParser,
createStackParser: () => createStackParser,
createDefaultStackParser: () => createDefaultStackParser,
chromeStackLineParser: () => chromeStackLineParser,
StringCoercer: () => StringCoercer,
ReduceableCache: () => ReduceableCache,
PromiseRejectionEventCoercer: () => PromiseRejectionEventCoercer,
PrimitiveCoercer: () => PrimitiveCoercer,
ObjectCoercer: () => ObjectCoercer,
ExceptionStepsBuffer: () => ExceptionStepsBuffer,
EventCoercer: () => EventCoercer,
ErrorPropertiesBuilder: () => ErrorPropertiesBuilder,
ErrorEventCoercer: () => ErrorEventCoercer,
ErrorCoercer: () => ErrorCoercer,
EXCEPTION_STEP_INTERNAL_FIELDS: () => EXCEPTION_STEP_INTERNAL_FIELDS,
DOMExceptionCoercer: () => DOMExceptionCoercer,
DEFAULT_EXCEPTION_STEPS_CONFIG: () => DEFAULT_EXCEPTION_STEPS_CONFIG
});
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/chunk-ids.mjs
var parsedStackResults;
var lastKeysCount;
var cachedFilenameChunkIds;
function getFilenameToChunkIdMap(stackParser) {
const chunkIdMap = globalThis._posthogChunkIds;
if (!chunkIdMap)
return;
const chunkIdKeys = Object.keys(chunkIdMap);
if (cachedFilenameChunkIds && chunkIdKeys.length === lastKeysCount)
return cachedFilenameChunkIds;
lastKeysCount = chunkIdKeys.length;
cachedFilenameChunkIds = chunkIdKeys.reduce((acc, stackKey) => {
if (!parsedStackResults)
parsedStackResults = {};
const result = parsedStackResults[stackKey];
if (result)
acc[result[0]] = result[1];
else {
const parsedStack = stackParser(stackKey);
for (let i = parsedStack.length - 1;i >= 0; i--) {
const stackFrame = parsedStack[i];
const filename = stackFrame?.filename;
const chunkId = chunkIdMap[stackKey];
if (filename && chunkId) {
acc[filename] = chunkId;
parsedStackResults[stackKey] = [
filename,
chunkId
];
break;
}
}
}
return acc;
}, {});
return cachedFilenameChunkIds;
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/error-properties-builder.mjs
var MAX_CAUSE_RECURSION = 4;
class ErrorPropertiesBuilder {
constructor(coercers, stackParser, modifiers = []) {
this.coercers = coercers;
this.stackParser = stackParser;
this.modifiers = modifiers;
}
buildFromUnknown(input, hint = {}) {
const providedMechanism = hint && hint.mechanism;
const mechanism = providedMechanism || {
handled: true,
type: "generic"
};
const coercingContext = this.buildCoercingContext(mechanism, hint, 0);
const exceptionWithCause = coercingContext.apply(input);
const parsingContext = this.buildParsingContext(hint);
const exceptionWithStack = this.parseStacktrace(exceptionWithCause, parsingContext);
const exceptionList = this.convertToExceptionList(exceptionWithStack, mechanism);
return {
$exception_list: exceptionList,
$exception_level: "error"
};
}
async modifyFrames(exceptionList) {
for (const exc of exceptionList)
if (exc.stacktrace && exc.stacktrace.frames && isArray(exc.stacktrace.frames))
exc.stacktrace.frames = await this.applyModifiers(exc.stacktrace.frames);
return exceptionList;
}
coerceFallback(ctx) {
return {
type: "Error",
value: "Unknown error",
stack: ctx.syntheticException?.stack,
synthetic: true
};
}
parseStacktrace(err, ctx) {
let cause;
if (err.cause != null)
cause = this.parseStacktrace(err.cause, ctx);
let stack;
if (err.stack != "" && err.stack != null)
stack = this.applyChunkIds(this.stackParser(err.stack, err.synthetic ? ctx.skipFirstLines : 0), ctx.chunkIdMap);
return {
...err,
cause,
stack
};
}
applyChunkIds(frames, chunkIdMap) {
return frames.map((frame) => {
if (frame.filename && chunkIdMap)
frame.chunk_id = chunkIdMap[frame.filename];
return frame;
});
}
applyCoercers(input, ctx) {
for (const adapter of this.coercers)
if (adapter.match(input))
return adapter.coerce(input, ctx);
return this.coerceFallback(ctx);
}
async applyModifiers(frames) {
let newFrames = frames;
for (const modifier of this.modifiers)
newFrames = await modifier(newFrames);
return newFrames;
}
convertToExceptionList(exceptionWithStack, mechanism) {
const currentException = {
type: exceptionWithStack.type,
value: exceptionWithStack.value,
mechanism: {
type: mechanism.type ?? "generic",
handled: mechanism.handled ?? true,
synthetic: exceptionWithStack.synthetic ?? false
}
};
if (exceptionWithStack.stack)
currentException.stacktrace = {
type: "raw",
frames: exceptionWithStack.stack
};
const exceptionList = [
currentException
];
if (exceptionWithStack.cause != null)
exceptionList.push(...this.convertToExceptionList(exceptionWithStack.cause, {
...mechanism,
handled: true
}));
return exceptionList;
}
buildParsingContext(hint) {
const context = {
chunkIdMap: getFilenameToChunkIdMap(this.stackParser),
skipFirstLines: hint.skipFirstLines ?? 1
};
return context;
}
buildCoercingContext(mechanism, hint, depth = 0) {
const coerce = (input, depth2) => {
if (!(depth2 <= MAX_CAUSE_RECURSION))
return;
{
const ctx = this.buildCoercingContext(mechanism, hint, depth2);
return this.applyCoercers(input, ctx);
}
};
const context = {
...hint,
syntheticException: depth == 0 ? hint.syntheticException : undefined,
mechanism,
apply: (input) => coerce(input, depth),
next: (input) => coerce(input, depth + 1)
};
return context;
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/parsers/base.mjs
var UNKNOWN_FUNCTION = "?";
function createFrame(platform, filename, func, lineno, colno) {
const frame = {
platform,
filename,
function: func === "<anonymous>" ? UNKNOWN_FUNCTION : func,
in_app: true
};
if (!isUndefined(lineno))
frame.lineno = lineno;
if (!isUndefined(colno))
frame.colno = colno;
return frame;
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/parsers/safari.mjs
var extractSafariExtensionDetails = (func, filename) => {
const isSafariExtension = func.indexOf("safari-extension") !== -1;
const isSafariWebExtension = func.indexOf("safari-web-extension") !== -1;
return isSafariExtension || isSafariWebExtension ? [
func.indexOf("@") !== -1 ? func.split("@")[0] : UNKNOWN_FUNCTION,
isSafariExtension ? `safari-extension:${filename}` : `safari-web-extension:${filename}`
] : [
func,
filename
];
};
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/parsers/chrome.mjs
var chromeRegexNoFnName = /^\s*at (\S+?)(?::(\d+))(?::(\d+))\s*$/i;
var chromeRegex = /^\s*at (?:(.+?\)(?: \[.+\])?|.*?) ?\((?:address at )?)?(?:async )?((?:<anonymous>|[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
var chromeEvalRegex = /\((\S*)(?::(\d+))(?::(\d+))\)/;
var chromeStackLineParser = (line, platform) => {
const noFnParts = chromeRegexNoFnName.exec(line);
if (noFnParts) {
const [, filename, line2, col] = noFnParts;
return createFrame(platform, filename, UNKNOWN_FUNCTION, +line2, +col);
}
const parts = chromeRegex.exec(line);
if (parts) {
const isEval = parts[2] && parts[2].indexOf("eval") === 0;
if (isEval) {
const subMatch = chromeEvalRegex.exec(parts[2]);
if (subMatch) {
parts[2] = subMatch[1];
parts[3] = subMatch[2];
parts[4] = subMatch[3];
}
}
const [func, filename] = extractSafariExtensionDetails(parts[1] || UNKNOWN_FUNCTION, parts[2]);
return createFrame(platform, filename, func, parts[3] ? +parts[3] : undefined, parts[4] ? +parts[4] : undefined);
}
};
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/parsers/gecko.mjs
var geckoREgex = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:[-a-z]+)?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i;
var geckoEvalRegex = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
var geckoStackLineParser = (line, platform) => {
const parts = geckoREgex.exec(line);
if (parts) {
const isEval = parts[3] && parts[3].indexOf(" > eval") > -1;
if (isEval) {
const subMatch = geckoEvalRegex.exec(parts[3]);
if (subMatch) {
parts[1] = parts[1] || "eval";
parts[3] = subMatch[1];
parts[4] = subMatch[2];
parts[5] = "";
}
}
let filename = parts[3];
let func = parts[1] || UNKNOWN_FUNCTION;
[func, filename] = extractSafariExtensionDetails(func, filename);
return createFrame(platform, filename, func, parts[4] ? +parts[4] : undefined, parts[5] ? +parts[5] : undefined);
}
};
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/parsers/winjs.mjs
var winjsRegex = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:[-a-z]+):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
var winjsStackLineParser = (line, platform) => {
const parts = winjsRegex.exec(line);
return parts ? createFrame(platform, parts[2], parts[1] || UNKNOWN_FUNCTION, +parts[3], parts[4] ? +parts[4] : undefined) : undefined;
};
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/parsers/opera.mjs
var opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i;
var opera10StackLineParser = (line, platform) => {
const parts = opera10Regex.exec(line);
return parts ? createFrame(platform, parts[2], parts[3] || UNKNOWN_FUNCTION, +parts[1]) : undefined;
};
var opera11Regex = / line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^)]+))\(.*\))? in (.*):\s*$/i;
var opera11StackLineParser = (line, platform) => {
const parts = opera11Regex.exec(line);
return parts ? createFrame(platform, parts[5], parts[3] || parts[4] || UNKNOWN_FUNCTION, +parts[1], +parts[2]) : undefined;
};
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/parsers/node.mjs
var FILENAME_MATCH = /^\s*[-]{4,}$/;
var FULL_MATCH = /at (?:async )?(?:(.+?)\s+\()?(?:(.+):(\d+):(\d+)?|([^)]+))\)?/;
var nodeStackLineParser = (line, platform) => {
const lineMatch = line.match(FULL_MATCH);
if (lineMatch) {
let object;
let method;
let functionName;
let typeName;
let methodName;
if (lineMatch[1]) {
functionName = lineMatch[1];
let methodStart = functionName.lastIndexOf(".");
if (functionName[methodStart - 1] === ".")
methodStart--;
if (methodStart > 0) {
object = functionName.slice(0, methodStart);
method = functionName.slice(methodStart + 1);
const objectEnd = object.indexOf(".Module");
if (objectEnd > 0) {
functionName = functionName.slice(objectEnd + 1);
object = object.slice(0, objectEnd);
}
}
typeName = undefined;
}
if (method) {
typeName = object;
methodName = method;
}
if (method === "<anonymous>") {
methodName = undefined;
functionName = undefined;
}
if (functionName === undefined) {
methodName = methodName || UNKNOWN_FUNCTION;
functionName = typeName ? `${typeName}.${methodName}` : methodName;
}
let filename = lineMatch[2]?.startsWith("file://") ? lineMatch[2].slice(7) : lineMatch[2];
const isNative = lineMatch[5] === "native";
if (filename?.match(/\/[A-Z]:/))
filename = filename.slice(1);
if (!filename && lineMatch[5] && !isNative)
filename = lineMatch[5];
return {
filename: filename ? decodeURI(filename) : undefined,
module: undefined,
function: functionName,
lineno: _parseIntOrUndefined(lineMatch[3]),
colno: _parseIntOrUndefined(lineMatch[4]),
in_app: filenameIsInApp(filename || "", isNative),
platform
};
}
if (line.match(FILENAME_MATCH))
return {
filename: line,
platform
};
};
function filenameIsInApp(filename, isNative = false) {
const isInternal = isNative || filename && !filename.startsWith("/") && !filename.match(/^[A-Z]:/) && !filename.startsWith(".") && !filename.match(/^[a-zA-Z]([a-zA-Z0-9.\-+])*:\/\//);
return !isInternal && filename !== undefined && !filename.includes("node_modules/");
}
function _parseIntOrUndefined(input) {
return parseInt(input || "", 10) || undefined;
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/parsers/index.mjs
var WEBPACK_ERROR_REGEXP = /\(error: (.*)\)/;
var STACKTRACE_FRAME_LIMIT = 50;
function reverseAndStripFrames(stack) {
if (!stack.length)
return [];
const localStack = Array.from(stack);
localStack.reverse();
return localStack.slice(0, STACKTRACE_FRAME_LIMIT).map((frame) => ({
...frame,
filename: frame.filename || getLastStackFrame(localStack).filename,
function: frame.function || UNKNOWN_FUNCTION
}));
}
function getLastStackFrame(arr) {
return arr[arr.length - 1] || {};
}
function createDefaultStackParser() {
return createStackParser("web:javascript", chromeStackLineParser, geckoStackLineParser);
}
function createStackParser(platform, ...parsers) {
return (stack, skipFirstLines = 0) => {
const frames = [];
const lines = stack.split(`
`);
for (let i = skipFirstLines;i < lines.length; i++) {
const line = lines[i];
if (line.length > 1024)
continue;
const cleanedLine = WEBPACK_ERROR_REGEXP.test(line) ? line.replace(WEBPACK_ERROR_REGEXP, "$1") : line;
if (!cleanedLine.match(/\S*Error: /)) {
for (const parser of parsers) {
const frame = parser(cleanedLine, platform);
if (frame) {
frames.push(frame);
break;
}
}
if (frames.length >= STACKTRACE_FRAME_LIMIT)
break;
}
}
return reverseAndStripFrames(frames);
};
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/coercers/dom-exception-coercer.mjs
class DOMExceptionCoercer {
match(err) {
return this.isDOMException(err) || this.isDOMError(err);
}
coerce(err, ctx) {
const hasStack = isString(err.stack);
return {
type: this.getType(err),
value: this.getValue(err),
stack: hasStack ? err.stack : undefined,
cause: err.cause ? ctx.next(err.cause) : undefined,
synthetic: false
};
}
getType(candidate) {
return this.isDOMError(candidate) ? "DOMError" : "DOMException";
}
getValue(err) {
const name = err.name || (this.isDOMError(err) ? "DOMError" : "DOMException");
const message = err.message ? `${name}: ${err.message}` : name;
return message;
}
isDOMException(err) {
return isBuiltin(err, "DOMException");
}
isDOMError(err) {
return isBuiltin(err, "DOMError");
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/coercers/error-coercer.mjs
class ErrorCoercer {
match(err) {
return isPlainError(err);
}
coerce(err, ctx) {
return {
type: this.getType(err),
value: this.getMessage(err, ctx),
stack: this.getStack(err),
cause: err.cause ? ctx.next(err.cause) : undefined,
synthetic: false
};
}
getType(err) {
return err.name || err.constructor.name;
}
getMessage(err, _ctx) {
const message = err.message;
if (message.error && typeof message.error.message == "string")
return String(message.error.message);
return String(message);
}
getStack(err) {
return err.stacktrace || err.stack || undefined;
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/coercers/error-event-coercer.mjs
class ErrorEventCoercer {
constructor() {}
match(err) {
return isErrorEvent(err) && err.error != null;
}
coerce(err, ctx) {
const exceptionLike = ctx.apply(err.error);
if (!exceptionLike)
return {
type: "ErrorEvent",
value: err.message,
stack: ctx.syntheticException?.stack,
synthetic: true
};
return exceptionLike;
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/coercers/string-coercer.mjs
var ERROR_TYPES_PATTERN = /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/i;
class StringCoercer {
match(input) {
return typeof input == "string";
}
coerce(input, ctx) {
const [type, value] = this.getInfos(input);
return {
type: type ?? "Error",
value: value ?? input,
stack: ctx.syntheticException?.stack,
synthetic: true
};
}
getInfos(candidate) {
let type = "Error";
let value = candidate;
const groups = candidate.match(ERROR_TYPES_PATTERN);
if (groups) {
type = groups[1];
value = groups[2];
}
return [
type,
value
];
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/types.mjs
var severityLevels = [
"fatal",
"error",
"warning",
"log",
"info",
"debug"
];
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/coercers/utils.mjs
function extractExceptionKeysForMessage(err, maxLength = 40) {
const keys = Object.keys(err);
keys.sort();
if (!keys.length)
return "[object has no keys]";
for (let i = keys.length;i > 0; i--) {
const serialized = keys.slice(0, i).join(", ");
if (!(serialized.length > maxLength)) {
if (i === keys.length)
return serialized;
return serialized.length <= maxLength ? serialized : `${serialized.slice(0, maxLength)}...`;
}
}
return "";
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/coercers/object-coercer.mjs
class ObjectCoercer {
match(candidate) {
return typeof candidate == "object" && candidate !== null;
}
coerce(candidate, ctx) {
const errorProperty = this.getErrorPropertyFromObject(candidate);
if (errorProperty)
return ctx.apply(errorProperty);
return {
type: this.getType(candidate),
value: this.getValue(candidate),
stack: ctx.syntheticException?.stack,
level: this.isSeverityLevel(candidate.level) ? candidate.level : "error",
synthetic: true
};
}
getType(err) {
return isEvent(err) ? err.constructor.name : "Error";
}
getValue(err) {
if ("name" in err && typeof err.name == "string") {
let message = `'${err.name}' captured as exception`;
if ("message" in err && typeof err.message == "string")
message += ` with message: '${err.message}'`;
return message;
}
if ("message" in err && typeof err.message == "string")
return err.message;
const className = this.getObjectClassName(err);
const keys = extractExceptionKeysForMessage(err);
return `${className && className !== "Object" ? `'${className}'` : "Object"} captured as exception with keys: ${keys}`;
}
isSeverityLevel(x) {
return isString(x) && !isEmptyString(x) && severityLevels.indexOf(x) >= 0;
}
getErrorPropertyFromObject(obj) {
for (const prop in obj)
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
const value = obj[prop];
if (isError(value))
return value;
}
}
getObjectClassName(obj) {
try {
const prototype = Object.getPrototypeOf(obj);
return prototype ? prototype.constructor.name : undefined;
} catch (e) {
return;
}
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/coercers/event-coercer.mjs
class EventCoercer {
match(err) {
return isEvent(err);
}
coerce(evt, ctx) {
const constructorName = evt.constructor.name;
return {
type: constructorName,
value: `${constructorName} captured as exception with keys: ${extractExceptionKeysForMessage(evt)}`,
stack: ctx.syntheticException?.stack,
synthetic: true
};
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/coercers/primitive-coercer.mjs
class PrimitiveCoercer {
match(candidate) {
return isPrimitive(candidate);
}
coerce(value, ctx) {
return {
type: "Error",
value: `Primitive value captured as exception: ${String(value)}`,
stack: ctx.syntheticException?.stack,
synthetic: true
};
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/coercers/promise-rejection-event.mjs
class PromiseRejectionEventCoercer {
match(err) {
return isBuiltin(err, "PromiseRejectionEvent") || this.isCustomEventWrappingRejection(err);
}
isCustomEventWrappingRejection(err) {
if (!isEvent(err))
return false;
try {
const detail = err.detail;
return detail != null && typeof detail == "object" && "reason" in detail;
} catch {
return false;
}
}
coerce(err, ctx) {
const reason = this.getUnhandledRejectionReason(err);
if (isPrimitive(reason))
return {
type: "UnhandledRejection",
value: `Non-Error promise rejection captured with value: ${String(reason)}`,
stack: ctx.syntheticException?.stack,
synthetic: true
};
return ctx.apply(reason);
}
getUnhandledRejectionReason(error) {
try {
if ("reason" in error)
return error.reason;
if ("detail" in error && error.detail != null && typeof error.detail == "object" && "reason" in error.detail)
return error.detail.reason;
} catch {}
return error;
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/utils.mjs
class ReduceableCache {
constructor(_maxSize) {
this._maxSize = _maxSize;
this._cache = new Map;
}
get(key) {
const value = this._cache.get(key);
if (value === undefined)
return;
this._cache.delete(key);
this._cache.set(key, value);
return value;
}
set(key, value) {
this._cache.set(key, value);
}
reduce() {
while (this._cache.size >= this._maxSize) {
const value = this._cache.keys().next().value;
if (value)
this._cache.delete(value);
}
}
}
// ../../node_modules/.bun/@posthog+core@1.28.0/node_modules/@posthog/core/dist/error-tracking/exception-steps.mjs
var EXCEPTION_STEP_INTERNAL_FIELDS = {
MESSAGE: "$message",
TIMESTAMP: "$timestamp"
};
var RESERVED_EXCEPTION_STEP_KEYS = new Set([
EXCEPTION_STEP_INTERNAL_FIELDS.MESSAGE,
EXCEPTION_STEP_INTERNAL_FIELDS.TIMESTAMP
]);
var DEFAULT_EXCEPTION_STEPS_CONFIG = {
enabled: true,
max_bytes: 32768
};
function resolveExceptionStepsConfig(config) {
if (!config)
return {
...DEFAULT_EXCEPTION_STEPS_CONFIG
};
return {
enabled: config.enabled ?? DEFAULT_EXCEPTION_STEPS_CONFIG.enabled,
max_bytes: normalizePositiveInteger(config.max_bytes, DEFAULT_EXCEPTION_STEPS_CONFIG.max_bytes)
};
}
function stripReservedExceptionStepFields(properties) {
if (!properties)
return {
sanitizedProperties: {},
droppedKeys: []
};
const droppedKeys = [];
const sanitizedProperties = Object.keys(properties).reduce((acc, key) => {
if (RESERVED_EXCEPTION_STEP_KEYS.has(key)) {
droppedKeys.push(key);
return acc;
}
acc[key] = properties[key];
return acc;
}, {});
return {
sanitizedProperties,
droppedKeys
};
}
class ExceptionStepsBuffer {
constructor(config) {
this._entries = [];
this._totalBytes = 0;
this._config = resolveExceptionStepsConfig(config);
}
setConfig(config) {
this._config = resolveExceptionStepsConfig(config);
this._trimToMaxBytes();
}
add(step) {
const serialized = normalizeAndSerializeStep(step);
if (!serialized)
return;
const bytes = getUtf8ByteLength(serialized.json);
if (bytes > this._config.max_bytes)
return;
this._entries.push({
step: serialized.step,
bytes
});
this._totalBytes += bytes;
this._trimToMaxBytes();
}
getAttachable() {
return this._entries.map((e) => e.step);
}
clear() {
this._entries = [];
this._totalBytes = 0;
}
size() {
return this._entries.length;
}
_trimToMaxBytes() {
while (this._totalBytes > this._config.max_bytes && this._entries.length > 0) {
const evicted = this._entries.shift();
if (evicted)
this._totalBytes -= evicted.bytes;
}
}
}
function normalizePositiveInteger(input, fallback) {
if (!isNumber(input) || input === 1 / 0 || input === -1 / 0)
return fallback;
const normalized = Math.floor(input);
if (normalized < 0)
return fallback;
return normalized;
}
function normalizeAndSerializeStep(step) {
const json = safeStringify(step);
if (!json)
return;
try {
const parsed = JSON.parse(json);
if (!isObject(parsed))
return;
const parsedStep = parsed;
const message = parsedStep[EXCEPTION_STEP_INTERNAL_FIELDS.MESSAGE];
const timestamp = parsedStep[EXCEPTION_STEP_INTERNAL_FIELDS.TIMESTAMP];
if (!isString(message) || message.trim().length === 0)
return;
if (!isString(timestamp) && !isNumber(timestamp))
return;
return {
step: parsedStep,
json
};
} catch {
return;
}
}
function safeStringify(value) {
const seen = new WeakSet;
try {
return JSON.stringify(value, (_key, replacementValue) => {
if (typeof replacementValue == "bigint")
return replacementValue.toString();
if (typeof replacementValue == "function" || typeof replacementValue == "symbol")
return;
if (replacementValue instanceof Date)
return replacementValue.toISOString();
if (replacementValue instanceof Error)
return {
name: replacementValue.name,
message: replacementValue.message,
stack: replacementValue.stack
};
if (replacementValue && typeof replacementValue == "object") {
if (seen.has(replacementValue))
return "[Circular]";
seen.add(replacementValue);
}
return replacementValue;
});
} catch {
return;
}
}
function getUtf8ByteLength(value) {
if (typeof TextEncoder != "undefined")
return new TextEncoder().encode(value).length;
const encoded = encodeURIComponent(value);
let byteLength = 0;
for (let i = 0;i < encoded.length; i++)
if (encoded[i] === "%") {
byteLength += 1;
i += 2;
} else
byteLength += 1;
return byteLength;
}
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/extensions/error-tracking/modifiers/context-lines.node.mjs
import { createReadStream } from "fs";
import { createInterface } from "readline";
var LRU_FILE_CONTENTS_CACHE = new exports_error_tracking.ReduceableCache(25);
var LRU_FILE_CONTENTS_FS_READ_FAILED = new exports_error_tracking.ReduceableCache(20);
var DEFAULT_LINES_OF_CONTEXT = 7;
var MAX_CONTEXTLINES_COLNO = 1000;
var MAX_CONTEXTLINES_LINENO = 1e4;
async function addSourceContext(frames) {
const filesToLines = {};
for (let i = frames.length - 1;i >= 0; i--) {
const frame = frames[i];
const filename = frame?.filename;
if (!frame || typeof filename != "string" || typeof frame.lineno != "number" || shouldSkipContextLinesForFile(filename) || shouldSkipContextLinesForFrame(frame))
continue;
const filesToLinesOutput = filesToLines[filename];
if (!filesToLinesOutput)
filesToLines[filename] = [];
filesToLines[filename].push(frame.lineno);
}
const files = Object.keys(filesToLines);
if (files.length == 0)
return frames;
const readlinePromises = [];
for (const file of files) {
if (LRU_FILE_CONTENTS_FS_READ_FAILED.get(file))
continue;
const filesToLineRanges = filesToLines[file];
if (!filesToLineRanges)
continue;
filesToLineRanges.sort((a, b) => a - b);
const ranges = makeLineReaderRanges(filesToLineRanges);
if (ranges.every((r) => rangeExistsInContentCache(file, r)))
continue;
const cache = emplace(LRU_FILE_CONTENTS_CACHE, file, {});
readlinePromises.push(getContextLinesFromFile(file, ranges, cache));
}
await Promise.all(readlinePromises).catch(() => {});
if (frames && frames.length > 0)
addSourceContextToFrames(frames, LRU_FILE_CONTENTS_CACHE);
LRU_FILE_CONTENTS_CACHE.reduce();
return frames;
}
function getContextLinesFromFile(path, ranges, output) {
return new Promise((resolve) => {
const stream = createReadStream(path);
const lineReaded = createInterface({
input: stream
});
function destroyStreamAndResolve() {
stream.destroy();
resolve();
}
let lineNumber = 0;
let currentRangeIndex = 0;
const range = ranges[currentRangeIndex];
if (range === undefined)
return void destroyStreamAndResolve();
let rangeStart = range[0];
let rangeEnd = range[1];
function onStreamError() {
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path, 1);
lineReaded.close();
lineReaded.removeAllListeners();
destroyStreamAndResolve();
}
stream.on("error", onStreamError);
lineReaded.on("error", onStreamError);
lineReaded.on("close", destroyStreamAndResolve);
lineReaded.on("line", (line) => {
lineNumber++;
if (lineNumber < rangeStart)
return;
output[lineNumber] = snipLine(line, 0);
if (lineNumber >= rangeEnd) {
if (currentRangeIndex === ranges.length - 1) {
lineReaded.close();
lineReaded.removeAllListeners();
return;
}
currentRangeIndex++;
const range2 = ranges[currentRangeIndex];
if (range2 === undefined) {
lineReaded.close();
lineReaded.removeAllListeners();
return;
}
rangeStart = range2[0];
rangeEnd = range2[1];
}
});
});
}
function addSourceContextToFrames(frames, cache) {
for (const frame of frames)
if (frame.filename && frame.context_line === undefined && typeof frame.lineno == "number") {
const contents = cache.get(frame.filename);
if (contents === undefined)
continue;
addContextToFrame(frame.lineno, frame, contents);
}
}
function addContextToFrame(lineno, frame, contents) {
if (frame.lineno === undefined || contents === undefined)
return;
frame.pre_context = [];
for (let i = makeRangeStart(lineno);i < lineno; i++) {
const line = contents[i];
if (line === undefined)
return void clearLineContext(frame);
frame.pre_context.push(line);
}
if (contents[lineno] === undefined)
return void clearLineContext(frame);
frame.context_line = contents[lineno];
const end = makeRangeEnd(lineno);
frame.post_context = [];
for (let i = lineno + 1;i <= end; i++) {
const line = contents[i];
if (line === undefined)
break;
frame.post_context.push(line);
}
}
function clearLineContext(frame) {
delete frame.pre_context;
delete frame.context_line;
delete frame.post_context;
}
function shouldSkipContextLinesForFile(path) {
return path.startsWith("node:") || path.endsWith(".min.js") || path.endsWith(".min.cjs") || path.endsWith(".min.mjs") || path.startsWith("data:");
}
function shouldSkipContextLinesForFrame(frame) {
if (frame.lineno !== undefined && frame.lineno > MAX_CONTEXTLINES_LINENO)
return true;
if (frame.colno !== undefined && frame.colno > MAX_CONTEXTLINES_COLNO)
return true;
return false;
}
function rangeExistsInContentCache(file, range) {
const contents = LRU_FILE_CONTENTS_CACHE.get(file);
if (contents === undefined)
return false;
for (let i = range[0];i <= range[1]; i++)
if (contents[i] === undefined)
return false;
return true;
}
function makeLineReaderRanges(lines) {
if (!lines.length)
return [];
let i = 0;
const line = lines[0];
if (typeof line != "number")
return [];
let current = makeContextRange(line);
const out = [];
while (true) {
if (i === lines.length - 1) {
out.push(current);
break;
}
const next = lines[i + 1];
if (typeof next != "number")
break;
if (next <= current[1])
current[1] = next + DEFAULT_LINES_OF_CONTEXT;
else {
out.push(current);
current = makeContextRange(next);
}
i++;
}
return out;
}
function makeContextRange(line) {
return [
makeRangeStart(line),
makeRangeEnd(line)
];
}
function makeRangeStart(line) {
return Math.max(1, line - DEFAULT_LINES_OF_CONTEXT);
}
function makeRangeEnd(line) {
return line + DEFAULT_LINES_OF_CONTEXT;
}
function emplace(map, key, contents) {
const value = map.get(key);
if (value === undefined) {
map.set(key, contents);
return contents;
}
return value;
}
function snipLine(line, colno) {
let newLine = line;
const lineLength = newLine.length;
if (lineLength <= 150)
return newLine;
if (colno > lineLength)
colno = lineLength;
let start = Math.max(colno - 60, 0);
if (start < 5)
start = 0;
let end = Math.min(start + 140, lineLength);
if (end > lineLength - 5)
end = lineLength;
if (end === lineLength)
start = Math.max(end - 140, 0);
newLine = newLine.slice(start, end);
if (start > 0)
newLine = `...${newLine}`;
if (end < lineLength)
newLine += "...";
return newLine;
}
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/extensions/error-tracking/modifiers/relative-path.node.mjs
import { isAbsolute, relative, sep as sep2 } from "path";
function createRelativePathModifier(basePath = process.cwd()) {
const isWindows = sep2 === "\\";
const toUnix = (p) => isWindows ? p.replace(/\\/g, "/") : p;
const normalizedBase = toUnix(basePath);
return async (frames) => {
for (const frame of frames)
if (!(!frame.filename || frame.filename.startsWith("node:") || frame.filename.startsWith("data:"))) {
if (isAbsolute(frame.filename))
frame.filename = toUnix(relative(normalizedBase, toUnix(frame.filename)));
}
return frames;
};
}
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/extensions/error-tracking/autocapture.mjs
function makeUncaughtExceptionHandler(captureFn, onFatalFn) {
let calledFatalError = false;
return Object.assign((error) => {
const userProvidedListenersCount = global.process.listeners("uncaughtException").filter((listener) => listener.name !== "domainUncaughtExceptionClear" && listener._posthogErrorHandler !== true).length;
const processWouldExit = userProvidedListenersCount === 0;
captureFn(error, {
mechanism: {
type: "onuncaughtexception",
handled: false
}
});
if (!calledFatalError && processWouldExit) {
calledFatalError = true;
onFatalFn(error);
}
}, {
_posthogErrorHandler: true
});
}
function addUncaughtExceptionListener(captureFn, onFatalFn) {
globalThis.process?.on("uncaughtException", makeUncaughtExceptionHandler(captureFn, onFatalFn));
}
function addUnhandledRejectionListener(captureFn) {
globalThis.process?.on("unhandledRejection", (reason) => captureFn(reason, {
mechanism: {
type: "onunhandledrejection",
handled: false
}
}));
}
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/extensions/error-tracking/index.mjs
var SHUTDOWN_TIMEOUT = 2000;
class ErrorTracking {
constructor(client, options, _logger) {
this.client = client;
this._exceptionAutocaptureEnabled = options.enableExceptionAutocapture || false;
this._logger = _logger;
this._rateLimiter = new BucketedRateLimiter({
refillRate: 1,
bucketSize: 10,
refillInterval: 1e4,
_logger: this._logger
});
this.startAutocaptureIfEnabled();
}
static isPreviouslyCapturedError(x) {
return isObject(x) && "__posthog_previously_captured_error" in x && x.__posthog_previously_captured_error === true;
}
static async buildEventMessage(error, hint, distinctId, additionalProperties) {
const properties = {
...additionalProperties
};
const exceptionProperties = this.errorPropertiesBuilder.buildFromUnknown(error, hint);
exceptionProperties.$exception_list = await this.errorPropertiesBuilder.modifyFrames(exceptionProperties.$exception_list);
return {
event: "$exception",
distinctId,
properties: {
...exceptionProperties,
...properties
},
_originatedFromCaptureException: true
};
}
startAutocaptureIfEnabled() {
if (this.isEnabled()) {
addUncaughtExceptionListener(this.onException.bind(this), this.onFatalError.bind(this));
addUnhandledRejectionListener(this.onException.bind(this));
}
}
onException(exception, hint) {
this.client.addPendingPromise((async () => {
if (!ErrorTracking.isPreviouslyCapturedError(exception)) {
const eventMessage = await ErrorTracking.buildEventMessage(exception, hint);
const exceptionProperties = eventMessage.properties;
const exceptionType = exceptionProperties?.$exception_list[0]?.type ?? "Exception";
const isRateLimited = this._rateLimiter.consumeRateLimit(exceptionType);
if (isRateLimited)
return void this._logger.info("Skipping exception capture because of client rate limiting.", {
exception: exceptionType
});
return this.client.capture(eventMessage);
}
})());
}
async onFatalError(exception) {
console.error(exception);
await this.client.shutdown(SHUTDOWN_TIMEOUT);
process.exit(1);
}
isEnabled() {
return !this.client.isDisabled && this._exceptionAutocaptureEnabled;
}
shutdown() {
this._rateLimiter.stop();
}
}
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/version.mjs
var version = "5.32.1";
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/types.mjs
var FeatureFlagError2 = {
ERRORS_WHILE_COMPUTING: "errors_while_computing_flags",
FLAG_MISSING: "flag_missing",
QUOTA_LIMITED: "quota_limited",
UNKNOWN_ERROR: "unknown_error"
};
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/extensions/feature-flags/crypto.mjs
async function hashSHA1(text) {
const subtle = globalThis.crypto?.subtle;
if (!subtle)
throw new Error("SubtleCrypto API not available");
const hashBuffer = await subtle.digest("SHA-1", new TextEncoder().encode(text));
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
}
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/extensions/feature-flags/feature-flags.mjs
var SIXTY_SECONDS = 60000;
var LONG_SCALE = 1152921504606847000;
var NULL_VALUES_ALLOWED_OPERATORS = [
"is_not"
];
class ClientError extends Error {
constructor(message) {
super();
Error.captureStackTrace(this, this.constructor);
this.name = "ClientError";
this.message = message;
Object.setPrototypeOf(this, ClientError.prototype);
}
}
class InconclusiveMatchError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
Object.setPrototypeOf(this, InconclusiveMatchError.prototype);
}
}
class RequiresServerEvaluation extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
Object.setPrototypeOf(this, RequiresServerEvaluation.prototype);
}
}
class FeatureFlagsPoller {
constructor({ pollingInterval, personalApiKey, projectApiKey, timeout, host, customHeaders, ...options }) {
this.debugMode = false;
this.shouldBeginExponentialBackoff = false;
this.backOffCount = 0;
this.pollingInterval = pollingInterval;
this.personalApiKey = personalApiKey;
this.featureFlags = [];
this.featureFlagsByKey = {};
this.groupTypeMapping = {};
this.cohorts = {};
this.loadedSuccessfullyOnce = false;
this.timeout = timeout;
this.projectApiKey = projectApiKey;
this.host = host;
this.poller = undefined;
this.fetch = options.fetch || fetch;
this.onError = options.onError;
this.customHeaders = customHeaders;
this.onLoad = options.onLoad;
this.cacheProvider = options.cacheProvider;
this.strictLocalEvaluation = options.strictLocalEvaluation ?? false;
this.loadFeatureFlags();
}
debug(enabled = true) {
this.debugMode = enabled;
}
logMsgIfDebug(fn) {
if (this.debugMode)
fn();
}
createEvaluationContext(distinctId, groups = {}, personProperties = {}, groupProperties = {}, evaluationCache = {}) {
return {
distinctId,
groups,
personProperties,
groupProperties,
evaluationCache
};
}
async getFeatureFlag(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}) {
await this.loadFeatureFlags();
let response;
let featureFlag;
if (!this.loadedSuccessfullyOnce)
return response;
featureFlag = this.featureFlagsByKey[key];
if (featureFlag !== undefined) {
const evaluationContext = this.createEvaluationContext(distinctId, groups, personProperties, groupProperties);
try {
const result = await this.computeFlagAndPayloadLocally(featureFlag, evaluationContext);
response = result.value;
this.logMsgIfDebug(() => console.debug(`Successfully computed flag locally: ${key} -> ${response}`));
} catch (e) {
if (e instanceof RequiresServerEvaluation || e instanceof InconclusiveMatchError)
this.logMsgIfDebug(() => console.debug(`${e.name} when computing flag locally: ${key}: ${e.message}`));
else if (e instanceof Error)
this.onError?.(new Error(`Error computing flag locally: ${key}: ${e}`));
}
}
return response;
}
async getAllFlagsAndPayloads(evaluationContext, flagKeysToExplicitlyEvaluate) {
await this.loadFeatureFlags();
const response = {};
const payloads = {};
let fallbackToFlags = this.featureFlags.length == 0;
const flagsToEvaluate = flagKeysToExplicitlyEvaluate ? flagKeysToExplicitlyEvaluate.map((key) => this.featureFlagsByKey[key]).filter(Boolean) : this.featureFlags;
const sharedEvaluationContext = {
...evaluationContext,
evaluationCache: evaluationContext.evaluationCache ?? {}
};
await Promise.all(flagsToEvaluate.map(async (flag) => {
try {
const { value: matchValue, payload: matchPayload } = await this.computeFlagAndPayloadLocally(flag, sharedEvaluationContext);
response[flag.key] = matchValue;
if (matchPayload)
payloads[flag.key] = matchPayload;
} catch (e) {
if (e instanceof RequiresServerEvaluation || e instanceof InconclusiveMatchError)
this.logMsgIfDebug(() => console.debug(`${e.name} when computing flag locally: ${flag.key}: ${e.message}`));
else if (e instanceof Error)
this.onError?.(new Error(`Error computing flag locally: ${flag.key}: ${e}`));
fallbackToFlags = true;
}
}));
return {
response,
payloads,
fallbackToFlags
};
}
async computeFlagAndPayloadLocally(flag, evaluationContext, options = {}) {
const { matchValue, skipLoadCheck = false } = options;
if (!skipLoadCheck)
await this.loadFeatureFlags();
if (!this.loadedSuccessfullyOnce)
return {
value: false,
payload: null
};
let flagValue;
flagValue = matchValue !== undefined ? matchValue : await this.computeFlagValueLocally(flag, evaluationContext);
const payload = this.getFeatureFlagPayload(flag.key, flagValue);
return {
value: flagValue,
payload
};
}
async computeFlagValueLocally(flag, evaluationContext) {
const { distinctId, groups, personProperties, groupProperties } = evaluationContext;
if (flag.ensure_experience_continuity)
throw new InconclusiveMatchError("Flag has experience continuity enabled");
if (!flag.active)
return false;
const flagFilters = flag.filters || {};
const aggregation_group_type_index = flagFilters.aggregation_group_type_index;
if (aggregation_group_type_index != null) {
const groupName = this.groupTypeMapping[String(aggregation_group_type_index)];
if (!groupName) {
this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Unknown group type index ${aggregation_group_type_index} for feature flag ${flag.key}`));
throw new InconclusiveMatchError("Flag has unknown group type index");
}
if (!(groupName in groups)) {
this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Can't compute group feature flag: ${flag.key} without group names passed in`));
return false;
}
if (flag.bucketing_identifier === "device_id" && (personProperties?.$device_id === undefined || personProperties?.$device_id === null || personProperties?.$device_id === ""))
this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Ignoring bucketing_identifier for group flag: ${flag.key}`));
const focusedGroupProperties = groupProperties[groupName];
return await this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties, evaluationContext);
}
{
const bucketingValue = this.getBucketingValueForFlag(flag, distinctId, personProperties);
if (bucketingValue === undefined) {
this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Can't compute feature flag: ${flag.key} without $device_id, falling back to server evaluation`));
throw new InconclusiveMatchError(`Can't compute feature flag: ${flag.key} without $device_id`);
}
return await this.matchFeatureFlagProperties(flag, bucketingValue, personProperties, evaluationContext);
}
}
getBucketingValueForFlag(flag, distinctId, properties) {
if (flag.filters?.aggregation_group_type_index != null)
return distinctId;
if (flag.bucketing_identifier === "device_id") {
const deviceId = properties?.$device_id;
if (deviceId == null || deviceId === "")
return;
return deviceId;
}
return distinctId;
}
getFeatureFlagPayload(key, flagValue) {
let payload = null;
if (flagValue !== false && flagValue != null) {
if (typeof flagValue == "boolean")
payload = this.featureFlagsByKey?.[key]?.filters?.payloads?.[flagValue.toString()] || null;
else if (typeof flagValue == "string")
payload = this.featureFlagsByKey?.[key]?.filters?.payloads?.[flagValue] || null;
if (payload != null) {
if (typeof payload == "object")
return payload;
if (typeof payload == "string")
try {
return JSON.parse(payload);
} catch {}
return payload;
}
}
return null;
}
async evaluateFlagDependency(property, properties, evaluationContext) {
const { evaluationCache } = evaluationContext;
const targetFlagKey = property.key;
if (!this.featureFlagsByKey)
throw new InconclusiveMatchError("Feature flags not available for dependency evaluation");
if (!("dependency_chain" in property))
throw new InconclusiveMatchError(`Flag dependency property for '${targetFlagKey}' is missing required 'dependency_chain' field`);
const dependencyChain = property.dependency_chain;
if (!Array.isArray(dependencyChain))
throw new InconclusiveMatchError(`Flag dependency property for '${targetFlagKey}' has an invalid 'dependency_chain' (expected array, got ${typeof dependencyChain})`);
if (dependencyChain.length === 0)
throw new InconclusiveMatchError(`Circular dependency detected for flag '${targetFlagKey}' (empty dependency chain)`);
for (const depFlagKey of dependencyChain) {
if (!(depFlagKey in evaluationCache)) {
const depFlag = this.featureFlagsByKey[depFlagKey];
if (depFlag)
if (depFlag.active)
try {
const depResult = await this.computeFlagValueLocally(depFlag, evaluationContext);
evaluationCache[depFlagKey] = depResult;
} catch (error) {
throw new InconclusiveMatchError(`Error evaluating flag dependency '${depFlagKey}' for flag '${targetFlagKey}': ${error}`);
}
else
evaluationCache[depFlagKey] = false;
else
throw new InconclusiveMatchError(`Missing flag dependency '${depFlagKey}' for flag '${targetFlagKey}'`);
}
const cachedResult = evaluationCache[depFlagKey];
if (cachedResult == null)
throw new InconclusiveMatchError(`Dependency '${depFlagKey}' could not be evaluated`);
}
const targetFlagValue = evaluationCache[targetFlagKey];
return this.flagEvaluatesToExpectedValue(property.value, targetFlagValue);
}
flagEvaluatesToExpectedValue(expectedValue, flagValue) {
if (typeof expectedValue == "boolean")
return expectedValue === flagValue || typeof flagValue == "string" && flagValue !== "" && expectedValue === true;
if (typeof expectedValue == "string")
return flagValue === expectedValue;
return false;
}
async matchFeatureFlagProperties(flag, bucketingValue, properties, evaluationContext) {
const flagFilters = flag.filters || {};
const flagConditions = flagFilters.groups || [];
const flagAggregation = flagFilters.aggregation_group_type_index;
const { groups, groupProperties } = evaluationContext;
let isInconclusive = false;
let result;
for (const condition of flagConditions)
try {
const conditionAggregation = condition.aggregation_group_type_index !== undefined ? condition.aggregation_group_type_index : flagAggregation;
let effectiveProperties = properties;
let effectiveBucketingValue = bucketingValue;
if (conditionAggregation !== flagAggregation) {
if (conditionAggregation != null) {
const groupName = this.groupTypeMapping[String(conditionAggregation)];
if (!groupName || !(groupName in groups)) {
this.logMsgIfDebug(() => console.debug(`[FEATURE FLAGS] Skipping group condition for flag '${flag.key}': group type index ${conditionAggregation} not available`));
continue;
}
if (!(groupName in groupProperties)) {
isInconclusive = true;
continue;
}
effectiveProperties = groupProperties[groupName];
effectiveBucketingValue = groups[groupName];
}
}
if (await this.isConditionMatch(flag, effectiveBucketingValue, condition, effectiveProperties, evaluationContext)) {
const variantOverride = condition.variant;
const flagVariants = flagFilters.multivariate?.variants || [];
result = variantOverride && flagVariants.some((variant) => variant.key === variantOverride) ? variantOverride : await this.getMatchingVariant(flag, effectiveBucketingValue) || true;
break;
}
} catch (e) {
if (e instanceof RequiresServerEvaluation)
throw e;
if (e instanceof InconclusiveMatchError)
isInconclusive = true;
else
throw e;
}
if (result !== undefined)
return result;
if (isInconclusive)
throw new InconclusiveMatchError("Can't determine if feature flag is enabled or not with given properties");
return false;
}
async isConditionMatch(flag, bucketingValue, condition, properties, evaluationContext) {
const rolloutPercentage = condition.rollout_percentage;
const warnFunction = (msg) => {
this.logMsgIfDebug(() => console.warn(msg));
};
if ((condition.properties || []).length > 0) {
for (const prop of condition.properties) {
const propertyType = prop.type;
let matches = false;
matches = propertyType === "cohort" ? matchCohort(prop, properties, this.cohorts, this.debugMode) : propertyType === "flag" ? await this.evaluateFlagDependency(prop, properties, evaluationContext) : matchProperty(prop, properties, warnFunction);
if (!matches)
return false;
}
if (rolloutPercentage == undefined)
return true;
}
if (rolloutPercentage != null && await _hash(flag.key, bucketingValue) > rolloutPercentage / 100)
return false;
return true;
}
async getMatchingVariant(flag, bucketingValue) {
const hashValue = await _hash(flag.key, bucketingValue, "variant");
const matchingVariant = this.variantLookupTable(flag).find((variant) => hashValue >= variant.valueMin && hashValue < variant.valueMax);
if (matchingVariant)
return matchingVariant.key;
}
variantLookupTable(flag) {
const lookupTable = [];
let valueMin = 0;
let valueMax = 0;
const flagFilters = flag.filters || {};
const multivariates = flagFilters.multivariate?.variants || [];
multivariates.forEach((variant) => {
valueMax = valueMin + variant.rollout_percentage / 100;
lookupTable.push({
valueMin,
valueMax,
key: variant.key
});
valueMin = valueMax;
});
return lookupTable;
}
updateFlagState(flagData) {
this.featureFlags = flagData.flags;
this.featureFlagsByKey = flagData.flags.reduce((acc, curr) => (acc[curr.key] = curr, acc), {});
this.groupTypeMapping = flagData.groupTypeMapping;
this.cohorts = flagData.cohorts;
this.loadedSuccessfullyOnce = true;
}
warnAboutExperienceContinuityFlags(flags) {
if (this.strictLocalEvaluation)
return;
const experienceContinuityFlags = flags.filter((f) => f.ensure_experience_continuity);
if (experienceContinuityFlags.length > 0)
console.warn(`[PostHog] You are using local evaluation but ${experienceContinuityFlags.length} flag(s) have experience continuity enabled: ${experienceContinuityFlags.map((f) => f.key).join(", ")}. Experience continuity is incompatible with local evaluation and will cause a server request on every flag evaluation, negating local evaluation cost savings. To avoid server requests and unexpected costs, either disable experience continuity on these flags in PostHog, use strictLocalEvaluation: true in client init, or pass onlyEvaluateLocally: true per flag call (flags that cannot be evaluated locally will return undefined).`);
}
async loadFromCache(debugMessage) {
if (!this.cacheProvider)
return false;
try {
const cached = await this.cacheProvider.getFlagDefinitions();
if (cached) {
this.updateFlagState(cached);
this.logMsgIfDebug(() => console.debug(`[FEATURE FLAGS] ${debugMessage} (${cached.flags.length} flags)`));
this.onLoad?.(this.featureFlags.length);
this.warnAboutExperienceContinuityFlags(cached.flags);
return true;
}
return false;
} catch (err) {
this.onError?.(new Error(`Failed to load from cache: ${err}`));
return false;
}
}
async loadFeatureFlags(forceReload = false) {
if (this.loadedSuccessfullyOnce && !forceReload)
return;
if (!forceReload && this.nextFetchAllowedAt && Date.now() < this.nextFetchAllowedAt)
return void this.logMsgIfDebug(() => console.debug("[FEATURE FLAGS] Skipping fetch, in backoff period"));
if (!this.loadingPromise)
this.loadingPromise = this._loadFeatureFlags().catch((err) => this.logMsgIfDebug(() => console.debug(`[FEATURE FLAGS] Failed to load feature flags: ${err}`))).finally(() => {
this.loadingPromise = undefined;
});
return this.loadingPromise;
}
isLocalEvaluationReady() {
return (this.loadedSuccessfullyOnce ?? false) && (this.featureFlags?.length ?? 0) > 0;
}
getFlagDefinitionsLoadedAt() {
return this.flagDefinitionsLoadedAt;
}
getPollingInterval() {
if (!this.shouldBeginExponentialBackoff)
return this.pollingInterval;
return Math.min(SIXTY_SECONDS, this.pollingInterval * 2 ** this.backOffCount);
}
beginBackoff() {
this.shouldBeginExponentialBackoff = true;
this.backOffCount += 1;
this.nextFetchAllowedAt = Date.now() + this.getPollingInterval();
}
clearBackoff() {
this.shouldBeginExponentialBackoff = false;
this.backOffCount = 0;
this.nextFetchAllowedAt = undefined;
}
async _loadFeatureFlags() {
if (this.poller) {
clearTimeout(this.poller);
this.poller = undefined;
}
this.poller = setTimeout(() => this.loadFeatureFlags(true), this.getPollingInterval());
try {
let shouldFetch = true;
if (this.cacheProvider)
try {
shouldFetch = await this.cacheProvider.shouldFetchFlagDefinitions();
} catch (err) {
this.onError?.(new Error(`Error in shouldFetchFlagDefinitions: ${err}`));
}
if (!shouldFetch) {
const loaded = await this.loadFromCache("Loaded flags from cache (skipped fetch)");
if (loaded)
return;
if (this.loadedSuccessfullyOnce)
return;
}
const res = await this._requestFeatureFlagDefinitions();
if (!res)
return;
switch (res.status) {
case 304:
this.logMsgIfDebug(() => console.debug("[FEATURE FLAGS] Flags not modified (304), using cached data"));
this.flagsEtag = res.headers?.get("ETag") ?? this.flagsEtag;
this.loadedSuccessfullyOnce = true;
this.clearBackoff();
return;
case 401:
this.beginBackoff();
throw new ClientError(`Your project key or personal API key is invalid. Setting next polling interval to ${this.getPollingInterval()}ms. More information: https://posthog.com/docs/api#rate-limiting`);
case 402:
console.warn("[FEATURE FLAGS] Feature flags quota limit exceeded - unsetting all local flags. Learn more about billing limits at https://posthog.com/docs/billing/limits-alerts");
this.featureFlags = [];
this.featureFlagsByKey = {};
this.groupTypeMapping = {};
this.cohorts = {};
return;
case 403:
this.beginBackoff();
throw new ClientError(`Your personal API key does not have permission to fetch feature flag definitions for local evaluation. Setting next polling interval to ${this.getPollingInterval()}ms. Are you sure you're using the correct personal and Project API key pair? More information: https://posthog.com/docs/api/overview`);
case 429:
this.beginBackoff();
throw new ClientError(`You are being rate limited. Setting next polling interval to ${this.getPollingInterval()}ms. More information: https://posthog.com/docs/api#rate-limiting`);
case 200: {
const responseJson = await res.json() ?? {};
if (!("flags" in responseJson))
return void this.onError?.(new Error(`Invalid response when getting feature flags: ${JSON.stringify(responseJson)}`));
this.flagsEtag = res.headers?.get("ETag") ?? undefined;
const flagData = {
flags: responseJson.flags ?? [],
groupTypeMapping: responseJson.group_type_mapping || {},
cohorts: responseJson.cohorts || {}
};
this.updateFlagState(flagData);
this.flagDefinitionsLoadedAt = Date.now();
this.clearBackoff();
if (this.cacheProvider && shouldFetch)
try {
await this.cacheProvider.onFlagDefinitionsReceived(flagData);
} catch (err) {
this.onError?.(new Error(`Failed to store in cache: ${err}`));
}
this.onLoad?.(this.featureFlags.length);
this.warnAboutExperienceContinuityFlags(flagData.flags);
break;
}
default:
return;
}
} catch (err) {
if (err instanceof ClientError)
this.onError?.(err);
}
}
getPersonalApiKeyRequestOptions(method = "GET", etag) {
const headers = {
...this.customHeaders,
"Content-Type": "application/json",
Authorization: `Bearer ${this.personalApiKey}`
};
if (etag)
headers["If-None-Match"] = etag;
return {
method,
headers
};
}
_requestFeatureFlagDefinitions() {
const url = `${this.host}/flags/definitions?token=${this.projectApiKey}&send_cohorts`;
const options = this.getPersonalApiKeyRequestOptions("GET", this.flagsEtag);
let abortTimeout = null;
if (this.timeout && typeof this.timeout == "number") {
const controller = new AbortController;
abortTimeout = safeSetTimeout(() => {
controller.abort();
}, this.timeout);
options.signal = controller.signal;
}
try {
const fetch1 = this.fetch;
return fetch1(url, options);
} finally {
clearTimeout(abortTimeout);
}
}
async stopPoller(timeoutMs = 30000) {
clearTimeout(this.poller);
if (this.cacheProvider)
try {
const shutdownResult = this.cacheProvider.shutdown();
if (shutdownResult instanceof Promise)
await Promise.race([
shutdownResult,
new Promise((_, reject) => setTimeout(() => reject(new Error(`Cache shutdown timeout after ${timeoutMs}ms`)), timeoutMs))
]);
} catch (err) {
this.onError?.(new Error(`Error during cache shutdown: ${err}`));
}
}
}
async function _hash(key, bucketingValue, salt = "") {
const hashString = await hashSHA1(`${key}.${bucketingValue}${salt}`);
return parseInt(hashString.slice(0, 15), 16) / LONG_SCALE;
}
function matchProperty(property, propertyValues, warnFunction) {
const key = property.key;
const value = property.value;
const operator = property.operator || "exact";
if (key in propertyValues) {
if (operator === "is_not_set")
throw new InconclusiveMatchError("Operator is_not_set is not supported");
} else
throw new InconclusiveMatchError(`Property ${key} not found in propertyValues`);
const overrideValue = propertyValues[key];
if (overrideValue == null && !NULL_VALUES_ALLOWED_OPERATORS.includes(operator)) {
if (warnFunction)
warnFunction(`Property ${key} cannot have a value of null/undefined with the ${operator} operator`);
return false;
}
function computeExactMatch(value2, overrideValue2) {
if (Array.isArray(value2))
return value2.map((val) => String(val).toLowerCase()).includes(String(overrideValue2).toLowerCase());
return String(value2).toLowerCase() === String(overrideValue2).toLowerCase();
}
function compare(lhs, rhs, operator2) {
if (operator2 === "gt")
return lhs > rhs;
if (operator2 === "gte")
return lhs >= rhs;
if (operator2 === "lt")
return lhs < rhs;
if (operator2 === "lte")
return lhs <= rhs;
throw new Error(`Invalid operator: ${operator2}`);
}
switch (operator) {
case "exact":
return computeExactMatch(value, overrideValue);
case "is_not":
return !computeExactMatch(value, overrideValue);
case "is_set":
return key in propertyValues;
case "icontains":
return String(overrideValue).toLowerCase().includes(String(value).toLowerCase());
case "not_icontains":
return !String(overrideValue).toLowerCase().includes(String(value).toLowerCase());
case "regex":
return isValidRegex(String(value)) && String(overrideValue).match(String(value)) !== null;
case "not_regex":
return isValidRegex(String(value)) && String(overrideValue).match(String(value)) === null;
case "gt":
case "gte":
case "lt":
case "lte": {
let parsedValue = typeof value == "number" ? value : null;
if (typeof value == "string")
try {
parsedValue = parseFloat(value);
} catch (err) {}
if (parsedValue == null || overrideValue == null)
return compare(String(overrideValue), String(value), operator);
if (typeof overrideValue == "string")
return compare(overrideValue, String(value), operator);
return compare(overrideValue, parsedValue, operator);
}
case "is_date_after":
case "is_date_before": {
if (typeof value == "boolean")
throw new InconclusiveMatchError("Date operations cannot be performed on boolean values");
let parsedDate = relativeDateParseForFeatureFlagMatching(String(value));
if (parsedDate == null)
parsedDate = convertToDateTime(value);
if (parsedDate == null)
throw new InconclusiveMatchError(`Invalid date: ${value}`);
const overrideDate = convertToDateTime(overrideValue);
if ([
"is_date_before"
].includes(operator))
return overrideDate < parsedDate;
return overrideDate > parsedDate;
}
case "semver_eq": {
const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
return cmp === 0;
}
case "semver_neq": {
const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
return cmp !== 0;
}
case "semver_gt": {
const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
return cmp > 0;
}
case "semver_gte": {
const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
return cmp >= 0;
}
case "semver_lt": {
const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
return cmp < 0;
}
case "semver_lte": {
const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
return cmp <= 0;
}
case "semver_tilde": {
const overrideParsed = parseSemver(String(overrideValue));
const { lower, upper } = computeTildeBounds(String(value));
return compareSemverTuples(overrideParsed, lower) >= 0 && compareSemverTuples(overrideParsed, upper) < 0;
}
case "semver_caret": {
const overrideParsed = parseSemver(String(overrideValue));
const { lower, upper } = computeCaretBounds(String(value));
return compareSemverTuples(overrideParsed, lower) >= 0 && compareSemverTuples(overrideParsed, upper) < 0;
}
case "semver_wildcard": {
const overrideParsed = parseSemver(String(overrideValue));
const { lower, upper } = computeWildcardBounds(String(value));
return compareSemverTuples(overrideParsed, lower) >= 0 && compareSemverTuples(overrideParsed, upper) < 0;
}
default:
throw new InconclusiveMatchError(`Unknown operator: ${operator}`);
}
}
function checkCohortExists(cohortId, cohortProperties) {
if (!(cohortId in cohortProperties))
throw new RequiresServerEvaluation(`cohort ${cohortId} not found in local cohorts - likely a static cohort that requires server evaluation`);
}
function matchCohort(property, propertyValues, cohortProperties, debugMode = false) {
const cohortId = String(property.value);
checkCohortExists(cohortId, cohortProperties);
const propertyGroup = cohortProperties[cohortId];
return matchPropertyGroup(propertyGroup, propertyValues, cohortProperties, debugMode);
}
function matchPropertyGroup(propertyGroup, propertyValues, cohortProperties, debugMode = false) {
if (!propertyGroup)
return true;
const propertyGroupType = propertyGroup.type;
const properties = propertyGroup.values;
if (!properties || properties.length === 0)
return true;
let errorMatchingLocally = false;
if ("values" in properties[0]) {
for (const prop of properties)
try {
const matches = matchPropertyGroup(prop, propertyValues, cohortProperties, debugMode);
if (propertyGroupType === "AND") {
if (!matches)
return false;
} else if (matches)
return true;
} catch (err) {
if (err instanceof RequiresServerEvaluation)
throw err;
if (err instanceof InconclusiveMatchError) {
if (debugMode)
console.debug(`Failed to compute property ${prop} locally: ${err}`);
errorMatchingLocally = true;
} else
throw err;
}
if (errorMatchingLocally)
throw new InconclusiveMatchError("Can't match cohort without a given cohort property value");
return propertyGroupType === "AND";
}
for (const prop of properties)
try {
let matches;
if (prop.type === "cohort")
matches = matchCohort(prop, propertyValues, cohortProperties, debugMode);
else if (prop.type === "flag") {
if (debugMode)
console.warn(`[FEATURE FLAGS] Flag dependency filters are not supported in local evaluation. Skipping condition with dependency on flag '${prop.key || "unknown"}'`);
continue;
} else
matches = matchProperty(prop, propertyValues);
const negation = prop.negation || false;
if (propertyGroupType === "AND") {
if (!matches && !negation)
return false;
if (matches && negation)
return false;
} else {
if (matches && !negation)
return true;
if (!matches && negation)
return true;
}
} catch (err) {
if (err instanceof RequiresServerEvaluation)
throw err;
if (err instanceof InconclusiveMatchError) {
if (debugMode)
console.debug(`Failed to compute property ${prop} locally: ${err}`);
errorMatchingLocally = true;
} else
throw err;
}
if (errorMatchingLocally)
throw new InconclusiveMatchError("can't match cohort without a given cohort property value");
return propertyGroupType === "AND";
}
function isValidRegex(regex) {
try {
new RegExp(regex);
return true;
} catch (err) {
return false;
}
}
function parseSemver(value) {
const text = String(value).trim().replace(/^[vV]/, "");
const baseVersion = text.split("-")[0].split("+")[0];
if (!baseVersion || baseVersion.startsWith("."))
throw new InconclusiveMatchError(`Invalid semver: ${value}`);
const parts = baseVersion.split(".");
const parsePart = (part) => {
if (part === undefined || part === "")
return 0;
if (!/^\d+$/.test(part))
throw new InconclusiveMatchError(`Invalid semver: ${value}`);
return parseInt(part, 10);
};
const major = parsePart(parts[0]);
const minor = parsePart(parts[1]);
const patch = parsePart(parts[2]);
return [
major,
minor,
patch
];
}
function compareSemverTuples(a, b) {
for (let i = 0;i < 3; i++) {
if (a[i] < b[i])
return -1;
if (a[i] > b[i])
return 1;
}
return 0;
}
function computeTildeBounds(value) {
const parsed = parseSemver(value);
const lower = [
parsed[0],
parsed[1],
parsed[2]
];
const upper = [
parsed[0],
parsed[1] + 1,
0
];
return {
lower,
upper
};
}
function computeCaretBounds(value) {
const parsed = parseSemver(value);
const [major, minor, patch] = parsed;
const lower = [
major,
minor,
patch
];
let upper;
upper = major > 0 ? [
major + 1,
0,
0
] : minor > 0 ? [
0,
minor + 1,
0
] : [
0,
0,
patch + 1
];
return {
lower,
upper
};
}
function computeWildcardBounds(value) {
const text = String(value).trim().replace(/^[vV]/, "");
const cleanedText = text.replace(/\.\*$/, "").replace(/\*$/, "");
if (!cleanedText)
throw new InconclusiveMatchError(`Invalid wildcard semver: ${value}`);
const parts = cleanedText.split(".");
const major = parseInt(parts[0], 10);
if (isNaN(major))
throw new InconclusiveMatchError(`Invalid wildcard semver: ${value}`);
let lower;
let upper;
if (parts.length === 1) {
lower = [
major,
0,
0
];
upper = [
major + 1,
0,
0
];
} else {
const minor = parseInt(parts[1], 10);
if (isNaN(minor))
throw new InconclusiveMatchError(`Invalid wildcard semver: ${value}`);
lower = [
major,
minor,
0
];
upper = [
major,
minor + 1,
0
];
}
return {
lower,
upper
};
}
function convertToDateTime(value) {
if (value instanceof Date)
return value;
if (typeof value == "string" || typeof value == "number") {
const date = new Date(value);
if (!isNaN(date.valueOf()))
return date;
throw new InconclusiveMatchError(`${value} is in an invalid date format`);
}
throw new InconclusiveMatchError(`The date provided ${value} must be a string, number, or date object`);
}
function relativeDateParseForFeatureFlagMatching(value) {
const regex = /^-?(?<number>[0-9]+)(?<interval>[a-z])$/;
const match = value.match(regex);
const parsedDt = new Date(new Date().toISOString());
if (!match)
return null;
{
if (!match.groups)
return null;
const number = parseInt(match.groups["number"]);
if (number >= 1e4)
return null;
const interval = match.groups["interval"];
if (interval == "h")
parsedDt.setUTCHours(parsedDt.getUTCHours() - number);
else if (interval == "d")
parsedDt.setUTCDate(parsedDt.getUTCDate() - number);
else if (interval == "w")
parsedDt.setUTCDate(parsedDt.getUTCDate() - 7 * number);
else if (interval == "m")
parsedDt.setUTCMonth(parsedDt.getUTCMonth() - number);
else {
if (interval != "y")
return null;
parsedDt.setUTCFullYear(parsedDt.getUTCFullYear() - number);
}
return parsedDt;
}
}
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/storage-memory.mjs
class PostHogMemoryStorage {
getProperty(key) {
return this._memoryStorage[key];
}
setProperty(key, value) {
this._memoryStorage[key] = value !== null ? value : undefined;
}
constructor() {
this._memoryStorage = {};
}
}
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/client.mjs
var MINIMUM_POLLING_INTERVAL = 100;
var THIRTY_SECONDS = 30000;
var MAX_CACHE_SIZE = 50000;
var WAITUNTIL_DEBOUNCE_MS = 50;
var WAITUNTIL_MAX_WAIT_MS = 500;
var DEFAULT_NODE_HOST = "https://us.i.posthog.com";
function normalizeApiKey(value) {
return typeof value == "string" ? value.trim() : "";
}
function normalizePersonalApiKey(value) {
const normalizedValue = typeof value == "string" ? value.trim() : "";
return normalizedValue || undefined;
}
function normalizeHost(value) {
const normalizedValue = typeof value == "string" ? value.trim() : "";
return normalizedValue || DEFAULT_NODE_HOST;
}
class PostHogBackendClient extends PostHogCoreStateless {
constructor(apiKey, options = {}) {
const normalizedApiKey = normalizeApiKey(apiKey);
const normalizedOptions = {
...options,
host: normalizeHost(options.host),
personalApiKey: normalizePersonalApiKey(options.personalApiKey)
};
super(normalizedApiKey, normalizedOptions), this._memoryStorage = new PostHogMemoryStorage;
this.options = normalizedOptions;
this.context = this.initializeContext();
this.options.featureFlagsPollingInterval = typeof normalizedOptions.featureFlagsPollingInterval == "number" ? Math.max(normalizedOptions.featureFlagsPollingInterval, MINIMUM_POLLING_INTERVAL) : THIRTY_SECONDS;
if (typeof normalizedOptions.waitUntilDebounceMs == "number")
this.options.waitUntilDebounceMs = Math.max(normalizedOptions.waitUntilDebounceMs, 0);
if (typeof normalizedOptions.waitUntilMaxWaitMs == "number")
this.options.waitUntilMaxWaitMs = Math.max(normalizedOptions.waitUntilMaxWaitMs, 0);
if (normalizedOptions.personalApiKey) {
if (normalizedOptions.personalApiKey.includes("phc_"))
throw new Error('Your Personal API key is invalid. These keys are prefixed with "phx_" and can be created in PostHog project settings.');
const shouldEnableLocalEvaluation = normalizedOptions.enableLocalEvaluation !== false;
if (shouldEnableLocalEvaluation)
this.featureFlagsPoller = new FeatureFlagsPoller({
pollingInterval: this.options.featureFlagsPollingInterval,
personalApiKey: normalizedOptions.personalApiKey,
projectApiKey: normalizedApiKey,
timeout: normalizedOptions.requestTimeout ?? 1e4,
host: this.host,
fetch: normalizedOptions.fetch,
onError: (err) => {
this._events.emit("error", err);
},
onLoad: (count) => {
this._events.emit("localEvaluationFlagsLoaded", count);
},
customHeaders: this.getCustomHeaders(),
cacheProvider: normalizedOptions.flagDefinitionCacheProvider,
strictLocalEvaluation: normalizedOptions.strictLocalEvaluation
});
}
this.errorTracking = new ErrorTracking(this, normalizedOptions, this._logger);
this.distinctIdHasSentFlagCalls = {};
this.maxCacheSize = normalizedOptions.maxCacheSize || MAX_CACHE_SIZE;
}
enqueue(type, message, options) {
super.enqueue(type, message, options);
this.scheduleDebouncedFlush();
}
async flush() {
const flushPromise = super.flush();
const waitUntil = this.options.waitUntil;
if (waitUntil && !this._waitUntilCycle)
try {
waitUntil(flushPromise.catch(() => {}));
} catch {}
return flushPromise;
}
scheduleDebouncedFlush() {
const waitUntil = this.options.waitUntil;
if (!waitUntil)
return;
if (this.disabled || this.optedOut)
return;
if (!this._waitUntilCycle) {
let resolve;
const promise = new Promise((r) => {
resolve = r;
});
try {
waitUntil(promise);
} catch {
return;
}
this._waitUntilCycle = {
resolve,
startedAt: Date.now(),
timer: undefined
};
}
const elapsed = Date.now() - this._waitUntilCycle.startedAt;
const maxWaitMs = this.options.waitUntilMaxWaitMs ?? WAITUNTIL_MAX_WAIT_MS;
const flushNow = elapsed >= maxWaitMs;
if (this._waitUntilCycle.timer !== undefined)
clearTimeout(this._waitUntilCycle.timer);
if (flushNow)
return void this.resolveWaitUntilFlush();
const debounceMs = this.options.waitUntilDebounceMs ?? WAITUNTIL_DEBOUNCE_MS;
this._waitUntilCycle.timer = safeSetTimeout(() => {
this.resolveWaitUntilFlush();
}, debounceMs);
}
_consumeWaitUntilCycle() {
const cycle = this._waitUntilCycle;
if (cycle) {
clearTimeout(cycle.timer);
this._waitUntilCycle = undefined;
}
return cycle?.resolve;
}
async resolveWaitUntilFlush() {
const resolve = this._consumeWaitUntilCycle();
try {
await super.flush();
} catch {} finally {
resolve?.();
}
}
getPersistedProperty(key) {
return this._memoryStorage.getProperty(key);
}
setPersistedProperty(key, value) {
return this._memoryStorage.setProperty(key, value);
}
fetch(url, options) {
return this.options.fetch ? this.options.fetch(url, options) : fetch(url, options);
}
getLibraryVersion() {
return version;
}
getCustomUserAgent() {
return `${this.getLibraryId()}/${this.getLibraryVersion()}`;
}
enable() {
return super.optIn();
}
disable() {
return super.optOut();
}
debug(enabled = true) {
super.debug(enabled);
this.featureFlagsPoller?.debug(enabled);
}
capture(props) {
if (typeof props == "string")
this._logger.warn("Called capture() with a string as the first argument when an object was expected.");
if (props.event === "$exception" && !props._originatedFromCaptureException)
this._logger.warn("Using `posthog.capture('$exception')` is unreliable because it does not attach required metadata. Use `posthog.captureException(error)` instead, which attaches required metadata automatically.");
this.addPendingPromise(this.prepareEventMessage(props).then(({ distinctId, event, properties, options }) => super.captureStateless(distinctId, event, properties, {
timestamp: options.timestamp,
disableGeoip: options.disableGeoip,
uuid: options.uuid
})).catch((err) => {
if (err)
console.error(err);
}));
}
async captureImmediate(props) {
if (typeof props == "string")
this._logger.warn("Called captureImmediate() with a string as the first argument when an object was expected.");
if (props.event === "$exception" && !props._originatedFromCaptureException)
this._logger.warn("Capturing a `$exception` event via `posthog.captureImmediate('$exception')` is unreliable because it does not attach required metadata. Use `posthog.captureExceptionImmediate(error)` instead, which attaches this metadata by default.");
return this.addPendingPromise(this.prepareEventMessage(props).then(({ distinctId, event, properties, options }) => super.captureStatelessImmediate(distinctId, event, properties, {
timestamp: options.timestamp,
disableGeoip: options.disableGeoip,
uuid: options.uuid
})).catch((err) => {
if (err)
console.error(err);
}));
}
identify({ distinctId, properties = {}, disableGeoip }) {
const { $set, $set_once, $anon_distinct_id, ...rest } = properties;
const setProps = $set || rest;
const setOnceProps = $set_once || {};
const eventProperties = {
$set: setProps,
$set_once: setOnceProps,
$anon_distinct_id: $anon_distinct_id ?? undefined
};
super.identifyStateless(distinctId, eventProperties, {
disableGeoip
});
}
async identifyImmediate({ distinctId, properties = {}, disableGeoip }) {
const { $set, $set_once, $anon_distinct_id, ...rest } = properties;
const setProps = $set || rest;
const setOnceProps = $set_once || {};
const eventProperties = {
$set: setProps,
$set_once: setOnceProps,
$anon_distinct_id: $anon_distinct_id ?? undefined
};
super.identifyStatelessImmediate(distinctId, eventProperties, {
disableGeoip
});
}
alias(data) {
super.aliasStateless(data.alias, data.distinctId, undefined, {
disableGeoip: data.disableGeoip
});
}
async aliasImmediate(data) {
await super.aliasStatelessImmediate(data.alias, data.distinctId, undefined, {
disableGeoip: data.disableGeoip
});
}
isLocalEvaluationReady() {
return this.featureFlagsPoller?.isLocalEvaluationReady() ?? false;
}
async waitForLocalEvaluationReady(timeoutMs = THIRTY_SECONDS) {
if (this.isLocalEvaluationReady())
return true;
if (this.featureFlagsPoller === undefined)
return false;
return new Promise((resolve) => {
const timeout = setTimeout(() => {
cleanup();
resolve(false);
}, timeoutMs);
const cleanup = this._events.on("localEvaluationFlagsLoaded", (count) => {
clearTimeout(timeout);
cleanup();
resolve(count > 0);
});
});
}
_resolveDistinctId(distinctIdOrOptions, options) {
if (typeof distinctIdOrOptions == "string")
return {
distinctId: distinctIdOrOptions,
options
};
return {
distinctId: this.context?.get()?.distinctId,
options: distinctIdOrOptions
};
}
async _getFeatureFlagResult(key, distinctId, options = {}, matchValue) {
const sendFeatureFlagEvents = options.sendFeatureFlagEvents ?? true;
if (this._flagOverrides !== undefined && key in this._flagOverrides) {
const overrideValue = this._flagOverrides[key];
if (overrideValue === undefined)
return;
const overridePayload = this._payloadOverrides?.[key];
return {
key,
enabled: overrideValue !== false,
variant: typeof overrideValue == "string" ? overrideValue : undefined,
payload: overridePayload
};
}
const { groups, disableGeoip } = options;
let { onlyEvaluateLocally, personProperties, groupProperties } = options;
const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
personProperties = adjustedProperties.allPersonProperties;
groupProperties = adjustedProperties.allGroupProperties;
const evaluationContext = this.createFeatureFlagEvaluationContext(distinctId, groups, personProperties, groupProperties);
if (onlyEvaluateLocally == undefined)
onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false;
let result;
let flagWasLocallyEvaluated = false;
let requestId;
let evaluatedAt;
let featureFlagError;
let flagId;
let flagVersion;
let flagReason;
const localEvaluationEnabled = this.featureFlagsPoller !== undefined;
if (localEvaluationEnabled) {
await this.featureFlagsPoller?.loadFeatureFlags();
const flag = this.featureFlagsPoller?.featureFlagsByKey[key];
if (flag)
try {
const localResult = await this.featureFlagsPoller?.computeFlagAndPayloadLocally(flag, evaluationContext, {
matchValue
});
if (localResult) {
flagWasLocallyEvaluated = true;
const value = localResult.value;
flagId = flag.id;
flagReason = "Evaluated locally";
result = {
key,
enabled: value !== false,
variant: typeof value == "string" ? value : undefined,
payload: localResult.payload ?? undefined
};
}
} catch (e) {
if (e instanceof RequiresServerEvaluation || e instanceof InconclusiveMatchError)
this._logger?.info(`${e.name} when computing flag locally: ${key}: ${e.message}`);
else
throw e;
}
}
if (!flagWasLocallyEvaluated && !onlyEvaluateLocally) {
const flagsResponse = await super.getFeatureFlagDetailsStateless(evaluationContext.distinctId, evaluationContext.groups, evaluationContext.personProperties, evaluationContext.groupProperties, disableGeoip, [
key
]);
if (flagsResponse === undefined)
featureFlagError = FeatureFlagError2.UNKNOWN_ERROR;
else {
requestId = flagsResponse.requestId;
evaluatedAt = flagsResponse.evaluatedAt;
const errors = [];
if (flagsResponse.errorsWhileComputingFlags)
errors.push(FeatureFlagError2.ERRORS_WHILE_COMPUTING);
if (flagsResponse.quotaLimited?.includes("feature_flags"))
errors.push(FeatureFlagError2.QUOTA_LIMITED);
const flagDetail = flagsResponse.flags[key];
if (flagDetail === undefined)
errors.push(FeatureFlagError2.FLAG_MISSING);
else {
flagId = flagDetail.metadata?.id;
flagVersion = flagDetail.metadata?.version;
flagReason = flagDetail.reason?.description ?? flagDetail.reason?.code;
let parsedPayload;
if (flagDetail.metadata?.payload !== undefined)
try {
parsedPayload = JSON.parse(flagDetail.metadata.payload);
} catch {
parsedPayload = flagDetail.metadata.payload;
}
result = {
key,
enabled: flagDetail.enabled,
variant: flagDetail.variant,
payload: parsedPayload
};
}
if (errors.length > 0)
featureFlagError = errors.join(",");
}
}
if (sendFeatureFlagEvents) {
const response = result === undefined ? undefined : result.enabled === false ? false : result.variant ?? true;
const featureFlagReportedKey = `${key}_${response}`;
if (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey)) {
if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize)
this.distinctIdHasSentFlagCalls = {};
if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId]))
this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
else
this.distinctIdHasSentFlagCalls[distinctId] = [
featureFlagReportedKey
];
const properties = {
$feature_flag: key,
$feature_flag_response: response,
$feature_flag_id: flagId,
$feature_flag_version: flagVersion,
$feature_flag_reason: flagReason,
locally_evaluated: flagWasLocallyEvaluated,
[`$feature/${key}`]: response,
$feature_flag_request_id: requestId,
$feature_flag_evaluated_at: flagWasLocallyEvaluated ? Date.now() : evaluatedAt
};
if (flagWasLocallyEvaluated && this.featureFlagsPoller) {
const flagDefinitionsLoadedAt = this.featureFlagsPoller.getFlagDefinitionsLoadedAt();
if (flagDefinitionsLoadedAt !== undefined)
properties.$feature_flag_definitions_loaded_at = flagDefinitionsLoadedAt;
}
if (featureFlagError)
properties.$feature_flag_error = featureFlagError;
this.capture({
distinctId,
event: "$feature_flag_called",
properties,
groups,
disableGeoip
});
}
}
if (result !== undefined && this._payloadOverrides !== undefined && key in this._payloadOverrides)
result = {
...result,
payload: this._payloadOverrides[key]
};
return result;
}
async getFeatureFlag(key, distinctId, options) {
const result = await this._getFeatureFlagResult(key, distinctId, {
...options,
sendFeatureFlagEvents: options?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true
});
if (result === undefined)
return;
if (result.enabled === false)
return false;
return result.variant ?? true;
}
async getFeatureFlagPayload(key, distinctId, matchValue, options) {
if (this._payloadOverrides !== undefined && key in this._payloadOverrides)
return this._payloadOverrides[key];
const result = await this._getFeatureFlagResult(key, distinctId, {
...options,
sendFeatureFlagEvents: false
}, matchValue);
if (result === undefined)
return;
return result.payload ?? null;
}
async getFeatureFlagResult(key, distinctIdOrOptions, options) {
const { distinctId: resolvedDistinctId, options: resolvedOptions } = this._resolveDistinctId(distinctIdOrOptions, options);
if (!resolvedDistinctId)
return void this._logger.warn("[PostHog] distinctId is required \u2014 pass it explicitly or use withContext()");
return this._getFeatureFlagResult(key, resolvedDistinctId, {
...resolvedOptions,
sendFeatureFlagEvents: resolvedOptions?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true
});
}
async getRemoteConfigPayload(flagKey) {
if (!this.options.personalApiKey)
throw new Error("Personal API key is required for remote config payload decryption");
const response = await this._requestRemoteConfigPayload(flagKey);
if (!response)
return;
const parsed = await response.json();
if (typeof parsed == "string")
try {
return JSON.parse(parsed);
} catch (e) {}
return parsed;
}
async isFeatureEnabled(key, distinctId, options) {
const feat = await this.getFeatureFlag(key, distinctId, options);
if (feat === undefined)
return;
return !!feat || false;
}
async getAllFlags(distinctIdOrOptions, options) {
const { distinctId: resolvedDistinctId, options: resolvedOptions } = this._resolveDistinctId(distinctIdOrOptions, options);
if (!resolvedDistinctId) {
this._logger.warn("[PostHog] distinctId is required to get feature flags \u2014 pass it explicitly or use withContext()");
return {};
}
const response = await this.getAllFlagsAndPayloads(resolvedDistinctId, resolvedOptions);
return response.featureFlags || {};
}
async getAllFlagsAndPayloads(distinctIdOrOptions, options) {
const { distinctId: resolvedDistinctId, options: resolvedOptions } = this._resolveDistinctId(distinctIdOrOptions, options);
if (!resolvedDistinctId) {
this._logger.warn("[PostHog] distinctId is required to get feature flags and payloads \u2014 pass it explicitly or use withContext()");
return {
featureFlags: {},
featureFlagPayloads: {}
};
}
const { groups, disableGeoip, flagKeys } = resolvedOptions || {};
let { onlyEvaluateLocally, personProperties, groupProperties } = resolvedOptions || {};
const adjustedProperties = this.addLocalPersonAndGroupProperties(resolvedDistinctId, groups, personProperties, groupProperties);
personProperties = adjustedProperties.allPersonProperties;
groupProperties = adjustedProperties.allGroupProperties;
const evaluationContext = this.createFeatureFlagEvaluationContext(resolvedDistinctId, groups, personProperties, groupProperties);
if (onlyEvaluateLocally == undefined)
onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false;
const localEvaluationResult = await this.featureFlagsPoller?.getAllFlagsAndPayloads(evaluationContext, flagKeys);
let featureFlags = {};
let featureFlagPayloads = {};
let fallbackToFlags = true;
if (localEvaluationResult) {
featureFlags = localEvaluationResult.response;
featureFlagPayloads = localEvaluationResult.payloads;
fallbackToFlags = localEvaluationResult.fallbackToFlags;
}
if (fallbackToFlags && !onlyEvaluateLocally) {
const remoteEvaluationResult = await super.getFeatureFlagsAndPayloadsStateless(evaluationContext.distinctId, evaluationContext.groups, evaluationContext.personProperties, evaluationContext.groupProperties, disableGeoip, flagKeys);
featureFlags = {
...featureFlags,
...remoteEvaluationResult.flags || {}
};
featureFlagPayloads = {
...featureFlagPayloads,
...remoteEvaluationResult.payloads || {}
};
}
if (this._flagOverrides !== undefined)
featureFlags = {
...featureFlags,
...this._flagOverrides
};
if (this._payloadOverrides !== undefined)
featureFlagPayloads = {
...featureFlagPayloads,
...this._payloadOverrides
};
return {
featureFlags,
featureFlagPayloads
};
}
groupIdentify({ groupType, groupKey, properties, distinctId, disableGeoip }) {
super.groupIdentifyStateless(groupType, groupKey, properties, {
disableGeoip
}, distinctId);
}
async reloadFeatureFlags() {
await this.featureFlagsPoller?.loadFeatureFlags(true);
}
overrideFeatureFlags(overrides) {
const flagArrayToRecord = (flags) => Object.fromEntries(flags.map((f) => [
f,
true
]));
if (overrides === false) {
this._flagOverrides = undefined;
this._payloadOverrides = undefined;
return;
}
if (Array.isArray(overrides)) {
this._flagOverrides = flagArrayToRecord(overrides);
return;
}
if (this._isFeatureFlagOverrideOptions(overrides)) {
if ("flags" in overrides) {
if (overrides.flags === false)
this._flagOverrides = undefined;
else if (Array.isArray(overrides.flags))
this._flagOverrides = flagArrayToRecord(overrides.flags);
else if (overrides.flags !== undefined)
this._flagOverrides = {
...overrides.flags
};
}
if ("payloads" in overrides) {
if (overrides.payloads === false)
this._payloadOverrides = undefined;
else if (overrides.payloads !== undefined)
this._payloadOverrides = {
...overrides.payloads
};
}
return;
}
this._flagOverrides = {
...overrides
};
}
_isFeatureFlagOverrideOptions(overrides) {
if (typeof overrides != "object" || overrides === null || Array.isArray(overrides))
return false;
const obj = overrides;
if ("flags" in obj) {
const flagsValue = obj["flags"];
if (flagsValue === false || Array.isArray(flagsValue) || typeof flagsValue == "object" && flagsValue !== null)
return true;
}
if ("payloads" in obj) {
const payloadsValue = obj["payloads"];
if (payloadsValue === false || typeof payloadsValue == "object" && payloadsValue !== null)
return true;
}
return false;
}
withContext(data, fn, options) {
if (!this.context)
return fn();
return this.context.run(data, fn, options);
}
getContext() {
return this.context?.get();
}
enterContext(data, options) {
this.context?.enter(data, options);
}
async _shutdown(shutdownTimeoutMs) {
const resolve = this._consumeWaitUntilCycle();
await this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
this.errorTracking.shutdown();
try {
return await super._shutdown(shutdownTimeoutMs);
} finally {
resolve?.();
}
}
async _requestRemoteConfigPayload(flagKey) {
if (!this.options.personalApiKey)
return;
const url = `${this.host}/api/projects/@current/feature_flags/${flagKey}/remote_config?token=${encodeURIComponent(this.apiKey)}`;
const options = {
method: "GET",
headers: {
...this.getCustomHeaders(),
"Content-Type": "application/json",
Authorization: `Bearer ${this.options.personalApiKey}`
}
};
let abortTimeout = null;
if (this.options.requestTimeout && typeof this.options.requestTimeout == "number") {
const controller = new AbortController;
abortTimeout = safeSetTimeout(() => {
controller.abort();
}, this.options.requestTimeout);
options.signal = controller.signal;
}
try {
return await this.fetch(url, options);
} catch (error) {
this._events.emit("error", error);
return;
} finally {
if (abortTimeout)
clearTimeout(abortTimeout);
}
}
extractPropertiesFromEvent(eventProperties, groups) {
if (!eventProperties)
return {
personProperties: {},
groupProperties: {}
};
const personProperties = {};
const groupProperties = {};
for (const [key, value] of Object.entries(eventProperties))
if (isPlainObject(value) && groups && key in groups) {
const groupProps = {};
for (const [groupKey, groupValue] of Object.entries(value))
groupProps[String(groupKey)] = String(groupValue);
groupProperties[String(key)] = groupProps;
} else
personProperties[String(key)] = String(value);
return {
personProperties,
groupProperties
};
}
async getFeatureFlagsForEvent(distinctId, groups, disableGeoip, sendFeatureFlagsOptions) {
const finalPersonProperties = sendFeatureFlagsOptions?.personProperties || {};
const finalGroupProperties = sendFeatureFlagsOptions?.groupProperties || {};
const flagKeys = sendFeatureFlagsOptions?.flagKeys;
const onlyEvaluateLocally = sendFeatureFlagsOptions?.onlyEvaluateLocally ?? this.options.strictLocalEvaluation ?? false;
if (onlyEvaluateLocally)
if (!((this.featureFlagsPoller?.featureFlags?.length || 0) > 0))
return {};
else {
const groupsWithStringValues = {};
for (const [key, value] of Object.entries(groups || {}))
groupsWithStringValues[key] = String(value);
return await this.getAllFlags(distinctId, {
groups: groupsWithStringValues,
personProperties: finalPersonProperties,
groupProperties: finalGroupProperties,
disableGeoip,
onlyEvaluateLocally: true,
flagKeys
});
}
if ((this.featureFlagsPoller?.featureFlags?.length || 0) > 0) {
const groupsWithStringValues = {};
for (const [key, value] of Object.entries(groups || {}))
groupsWithStringValues[key] = String(value);
return await this.getAllFlags(distinctId, {
groups: groupsWithStringValues,
personProperties: finalPersonProperties,
groupProperties: finalGroupProperties,
disableGeoip,
onlyEvaluateLocally: true,
flagKeys
});
}
return (await super.getFeatureFlagsStateless(distinctId, groups, finalPersonProperties, finalGroupProperties, disableGeoip)).flags;
}
addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties) {
const allPersonProperties = {
distinct_id: distinctId,
...personProperties || {}
};
const allGroupProperties = {};
if (groups)
for (const groupName of Object.keys(groups))
allGroupProperties[groupName] = {
$group_key: groups[groupName],
...groupProperties?.[groupName] || {}
};
return {
allPersonProperties,
allGroupProperties
};
}
createFeatureFlagEvaluationContext(distinctId, groups, personProperties, groupProperties) {
return {
distinctId,
groups: groups || {},
personProperties: personProperties || {},
groupProperties: groupProperties || {},
evaluationCache: {}
};
}
captureException(error, distinctId, additionalProperties, uuid) {
if (!ErrorTracking.isPreviouslyCapturedError(error)) {
const syntheticException = new Error("PostHog syntheticException");
this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
syntheticException
}, distinctId, additionalProperties).then((msg) => this.capture({
...msg,
uuid
})));
}
}
async captureExceptionImmediate(error, distinctId, additionalProperties) {
if (!ErrorTracking.isPreviouslyCapturedError(error)) {
const syntheticException = new Error("PostHog syntheticException");
return this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
syntheticException
}, distinctId, additionalProperties).then((msg) => this.captureImmediate(msg)));
}
}
async prepareEventMessage(props) {
const { distinctId, event, properties, groups, sendFeatureFlags, timestamp, disableGeoip, uuid } = props;
const contextData = this.context?.get();
let mergedDistinctId = distinctId || contextData?.distinctId;
const mergedProperties = {
...this.props,
...contextData?.properties || {},
...properties || {}
};
if (!mergedDistinctId) {
mergedDistinctId = uuidv7();
mergedProperties.$process_person_profile = false;
}
if (contextData?.sessionId && !mergedProperties.$session_id)
mergedProperties.$session_id = contextData.sessionId;
const eventMessage = this._runBeforeSend({
distinctId: mergedDistinctId,
event,
properties: mergedProperties,
groups,
sendFeatureFlags,
timestamp,
disableGeoip,
uuid
});
if (!eventMessage)
return Promise.reject(null);
const eventProperties = await Promise.resolve().then(async () => {
if (sendFeatureFlags) {
const sendFeatureFlagsOptions = typeof sendFeatureFlags == "object" ? sendFeatureFlags : undefined;
return await this.getFeatureFlagsForEvent(eventMessage.distinctId, groups, disableGeoip, sendFeatureFlagsOptions);
}
eventMessage.event;
return {};
}).then((flags) => {
const additionalProperties = {};
if (flags)
for (const [feature, variant] of Object.entries(flags))
additionalProperties[`$feature/${feature}`] = variant;
const activeFlags = Object.keys(flags || {}).filter((flag) => flags?.[flag] !== false).sort();
if (activeFlags.length > 0)
additionalProperties["$active_feature_flags"] = activeFlags;
return additionalProperties;
}).catch(() => ({})).then((additionalProperties) => {
const props2 = {
...additionalProperties,
...eventMessage.properties || {},
$groups: eventMessage.groups || groups
};
return props2;
});
if (eventMessage.event === "$pageview" && this.options.__preview_capture_bot_pageviews && typeof eventProperties.$raw_user_agent == "string") {
if (isBlockedUA(eventProperties.$raw_user_agent, this.options.custom_blocked_useragents || [])) {
eventMessage.event = "$bot_pageview";
eventProperties.$browser_type = "bot";
}
}
return {
distinctId: eventMessage.distinctId,
event: eventMessage.event,
properties: eventProperties,
options: {
timestamp: eventMessage.timestamp,
disableGeoip: eventMessage.disableGeoip,
uuid: eventMessage.uuid
}
};
}
_runBeforeSend(eventMessage) {
const beforeSend = this.options.before_send;
if (!beforeSend)
return eventMessage;
const fns = Array.isArray(beforeSend) ? beforeSend : [
beforeSend
];
let result = eventMessage;
for (const fn of fns) {
result = fn(result);
if (!result) {
this._logger.info(`Event '${eventMessage.event}' was rejected in beforeSend function`);
return null;
}
if (!result.properties || Object.keys(result.properties).length === 0) {
const message = `Event '${result.event}' has no properties after beforeSend function, this is likely an error.`;
this._logger.warn(message);
}
}
return result;
}
}
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/extensions/context/context.mjs
import { AsyncLocalStorage } from "async_hooks";
class PostHogContext {
constructor() {
this.storage = new AsyncLocalStorage;
}
get() {
return this.storage.getStore();
}
run(context, fn, options) {
return this.storage.run(this.resolve(context, options), fn);
}
enter(context, options) {
this.storage.enterWith(this.resolve(context, options));
}
resolve(context, options) {
if (options?.fresh === true)
return context;
const current = this.get() || {};
return {
distinctId: context.distinctId ?? current.distinctId,
sessionId: context.sessionId ?? current.sessionId,
properties: {
...current.properties || {},
...context.properties || {}
}
};
}
}
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/extensions/sentry-integration.mjs
var NAME = "posthog-node";
function createEventProcessor(_posthog, { organization, projectId, prefix, severityAllowList = [
"error"
], sendExceptionsToPostHog = true } = {}) {
return (event) => {
const shouldProcessLevel = severityAllowList === "*" || severityAllowList.includes(event.level);
if (!shouldProcessLevel)
return event;
if (!event.tags)
event.tags = {};
const userId = event.tags[PostHogSentryIntegration.POSTHOG_ID_TAG];
if (userId === undefined)
return event;
const uiHost = _posthog.options.host ?? "https://us.i.posthog.com";
const personUrl = new URL(`/project/${_posthog.apiKey}/person/${userId}`, uiHost).toString();
event.tags["PostHog Person URL"] = personUrl;
const exceptions = event.exception?.values || [];
const exceptionList = exceptions.map((exception) => ({
...exception,
stacktrace: exception.stacktrace ? {
...exception.stacktrace,
type: "raw",
frames: (exception.stacktrace.frames || []).map((frame) => ({
...frame,
platform: "node:javascript"
}))
} : undefined
}));
const properties = {
$exception_message: exceptions[0]?.value || event.message,
$exception_type: exceptions[0]?.type,
$exception_level: event.level,
$exception_list: exceptionList,
$sentry_event_id: event.event_id,
$sentry_exception: event.exception,
$sentry_exception_message: exceptions[0]?.value || event.message,
$sentry_exception_type: exceptions[0]?.type,
$sentry_tags: event.tags
};
if (organization && projectId)
properties["$sentry_url"] = (prefix || "https://sentry.io/organizations/") + organization + "/issues/?project=" + projectId + "&query=" + event.event_id;
if (sendExceptionsToPostHog)
_posthog.capture({
event: "$exception",
distinctId: userId,
properties
});
return event;
};
}
class PostHogSentryIntegration {
static #_ = this.POSTHOG_ID_TAG = "posthog_distinct_id";
constructor(_posthog, organization, prefix, severityAllowList, sendExceptionsToPostHog) {
this.name = NAME;
this.name = NAME;
this.setupOnce = function(addGlobalEventProcessor, getCurrentHub) {
const projectId = getCurrentHub()?.getClient()?.getDsn()?.projectId;
addGlobalEventProcessor(createEventProcessor(_posthog, {
organization,
projectId,
prefix,
severityAllowList,
sendExceptionsToPostHog: sendExceptionsToPostHog ?? true
}));
};
}
}
// ../../node_modules/.bun/posthog-node@5.32.1/node_modules/posthog-node/dist/entrypoints/index.node.mjs
ErrorTracking.errorPropertiesBuilder = new exports_error_tracking.ErrorPropertiesBuilder([
new exports_error_tracking.EventCoercer,
new exports_error_tracking.ErrorCoercer,
new exports_error_tracking.ObjectCoercer,
new exports_error_tracking.StringCoercer,
new exports_error_tracking.PrimitiveCoercer
], exports_error_tracking.createStackParser("node:javascript", exports_error_tracking.nodeStackLineParser), [
createModulerModifier(),
addSourceContext,
createRelativePathModifier()
]);
class PostHog extends PostHogBackendClient {
getLibraryId() {
return "posthog-node";
}
initializeContext() {
return new PostHogContext;
}
}
// src/utils/telemetry.ts
import { existsSync, readFileSync, unlinkSync, writeFileSync } from "fs";
import os from "os";
var FATAL_SPOOL_MAX_SEND = 20;
class TelemetryService {
client = null;
config;
isInitialized = false;
identifiedUserId = null;
_shutdownCalled = false;
_spoolFlushed = false;
superProperties = {};
fatalSpoolFile;
constructor(options = {}) {
this.fatalSpoolFile = options.fatalSpoolFile ?? FATAL_SPOOL_FILE;
this.config = this.loadConfig();
if (this.config.enabled && POSTHOG_API_KEY && !this.isDoNotTrackSet()) {
this.initializeClient();
}
}
loadConfig() {
try {
if (existsSync(TELEMETRY_CONFIG_FILE)) {
const data = readFileSync(TELEMETRY_CONFIG_FILE, "utf-8");
return JSON.parse(data);
}
} catch {}
return { enabled: true };
}
saveConfig() {
try {
const dir = TELEMETRY_CONFIG_DIR;
if (!existsSync(dir)) {
const fs = __require("fs");
fs.mkdirSync(dir, { recursive: true });
}
writeFileSync(TELEMETRY_CONFIG_FILE, JSON.stringify(this.config, null, 2));
} catch {}
}
initializeClient() {
try {
this.client = new PostHog(POSTHOG_API_KEY, {
host: POSTHOG_HOST,
flushAt: 20,
flushInterval: 1e4
});
this.isInitialized = true;
} catch {
this.client = null;
this.isInitialized = false;
}
}
identify(userId, properties = {}) {
if (!this.isEnabled())
return;
try {
const isFirstIdentify = !this.identifiedUserId;
const previousDistinctId = this.getDistinctId();
this.identifiedUserId = userId;
this.register({
account_id: userId,
...properties.email !== undefined ? { email: properties.email } : {},
...properties.workspaceId !== undefined ? { workspace_id: properties.workspaceId } : {},
...properties.workspaceName !== undefined ? { workspace_name: properties.workspaceName } : {},
...properties.botId !== undefined ? { bot_id: properties.botId } : {},
...properties.plan !== undefined ? { plan: properties.plan } : {}
});
const osProps = {
$os: process.platform,
$os_version: os.release(),
$arch: os.arch()
};
this.client?.identify({
distinctId: userId,
properties: {
$set: { ...properties, $user_id: userId, ...osProps },
$set_once: {
$initial_os: process.platform,
$initial_os_version: os.release(),
$initial_arch: os.arch()
},
$anon_distinct_id: isFirstIdentify && previousDistinctId !== userId ? previousDistinctId : undefined
}
});
} catch {}
}
reset() {
this.client?.flush();
this.identifiedUserId = null;
this.config.anonymousId = `anon_${Math.random().toString(36).substring(2, 15)}_${Date.now()}`;
this.saveConfig();
}
register(properties) {
this.superProperties = { ...this.superProperties, ...properties };
}
track(event, properties) {
if (!this.isEnabled())
return;
try {
this.client?.capture({
distinctId: this.getDistinctId(),
event,
properties: {
...this.superProperties,
...properties,
adk_version: CLI_VERSION,
timestamp: new Date().toISOString()
}
});
} catch {}
}
captureException(error, properties = {}) {
if (!this.isEnabled())
return;
try {
this.client?.captureException(toSanitizedError(error), this.getDistinctId(), {
...this.superProperties,
...properties,
error_type: error instanceof Error ? error.constructor.name : "UnknownError",
...isAdkError(error) ? { error_code: error.code, expected: error.expected } : {},
adk_version: CLI_VERSION,
timestamp: new Date().toISOString()
});
} catch {}
}
flushSpooledExceptions() {
if (this._spoolFlushed)
return;
this._spoolFlushed = true;
if (!this.isEnabled())
return;
try {
if (!existsSync(this.fatalSpoolFile))
return;
const lines = readFileSync(this.fatalSpoolFile, "utf-8").split(`
`).filter(Boolean);
unlinkSync(this.fatalSpoolFile);
for (const line of lines.slice(0, FATAL_SPOOL_MAX_SEND)) {
let record;
try {
record = JSON.parse(line);
} catch {
continue;
}
const error = new Error(record.message);
error.name = record.name;
if (record.stack)
error.stack = record.stack;
this.client?.captureException(error, record.distinctId ?? this.getDistinctId(), {
...this.superProperties,
...record.properties
});
}
} catch {}
}
getDistinctId() {
if (this.identifiedUserId) {
return this.identifiedUserId;
}
if (!this.config.anonymousId) {
this.config.anonymousId = `anon_${Math.random().toString(36).substring(2, 15)}_${Date.now()}`;
this.saveConfig();
}
return this.config.anonymousId;
}
isDoNotTrackSet() {
return process.env.DO_NOT_TRACK === "1" || process.env.DO_NOT_TRACK === "true";
}
isEnabled() {
if (this.isDoNotTrackSet()) {
return false;
}
return this.config.enabled && this.isInitialized && this.client !== null;
}
optOut() {
this.track("telemetry.opt_out", { source: "cli" });
this.config.enabled = false;
this.config.lastOptOut = new Date().toISOString();
this.saveConfig();
this.identifiedUserId = null;
this.shutdown();
}
optIn() {
this.config.enabled = true;
this.saveConfig();
if (!this.isInitialized && !this.isDoNotTrackSet()) {
this.initializeClient();
}
this.track("telemetry.opt_in", { source: "cli" });
}
async shutdown() {
if (this._shutdownCalled || !this.client)
return;
this._shutdownCalled = true;
try {
await this.client.shutdown();
} catch {}
}
}
var telemetry = new TelemetryService;
var telemetry_default = telemetry;
export { TelemetryService, telemetry, telemetry_default };