opencode-posthog 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -0
  3. package/dist/index.js +4942 -0
  4. package/package.json +62 -0
package/dist/index.js ADDED
@@ -0,0 +1,4942 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, {
5
+ get: all[name],
6
+ enumerable: true,
7
+ configurable: true,
8
+ set: (newValue) => all[name] = () => newValue
9
+ });
10
+ };
11
+
12
+ // node_modules/posthog-node/dist/extensions/error-tracking/modifiers/module.node.mjs
13
+ import { dirname, posix, sep } from "path";
14
+ function createModulerModifier() {
15
+ const getModuleFromFileName = createGetModuleFromFilename();
16
+ return async (frames) => {
17
+ for (const frame of frames)
18
+ frame.module = getModuleFromFileName(frame.filename);
19
+ return frames;
20
+ };
21
+ }
22
+ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname(process.argv[1]) : process.cwd(), isWindows = sep === "\\") {
23
+ const normalizedBase = isWindows ? normalizeWindowsPath(basePath) : basePath;
24
+ return (filename) => {
25
+ if (!filename)
26
+ return;
27
+ const normalizedFilename = isWindows ? normalizeWindowsPath(filename) : filename;
28
+ let { dir, base: file, ext } = posix.parse(normalizedFilename);
29
+ if (ext === ".js" || ext === ".mjs" || ext === ".cjs")
30
+ file = file.slice(0, -1 * ext.length);
31
+ const decodedFile = decodeURIComponent(file);
32
+ if (!dir)
33
+ dir = ".";
34
+ const n = dir.lastIndexOf("/node_modules");
35
+ if (n > -1)
36
+ return `${dir.slice(n + 14).replace(/\//g, ".")}:${decodedFile}`;
37
+ if (dir.startsWith(normalizedBase)) {
38
+ const moduleName = dir.slice(normalizedBase.length + 1).replace(/\//g, ".");
39
+ return moduleName ? `${moduleName}:${decodedFile}` : decodedFile;
40
+ }
41
+ return decodedFile;
42
+ };
43
+ }
44
+ function normalizeWindowsPath(path) {
45
+ return path.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
46
+ }
47
+
48
+ // node_modules/@posthog/core/dist/featureFlagUtils.mjs
49
+ var normalizeFlagsResponse = (flagsResponse) => {
50
+ if ("flags" in flagsResponse) {
51
+ const featureFlags = getFlagValuesFromFlags(flagsResponse.flags);
52
+ const featureFlagPayloads = getPayloadsFromFlags(flagsResponse.flags);
53
+ return {
54
+ ...flagsResponse,
55
+ featureFlags,
56
+ featureFlagPayloads
57
+ };
58
+ }
59
+ {
60
+ const featureFlags = flagsResponse.featureFlags ?? {};
61
+ const featureFlagPayloads = Object.fromEntries(Object.entries(flagsResponse.featureFlagPayloads || {}).map(([k, v]) => [
62
+ k,
63
+ parsePayload(v)
64
+ ]));
65
+ const flags = Object.fromEntries(Object.entries(featureFlags).map(([key, value]) => [
66
+ key,
67
+ getFlagDetailFromFlagAndPayload(key, value, featureFlagPayloads[key])
68
+ ]));
69
+ return {
70
+ ...flagsResponse,
71
+ featureFlags,
72
+ featureFlagPayloads,
73
+ flags
74
+ };
75
+ }
76
+ };
77
+ function getFlagDetailFromFlagAndPayload(key, value, payload) {
78
+ return {
79
+ key,
80
+ enabled: typeof value == "string" ? true : value,
81
+ variant: typeof value == "string" ? value : undefined,
82
+ reason: undefined,
83
+ metadata: {
84
+ id: undefined,
85
+ version: undefined,
86
+ payload: payload ? JSON.stringify(payload) : undefined,
87
+ description: undefined
88
+ }
89
+ };
90
+ }
91
+ var getFlagValuesFromFlags = (flags) => Object.fromEntries(Object.entries(flags ?? {}).map(([key, detail]) => [
92
+ key,
93
+ getFeatureFlagValue(detail)
94
+ ]).filter(([, value]) => value !== undefined));
95
+ var getPayloadsFromFlags = (flags) => {
96
+ const safeFlags = flags ?? {};
97
+ return Object.fromEntries(Object.keys(safeFlags).filter((flag) => {
98
+ const details = safeFlags[flag];
99
+ return details.enabled && details.metadata && details.metadata.payload !== undefined;
100
+ }).map((flag) => {
101
+ const payload = safeFlags[flag].metadata?.payload;
102
+ return [
103
+ flag,
104
+ payload ? parsePayload(payload) : undefined
105
+ ];
106
+ }));
107
+ };
108
+ var getFeatureFlagValue = (detail) => detail === undefined ? undefined : detail.variant ?? detail.enabled;
109
+ var parsePayload = (response) => {
110
+ if (typeof response != "string")
111
+ return response;
112
+ try {
113
+ return JSON.parse(response);
114
+ } catch {
115
+ return response;
116
+ }
117
+ };
118
+
119
+ // node_modules/@posthog/core/dist/gzip.mjs
120
+ function isGzipSupported() {
121
+ return "CompressionStream" in globalThis;
122
+ }
123
+ async function gzipCompress(input, isDebug = true) {
124
+ try {
125
+ const dataStream = new Blob([
126
+ input
127
+ ], {
128
+ type: "text/plain"
129
+ }).stream();
130
+ const compressedStream = dataStream.pipeThrough(new CompressionStream("gzip"));
131
+ return await new Response(compressedStream).blob();
132
+ } catch (error) {
133
+ if (isDebug)
134
+ console.error("Failed to gzip compress data", error);
135
+ return null;
136
+ }
137
+ }
138
+
139
+ // node_modules/@posthog/core/dist/vendor/uuidv7.mjs
140
+ /*! For license information please see uuidv7.mjs.LICENSE.txt */
141
+ var DIGITS = "0123456789abcdef";
142
+
143
+ class UUID {
144
+ constructor(bytes) {
145
+ this.bytes = bytes;
146
+ }
147
+ static ofInner(bytes) {
148
+ if (bytes.length === 16)
149
+ return new UUID(bytes);
150
+ throw new TypeError("not 128-bit length");
151
+ }
152
+ static fromFieldsV7(unixTsMs, randA, randBHi, randBLo) {
153
+ 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)
154
+ throw new RangeError("invalid field value");
155
+ const bytes = new Uint8Array(16);
156
+ bytes[0] = unixTsMs / 2 ** 40;
157
+ bytes[1] = unixTsMs / 2 ** 32;
158
+ bytes[2] = unixTsMs / 2 ** 24;
159
+ bytes[3] = unixTsMs / 2 ** 16;
160
+ bytes[4] = unixTsMs / 256;
161
+ bytes[5] = unixTsMs;
162
+ bytes[6] = 112 | randA >>> 8;
163
+ bytes[7] = randA;
164
+ bytes[8] = 128 | randBHi >>> 24;
165
+ bytes[9] = randBHi >>> 16;
166
+ bytes[10] = randBHi >>> 8;
167
+ bytes[11] = randBHi;
168
+ bytes[12] = randBLo >>> 24;
169
+ bytes[13] = randBLo >>> 16;
170
+ bytes[14] = randBLo >>> 8;
171
+ bytes[15] = randBLo;
172
+ return new UUID(bytes);
173
+ }
174
+ static parse(uuid) {
175
+ let hex;
176
+ switch (uuid.length) {
177
+ case 32:
178
+ hex = /^[0-9a-f]{32}$/i.exec(uuid)?.[0];
179
+ break;
180
+ case 36:
181
+ 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("");
182
+ break;
183
+ case 38:
184
+ 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("");
185
+ break;
186
+ case 45:
187
+ 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("");
188
+ break;
189
+ default:
190
+ break;
191
+ }
192
+ if (hex) {
193
+ const inner = new Uint8Array(16);
194
+ for (let i = 0;i < 16; i += 4) {
195
+ const n = parseInt(hex.substring(2 * i, 2 * i + 8), 16);
196
+ inner[i + 0] = n >>> 24;
197
+ inner[i + 1] = n >>> 16;
198
+ inner[i + 2] = n >>> 8;
199
+ inner[i + 3] = n;
200
+ }
201
+ return new UUID(inner);
202
+ }
203
+ throw new SyntaxError("could not parse UUID string");
204
+ }
205
+ toString() {
206
+ let text = "";
207
+ for (let i = 0;i < this.bytes.length; i++) {
208
+ text += DIGITS.charAt(this.bytes[i] >>> 4);
209
+ text += DIGITS.charAt(15 & this.bytes[i]);
210
+ if (i === 3 || i === 5 || i === 7 || i === 9)
211
+ text += "-";
212
+ }
213
+ return text;
214
+ }
215
+ toHex() {
216
+ let text = "";
217
+ for (let i = 0;i < this.bytes.length; i++) {
218
+ text += DIGITS.charAt(this.bytes[i] >>> 4);
219
+ text += DIGITS.charAt(15 & this.bytes[i]);
220
+ }
221
+ return text;
222
+ }
223
+ toJSON() {
224
+ return this.toString();
225
+ }
226
+ getVariant() {
227
+ const n = this.bytes[8] >>> 4;
228
+ if (n < 0)
229
+ throw new Error("unreachable");
230
+ if (n <= 7)
231
+ return this.bytes.every((e) => e === 0) ? "NIL" : "VAR_0";
232
+ if (n <= 11)
233
+ return "VAR_10";
234
+ if (n <= 13)
235
+ return "VAR_110";
236
+ if (n <= 15)
237
+ return this.bytes.every((e) => e === 255) ? "MAX" : "VAR_RESERVED";
238
+ else
239
+ throw new Error("unreachable");
240
+ }
241
+ getVersion() {
242
+ return this.getVariant() === "VAR_10" ? this.bytes[6] >>> 4 : undefined;
243
+ }
244
+ clone() {
245
+ return new UUID(this.bytes.slice(0));
246
+ }
247
+ equals(other) {
248
+ return this.compareTo(other) === 0;
249
+ }
250
+ compareTo(other) {
251
+ for (let i = 0;i < 16; i++) {
252
+ const diff = this.bytes[i] - other.bytes[i];
253
+ if (diff !== 0)
254
+ return Math.sign(diff);
255
+ }
256
+ return 0;
257
+ }
258
+ }
259
+
260
+ class V7Generator {
261
+ constructor(randomNumberGenerator) {
262
+ this.timestamp = 0;
263
+ this.counter = 0;
264
+ this.random = randomNumberGenerator ?? getDefaultRandom();
265
+ }
266
+ generate() {
267
+ return this.generateOrResetCore(Date.now(), 1e4);
268
+ }
269
+ generateOrAbort() {
270
+ return this.generateOrAbortCore(Date.now(), 1e4);
271
+ }
272
+ generateOrResetCore(unixTsMs, rollbackAllowance) {
273
+ let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
274
+ if (value === undefined) {
275
+ this.timestamp = 0;
276
+ value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
277
+ }
278
+ return value;
279
+ }
280
+ generateOrAbortCore(unixTsMs, rollbackAllowance) {
281
+ const MAX_COUNTER = 4398046511103;
282
+ if (!Number.isInteger(unixTsMs) || unixTsMs < 1 || unixTsMs > 281474976710655)
283
+ throw new RangeError("`unixTsMs` must be a 48-bit positive integer");
284
+ if (rollbackAllowance < 0 || rollbackAllowance > 281474976710655)
285
+ throw new RangeError("`rollbackAllowance` out of reasonable range");
286
+ if (unixTsMs > this.timestamp) {
287
+ this.timestamp = unixTsMs;
288
+ this.resetCounter();
289
+ } else {
290
+ if (!(unixTsMs + rollbackAllowance >= this.timestamp))
291
+ return;
292
+ this.counter++;
293
+ if (this.counter > MAX_COUNTER) {
294
+ this.timestamp++;
295
+ this.resetCounter();
296
+ }
297
+ }
298
+ return UUID.fromFieldsV7(this.timestamp, Math.trunc(this.counter / 2 ** 30), this.counter & 2 ** 30 - 1, this.random.nextUint32());
299
+ }
300
+ resetCounter() {
301
+ this.counter = 1024 * this.random.nextUint32() + (1023 & this.random.nextUint32());
302
+ }
303
+ generateV4() {
304
+ const bytes = new Uint8Array(Uint32Array.of(this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32()).buffer);
305
+ bytes[6] = 64 | bytes[6] >>> 4;
306
+ bytes[8] = 128 | bytes[8] >>> 2;
307
+ return UUID.ofInner(bytes);
308
+ }
309
+ }
310
+ var getDefaultRandom = () => ({
311
+ nextUint32: () => 65536 * Math.trunc(65536 * Math.random()) + Math.trunc(65536 * Math.random())
312
+ });
313
+ var defaultGenerator;
314
+ var uuidv7 = () => uuidv7obj().toString();
315
+ var uuidv7obj = () => (defaultGenerator || (defaultGenerator = new V7Generator)).generate();
316
+
317
+ // node_modules/@posthog/core/dist/types.mjs
318
+ var types_PostHogPersistedProperty = /* @__PURE__ */ function(PostHogPersistedProperty) {
319
+ PostHogPersistedProperty["AnonymousId"] = "anonymous_id";
320
+ PostHogPersistedProperty["DistinctId"] = "distinct_id";
321
+ PostHogPersistedProperty["Props"] = "props";
322
+ PostHogPersistedProperty["EnablePersonProcessing"] = "enable_person_processing";
323
+ PostHogPersistedProperty["PersonMode"] = "person_mode";
324
+ PostHogPersistedProperty["FeatureFlagDetails"] = "feature_flag_details";
325
+ PostHogPersistedProperty["FeatureFlags"] = "feature_flags";
326
+ PostHogPersistedProperty["FeatureFlagPayloads"] = "feature_flag_payloads";
327
+ PostHogPersistedProperty["BootstrapFeatureFlagDetails"] = "bootstrap_feature_flag_details";
328
+ PostHogPersistedProperty["BootstrapFeatureFlags"] = "bootstrap_feature_flags";
329
+ PostHogPersistedProperty["BootstrapFeatureFlagPayloads"] = "bootstrap_feature_flag_payloads";
330
+ PostHogPersistedProperty["OverrideFeatureFlags"] = "override_feature_flags";
331
+ PostHogPersistedProperty["Queue"] = "queue";
332
+ PostHogPersistedProperty["OptedOut"] = "opted_out";
333
+ PostHogPersistedProperty["SessionId"] = "session_id";
334
+ PostHogPersistedProperty["SessionStartTimestamp"] = "session_start_timestamp";
335
+ PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
336
+ PostHogPersistedProperty["PersonProperties"] = "person_properties";
337
+ PostHogPersistedProperty["GroupProperties"] = "group_properties";
338
+ PostHogPersistedProperty["InstalledAppBuild"] = "installed_app_build";
339
+ PostHogPersistedProperty["InstalledAppVersion"] = "installed_app_version";
340
+ PostHogPersistedProperty["SessionReplay"] = "session_replay";
341
+ PostHogPersistedProperty["SurveyLastSeenDate"] = "survey_last_seen_date";
342
+ PostHogPersistedProperty["SurveysSeen"] = "surveys_seen";
343
+ PostHogPersistedProperty["Surveys"] = "surveys";
344
+ PostHogPersistedProperty["RemoteConfig"] = "remote_config";
345
+ PostHogPersistedProperty["FlagsEndpointWasHit"] = "flags_endpoint_was_hit";
346
+ return PostHogPersistedProperty;
347
+ }({});
348
+
349
+ // node_modules/@posthog/core/dist/utils/bot-detection.mjs
350
+ var DEFAULT_BLOCKED_UA_STRS = [
351
+ "amazonbot",
352
+ "amazonproductbot",
353
+ "app.hypefactors.com",
354
+ "applebot",
355
+ "archive.org_bot",
356
+ "awariobot",
357
+ "backlinksextendedbot",
358
+ "baiduspider",
359
+ "bingbot",
360
+ "bingpreview",
361
+ "chrome-lighthouse",
362
+ "dataforseobot",
363
+ "deepscan",
364
+ "duckduckbot",
365
+ "facebookexternal",
366
+ "facebookcatalog",
367
+ "http://yandex.com/bots",
368
+ "hubspot",
369
+ "ia_archiver",
370
+ "leikibot",
371
+ "linkedinbot",
372
+ "meta-externalagent",
373
+ "mj12bot",
374
+ "msnbot",
375
+ "nessus",
376
+ "petalbot",
377
+ "pinterest",
378
+ "prerender",
379
+ "rogerbot",
380
+ "screaming frog",
381
+ "sebot-wa",
382
+ "sitebulb",
383
+ "slackbot",
384
+ "slurp",
385
+ "trendictionbot",
386
+ "turnitin",
387
+ "twitterbot",
388
+ "vercel-screenshot",
389
+ "vercelbot",
390
+ "yahoo! slurp",
391
+ "yandexbot",
392
+ "zoombot",
393
+ "bot.htm",
394
+ "bot.php",
395
+ "(bot;",
396
+ "bot/",
397
+ "crawler",
398
+ "ahrefsbot",
399
+ "ahrefssiteaudit",
400
+ "semrushbot",
401
+ "siteauditbot",
402
+ "splitsignalbot",
403
+ "gptbot",
404
+ "oai-searchbot",
405
+ "chatgpt-user",
406
+ "perplexitybot",
407
+ "better uptime bot",
408
+ "sentryuptimebot",
409
+ "uptimerobot",
410
+ "headlesschrome",
411
+ "cypress",
412
+ "google-hoteladsverifier",
413
+ "adsbot-google",
414
+ "apis-google",
415
+ "duplexweb-google",
416
+ "feedfetcher-google",
417
+ "google favicon",
418
+ "google web preview",
419
+ "google-read-aloud",
420
+ "googlebot",
421
+ "googleother",
422
+ "google-cloudvertexbot",
423
+ "googleweblight",
424
+ "mediapartners-google",
425
+ "storebot-google",
426
+ "google-inspectiontool",
427
+ "bytespider"
428
+ ];
429
+ var isBlockedUA = function(ua, customBlockedUserAgents = []) {
430
+ if (!ua)
431
+ return false;
432
+ const uaLower = ua.toLowerCase();
433
+ return DEFAULT_BLOCKED_UA_STRS.concat(customBlockedUserAgents).some((blockedUA) => {
434
+ const blockedUaLower = blockedUA.toLowerCase();
435
+ return uaLower.indexOf(blockedUaLower) !== -1;
436
+ });
437
+ };
438
+ // node_modules/@posthog/core/dist/utils/type-utils.mjs
439
+ var nativeIsArray = Array.isArray;
440
+ var ObjProto = Object.prototype;
441
+ var type_utils_hasOwnProperty = ObjProto.hasOwnProperty;
442
+ var type_utils_toString = ObjProto.toString;
443
+ var isArray = nativeIsArray || function(obj) {
444
+ return type_utils_toString.call(obj) === "[object Array]";
445
+ };
446
+ var isObject = (x) => x === Object(x) && !isArray(x);
447
+ var isUndefined = (x) => x === undefined;
448
+ var isString = (x) => type_utils_toString.call(x) == "[object String]";
449
+ var isEmptyString = (x) => isString(x) && x.trim().length === 0;
450
+ var isNumber = (x) => type_utils_toString.call(x) == "[object Number]" && x === x;
451
+ var isPlainError = (x) => x instanceof Error;
452
+ function isPrimitive(value) {
453
+ return value === null || typeof value != "object";
454
+ }
455
+ function isBuiltin(candidate, className) {
456
+ return Object.prototype.toString.call(candidate) === `[object ${className}]`;
457
+ }
458
+ function isErrorEvent(event) {
459
+ return isBuiltin(event, "ErrorEvent");
460
+ }
461
+ function isEvent(candidate) {
462
+ return typeof Event != "undefined" && isInstanceOf(candidate, Event);
463
+ }
464
+ function isPlainObject(candidate) {
465
+ return isBuiltin(candidate, "Object");
466
+ }
467
+ function isInstanceOf(candidate, base) {
468
+ try {
469
+ return candidate instanceof base;
470
+ } catch {
471
+ return false;
472
+ }
473
+ }
474
+
475
+ // node_modules/@posthog/core/dist/utils/number-utils.mjs
476
+ function clampToRange(value, min, max, logger, fallbackValue) {
477
+ if (min > max) {
478
+ logger.warn("min cannot be greater than max.");
479
+ min = max;
480
+ }
481
+ if (isNumber(value))
482
+ if (value > max) {
483
+ logger.warn(" cannot be greater than max: " + max + ". Using max value instead.");
484
+ return max;
485
+ } else {
486
+ if (!(value < min))
487
+ return value;
488
+ logger.warn(" cannot be less than min: " + min + ". Using min value instead.");
489
+ return min;
490
+ }
491
+ logger.warn(" must be a number. using max or fallback. max: " + max + ", fallback: " + fallbackValue);
492
+ return clampToRange(fallbackValue || max, min, max, logger);
493
+ }
494
+
495
+ // node_modules/@posthog/core/dist/utils/bucketed-rate-limiter.mjs
496
+ var ONE_DAY_IN_MS = 86400000;
497
+
498
+ class BucketedRateLimiter {
499
+ constructor(options) {
500
+ this._buckets = {};
501
+ this._onBucketRateLimited = options._onBucketRateLimited;
502
+ this._bucketSize = clampToRange(options.bucketSize, 0, 100, options._logger);
503
+ this._refillRate = clampToRange(options.refillRate, 0, this._bucketSize, options._logger);
504
+ this._refillInterval = clampToRange(options.refillInterval, 0, ONE_DAY_IN_MS, options._logger);
505
+ }
506
+ _applyRefill(bucket, now) {
507
+ const elapsedMs = now - bucket.lastAccess;
508
+ const refillIntervals = Math.floor(elapsedMs / this._refillInterval);
509
+ if (refillIntervals > 0) {
510
+ const tokensToAdd = refillIntervals * this._refillRate;
511
+ bucket.tokens = Math.min(bucket.tokens + tokensToAdd, this._bucketSize);
512
+ bucket.lastAccess = bucket.lastAccess + refillIntervals * this._refillInterval;
513
+ }
514
+ }
515
+ consumeRateLimit(key) {
516
+ const now = Date.now();
517
+ const keyStr = String(key);
518
+ let bucket = this._buckets[keyStr];
519
+ if (bucket)
520
+ this._applyRefill(bucket, now);
521
+ else {
522
+ bucket = {
523
+ tokens: this._bucketSize,
524
+ lastAccess: now
525
+ };
526
+ this._buckets[keyStr] = bucket;
527
+ }
528
+ if (bucket.tokens === 0)
529
+ return true;
530
+ bucket.tokens--;
531
+ if (bucket.tokens === 0)
532
+ this._onBucketRateLimited?.(key);
533
+ return bucket.tokens === 0;
534
+ }
535
+ stop() {
536
+ this._buckets = {};
537
+ }
538
+ }
539
+ // node_modules/@posthog/core/dist/utils/promise-queue.mjs
540
+ class PromiseQueue {
541
+ add(promise) {
542
+ const promiseUUID = uuidv7();
543
+ this.promiseByIds[promiseUUID] = promise;
544
+ promise.catch(() => {}).finally(() => {
545
+ delete this.promiseByIds[promiseUUID];
546
+ });
547
+ return promise;
548
+ }
549
+ async join() {
550
+ let promises = Object.values(this.promiseByIds);
551
+ let length = promises.length;
552
+ while (length > 0) {
553
+ await Promise.all(promises);
554
+ promises = Object.values(this.promiseByIds);
555
+ length = promises.length;
556
+ }
557
+ }
558
+ get length() {
559
+ return Object.keys(this.promiseByIds).length;
560
+ }
561
+ constructor() {
562
+ this.promiseByIds = {};
563
+ }
564
+ }
565
+ // node_modules/@posthog/core/dist/utils/logger.mjs
566
+ function createConsole(consoleLike = console) {
567
+ const lockedMethods = {
568
+ log: consoleLike.log.bind(consoleLike),
569
+ warn: consoleLike.warn.bind(consoleLike),
570
+ error: consoleLike.error.bind(consoleLike),
571
+ debug: consoleLike.debug.bind(consoleLike)
572
+ };
573
+ return lockedMethods;
574
+ }
575
+ var _createLogger = (prefix, maybeCall, consoleLike) => {
576
+ function _log(level, ...args) {
577
+ maybeCall(() => {
578
+ const consoleMethod = consoleLike[level];
579
+ consoleMethod(prefix, ...args);
580
+ });
581
+ }
582
+ const logger = {
583
+ info: (...args) => {
584
+ _log("log", ...args);
585
+ },
586
+ warn: (...args) => {
587
+ _log("warn", ...args);
588
+ },
589
+ error: (...args) => {
590
+ _log("error", ...args);
591
+ },
592
+ critical: (...args) => {
593
+ consoleLike["error"](prefix, ...args);
594
+ },
595
+ createLogger: (additionalPrefix) => _createLogger(`${prefix} ${additionalPrefix}`, maybeCall, consoleLike)
596
+ };
597
+ return logger;
598
+ };
599
+ var passThrough = (fn) => fn();
600
+ function createLogger(prefix, maybeCall = passThrough) {
601
+ return _createLogger(prefix, maybeCall, createConsole());
602
+ }
603
+ // node_modules/@posthog/core/dist/utils/user-agent-utils.mjs
604
+ var MOBILE = "Mobile";
605
+ var IOS = "iOS";
606
+ var ANDROID = "Android";
607
+ var TABLET = "Tablet";
608
+ var ANDROID_TABLET = ANDROID + " " + TABLET;
609
+ var APPLE = "Apple";
610
+ var APPLE_WATCH = APPLE + " Watch";
611
+ var SAFARI = "Safari";
612
+ var BLACKBERRY = "BlackBerry";
613
+ var SAMSUNG = "Samsung";
614
+ var SAMSUNG_BROWSER = SAMSUNG + "Browser";
615
+ var SAMSUNG_INTERNET = SAMSUNG + " Internet";
616
+ var CHROME = "Chrome";
617
+ var CHROME_OS = CHROME + " OS";
618
+ var CHROME_IOS = CHROME + " " + IOS;
619
+ var INTERNET_EXPLORER = "Internet Explorer";
620
+ var INTERNET_EXPLORER_MOBILE = INTERNET_EXPLORER + " " + MOBILE;
621
+ var OPERA = "Opera";
622
+ var OPERA_MINI = OPERA + " Mini";
623
+ var EDGE = "Edge";
624
+ var MICROSOFT_EDGE = "Microsoft " + EDGE;
625
+ var FIREFOX = "Firefox";
626
+ var FIREFOX_IOS = FIREFOX + " " + IOS;
627
+ var NINTENDO = "Nintendo";
628
+ var PLAYSTATION = "PlayStation";
629
+ var XBOX = "Xbox";
630
+ var ANDROID_MOBILE = ANDROID + " " + MOBILE;
631
+ var MOBILE_SAFARI = MOBILE + " " + SAFARI;
632
+ var WINDOWS = "Windows";
633
+ var WINDOWS_PHONE = WINDOWS + " Phone";
634
+ var GENERIC = "Generic";
635
+ var GENERIC_MOBILE = GENERIC + " " + MOBILE.toLowerCase();
636
+ var GENERIC_TABLET = GENERIC + " " + TABLET.toLowerCase();
637
+ var KONQUEROR = "Konqueror";
638
+ var BROWSER_VERSION_REGEX_SUFFIX = "(\\d+(\\.\\d+)?)";
639
+ var DEFAULT_BROWSER_VERSION_REGEX = new RegExp("Version/" + BROWSER_VERSION_REGEX_SUFFIX);
640
+ var XBOX_REGEX = new RegExp(XBOX, "i");
641
+ var PLAYSTATION_REGEX = new RegExp(PLAYSTATION + " \\w+", "i");
642
+ var NINTENDO_REGEX = new RegExp(NINTENDO + " \\w+", "i");
643
+ var BLACKBERRY_REGEX = new RegExp(BLACKBERRY + "|PlayBook|BB10", "i");
644
+ var windowsVersionMap = {
645
+ "NT3.51": "NT 3.11",
646
+ "NT4.0": "NT 4.0",
647
+ "5.0": "2000",
648
+ "5.1": "XP",
649
+ "5.2": "XP",
650
+ "6.0": "Vista",
651
+ "6.1": "7",
652
+ "6.2": "8",
653
+ "6.3": "8.1",
654
+ "6.4": "10",
655
+ "10.0": "10"
656
+ };
657
+ var versionRegexes = {
658
+ [INTERNET_EXPLORER_MOBILE]: [
659
+ new RegExp("rv:" + BROWSER_VERSION_REGEX_SUFFIX)
660
+ ],
661
+ [MICROSOFT_EDGE]: [
662
+ new RegExp(EDGE + "?\\/" + BROWSER_VERSION_REGEX_SUFFIX)
663
+ ],
664
+ [CHROME]: [
665
+ new RegExp("(" + CHROME + "|CrMo)\\/" + BROWSER_VERSION_REGEX_SUFFIX)
666
+ ],
667
+ [CHROME_IOS]: [
668
+ new RegExp("CriOS\\/" + BROWSER_VERSION_REGEX_SUFFIX)
669
+ ],
670
+ "UC Browser": [
671
+ new RegExp("(UCBrowser|UCWEB)\\/" + BROWSER_VERSION_REGEX_SUFFIX)
672
+ ],
673
+ [SAFARI]: [
674
+ DEFAULT_BROWSER_VERSION_REGEX
675
+ ],
676
+ [MOBILE_SAFARI]: [
677
+ DEFAULT_BROWSER_VERSION_REGEX
678
+ ],
679
+ [OPERA]: [
680
+ new RegExp("(" + OPERA + "|OPR)\\/" + BROWSER_VERSION_REGEX_SUFFIX)
681
+ ],
682
+ [FIREFOX]: [
683
+ new RegExp(FIREFOX + "\\/" + BROWSER_VERSION_REGEX_SUFFIX)
684
+ ],
685
+ [FIREFOX_IOS]: [
686
+ new RegExp("FxiOS\\/" + BROWSER_VERSION_REGEX_SUFFIX)
687
+ ],
688
+ [KONQUEROR]: [
689
+ new RegExp("Konqueror[:/]?" + BROWSER_VERSION_REGEX_SUFFIX, "i")
690
+ ],
691
+ [BLACKBERRY]: [
692
+ new RegExp(BLACKBERRY + " " + BROWSER_VERSION_REGEX_SUFFIX),
693
+ DEFAULT_BROWSER_VERSION_REGEX
694
+ ],
695
+ [ANDROID_MOBILE]: [
696
+ new RegExp("android\\s" + BROWSER_VERSION_REGEX_SUFFIX, "i")
697
+ ],
698
+ [SAMSUNG_INTERNET]: [
699
+ new RegExp(SAMSUNG_BROWSER + "\\/" + BROWSER_VERSION_REGEX_SUFFIX)
700
+ ],
701
+ [INTERNET_EXPLORER]: [
702
+ new RegExp("(rv:|MSIE )" + BROWSER_VERSION_REGEX_SUFFIX)
703
+ ],
704
+ Mozilla: [
705
+ new RegExp("rv:" + BROWSER_VERSION_REGEX_SUFFIX)
706
+ ]
707
+ };
708
+ var osMatchers = [
709
+ [
710
+ new RegExp(XBOX + "; " + XBOX + " (.*?)[);]", "i"),
711
+ (match) => [
712
+ XBOX,
713
+ match && match[1] || ""
714
+ ]
715
+ ],
716
+ [
717
+ new RegExp(NINTENDO, "i"),
718
+ [
719
+ NINTENDO,
720
+ ""
721
+ ]
722
+ ],
723
+ [
724
+ new RegExp(PLAYSTATION, "i"),
725
+ [
726
+ PLAYSTATION,
727
+ ""
728
+ ]
729
+ ],
730
+ [
731
+ BLACKBERRY_REGEX,
732
+ [
733
+ BLACKBERRY,
734
+ ""
735
+ ]
736
+ ],
737
+ [
738
+ new RegExp(WINDOWS, "i"),
739
+ (_, user_agent) => {
740
+ if (/Phone/.test(user_agent) || /WPDesktop/.test(user_agent))
741
+ return [
742
+ WINDOWS_PHONE,
743
+ ""
744
+ ];
745
+ if (new RegExp(MOBILE).test(user_agent) && !/IEMobile\b/.test(user_agent))
746
+ return [
747
+ WINDOWS + " " + MOBILE,
748
+ ""
749
+ ];
750
+ const match = /Windows NT ([0-9.]+)/i.exec(user_agent);
751
+ if (match && match[1]) {
752
+ const version = match[1];
753
+ let osVersion = windowsVersionMap[version] || "";
754
+ if (/arm/i.test(user_agent))
755
+ osVersion = "RT";
756
+ return [
757
+ WINDOWS,
758
+ osVersion
759
+ ];
760
+ }
761
+ return [
762
+ WINDOWS,
763
+ ""
764
+ ];
765
+ }
766
+ ],
767
+ [
768
+ /((iPhone|iPad|iPod).*?OS (\d+)_(\d+)_?(\d+)?|iPhone)/,
769
+ (match) => {
770
+ if (match && match[3]) {
771
+ const versionParts = [
772
+ match[3],
773
+ match[4],
774
+ match[5] || "0"
775
+ ];
776
+ return [
777
+ IOS,
778
+ versionParts.join(".")
779
+ ];
780
+ }
781
+ return [
782
+ IOS,
783
+ ""
784
+ ];
785
+ }
786
+ ],
787
+ [
788
+ /(watch.*\/(\d+\.\d+\.\d+)|watch os,(\d+\.\d+),)/i,
789
+ (match) => {
790
+ let version = "";
791
+ if (match && match.length >= 3)
792
+ version = isUndefined(match[2]) ? match[3] : match[2];
793
+ return [
794
+ "watchOS",
795
+ version
796
+ ];
797
+ }
798
+ ],
799
+ [
800
+ new RegExp("(" + ANDROID + " (\\d+)\\.(\\d+)\\.?(\\d+)?|" + ANDROID + ")", "i"),
801
+ (match) => {
802
+ if (match && match[2]) {
803
+ const versionParts = [
804
+ match[2],
805
+ match[3],
806
+ match[4] || "0"
807
+ ];
808
+ return [
809
+ ANDROID,
810
+ versionParts.join(".")
811
+ ];
812
+ }
813
+ return [
814
+ ANDROID,
815
+ ""
816
+ ];
817
+ }
818
+ ],
819
+ [
820
+ /Mac OS X (\d+)[_.](\d+)[_.]?(\d+)?/i,
821
+ (match) => {
822
+ const result = [
823
+ "Mac OS X",
824
+ ""
825
+ ];
826
+ if (match && match[1]) {
827
+ const versionParts = [
828
+ match[1],
829
+ match[2],
830
+ match[3] || "0"
831
+ ];
832
+ result[1] = versionParts.join(".");
833
+ }
834
+ return result;
835
+ }
836
+ ],
837
+ [
838
+ /Mac/i,
839
+ [
840
+ "Mac OS X",
841
+ ""
842
+ ]
843
+ ],
844
+ [
845
+ /CrOS/,
846
+ [
847
+ CHROME_OS,
848
+ ""
849
+ ]
850
+ ],
851
+ [
852
+ /Linux|debian/i,
853
+ [
854
+ "Linux",
855
+ ""
856
+ ]
857
+ ]
858
+ ];
859
+
860
+ // node_modules/@posthog/core/dist/utils/index.mjs
861
+ var STRING_FORMAT = "utf8";
862
+ function assert(truthyValue, message) {
863
+ if (!truthyValue || typeof truthyValue != "string" || isEmpty(truthyValue))
864
+ throw new Error(message);
865
+ }
866
+ function isEmpty(truthyValue) {
867
+ if (truthyValue.trim().length === 0)
868
+ return true;
869
+ return false;
870
+ }
871
+ function removeTrailingSlash(url) {
872
+ return url?.replace(/\/+$/, "");
873
+ }
874
+ async function retriable(fn, props) {
875
+ let lastError = null;
876
+ for (let i = 0;i < props.retryCount + 1; i++) {
877
+ if (i > 0)
878
+ await new Promise((r) => setTimeout(r, props.retryDelay));
879
+ try {
880
+ const res = await fn();
881
+ return res;
882
+ } catch (e) {
883
+ lastError = e;
884
+ if (!props.retryCheck(e))
885
+ throw e;
886
+ }
887
+ }
888
+ throw lastError;
889
+ }
890
+ function currentISOTime() {
891
+ return new Date().toISOString();
892
+ }
893
+ function safeSetTimeout(fn, timeout) {
894
+ const t = setTimeout(fn, timeout);
895
+ t?.unref && t?.unref();
896
+ return t;
897
+ }
898
+ var isError = (x) => x instanceof Error;
899
+ function allSettled(promises) {
900
+ return Promise.all(promises.map((p) => (p ?? Promise.resolve()).then((value) => ({
901
+ status: "fulfilled",
902
+ value
903
+ }), (reason) => ({
904
+ status: "rejected",
905
+ reason
906
+ }))));
907
+ }
908
+ // node_modules/@posthog/core/dist/eventemitter.mjs
909
+ class SimpleEventEmitter {
910
+ constructor() {
911
+ this.events = {};
912
+ this.events = {};
913
+ }
914
+ on(event, listener) {
915
+ if (!this.events[event])
916
+ this.events[event] = [];
917
+ this.events[event].push(listener);
918
+ return () => {
919
+ this.events[event] = this.events[event].filter((x) => x !== listener);
920
+ };
921
+ }
922
+ emit(event, payload) {
923
+ for (const listener of this.events[event] || [])
924
+ listener(payload);
925
+ for (const listener of this.events["*"] || [])
926
+ listener(event, payload);
927
+ }
928
+ }
929
+
930
+ // node_modules/@posthog/core/dist/posthog-core-stateless.mjs
931
+ class PostHogFetchHttpError extends Error {
932
+ constructor(response, reqByteLength) {
933
+ super("HTTP error while fetching PostHog: status=" + response.status + ", reqByteLength=" + reqByteLength), this.response = response, this.reqByteLength = reqByteLength, this.name = "PostHogFetchHttpError";
934
+ }
935
+ get status() {
936
+ return this.response.status;
937
+ }
938
+ get text() {
939
+ return this.response.text();
940
+ }
941
+ get json() {
942
+ return this.response.json();
943
+ }
944
+ }
945
+
946
+ class PostHogFetchNetworkError extends Error {
947
+ constructor(error) {
948
+ super("Network error while fetching PostHog", error instanceof Error ? {
949
+ cause: error
950
+ } : {}), this.error = error, this.name = "PostHogFetchNetworkError";
951
+ }
952
+ }
953
+ async function logFlushError(err) {
954
+ if (err instanceof PostHogFetchHttpError) {
955
+ let text = "";
956
+ try {
957
+ text = await err.text;
958
+ } catch {}
959
+ console.error(`Error while flushing PostHog: message=${err.message}, response body=${text}`, err);
960
+ } else
961
+ console.error("Error while flushing PostHog", err);
962
+ return Promise.resolve();
963
+ }
964
+ function isPostHogFetchError(err) {
965
+ return typeof err == "object" && (err instanceof PostHogFetchHttpError || err instanceof PostHogFetchNetworkError);
966
+ }
967
+ function isPostHogFetchContentTooLargeError(err) {
968
+ return typeof err == "object" && err instanceof PostHogFetchHttpError && err.status === 413;
969
+ }
970
+ class PostHogCoreStateless {
971
+ constructor(apiKey, options = {}) {
972
+ this.flushPromise = null;
973
+ this.shutdownPromise = null;
974
+ this.promiseQueue = new PromiseQueue;
975
+ this._events = new SimpleEventEmitter;
976
+ this._isInitialized = false;
977
+ assert(apiKey, "You must pass your PostHog project's api key.");
978
+ this.apiKey = apiKey;
979
+ this.host = removeTrailingSlash(options.host || "https://us.i.posthog.com");
980
+ this.flushAt = options.flushAt ? Math.max(options.flushAt, 1) : 20;
981
+ this.maxBatchSize = Math.max(this.flushAt, options.maxBatchSize ?? 100);
982
+ this.maxQueueSize = Math.max(this.flushAt, options.maxQueueSize ?? 1000);
983
+ this.flushInterval = options.flushInterval ?? 1e4;
984
+ this.preloadFeatureFlags = options.preloadFeatureFlags ?? true;
985
+ this.defaultOptIn = options.defaultOptIn ?? true;
986
+ this.disableSurveys = options.disableSurveys ?? false;
987
+ this._retryOptions = {
988
+ retryCount: options.fetchRetryCount ?? 3,
989
+ retryDelay: options.fetchRetryDelay ?? 3000,
990
+ retryCheck: isPostHogFetchError
991
+ };
992
+ this.requestTimeout = options.requestTimeout ?? 1e4;
993
+ this.featureFlagsRequestTimeoutMs = options.featureFlagsRequestTimeoutMs ?? 3000;
994
+ this.remoteConfigRequestTimeoutMs = options.remoteConfigRequestTimeoutMs ?? 3000;
995
+ this.disableGeoip = options.disableGeoip ?? true;
996
+ this.disabled = options.disabled ?? false;
997
+ this.historicalMigration = options?.historicalMigration ?? false;
998
+ this._initPromise = Promise.resolve();
999
+ this._isInitialized = true;
1000
+ this._logger = createLogger("[PostHog]", this.logMsgIfDebug.bind(this));
1001
+ this.evaluationContexts = options?.evaluationContexts ?? options?.evaluationEnvironments;
1002
+ if (options?.evaluationEnvironments && !options?.evaluationContexts)
1003
+ this._logger.warn("evaluationEnvironments is deprecated. Use evaluationContexts instead. This property will be removed in a future version.");
1004
+ this.disableCompression = !isGzipSupported() || (options?.disableCompression ?? false);
1005
+ }
1006
+ logMsgIfDebug(fn) {
1007
+ if (this.isDebug)
1008
+ fn();
1009
+ }
1010
+ wrap(fn) {
1011
+ if (this.disabled)
1012
+ return void this._logger.warn("The client is disabled");
1013
+ if (this._isInitialized)
1014
+ return fn();
1015
+ this._initPromise.then(() => fn());
1016
+ }
1017
+ getCommonEventProperties() {
1018
+ return {
1019
+ $lib: this.getLibraryId(),
1020
+ $lib_version: this.getLibraryVersion()
1021
+ };
1022
+ }
1023
+ get optedOut() {
1024
+ return this.getPersistedProperty(types_PostHogPersistedProperty.OptedOut) ?? !this.defaultOptIn;
1025
+ }
1026
+ async optIn() {
1027
+ this.wrap(() => {
1028
+ this.setPersistedProperty(types_PostHogPersistedProperty.OptedOut, false);
1029
+ });
1030
+ }
1031
+ async optOut() {
1032
+ this.wrap(() => {
1033
+ this.setPersistedProperty(types_PostHogPersistedProperty.OptedOut, true);
1034
+ });
1035
+ }
1036
+ on(event, cb) {
1037
+ return this._events.on(event, cb);
1038
+ }
1039
+ debug(enabled = true) {
1040
+ this.removeDebugCallback?.();
1041
+ if (enabled) {
1042
+ const removeDebugCallback = this.on("*", (event, payload) => this._logger.info(event, payload));
1043
+ this.removeDebugCallback = () => {
1044
+ removeDebugCallback();
1045
+ this.removeDebugCallback = undefined;
1046
+ };
1047
+ }
1048
+ }
1049
+ get isDebug() {
1050
+ return !!this.removeDebugCallback;
1051
+ }
1052
+ get isDisabled() {
1053
+ return this.disabled;
1054
+ }
1055
+ buildPayload(payload) {
1056
+ return {
1057
+ distinct_id: payload.distinct_id,
1058
+ event: payload.event,
1059
+ properties: {
1060
+ ...payload.properties || {},
1061
+ ...this.getCommonEventProperties()
1062
+ }
1063
+ };
1064
+ }
1065
+ addPendingPromise(promise) {
1066
+ return this.promiseQueue.add(promise);
1067
+ }
1068
+ identifyStateless(distinctId, properties, options) {
1069
+ this.wrap(() => {
1070
+ const payload = {
1071
+ ...this.buildPayload({
1072
+ distinct_id: distinctId,
1073
+ event: "$identify",
1074
+ properties
1075
+ })
1076
+ };
1077
+ this.enqueue("identify", payload, options);
1078
+ });
1079
+ }
1080
+ async identifyStatelessImmediate(distinctId, properties, options) {
1081
+ const payload = {
1082
+ ...this.buildPayload({
1083
+ distinct_id: distinctId,
1084
+ event: "$identify",
1085
+ properties
1086
+ })
1087
+ };
1088
+ await this.sendImmediate("identify", payload, options);
1089
+ }
1090
+ captureStateless(distinctId, event, properties, options) {
1091
+ this.wrap(() => {
1092
+ const payload = this.buildPayload({
1093
+ distinct_id: distinctId,
1094
+ event,
1095
+ properties
1096
+ });
1097
+ this.enqueue("capture", payload, options);
1098
+ });
1099
+ }
1100
+ async captureStatelessImmediate(distinctId, event, properties, options) {
1101
+ const payload = this.buildPayload({
1102
+ distinct_id: distinctId,
1103
+ event,
1104
+ properties
1105
+ });
1106
+ await this.sendImmediate("capture", payload, options);
1107
+ }
1108
+ aliasStateless(alias, distinctId, properties, options) {
1109
+ this.wrap(() => {
1110
+ const payload = this.buildPayload({
1111
+ event: "$create_alias",
1112
+ distinct_id: distinctId,
1113
+ properties: {
1114
+ ...properties || {},
1115
+ distinct_id: distinctId,
1116
+ alias
1117
+ }
1118
+ });
1119
+ this.enqueue("alias", payload, options);
1120
+ });
1121
+ }
1122
+ async aliasStatelessImmediate(alias, distinctId, properties, options) {
1123
+ const payload = this.buildPayload({
1124
+ event: "$create_alias",
1125
+ distinct_id: distinctId,
1126
+ properties: {
1127
+ ...properties || {},
1128
+ distinct_id: distinctId,
1129
+ alias
1130
+ }
1131
+ });
1132
+ await this.sendImmediate("alias", payload, options);
1133
+ }
1134
+ groupIdentifyStateless(groupType, groupKey, groupProperties, options, distinctId, eventProperties) {
1135
+ this.wrap(() => {
1136
+ const payload = this.buildPayload({
1137
+ distinct_id: distinctId || `$${groupType}_${groupKey}`,
1138
+ event: "$groupidentify",
1139
+ properties: {
1140
+ $group_type: groupType,
1141
+ $group_key: groupKey,
1142
+ $group_set: groupProperties || {},
1143
+ ...eventProperties || {}
1144
+ }
1145
+ });
1146
+ this.enqueue("capture", payload, options);
1147
+ });
1148
+ }
1149
+ async getRemoteConfig() {
1150
+ await this._initPromise;
1151
+ let host = this.host;
1152
+ if (host === "https://us.i.posthog.com")
1153
+ host = "https://us-assets.i.posthog.com";
1154
+ else if (host === "https://eu.i.posthog.com")
1155
+ host = "https://eu-assets.i.posthog.com";
1156
+ const url = `${host}/array/${this.apiKey}/config`;
1157
+ const fetchOptions = {
1158
+ method: "GET",
1159
+ headers: {
1160
+ ...this.getCustomHeaders(),
1161
+ "Content-Type": "application/json"
1162
+ }
1163
+ };
1164
+ return this.fetchWithRetry(url, fetchOptions, {
1165
+ retryCount: 0
1166
+ }, this.remoteConfigRequestTimeoutMs).then((response) => response.json()).catch((error) => {
1167
+ this._logger.error("Remote config could not be loaded", error);
1168
+ this._events.emit("error", error);
1169
+ });
1170
+ }
1171
+ async getFlags(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}, fetchConfig = false) {
1172
+ await this._initPromise;
1173
+ const configParam = fetchConfig ? "&config=true" : "";
1174
+ const url = `${this.host}/flags/?v=2${configParam}`;
1175
+ const requestData = {
1176
+ token: this.apiKey,
1177
+ distinct_id: distinctId,
1178
+ groups,
1179
+ person_properties: personProperties,
1180
+ group_properties: groupProperties,
1181
+ ...extraPayload
1182
+ };
1183
+ if (this.evaluationContexts && this.evaluationContexts.length > 0)
1184
+ requestData.evaluation_contexts = this.evaluationContexts;
1185
+ const fetchOptions = {
1186
+ method: "POST",
1187
+ headers: {
1188
+ ...this.getCustomHeaders(),
1189
+ "Content-Type": "application/json"
1190
+ },
1191
+ body: JSON.stringify(requestData)
1192
+ };
1193
+ this._logger.info("Flags URL", url);
1194
+ return this.fetchWithRetry(url, fetchOptions, {
1195
+ retryCount: 0
1196
+ }, this.featureFlagsRequestTimeoutMs).then((response) => response.json()).then((response) => ({
1197
+ success: true,
1198
+ response: normalizeFlagsResponse(response)
1199
+ })).catch((error) => {
1200
+ this._events.emit("error", error);
1201
+ return {
1202
+ success: false,
1203
+ error: this.categorizeRequestError(error)
1204
+ };
1205
+ });
1206
+ }
1207
+ categorizeRequestError(error) {
1208
+ if (error instanceof PostHogFetchHttpError)
1209
+ return {
1210
+ type: "api_error",
1211
+ statusCode: error.status
1212
+ };
1213
+ if (error instanceof PostHogFetchNetworkError) {
1214
+ const cause = error.error;
1215
+ if (cause instanceof Error && (cause.name === "AbortError" || cause.name === "TimeoutError"))
1216
+ return {
1217
+ type: "timeout"
1218
+ };
1219
+ return {
1220
+ type: "connection_error"
1221
+ };
1222
+ }
1223
+ return {
1224
+ type: "unknown_error"
1225
+ };
1226
+ }
1227
+ async getFeatureFlagStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
1228
+ await this._initPromise;
1229
+ const flagDetailResponse = await this.getFeatureFlagDetailStateless(key, distinctId, groups, personProperties, groupProperties, disableGeoip);
1230
+ if (flagDetailResponse === undefined)
1231
+ return {
1232
+ response: undefined,
1233
+ requestId: undefined
1234
+ };
1235
+ let response = getFeatureFlagValue(flagDetailResponse.response);
1236
+ if (response === undefined)
1237
+ response = false;
1238
+ return {
1239
+ response,
1240
+ requestId: flagDetailResponse.requestId
1241
+ };
1242
+ }
1243
+ async getFeatureFlagDetailStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
1244
+ await this._initPromise;
1245
+ const flagsResponse = await this.getFeatureFlagDetailsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, [
1246
+ key
1247
+ ]);
1248
+ if (flagsResponse === undefined)
1249
+ return;
1250
+ const featureFlags = flagsResponse.flags;
1251
+ const flagDetail = featureFlags[key];
1252
+ return {
1253
+ response: flagDetail,
1254
+ requestId: flagsResponse.requestId,
1255
+ evaluatedAt: flagsResponse.evaluatedAt
1256
+ };
1257
+ }
1258
+ async getFeatureFlagPayloadStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
1259
+ await this._initPromise;
1260
+ const payloads = await this.getFeatureFlagPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, [
1261
+ key
1262
+ ]);
1263
+ if (!payloads)
1264
+ return;
1265
+ const response = payloads[key];
1266
+ if (response === undefined)
1267
+ return null;
1268
+ return response;
1269
+ }
1270
+ async getFeatureFlagPayloadsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip, flagKeysToEvaluate) {
1271
+ await this._initPromise;
1272
+ const payloads = (await this.getFeatureFlagsAndPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, flagKeysToEvaluate)).payloads;
1273
+ return payloads;
1274
+ }
1275
+ async getFeatureFlagsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip, flagKeysToEvaluate) {
1276
+ await this._initPromise;
1277
+ return await this.getFeatureFlagsAndPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, flagKeysToEvaluate);
1278
+ }
1279
+ async getFeatureFlagsAndPayloadsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip, flagKeysToEvaluate) {
1280
+ await this._initPromise;
1281
+ const featureFlagDetails = await this.getFeatureFlagDetailsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, flagKeysToEvaluate);
1282
+ if (!featureFlagDetails)
1283
+ return {
1284
+ flags: undefined,
1285
+ payloads: undefined,
1286
+ requestId: undefined
1287
+ };
1288
+ return {
1289
+ flags: featureFlagDetails.featureFlags,
1290
+ payloads: featureFlagDetails.featureFlagPayloads,
1291
+ requestId: featureFlagDetails.requestId
1292
+ };
1293
+ }
1294
+ async getFeatureFlagDetailsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip, flagKeysToEvaluate) {
1295
+ await this._initPromise;
1296
+ const extraPayload = {};
1297
+ if (disableGeoip ?? this.disableGeoip)
1298
+ extraPayload["geoip_disable"] = true;
1299
+ if (flagKeysToEvaluate)
1300
+ extraPayload["flag_keys_to_evaluate"] = flagKeysToEvaluate;
1301
+ const result = await this.getFlags(distinctId, groups, personProperties, groupProperties, extraPayload);
1302
+ if (!result.success)
1303
+ return;
1304
+ const flagsResponse = result.response;
1305
+ if (flagsResponse.errorsWhileComputingFlags)
1306
+ 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");
1307
+ if (flagsResponse.quotaLimited?.includes("feature_flags")) {
1308
+ 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");
1309
+ return {
1310
+ flags: {},
1311
+ featureFlags: {},
1312
+ featureFlagPayloads: {},
1313
+ requestId: flagsResponse?.requestId,
1314
+ quotaLimited: flagsResponse.quotaLimited
1315
+ };
1316
+ }
1317
+ return flagsResponse;
1318
+ }
1319
+ async getSurveysStateless() {
1320
+ await this._initPromise;
1321
+ if (this.disableSurveys === true) {
1322
+ this._logger.info("Loading surveys is disabled.");
1323
+ return [];
1324
+ }
1325
+ const url = `${this.host}/api/surveys/?token=${this.apiKey}`;
1326
+ const fetchOptions = {
1327
+ method: "GET",
1328
+ headers: {
1329
+ ...this.getCustomHeaders(),
1330
+ "Content-Type": "application/json"
1331
+ }
1332
+ };
1333
+ const response = await this.fetchWithRetry(url, fetchOptions).then((response2) => {
1334
+ if (response2.status !== 200 || !response2.json) {
1335
+ const msg = `Surveys API could not be loaded: ${response2.status}`;
1336
+ const error = new Error(msg);
1337
+ this._logger.error(error);
1338
+ this._events.emit("error", new Error(msg));
1339
+ return;
1340
+ }
1341
+ return response2.json();
1342
+ }).catch((error) => {
1343
+ this._logger.error("Surveys API could not be loaded", error);
1344
+ this._events.emit("error", error);
1345
+ });
1346
+ const newSurveys = response?.surveys;
1347
+ if (newSurveys)
1348
+ this._logger.info("Surveys fetched from API: ", JSON.stringify(newSurveys));
1349
+ return newSurveys ?? [];
1350
+ }
1351
+ get props() {
1352
+ if (!this._props)
1353
+ this._props = this.getPersistedProperty(types_PostHogPersistedProperty.Props);
1354
+ return this._props || {};
1355
+ }
1356
+ set props(val) {
1357
+ this._props = val;
1358
+ }
1359
+ async register(properties) {
1360
+ this.wrap(() => {
1361
+ this.props = {
1362
+ ...this.props,
1363
+ ...properties
1364
+ };
1365
+ this.setPersistedProperty(types_PostHogPersistedProperty.Props, this.props);
1366
+ });
1367
+ }
1368
+ async unregister(property) {
1369
+ this.wrap(() => {
1370
+ delete this.props[property];
1371
+ this.setPersistedProperty(types_PostHogPersistedProperty.Props, this.props);
1372
+ });
1373
+ }
1374
+ processBeforeEnqueue(message) {
1375
+ return message;
1376
+ }
1377
+ async flushStorage() {}
1378
+ enqueue(type, _message, options) {
1379
+ this.wrap(() => {
1380
+ if (this.optedOut)
1381
+ return void this._events.emit(type, "Library is disabled. Not sending event. To re-enable, call posthog.optIn()");
1382
+ let message = this.prepareMessage(type, _message, options);
1383
+ message = this.processBeforeEnqueue(message);
1384
+ if (message === null)
1385
+ return;
1386
+ const queue = this.getPersistedProperty(types_PostHogPersistedProperty.Queue) || [];
1387
+ if (queue.length >= this.maxQueueSize) {
1388
+ queue.shift();
1389
+ this._logger.info("Queue is full, the oldest event is dropped.");
1390
+ }
1391
+ queue.push({
1392
+ message
1393
+ });
1394
+ this.setPersistedProperty(types_PostHogPersistedProperty.Queue, queue);
1395
+ this._events.emit(type, message);
1396
+ if (queue.length >= this.flushAt)
1397
+ this.flushBackground();
1398
+ if (this.flushInterval && !this._flushTimer)
1399
+ this._flushTimer = safeSetTimeout(() => this.flushBackground(), this.flushInterval);
1400
+ });
1401
+ }
1402
+ async sendImmediate(type, _message, options) {
1403
+ if (this.disabled)
1404
+ return void this._logger.warn("The client is disabled");
1405
+ if (!this._isInitialized)
1406
+ await this._initPromise;
1407
+ if (this.optedOut)
1408
+ return void this._events.emit(type, "Library is disabled. Not sending event. To re-enable, call posthog.optIn()");
1409
+ let message = this.prepareMessage(type, _message, options);
1410
+ message = this.processBeforeEnqueue(message);
1411
+ if (message === null)
1412
+ return;
1413
+ const data = {
1414
+ api_key: this.apiKey,
1415
+ batch: [
1416
+ message
1417
+ ],
1418
+ sent_at: currentISOTime()
1419
+ };
1420
+ if (this.historicalMigration)
1421
+ data.historical_migration = true;
1422
+ const payload = JSON.stringify(data);
1423
+ const url = `${this.host}/batch/`;
1424
+ const gzippedPayload = this.disableCompression ? null : await gzipCompress(payload, this.isDebug);
1425
+ const fetchOptions = {
1426
+ method: "POST",
1427
+ headers: {
1428
+ ...this.getCustomHeaders(),
1429
+ "Content-Type": "application/json",
1430
+ ...gzippedPayload !== null && {
1431
+ "Content-Encoding": "gzip"
1432
+ }
1433
+ },
1434
+ body: gzippedPayload || payload
1435
+ };
1436
+ try {
1437
+ await this.fetchWithRetry(url, fetchOptions);
1438
+ } catch (err) {
1439
+ this._events.emit("error", err);
1440
+ }
1441
+ }
1442
+ prepareMessage(type, _message, options) {
1443
+ const message = {
1444
+ ..._message,
1445
+ type,
1446
+ library: this.getLibraryId(),
1447
+ library_version: this.getLibraryVersion(),
1448
+ timestamp: options?.timestamp ? options?.timestamp : currentISOTime(),
1449
+ uuid: options?.uuid ? options.uuid : uuidv7()
1450
+ };
1451
+ const addGeoipDisableProperty = options?.disableGeoip ?? this.disableGeoip;
1452
+ if (addGeoipDisableProperty) {
1453
+ if (!message.properties)
1454
+ message.properties = {};
1455
+ message["properties"]["$geoip_disable"] = true;
1456
+ }
1457
+ if (message.distinctId) {
1458
+ message.distinct_id = message.distinctId;
1459
+ delete message.distinctId;
1460
+ }
1461
+ return message;
1462
+ }
1463
+ clearFlushTimer() {
1464
+ if (this._flushTimer) {
1465
+ clearTimeout(this._flushTimer);
1466
+ this._flushTimer = undefined;
1467
+ }
1468
+ }
1469
+ flushBackground() {
1470
+ this.flush().catch(async (err) => {
1471
+ await logFlushError(err);
1472
+ });
1473
+ }
1474
+ async flush() {
1475
+ const nextFlushPromise = allSettled([
1476
+ this.flushPromise
1477
+ ]).then(() => this._flush());
1478
+ this.flushPromise = nextFlushPromise;
1479
+ this.addPendingPromise(nextFlushPromise);
1480
+ allSettled([
1481
+ nextFlushPromise
1482
+ ]).then(() => {
1483
+ if (this.flushPromise === nextFlushPromise)
1484
+ this.flushPromise = null;
1485
+ });
1486
+ return nextFlushPromise;
1487
+ }
1488
+ getCustomHeaders() {
1489
+ const customUserAgent = this.getCustomUserAgent();
1490
+ const headers = {};
1491
+ if (customUserAgent && customUserAgent !== "")
1492
+ headers["User-Agent"] = customUserAgent;
1493
+ return headers;
1494
+ }
1495
+ async _flush() {
1496
+ this.clearFlushTimer();
1497
+ await this._initPromise;
1498
+ let queue = this.getPersistedProperty(types_PostHogPersistedProperty.Queue) || [];
1499
+ if (!queue.length)
1500
+ return;
1501
+ const sentMessages = [];
1502
+ const originalQueueLength = queue.length;
1503
+ while (queue.length > 0 && sentMessages.length < originalQueueLength) {
1504
+ const batchItems = queue.slice(0, this.maxBatchSize);
1505
+ const batchMessages = batchItems.map((item) => item.message);
1506
+ const persistQueueChange = async () => {
1507
+ const refreshedQueue = this.getPersistedProperty(types_PostHogPersistedProperty.Queue) || [];
1508
+ const newQueue = refreshedQueue.slice(batchItems.length);
1509
+ this.setPersistedProperty(types_PostHogPersistedProperty.Queue, newQueue);
1510
+ queue = newQueue;
1511
+ await this.flushStorage();
1512
+ };
1513
+ const data = {
1514
+ api_key: this.apiKey,
1515
+ batch: batchMessages,
1516
+ sent_at: currentISOTime()
1517
+ };
1518
+ if (this.historicalMigration)
1519
+ data.historical_migration = true;
1520
+ const payload = JSON.stringify(data);
1521
+ const url = `${this.host}/batch/`;
1522
+ const gzippedPayload = this.disableCompression ? null : await gzipCompress(payload, this.isDebug);
1523
+ const fetchOptions = {
1524
+ method: "POST",
1525
+ headers: {
1526
+ ...this.getCustomHeaders(),
1527
+ "Content-Type": "application/json",
1528
+ ...gzippedPayload !== null && {
1529
+ "Content-Encoding": "gzip"
1530
+ }
1531
+ },
1532
+ body: gzippedPayload || payload
1533
+ };
1534
+ const retryOptions = {
1535
+ retryCheck: (err) => {
1536
+ if (isPostHogFetchContentTooLargeError(err))
1537
+ return false;
1538
+ return isPostHogFetchError(err);
1539
+ }
1540
+ };
1541
+ try {
1542
+ await this.fetchWithRetry(url, fetchOptions, retryOptions);
1543
+ } catch (err) {
1544
+ if (isPostHogFetchContentTooLargeError(err) && batchMessages.length > 1) {
1545
+ this.maxBatchSize = Math.max(1, Math.floor(batchMessages.length / 2));
1546
+ this._logger.warn(`Received 413 when sending batch of size ${batchMessages.length}, reducing batch size to ${this.maxBatchSize}`);
1547
+ continue;
1548
+ }
1549
+ if (!(err instanceof PostHogFetchNetworkError))
1550
+ await persistQueueChange();
1551
+ this._events.emit("error", err);
1552
+ throw err;
1553
+ }
1554
+ await persistQueueChange();
1555
+ sentMessages.push(...batchMessages);
1556
+ }
1557
+ this._events.emit("flush", sentMessages);
1558
+ }
1559
+ async fetchWithRetry(url, options, retryOptions, requestTimeout) {
1560
+ const body = options.body ? options.body : "";
1561
+ let reqByteLength = -1;
1562
+ try {
1563
+ reqByteLength = body instanceof Blob ? body.size : Buffer.byteLength(body, STRING_FORMAT);
1564
+ } catch {
1565
+ if (body instanceof Blob)
1566
+ reqByteLength = body.size;
1567
+ else {
1568
+ const encoded = new TextEncoder().encode(body);
1569
+ reqByteLength = encoded.length;
1570
+ }
1571
+ }
1572
+ return await retriable(async () => {
1573
+ const ctrl = new AbortController;
1574
+ const timeoutMs = requestTimeout ?? this.requestTimeout;
1575
+ const timer = safeSetTimeout(() => ctrl.abort(), timeoutMs);
1576
+ let res = null;
1577
+ try {
1578
+ res = await this.fetch(url, {
1579
+ signal: ctrl.signal,
1580
+ ...options
1581
+ });
1582
+ } catch (e) {
1583
+ throw new PostHogFetchNetworkError(e);
1584
+ } finally {
1585
+ clearTimeout(timer);
1586
+ }
1587
+ const isNoCors = options.mode === "no-cors";
1588
+ if (!isNoCors && (res.status < 200 || res.status >= 400))
1589
+ throw new PostHogFetchHttpError(res, reqByteLength);
1590
+ return res;
1591
+ }, {
1592
+ ...this._retryOptions,
1593
+ ...retryOptions
1594
+ });
1595
+ }
1596
+ async _shutdown(shutdownTimeoutMs = 30000) {
1597
+ await this._initPromise;
1598
+ let hasTimedOut = false;
1599
+ this.clearFlushTimer();
1600
+ const doShutdown = async () => {
1601
+ try {
1602
+ await this.promiseQueue.join();
1603
+ while (true) {
1604
+ const queue = this.getPersistedProperty(types_PostHogPersistedProperty.Queue) || [];
1605
+ if (queue.length === 0)
1606
+ break;
1607
+ await this.flush();
1608
+ if (hasTimedOut)
1609
+ break;
1610
+ }
1611
+ } catch (e) {
1612
+ if (!isPostHogFetchError(e))
1613
+ throw e;
1614
+ await logFlushError(e);
1615
+ }
1616
+ };
1617
+ let timeoutHandle;
1618
+ try {
1619
+ return await Promise.race([
1620
+ new Promise((_, reject) => {
1621
+ timeoutHandle = safeSetTimeout(() => {
1622
+ this._logger.error("Timed out while shutting down PostHog");
1623
+ hasTimedOut = true;
1624
+ reject("Timeout while shutting down PostHog. Some events may not have been sent.");
1625
+ }, shutdownTimeoutMs);
1626
+ }),
1627
+ doShutdown()
1628
+ ]);
1629
+ } finally {
1630
+ clearTimeout(timeoutHandle);
1631
+ }
1632
+ }
1633
+ async shutdown(shutdownTimeoutMs = 30000) {
1634
+ if (this.shutdownPromise)
1635
+ 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");
1636
+ else
1637
+ this.shutdownPromise = this._shutdown(shutdownTimeoutMs).finally(() => {
1638
+ this.shutdownPromise = null;
1639
+ });
1640
+ return this.shutdownPromise;
1641
+ }
1642
+ }
1643
+ // node_modules/@posthog/core/dist/error-tracking/index.mjs
1644
+ var exports_error_tracking = {};
1645
+ __export(exports_error_tracking, {
1646
+ winjsStackLineParser: () => winjsStackLineParser,
1647
+ reverseAndStripFrames: () => reverseAndStripFrames,
1648
+ opera11StackLineParser: () => opera11StackLineParser,
1649
+ opera10StackLineParser: () => opera10StackLineParser,
1650
+ nodeStackLineParser: () => nodeStackLineParser,
1651
+ geckoStackLineParser: () => geckoStackLineParser,
1652
+ createStackParser: () => createStackParser,
1653
+ createDefaultStackParser: () => createDefaultStackParser,
1654
+ chromeStackLineParser: () => chromeStackLineParser,
1655
+ StringCoercer: () => StringCoercer,
1656
+ ReduceableCache: () => ReduceableCache,
1657
+ PromiseRejectionEventCoercer: () => PromiseRejectionEventCoercer,
1658
+ PrimitiveCoercer: () => PrimitiveCoercer,
1659
+ ObjectCoercer: () => ObjectCoercer,
1660
+ EventCoercer: () => EventCoercer,
1661
+ ErrorPropertiesBuilder: () => ErrorPropertiesBuilder,
1662
+ ErrorEventCoercer: () => ErrorEventCoercer,
1663
+ ErrorCoercer: () => ErrorCoercer,
1664
+ DOMExceptionCoercer: () => DOMExceptionCoercer
1665
+ });
1666
+
1667
+ // node_modules/@posthog/core/dist/error-tracking/chunk-ids.mjs
1668
+ var parsedStackResults;
1669
+ var lastKeysCount;
1670
+ var cachedFilenameChunkIds;
1671
+ function getFilenameToChunkIdMap(stackParser) {
1672
+ const chunkIdMap = globalThis._posthogChunkIds;
1673
+ if (!chunkIdMap)
1674
+ return;
1675
+ const chunkIdKeys = Object.keys(chunkIdMap);
1676
+ if (cachedFilenameChunkIds && chunkIdKeys.length === lastKeysCount)
1677
+ return cachedFilenameChunkIds;
1678
+ lastKeysCount = chunkIdKeys.length;
1679
+ cachedFilenameChunkIds = chunkIdKeys.reduce((acc, stackKey) => {
1680
+ if (!parsedStackResults)
1681
+ parsedStackResults = {};
1682
+ const result = parsedStackResults[stackKey];
1683
+ if (result)
1684
+ acc[result[0]] = result[1];
1685
+ else {
1686
+ const parsedStack = stackParser(stackKey);
1687
+ for (let i = parsedStack.length - 1;i >= 0; i--) {
1688
+ const stackFrame = parsedStack[i];
1689
+ const filename = stackFrame?.filename;
1690
+ const chunkId = chunkIdMap[stackKey];
1691
+ if (filename && chunkId) {
1692
+ acc[filename] = chunkId;
1693
+ parsedStackResults[stackKey] = [
1694
+ filename,
1695
+ chunkId
1696
+ ];
1697
+ break;
1698
+ }
1699
+ }
1700
+ }
1701
+ return acc;
1702
+ }, {});
1703
+ return cachedFilenameChunkIds;
1704
+ }
1705
+
1706
+ // node_modules/@posthog/core/dist/error-tracking/error-properties-builder.mjs
1707
+ var MAX_CAUSE_RECURSION = 4;
1708
+
1709
+ class ErrorPropertiesBuilder {
1710
+ constructor(coercers, stackParser, modifiers = []) {
1711
+ this.coercers = coercers;
1712
+ this.stackParser = stackParser;
1713
+ this.modifiers = modifiers;
1714
+ }
1715
+ buildFromUnknown(input, hint = {}) {
1716
+ const providedMechanism = hint && hint.mechanism;
1717
+ const mechanism = providedMechanism || {
1718
+ handled: true,
1719
+ type: "generic"
1720
+ };
1721
+ const coercingContext = this.buildCoercingContext(mechanism, hint, 0);
1722
+ const exceptionWithCause = coercingContext.apply(input);
1723
+ const parsingContext = this.buildParsingContext(hint);
1724
+ const exceptionWithStack = this.parseStacktrace(exceptionWithCause, parsingContext);
1725
+ const exceptionList = this.convertToExceptionList(exceptionWithStack, mechanism);
1726
+ return {
1727
+ $exception_list: exceptionList,
1728
+ $exception_level: "error"
1729
+ };
1730
+ }
1731
+ async modifyFrames(exceptionList) {
1732
+ for (const exc of exceptionList)
1733
+ if (exc.stacktrace && exc.stacktrace.frames && isArray(exc.stacktrace.frames))
1734
+ exc.stacktrace.frames = await this.applyModifiers(exc.stacktrace.frames);
1735
+ return exceptionList;
1736
+ }
1737
+ coerceFallback(ctx) {
1738
+ return {
1739
+ type: "Error",
1740
+ value: "Unknown error",
1741
+ stack: ctx.syntheticException?.stack,
1742
+ synthetic: true
1743
+ };
1744
+ }
1745
+ parseStacktrace(err, ctx) {
1746
+ let cause;
1747
+ if (err.cause != null)
1748
+ cause = this.parseStacktrace(err.cause, ctx);
1749
+ let stack;
1750
+ if (err.stack != "" && err.stack != null)
1751
+ stack = this.applyChunkIds(this.stackParser(err.stack, err.synthetic ? ctx.skipFirstLines : 0), ctx.chunkIdMap);
1752
+ return {
1753
+ ...err,
1754
+ cause,
1755
+ stack
1756
+ };
1757
+ }
1758
+ applyChunkIds(frames, chunkIdMap) {
1759
+ return frames.map((frame) => {
1760
+ if (frame.filename && chunkIdMap)
1761
+ frame.chunk_id = chunkIdMap[frame.filename];
1762
+ return frame;
1763
+ });
1764
+ }
1765
+ applyCoercers(input, ctx) {
1766
+ for (const adapter of this.coercers)
1767
+ if (adapter.match(input))
1768
+ return adapter.coerce(input, ctx);
1769
+ return this.coerceFallback(ctx);
1770
+ }
1771
+ async applyModifiers(frames) {
1772
+ let newFrames = frames;
1773
+ for (const modifier of this.modifiers)
1774
+ newFrames = await modifier(newFrames);
1775
+ return newFrames;
1776
+ }
1777
+ convertToExceptionList(exceptionWithStack, mechanism) {
1778
+ const currentException = {
1779
+ type: exceptionWithStack.type,
1780
+ value: exceptionWithStack.value,
1781
+ mechanism: {
1782
+ type: mechanism.type ?? "generic",
1783
+ handled: mechanism.handled ?? true,
1784
+ synthetic: exceptionWithStack.synthetic ?? false
1785
+ }
1786
+ };
1787
+ if (exceptionWithStack.stack)
1788
+ currentException.stacktrace = {
1789
+ type: "raw",
1790
+ frames: exceptionWithStack.stack
1791
+ };
1792
+ const exceptionList = [
1793
+ currentException
1794
+ ];
1795
+ if (exceptionWithStack.cause != null)
1796
+ exceptionList.push(...this.convertToExceptionList(exceptionWithStack.cause, {
1797
+ ...mechanism,
1798
+ handled: true
1799
+ }));
1800
+ return exceptionList;
1801
+ }
1802
+ buildParsingContext(hint) {
1803
+ const context = {
1804
+ chunkIdMap: getFilenameToChunkIdMap(this.stackParser),
1805
+ skipFirstLines: hint.skipFirstLines ?? 1
1806
+ };
1807
+ return context;
1808
+ }
1809
+ buildCoercingContext(mechanism, hint, depth = 0) {
1810
+ const coerce = (input, depth2) => {
1811
+ if (!(depth2 <= MAX_CAUSE_RECURSION))
1812
+ return;
1813
+ {
1814
+ const ctx = this.buildCoercingContext(mechanism, hint, depth2);
1815
+ return this.applyCoercers(input, ctx);
1816
+ }
1817
+ };
1818
+ const context = {
1819
+ ...hint,
1820
+ syntheticException: depth == 0 ? hint.syntheticException : undefined,
1821
+ mechanism,
1822
+ apply: (input) => coerce(input, depth),
1823
+ next: (input) => coerce(input, depth + 1)
1824
+ };
1825
+ return context;
1826
+ }
1827
+ }
1828
+ // node_modules/@posthog/core/dist/error-tracking/parsers/base.mjs
1829
+ var UNKNOWN_FUNCTION = "?";
1830
+ function createFrame(platform, filename, func, lineno, colno) {
1831
+ const frame = {
1832
+ platform,
1833
+ filename,
1834
+ function: func === "<anonymous>" ? UNKNOWN_FUNCTION : func,
1835
+ in_app: true
1836
+ };
1837
+ if (!isUndefined(lineno))
1838
+ frame.lineno = lineno;
1839
+ if (!isUndefined(colno))
1840
+ frame.colno = colno;
1841
+ return frame;
1842
+ }
1843
+
1844
+ // node_modules/@posthog/core/dist/error-tracking/parsers/safari.mjs
1845
+ var extractSafariExtensionDetails = (func, filename) => {
1846
+ const isSafariExtension = func.indexOf("safari-extension") !== -1;
1847
+ const isSafariWebExtension = func.indexOf("safari-web-extension") !== -1;
1848
+ return isSafariExtension || isSafariWebExtension ? [
1849
+ func.indexOf("@") !== -1 ? func.split("@")[0] : UNKNOWN_FUNCTION,
1850
+ isSafariExtension ? `safari-extension:${filename}` : `safari-web-extension:${filename}`
1851
+ ] : [
1852
+ func,
1853
+ filename
1854
+ ];
1855
+ };
1856
+
1857
+ // node_modules/@posthog/core/dist/error-tracking/parsers/chrome.mjs
1858
+ var chromeRegexNoFnName = /^\s*at (\S+?)(?::(\d+))(?::(\d+))\s*$/i;
1859
+ var chromeRegex = /^\s*at (?:(.+?\)(?: \[.+\])?|.*?) ?\((?:address at )?)?(?:async )?((?:<anonymous>|[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
1860
+ var chromeEvalRegex = /\((\S*)(?::(\d+))(?::(\d+))\)/;
1861
+ var chromeStackLineParser = (line, platform) => {
1862
+ const noFnParts = chromeRegexNoFnName.exec(line);
1863
+ if (noFnParts) {
1864
+ const [, filename, line2, col] = noFnParts;
1865
+ return createFrame(platform, filename, UNKNOWN_FUNCTION, +line2, +col);
1866
+ }
1867
+ const parts = chromeRegex.exec(line);
1868
+ if (parts) {
1869
+ const isEval = parts[2] && parts[2].indexOf("eval") === 0;
1870
+ if (isEval) {
1871
+ const subMatch = chromeEvalRegex.exec(parts[2]);
1872
+ if (subMatch) {
1873
+ parts[2] = subMatch[1];
1874
+ parts[3] = subMatch[2];
1875
+ parts[4] = subMatch[3];
1876
+ }
1877
+ }
1878
+ const [func, filename] = extractSafariExtensionDetails(parts[1] || UNKNOWN_FUNCTION, parts[2]);
1879
+ return createFrame(platform, filename, func, parts[3] ? +parts[3] : undefined, parts[4] ? +parts[4] : undefined);
1880
+ }
1881
+ };
1882
+
1883
+ // node_modules/@posthog/core/dist/error-tracking/parsers/gecko.mjs
1884
+ var geckoREgex = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:[-a-z]+)?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i;
1885
+ var geckoEvalRegex = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
1886
+ var geckoStackLineParser = (line, platform) => {
1887
+ const parts = geckoREgex.exec(line);
1888
+ if (parts) {
1889
+ const isEval = parts[3] && parts[3].indexOf(" > eval") > -1;
1890
+ if (isEval) {
1891
+ const subMatch = geckoEvalRegex.exec(parts[3]);
1892
+ if (subMatch) {
1893
+ parts[1] = parts[1] || "eval";
1894
+ parts[3] = subMatch[1];
1895
+ parts[4] = subMatch[2];
1896
+ parts[5] = "";
1897
+ }
1898
+ }
1899
+ let filename = parts[3];
1900
+ let func = parts[1] || UNKNOWN_FUNCTION;
1901
+ [func, filename] = extractSafariExtensionDetails(func, filename);
1902
+ return createFrame(platform, filename, func, parts[4] ? +parts[4] : undefined, parts[5] ? +parts[5] : undefined);
1903
+ }
1904
+ };
1905
+
1906
+ // node_modules/@posthog/core/dist/error-tracking/parsers/winjs.mjs
1907
+ var winjsRegex = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:[-a-z]+):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
1908
+ var winjsStackLineParser = (line, platform) => {
1909
+ const parts = winjsRegex.exec(line);
1910
+ return parts ? createFrame(platform, parts[2], parts[1] || UNKNOWN_FUNCTION, +parts[3], parts[4] ? +parts[4] : undefined) : undefined;
1911
+ };
1912
+
1913
+ // node_modules/@posthog/core/dist/error-tracking/parsers/opera.mjs
1914
+ var opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i;
1915
+ var opera10StackLineParser = (line, platform) => {
1916
+ const parts = opera10Regex.exec(line);
1917
+ return parts ? createFrame(platform, parts[2], parts[3] || UNKNOWN_FUNCTION, +parts[1]) : undefined;
1918
+ };
1919
+ var opera11Regex = / line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^)]+))\(.*\))? in (.*):\s*$/i;
1920
+ var opera11StackLineParser = (line, platform) => {
1921
+ const parts = opera11Regex.exec(line);
1922
+ return parts ? createFrame(platform, parts[5], parts[3] || parts[4] || UNKNOWN_FUNCTION, +parts[1], +parts[2]) : undefined;
1923
+ };
1924
+
1925
+ // node_modules/@posthog/core/dist/error-tracking/parsers/node.mjs
1926
+ var FILENAME_MATCH = /^\s*[-]{4,}$/;
1927
+ var FULL_MATCH = /at (?:async )?(?:(.+?)\s+\()?(?:(.+):(\d+):(\d+)?|([^)]+))\)?/;
1928
+ var nodeStackLineParser = (line, platform) => {
1929
+ const lineMatch = line.match(FULL_MATCH);
1930
+ if (lineMatch) {
1931
+ let object;
1932
+ let method;
1933
+ let functionName;
1934
+ let typeName;
1935
+ let methodName;
1936
+ if (lineMatch[1]) {
1937
+ functionName = lineMatch[1];
1938
+ let methodStart = functionName.lastIndexOf(".");
1939
+ if (functionName[methodStart - 1] === ".")
1940
+ methodStart--;
1941
+ if (methodStart > 0) {
1942
+ object = functionName.slice(0, methodStart);
1943
+ method = functionName.slice(methodStart + 1);
1944
+ const objectEnd = object.indexOf(".Module");
1945
+ if (objectEnd > 0) {
1946
+ functionName = functionName.slice(objectEnd + 1);
1947
+ object = object.slice(0, objectEnd);
1948
+ }
1949
+ }
1950
+ typeName = undefined;
1951
+ }
1952
+ if (method) {
1953
+ typeName = object;
1954
+ methodName = method;
1955
+ }
1956
+ if (method === "<anonymous>") {
1957
+ methodName = undefined;
1958
+ functionName = undefined;
1959
+ }
1960
+ if (functionName === undefined) {
1961
+ methodName = methodName || UNKNOWN_FUNCTION;
1962
+ functionName = typeName ? `${typeName}.${methodName}` : methodName;
1963
+ }
1964
+ let filename = lineMatch[2]?.startsWith("file://") ? lineMatch[2].slice(7) : lineMatch[2];
1965
+ const isNative = lineMatch[5] === "native";
1966
+ if (filename?.match(/\/[A-Z]:/))
1967
+ filename = filename.slice(1);
1968
+ if (!filename && lineMatch[5] && !isNative)
1969
+ filename = lineMatch[5];
1970
+ return {
1971
+ filename: filename ? decodeURI(filename) : undefined,
1972
+ module: undefined,
1973
+ function: functionName,
1974
+ lineno: _parseIntOrUndefined(lineMatch[3]),
1975
+ colno: _parseIntOrUndefined(lineMatch[4]),
1976
+ in_app: filenameIsInApp(filename || "", isNative),
1977
+ platform
1978
+ };
1979
+ }
1980
+ if (line.match(FILENAME_MATCH))
1981
+ return {
1982
+ filename: line,
1983
+ platform
1984
+ };
1985
+ };
1986
+ function filenameIsInApp(filename, isNative = false) {
1987
+ const isInternal = isNative || filename && !filename.startsWith("/") && !filename.match(/^[A-Z]:/) && !filename.startsWith(".") && !filename.match(/^[a-zA-Z]([a-zA-Z0-9.\-+])*:\/\//);
1988
+ return !isInternal && filename !== undefined && !filename.includes("node_modules/");
1989
+ }
1990
+ function _parseIntOrUndefined(input) {
1991
+ return parseInt(input || "", 10) || undefined;
1992
+ }
1993
+
1994
+ // node_modules/@posthog/core/dist/error-tracking/parsers/index.mjs
1995
+ var WEBPACK_ERROR_REGEXP = /\(error: (.*)\)/;
1996
+ var STACKTRACE_FRAME_LIMIT = 50;
1997
+ function reverseAndStripFrames(stack) {
1998
+ if (!stack.length)
1999
+ return [];
2000
+ const localStack = Array.from(stack);
2001
+ localStack.reverse();
2002
+ return localStack.slice(0, STACKTRACE_FRAME_LIMIT).map((frame) => ({
2003
+ ...frame,
2004
+ filename: frame.filename || getLastStackFrame(localStack).filename,
2005
+ function: frame.function || UNKNOWN_FUNCTION
2006
+ }));
2007
+ }
2008
+ function getLastStackFrame(arr) {
2009
+ return arr[arr.length - 1] || {};
2010
+ }
2011
+ function createDefaultStackParser() {
2012
+ return createStackParser("web:javascript", chromeStackLineParser, geckoStackLineParser);
2013
+ }
2014
+ function createStackParser(platform, ...parsers) {
2015
+ return (stack, skipFirstLines = 0) => {
2016
+ const frames = [];
2017
+ const lines = stack.split(`
2018
+ `);
2019
+ for (let i = skipFirstLines;i < lines.length; i++) {
2020
+ const line = lines[i];
2021
+ if (line.length > 1024)
2022
+ continue;
2023
+ const cleanedLine = WEBPACK_ERROR_REGEXP.test(line) ? line.replace(WEBPACK_ERROR_REGEXP, "$1") : line;
2024
+ if (!cleanedLine.match(/\S*Error: /)) {
2025
+ for (const parser of parsers) {
2026
+ const frame = parser(cleanedLine, platform);
2027
+ if (frame) {
2028
+ frames.push(frame);
2029
+ break;
2030
+ }
2031
+ }
2032
+ if (frames.length >= STACKTRACE_FRAME_LIMIT)
2033
+ break;
2034
+ }
2035
+ }
2036
+ return reverseAndStripFrames(frames);
2037
+ };
2038
+ }
2039
+ // node_modules/@posthog/core/dist/error-tracking/coercers/dom-exception-coercer.mjs
2040
+ class DOMExceptionCoercer {
2041
+ match(err) {
2042
+ return this.isDOMException(err) || this.isDOMError(err);
2043
+ }
2044
+ coerce(err, ctx) {
2045
+ const hasStack = isString(err.stack);
2046
+ return {
2047
+ type: this.getType(err),
2048
+ value: this.getValue(err),
2049
+ stack: hasStack ? err.stack : undefined,
2050
+ cause: err.cause ? ctx.next(err.cause) : undefined,
2051
+ synthetic: false
2052
+ };
2053
+ }
2054
+ getType(candidate) {
2055
+ return this.isDOMError(candidate) ? "DOMError" : "DOMException";
2056
+ }
2057
+ getValue(err) {
2058
+ const name = err.name || (this.isDOMError(err) ? "DOMError" : "DOMException");
2059
+ const message = err.message ? `${name}: ${err.message}` : name;
2060
+ return message;
2061
+ }
2062
+ isDOMException(err) {
2063
+ return isBuiltin(err, "DOMException");
2064
+ }
2065
+ isDOMError(err) {
2066
+ return isBuiltin(err, "DOMError");
2067
+ }
2068
+ }
2069
+ // node_modules/@posthog/core/dist/error-tracking/coercers/error-coercer.mjs
2070
+ class ErrorCoercer {
2071
+ match(err) {
2072
+ return isPlainError(err);
2073
+ }
2074
+ coerce(err, ctx) {
2075
+ return {
2076
+ type: this.getType(err),
2077
+ value: this.getMessage(err, ctx),
2078
+ stack: this.getStack(err),
2079
+ cause: err.cause ? ctx.next(err.cause) : undefined,
2080
+ synthetic: false
2081
+ };
2082
+ }
2083
+ getType(err) {
2084
+ return err.name || err.constructor.name;
2085
+ }
2086
+ getMessage(err, _ctx) {
2087
+ const message = err.message;
2088
+ if (message.error && typeof message.error.message == "string")
2089
+ return String(message.error.message);
2090
+ return String(message);
2091
+ }
2092
+ getStack(err) {
2093
+ return err.stacktrace || err.stack || undefined;
2094
+ }
2095
+ }
2096
+ // node_modules/@posthog/core/dist/error-tracking/coercers/error-event-coercer.mjs
2097
+ class ErrorEventCoercer {
2098
+ constructor() {}
2099
+ match(err) {
2100
+ return isErrorEvent(err) && err.error != null;
2101
+ }
2102
+ coerce(err, ctx) {
2103
+ const exceptionLike = ctx.apply(err.error);
2104
+ if (!exceptionLike)
2105
+ return {
2106
+ type: "ErrorEvent",
2107
+ value: err.message,
2108
+ stack: ctx.syntheticException?.stack,
2109
+ synthetic: true
2110
+ };
2111
+ return exceptionLike;
2112
+ }
2113
+ }
2114
+ // node_modules/@posthog/core/dist/error-tracking/coercers/string-coercer.mjs
2115
+ var ERROR_TYPES_PATTERN = /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/i;
2116
+
2117
+ class StringCoercer {
2118
+ match(input) {
2119
+ return typeof input == "string";
2120
+ }
2121
+ coerce(input, ctx) {
2122
+ const [type, value] = this.getInfos(input);
2123
+ return {
2124
+ type: type ?? "Error",
2125
+ value: value ?? input,
2126
+ stack: ctx.syntheticException?.stack,
2127
+ synthetic: true
2128
+ };
2129
+ }
2130
+ getInfos(candidate) {
2131
+ let type = "Error";
2132
+ let value = candidate;
2133
+ const groups = candidate.match(ERROR_TYPES_PATTERN);
2134
+ if (groups) {
2135
+ type = groups[1];
2136
+ value = groups[2];
2137
+ }
2138
+ return [
2139
+ type,
2140
+ value
2141
+ ];
2142
+ }
2143
+ }
2144
+ // node_modules/@posthog/core/dist/error-tracking/types.mjs
2145
+ var severityLevels = [
2146
+ "fatal",
2147
+ "error",
2148
+ "warning",
2149
+ "log",
2150
+ "info",
2151
+ "debug"
2152
+ ];
2153
+
2154
+ // node_modules/@posthog/core/dist/error-tracking/coercers/utils.mjs
2155
+ function extractExceptionKeysForMessage(err, maxLength = 40) {
2156
+ const keys = Object.keys(err);
2157
+ keys.sort();
2158
+ if (!keys.length)
2159
+ return "[object has no keys]";
2160
+ for (let i = keys.length;i > 0; i--) {
2161
+ const serialized = keys.slice(0, i).join(", ");
2162
+ if (!(serialized.length > maxLength)) {
2163
+ if (i === keys.length)
2164
+ return serialized;
2165
+ return serialized.length <= maxLength ? serialized : `${serialized.slice(0, maxLength)}...`;
2166
+ }
2167
+ }
2168
+ return "";
2169
+ }
2170
+
2171
+ // node_modules/@posthog/core/dist/error-tracking/coercers/object-coercer.mjs
2172
+ class ObjectCoercer {
2173
+ match(candidate) {
2174
+ return typeof candidate == "object" && candidate !== null;
2175
+ }
2176
+ coerce(candidate, ctx) {
2177
+ const errorProperty = this.getErrorPropertyFromObject(candidate);
2178
+ if (errorProperty)
2179
+ return ctx.apply(errorProperty);
2180
+ return {
2181
+ type: this.getType(candidate),
2182
+ value: this.getValue(candidate),
2183
+ stack: ctx.syntheticException?.stack,
2184
+ level: this.isSeverityLevel(candidate.level) ? candidate.level : "error",
2185
+ synthetic: true
2186
+ };
2187
+ }
2188
+ getType(err) {
2189
+ return isEvent(err) ? err.constructor.name : "Error";
2190
+ }
2191
+ getValue(err) {
2192
+ if ("name" in err && typeof err.name == "string") {
2193
+ let message = `'${err.name}' captured as exception`;
2194
+ if ("message" in err && typeof err.message == "string")
2195
+ message += ` with message: '${err.message}'`;
2196
+ return message;
2197
+ }
2198
+ if ("message" in err && typeof err.message == "string")
2199
+ return err.message;
2200
+ const className = this.getObjectClassName(err);
2201
+ const keys = extractExceptionKeysForMessage(err);
2202
+ return `${className && className !== "Object" ? `'${className}'` : "Object"} captured as exception with keys: ${keys}`;
2203
+ }
2204
+ isSeverityLevel(x) {
2205
+ return isString(x) && !isEmptyString(x) && severityLevels.indexOf(x) >= 0;
2206
+ }
2207
+ getErrorPropertyFromObject(obj) {
2208
+ for (const prop in obj)
2209
+ if (Object.prototype.hasOwnProperty.call(obj, prop)) {
2210
+ const value = obj[prop];
2211
+ if (isError(value))
2212
+ return value;
2213
+ }
2214
+ }
2215
+ getObjectClassName(obj) {
2216
+ try {
2217
+ const prototype = Object.getPrototypeOf(obj);
2218
+ return prototype ? prototype.constructor.name : undefined;
2219
+ } catch (e) {
2220
+ return;
2221
+ }
2222
+ }
2223
+ }
2224
+ // node_modules/@posthog/core/dist/error-tracking/coercers/event-coercer.mjs
2225
+ class EventCoercer {
2226
+ match(err) {
2227
+ return isEvent(err);
2228
+ }
2229
+ coerce(evt, ctx) {
2230
+ const constructorName = evt.constructor.name;
2231
+ return {
2232
+ type: constructorName,
2233
+ value: `${constructorName} captured as exception with keys: ${extractExceptionKeysForMessage(evt)}`,
2234
+ stack: ctx.syntheticException?.stack,
2235
+ synthetic: true
2236
+ };
2237
+ }
2238
+ }
2239
+ // node_modules/@posthog/core/dist/error-tracking/coercers/primitive-coercer.mjs
2240
+ class PrimitiveCoercer {
2241
+ match(candidate) {
2242
+ return isPrimitive(candidate);
2243
+ }
2244
+ coerce(value, ctx) {
2245
+ return {
2246
+ type: "Error",
2247
+ value: `Primitive value captured as exception: ${String(value)}`,
2248
+ stack: ctx.syntheticException?.stack,
2249
+ synthetic: true
2250
+ };
2251
+ }
2252
+ }
2253
+ // node_modules/@posthog/core/dist/error-tracking/coercers/promise-rejection-event.mjs
2254
+ class PromiseRejectionEventCoercer {
2255
+ match(err) {
2256
+ return isBuiltin(err, "PromiseRejectionEvent") || this.isCustomEventWrappingRejection(err);
2257
+ }
2258
+ isCustomEventWrappingRejection(err) {
2259
+ if (!isEvent(err))
2260
+ return false;
2261
+ try {
2262
+ const detail = err.detail;
2263
+ return detail != null && typeof detail == "object" && "reason" in detail;
2264
+ } catch {
2265
+ return false;
2266
+ }
2267
+ }
2268
+ coerce(err, ctx) {
2269
+ const reason = this.getUnhandledRejectionReason(err);
2270
+ if (isPrimitive(reason))
2271
+ return {
2272
+ type: "UnhandledRejection",
2273
+ value: `Non-Error promise rejection captured with value: ${String(reason)}`,
2274
+ stack: ctx.syntheticException?.stack,
2275
+ synthetic: true
2276
+ };
2277
+ return ctx.apply(reason);
2278
+ }
2279
+ getUnhandledRejectionReason(error) {
2280
+ try {
2281
+ if ("reason" in error)
2282
+ return error.reason;
2283
+ if ("detail" in error && error.detail != null && typeof error.detail == "object" && "reason" in error.detail)
2284
+ return error.detail.reason;
2285
+ } catch {}
2286
+ return error;
2287
+ }
2288
+ }
2289
+ // node_modules/@posthog/core/dist/error-tracking/utils.mjs
2290
+ class ReduceableCache {
2291
+ constructor(_maxSize) {
2292
+ this._maxSize = _maxSize;
2293
+ this._cache = new Map;
2294
+ }
2295
+ get(key) {
2296
+ const value = this._cache.get(key);
2297
+ if (value === undefined)
2298
+ return;
2299
+ this._cache.delete(key);
2300
+ this._cache.set(key, value);
2301
+ return value;
2302
+ }
2303
+ set(key, value) {
2304
+ this._cache.set(key, value);
2305
+ }
2306
+ reduce() {
2307
+ while (this._cache.size >= this._maxSize) {
2308
+ const value = this._cache.keys().next().value;
2309
+ if (value)
2310
+ this._cache.delete(value);
2311
+ }
2312
+ }
2313
+ }
2314
+ // node_modules/posthog-node/dist/extensions/error-tracking/modifiers/context-lines.node.mjs
2315
+ import { createReadStream } from "node:fs";
2316
+ import { createInterface } from "node:readline";
2317
+ var LRU_FILE_CONTENTS_CACHE = new exports_error_tracking.ReduceableCache(25);
2318
+ var LRU_FILE_CONTENTS_FS_READ_FAILED = new exports_error_tracking.ReduceableCache(20);
2319
+ var DEFAULT_LINES_OF_CONTEXT = 7;
2320
+ var MAX_CONTEXTLINES_COLNO = 1000;
2321
+ var MAX_CONTEXTLINES_LINENO = 1e4;
2322
+ async function addSourceContext(frames) {
2323
+ const filesToLines = {};
2324
+ for (let i = frames.length - 1;i >= 0; i--) {
2325
+ const frame = frames[i];
2326
+ const filename = frame?.filename;
2327
+ if (!frame || typeof filename != "string" || typeof frame.lineno != "number" || shouldSkipContextLinesForFile(filename) || shouldSkipContextLinesForFrame(frame))
2328
+ continue;
2329
+ const filesToLinesOutput = filesToLines[filename];
2330
+ if (!filesToLinesOutput)
2331
+ filesToLines[filename] = [];
2332
+ filesToLines[filename].push(frame.lineno);
2333
+ }
2334
+ const files = Object.keys(filesToLines);
2335
+ if (files.length == 0)
2336
+ return frames;
2337
+ const readlinePromises = [];
2338
+ for (const file of files) {
2339
+ if (LRU_FILE_CONTENTS_FS_READ_FAILED.get(file))
2340
+ continue;
2341
+ const filesToLineRanges = filesToLines[file];
2342
+ if (!filesToLineRanges)
2343
+ continue;
2344
+ filesToLineRanges.sort((a, b) => a - b);
2345
+ const ranges = makeLineReaderRanges(filesToLineRanges);
2346
+ if (ranges.every((r) => rangeExistsInContentCache(file, r)))
2347
+ continue;
2348
+ const cache = emplace(LRU_FILE_CONTENTS_CACHE, file, {});
2349
+ readlinePromises.push(getContextLinesFromFile(file, ranges, cache));
2350
+ }
2351
+ await Promise.all(readlinePromises).catch(() => {});
2352
+ if (frames && frames.length > 0)
2353
+ addSourceContextToFrames(frames, LRU_FILE_CONTENTS_CACHE);
2354
+ LRU_FILE_CONTENTS_CACHE.reduce();
2355
+ return frames;
2356
+ }
2357
+ function getContextLinesFromFile(path, ranges, output) {
2358
+ return new Promise((resolve) => {
2359
+ const stream = createReadStream(path);
2360
+ const lineReaded = createInterface({
2361
+ input: stream
2362
+ });
2363
+ function destroyStreamAndResolve() {
2364
+ stream.destroy();
2365
+ resolve();
2366
+ }
2367
+ let lineNumber = 0;
2368
+ let currentRangeIndex = 0;
2369
+ const range = ranges[currentRangeIndex];
2370
+ if (range === undefined)
2371
+ return void destroyStreamAndResolve();
2372
+ let rangeStart = range[0];
2373
+ let rangeEnd = range[1];
2374
+ function onStreamError() {
2375
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path, 1);
2376
+ lineReaded.close();
2377
+ lineReaded.removeAllListeners();
2378
+ destroyStreamAndResolve();
2379
+ }
2380
+ stream.on("error", onStreamError);
2381
+ lineReaded.on("error", onStreamError);
2382
+ lineReaded.on("close", destroyStreamAndResolve);
2383
+ lineReaded.on("line", (line) => {
2384
+ lineNumber++;
2385
+ if (lineNumber < rangeStart)
2386
+ return;
2387
+ output[lineNumber] = snipLine(line, 0);
2388
+ if (lineNumber >= rangeEnd) {
2389
+ if (currentRangeIndex === ranges.length - 1) {
2390
+ lineReaded.close();
2391
+ lineReaded.removeAllListeners();
2392
+ return;
2393
+ }
2394
+ currentRangeIndex++;
2395
+ const range2 = ranges[currentRangeIndex];
2396
+ if (range2 === undefined) {
2397
+ lineReaded.close();
2398
+ lineReaded.removeAllListeners();
2399
+ return;
2400
+ }
2401
+ rangeStart = range2[0];
2402
+ rangeEnd = range2[1];
2403
+ }
2404
+ });
2405
+ });
2406
+ }
2407
+ function addSourceContextToFrames(frames, cache) {
2408
+ for (const frame of frames)
2409
+ if (frame.filename && frame.context_line === undefined && typeof frame.lineno == "number") {
2410
+ const contents = cache.get(frame.filename);
2411
+ if (contents === undefined)
2412
+ continue;
2413
+ addContextToFrame(frame.lineno, frame, contents);
2414
+ }
2415
+ }
2416
+ function addContextToFrame(lineno, frame, contents) {
2417
+ if (frame.lineno === undefined || contents === undefined)
2418
+ return;
2419
+ frame.pre_context = [];
2420
+ for (let i = makeRangeStart(lineno);i < lineno; i++) {
2421
+ const line = contents[i];
2422
+ if (line === undefined)
2423
+ return void clearLineContext(frame);
2424
+ frame.pre_context.push(line);
2425
+ }
2426
+ if (contents[lineno] === undefined)
2427
+ return void clearLineContext(frame);
2428
+ frame.context_line = contents[lineno];
2429
+ const end = makeRangeEnd(lineno);
2430
+ frame.post_context = [];
2431
+ for (let i = lineno + 1;i <= end; i++) {
2432
+ const line = contents[i];
2433
+ if (line === undefined)
2434
+ break;
2435
+ frame.post_context.push(line);
2436
+ }
2437
+ }
2438
+ function clearLineContext(frame) {
2439
+ delete frame.pre_context;
2440
+ delete frame.context_line;
2441
+ delete frame.post_context;
2442
+ }
2443
+ function shouldSkipContextLinesForFile(path) {
2444
+ return path.startsWith("node:") || path.endsWith(".min.js") || path.endsWith(".min.cjs") || path.endsWith(".min.mjs") || path.startsWith("data:");
2445
+ }
2446
+ function shouldSkipContextLinesForFrame(frame) {
2447
+ if (frame.lineno !== undefined && frame.lineno > MAX_CONTEXTLINES_LINENO)
2448
+ return true;
2449
+ if (frame.colno !== undefined && frame.colno > MAX_CONTEXTLINES_COLNO)
2450
+ return true;
2451
+ return false;
2452
+ }
2453
+ function rangeExistsInContentCache(file, range) {
2454
+ const contents = LRU_FILE_CONTENTS_CACHE.get(file);
2455
+ if (contents === undefined)
2456
+ return false;
2457
+ for (let i = range[0];i <= range[1]; i++)
2458
+ if (contents[i] === undefined)
2459
+ return false;
2460
+ return true;
2461
+ }
2462
+ function makeLineReaderRanges(lines) {
2463
+ if (!lines.length)
2464
+ return [];
2465
+ let i = 0;
2466
+ const line = lines[0];
2467
+ if (typeof line != "number")
2468
+ return [];
2469
+ let current = makeContextRange(line);
2470
+ const out = [];
2471
+ while (true) {
2472
+ if (i === lines.length - 1) {
2473
+ out.push(current);
2474
+ break;
2475
+ }
2476
+ const next = lines[i + 1];
2477
+ if (typeof next != "number")
2478
+ break;
2479
+ if (next <= current[1])
2480
+ current[1] = next + DEFAULT_LINES_OF_CONTEXT;
2481
+ else {
2482
+ out.push(current);
2483
+ current = makeContextRange(next);
2484
+ }
2485
+ i++;
2486
+ }
2487
+ return out;
2488
+ }
2489
+ function makeContextRange(line) {
2490
+ return [
2491
+ makeRangeStart(line),
2492
+ makeRangeEnd(line)
2493
+ ];
2494
+ }
2495
+ function makeRangeStart(line) {
2496
+ return Math.max(1, line - DEFAULT_LINES_OF_CONTEXT);
2497
+ }
2498
+ function makeRangeEnd(line) {
2499
+ return line + DEFAULT_LINES_OF_CONTEXT;
2500
+ }
2501
+ function emplace(map, key, contents) {
2502
+ const value = map.get(key);
2503
+ if (value === undefined) {
2504
+ map.set(key, contents);
2505
+ return contents;
2506
+ }
2507
+ return value;
2508
+ }
2509
+ function snipLine(line, colno) {
2510
+ let newLine = line;
2511
+ const lineLength = newLine.length;
2512
+ if (lineLength <= 150)
2513
+ return newLine;
2514
+ if (colno > lineLength)
2515
+ colno = lineLength;
2516
+ let start = Math.max(colno - 60, 0);
2517
+ if (start < 5)
2518
+ start = 0;
2519
+ let end = Math.min(start + 140, lineLength);
2520
+ if (end > lineLength - 5)
2521
+ end = lineLength;
2522
+ if (end === lineLength)
2523
+ start = Math.max(end - 140, 0);
2524
+ newLine = newLine.slice(start, end);
2525
+ if (start > 0)
2526
+ newLine = `...${newLine}`;
2527
+ if (end < lineLength)
2528
+ newLine += "...";
2529
+ return newLine;
2530
+ }
2531
+
2532
+ // node_modules/posthog-node/dist/extensions/error-tracking/autocapture.mjs
2533
+ function makeUncaughtExceptionHandler(captureFn, onFatalFn) {
2534
+ let calledFatalError = false;
2535
+ return Object.assign((error) => {
2536
+ const userProvidedListenersCount = global.process.listeners("uncaughtException").filter((listener) => listener.name !== "domainUncaughtExceptionClear" && listener._posthogErrorHandler !== true).length;
2537
+ const processWouldExit = userProvidedListenersCount === 0;
2538
+ captureFn(error, {
2539
+ mechanism: {
2540
+ type: "onuncaughtexception",
2541
+ handled: false
2542
+ }
2543
+ });
2544
+ if (!calledFatalError && processWouldExit) {
2545
+ calledFatalError = true;
2546
+ onFatalFn(error);
2547
+ }
2548
+ }, {
2549
+ _posthogErrorHandler: true
2550
+ });
2551
+ }
2552
+ function addUncaughtExceptionListener(captureFn, onFatalFn) {
2553
+ globalThis.process?.on("uncaughtException", makeUncaughtExceptionHandler(captureFn, onFatalFn));
2554
+ }
2555
+ function addUnhandledRejectionListener(captureFn) {
2556
+ globalThis.process?.on("unhandledRejection", (reason) => captureFn(reason, {
2557
+ mechanism: {
2558
+ type: "onunhandledrejection",
2559
+ handled: false
2560
+ }
2561
+ }));
2562
+ }
2563
+
2564
+ // node_modules/posthog-node/dist/extensions/error-tracking/index.mjs
2565
+ var SHUTDOWN_TIMEOUT = 2000;
2566
+
2567
+ class ErrorTracking {
2568
+ constructor(client, options, _logger) {
2569
+ this.client = client;
2570
+ this._exceptionAutocaptureEnabled = options.enableExceptionAutocapture || false;
2571
+ this._logger = _logger;
2572
+ this._rateLimiter = new BucketedRateLimiter({
2573
+ refillRate: 1,
2574
+ bucketSize: 10,
2575
+ refillInterval: 1e4,
2576
+ _logger: this._logger
2577
+ });
2578
+ this.startAutocaptureIfEnabled();
2579
+ }
2580
+ static isPreviouslyCapturedError(x) {
2581
+ return isObject(x) && "__posthog_previously_captured_error" in x && x.__posthog_previously_captured_error === true;
2582
+ }
2583
+ static async buildEventMessage(error, hint, distinctId, additionalProperties) {
2584
+ const properties = {
2585
+ ...additionalProperties
2586
+ };
2587
+ const exceptionProperties = this.errorPropertiesBuilder.buildFromUnknown(error, hint);
2588
+ exceptionProperties.$exception_list = await this.errorPropertiesBuilder.modifyFrames(exceptionProperties.$exception_list);
2589
+ return {
2590
+ event: "$exception",
2591
+ distinctId,
2592
+ properties: {
2593
+ ...exceptionProperties,
2594
+ ...properties
2595
+ },
2596
+ _originatedFromCaptureException: true
2597
+ };
2598
+ }
2599
+ startAutocaptureIfEnabled() {
2600
+ if (this.isEnabled()) {
2601
+ addUncaughtExceptionListener(this.onException.bind(this), this.onFatalError.bind(this));
2602
+ addUnhandledRejectionListener(this.onException.bind(this));
2603
+ }
2604
+ }
2605
+ onException(exception, hint) {
2606
+ this.client.addPendingPromise((async () => {
2607
+ if (!ErrorTracking.isPreviouslyCapturedError(exception)) {
2608
+ const eventMessage = await ErrorTracking.buildEventMessage(exception, hint);
2609
+ const exceptionProperties = eventMessage.properties;
2610
+ const exceptionType = exceptionProperties?.$exception_list[0]?.type ?? "Exception";
2611
+ const isRateLimited = this._rateLimiter.consumeRateLimit(exceptionType);
2612
+ if (isRateLimited)
2613
+ return void this._logger.info("Skipping exception capture because of client rate limiting.", {
2614
+ exception: exceptionType
2615
+ });
2616
+ return this.client.capture(eventMessage);
2617
+ }
2618
+ })());
2619
+ }
2620
+ async onFatalError(exception) {
2621
+ console.error(exception);
2622
+ await this.client.shutdown(SHUTDOWN_TIMEOUT);
2623
+ process.exit(1);
2624
+ }
2625
+ isEnabled() {
2626
+ return !this.client.isDisabled && this._exceptionAutocaptureEnabled;
2627
+ }
2628
+ shutdown() {
2629
+ this._rateLimiter.stop();
2630
+ }
2631
+ }
2632
+
2633
+ // node_modules/posthog-node/dist/version.mjs
2634
+ var version = "5.28.11";
2635
+
2636
+ // node_modules/posthog-node/dist/types.mjs
2637
+ var FeatureFlagError2 = {
2638
+ ERRORS_WHILE_COMPUTING: "errors_while_computing_flags",
2639
+ FLAG_MISSING: "flag_missing",
2640
+ QUOTA_LIMITED: "quota_limited",
2641
+ UNKNOWN_ERROR: "unknown_error"
2642
+ };
2643
+
2644
+ // node_modules/posthog-node/dist/extensions/feature-flags/crypto.mjs
2645
+ async function hashSHA1(text) {
2646
+ const subtle = globalThis.crypto?.subtle;
2647
+ if (!subtle)
2648
+ throw new Error("SubtleCrypto API not available");
2649
+ const hashBuffer = await subtle.digest("SHA-1", new TextEncoder().encode(text));
2650
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
2651
+ return hashArray.map((byte) => byte.toString(16).padStart(2, "0")).join("");
2652
+ }
2653
+
2654
+ // node_modules/posthog-node/dist/extensions/feature-flags/feature-flags.mjs
2655
+ var SIXTY_SECONDS = 60000;
2656
+ var LONG_SCALE = 1152921504606847000;
2657
+ var NULL_VALUES_ALLOWED_OPERATORS = [
2658
+ "is_not"
2659
+ ];
2660
+
2661
+ class ClientError extends Error {
2662
+ constructor(message) {
2663
+ super();
2664
+ Error.captureStackTrace(this, this.constructor);
2665
+ this.name = "ClientError";
2666
+ this.message = message;
2667
+ Object.setPrototypeOf(this, ClientError.prototype);
2668
+ }
2669
+ }
2670
+
2671
+ class InconclusiveMatchError extends Error {
2672
+ constructor(message) {
2673
+ super(message);
2674
+ this.name = this.constructor.name;
2675
+ Error.captureStackTrace(this, this.constructor);
2676
+ Object.setPrototypeOf(this, InconclusiveMatchError.prototype);
2677
+ }
2678
+ }
2679
+
2680
+ class RequiresServerEvaluation extends Error {
2681
+ constructor(message) {
2682
+ super(message);
2683
+ this.name = this.constructor.name;
2684
+ Error.captureStackTrace(this, this.constructor);
2685
+ Object.setPrototypeOf(this, RequiresServerEvaluation.prototype);
2686
+ }
2687
+ }
2688
+
2689
+ class FeatureFlagsPoller {
2690
+ constructor({ pollingInterval, personalApiKey, projectApiKey, timeout, host, customHeaders, ...options }) {
2691
+ this.debugMode = false;
2692
+ this.shouldBeginExponentialBackoff = false;
2693
+ this.backOffCount = 0;
2694
+ this.pollingInterval = pollingInterval;
2695
+ this.personalApiKey = personalApiKey;
2696
+ this.featureFlags = [];
2697
+ this.featureFlagsByKey = {};
2698
+ this.groupTypeMapping = {};
2699
+ this.cohorts = {};
2700
+ this.loadedSuccessfullyOnce = false;
2701
+ this.timeout = timeout;
2702
+ this.projectApiKey = projectApiKey;
2703
+ this.host = host;
2704
+ this.poller = undefined;
2705
+ this.fetch = options.fetch || fetch;
2706
+ this.onError = options.onError;
2707
+ this.customHeaders = customHeaders;
2708
+ this.onLoad = options.onLoad;
2709
+ this.cacheProvider = options.cacheProvider;
2710
+ this.strictLocalEvaluation = options.strictLocalEvaluation ?? false;
2711
+ this.loadFeatureFlags();
2712
+ }
2713
+ debug(enabled = true) {
2714
+ this.debugMode = enabled;
2715
+ }
2716
+ logMsgIfDebug(fn) {
2717
+ if (this.debugMode)
2718
+ fn();
2719
+ }
2720
+ createEvaluationContext(distinctId, groups = {}, personProperties = {}, groupProperties = {}, evaluationCache = {}) {
2721
+ return {
2722
+ distinctId,
2723
+ groups,
2724
+ personProperties,
2725
+ groupProperties,
2726
+ evaluationCache
2727
+ };
2728
+ }
2729
+ async getFeatureFlag(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}) {
2730
+ await this.loadFeatureFlags();
2731
+ let response;
2732
+ let featureFlag;
2733
+ if (!this.loadedSuccessfullyOnce)
2734
+ return response;
2735
+ featureFlag = this.featureFlagsByKey[key];
2736
+ if (featureFlag !== undefined) {
2737
+ const evaluationContext = this.createEvaluationContext(distinctId, groups, personProperties, groupProperties);
2738
+ try {
2739
+ const result = await this.computeFlagAndPayloadLocally(featureFlag, evaluationContext);
2740
+ response = result.value;
2741
+ this.logMsgIfDebug(() => console.debug(`Successfully computed flag locally: ${key} -> ${response}`));
2742
+ } catch (e) {
2743
+ if (e instanceof RequiresServerEvaluation || e instanceof InconclusiveMatchError)
2744
+ this.logMsgIfDebug(() => console.debug(`${e.name} when computing flag locally: ${key}: ${e.message}`));
2745
+ else if (e instanceof Error)
2746
+ this.onError?.(new Error(`Error computing flag locally: ${key}: ${e}`));
2747
+ }
2748
+ }
2749
+ return response;
2750
+ }
2751
+ async getAllFlagsAndPayloads(evaluationContext, flagKeysToExplicitlyEvaluate) {
2752
+ await this.loadFeatureFlags();
2753
+ const response = {};
2754
+ const payloads = {};
2755
+ let fallbackToFlags = this.featureFlags.length == 0;
2756
+ const flagsToEvaluate = flagKeysToExplicitlyEvaluate ? flagKeysToExplicitlyEvaluate.map((key) => this.featureFlagsByKey[key]).filter(Boolean) : this.featureFlags;
2757
+ const sharedEvaluationContext = {
2758
+ ...evaluationContext,
2759
+ evaluationCache: evaluationContext.evaluationCache ?? {}
2760
+ };
2761
+ await Promise.all(flagsToEvaluate.map(async (flag) => {
2762
+ try {
2763
+ const { value: matchValue, payload: matchPayload } = await this.computeFlagAndPayloadLocally(flag, sharedEvaluationContext);
2764
+ response[flag.key] = matchValue;
2765
+ if (matchPayload)
2766
+ payloads[flag.key] = matchPayload;
2767
+ } catch (e) {
2768
+ if (e instanceof RequiresServerEvaluation || e instanceof InconclusiveMatchError)
2769
+ this.logMsgIfDebug(() => console.debug(`${e.name} when computing flag locally: ${flag.key}: ${e.message}`));
2770
+ else if (e instanceof Error)
2771
+ this.onError?.(new Error(`Error computing flag locally: ${flag.key}: ${e}`));
2772
+ fallbackToFlags = true;
2773
+ }
2774
+ }));
2775
+ return {
2776
+ response,
2777
+ payloads,
2778
+ fallbackToFlags
2779
+ };
2780
+ }
2781
+ async computeFlagAndPayloadLocally(flag, evaluationContext, options = {}) {
2782
+ const { matchValue, skipLoadCheck = false } = options;
2783
+ if (!skipLoadCheck)
2784
+ await this.loadFeatureFlags();
2785
+ if (!this.loadedSuccessfullyOnce)
2786
+ return {
2787
+ value: false,
2788
+ payload: null
2789
+ };
2790
+ let flagValue;
2791
+ flagValue = matchValue !== undefined ? matchValue : await this.computeFlagValueLocally(flag, evaluationContext);
2792
+ const payload = this.getFeatureFlagPayload(flag.key, flagValue);
2793
+ return {
2794
+ value: flagValue,
2795
+ payload
2796
+ };
2797
+ }
2798
+ async computeFlagValueLocally(flag, evaluationContext) {
2799
+ const { distinctId, groups, personProperties, groupProperties } = evaluationContext;
2800
+ if (flag.ensure_experience_continuity)
2801
+ throw new InconclusiveMatchError("Flag has experience continuity enabled");
2802
+ if (!flag.active)
2803
+ return false;
2804
+ const flagFilters = flag.filters || {};
2805
+ const aggregation_group_type_index = flagFilters.aggregation_group_type_index;
2806
+ if (aggregation_group_type_index != null) {
2807
+ const groupName = this.groupTypeMapping[String(aggregation_group_type_index)];
2808
+ if (!groupName) {
2809
+ this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Unknown group type index ${aggregation_group_type_index} for feature flag ${flag.key}`));
2810
+ throw new InconclusiveMatchError("Flag has unknown group type index");
2811
+ }
2812
+ if (!(groupName in groups)) {
2813
+ this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Can't compute group feature flag: ${flag.key} without group names passed in`));
2814
+ return false;
2815
+ }
2816
+ if (flag.bucketing_identifier === "device_id" && (personProperties?.$device_id === undefined || personProperties?.$device_id === null || personProperties?.$device_id === ""))
2817
+ this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Ignoring bucketing_identifier for group flag: ${flag.key}`));
2818
+ const focusedGroupProperties = groupProperties[groupName];
2819
+ return await this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties, evaluationContext);
2820
+ }
2821
+ {
2822
+ const bucketingValue = this.getBucketingValueForFlag(flag, distinctId, personProperties);
2823
+ if (bucketingValue === undefined) {
2824
+ this.logMsgIfDebug(() => console.warn(`[FEATURE FLAGS] Can't compute feature flag: ${flag.key} without $device_id, falling back to server evaluation`));
2825
+ throw new InconclusiveMatchError(`Can't compute feature flag: ${flag.key} without $device_id`);
2826
+ }
2827
+ return await this.matchFeatureFlagProperties(flag, bucketingValue, personProperties, evaluationContext);
2828
+ }
2829
+ }
2830
+ getBucketingValueForFlag(flag, distinctId, properties) {
2831
+ if (flag.filters?.aggregation_group_type_index != null)
2832
+ return distinctId;
2833
+ if (flag.bucketing_identifier === "device_id") {
2834
+ const deviceId = properties?.$device_id;
2835
+ if (deviceId == null || deviceId === "")
2836
+ return;
2837
+ return deviceId;
2838
+ }
2839
+ return distinctId;
2840
+ }
2841
+ getFeatureFlagPayload(key, flagValue) {
2842
+ let payload = null;
2843
+ if (flagValue !== false && flagValue != null) {
2844
+ if (typeof flagValue == "boolean")
2845
+ payload = this.featureFlagsByKey?.[key]?.filters?.payloads?.[flagValue.toString()] || null;
2846
+ else if (typeof flagValue == "string")
2847
+ payload = this.featureFlagsByKey?.[key]?.filters?.payloads?.[flagValue] || null;
2848
+ if (payload != null) {
2849
+ if (typeof payload == "object")
2850
+ return payload;
2851
+ if (typeof payload == "string")
2852
+ try {
2853
+ return JSON.parse(payload);
2854
+ } catch {}
2855
+ return payload;
2856
+ }
2857
+ }
2858
+ return null;
2859
+ }
2860
+ async evaluateFlagDependency(property, properties, evaluationContext) {
2861
+ const { evaluationCache } = evaluationContext;
2862
+ const targetFlagKey = property.key;
2863
+ if (!this.featureFlagsByKey)
2864
+ throw new InconclusiveMatchError("Feature flags not available for dependency evaluation");
2865
+ if (!("dependency_chain" in property))
2866
+ throw new InconclusiveMatchError(`Flag dependency property for '${targetFlagKey}' is missing required 'dependency_chain' field`);
2867
+ const dependencyChain = property.dependency_chain;
2868
+ if (!Array.isArray(dependencyChain))
2869
+ throw new InconclusiveMatchError(`Flag dependency property for '${targetFlagKey}' has an invalid 'dependency_chain' (expected array, got ${typeof dependencyChain})`);
2870
+ if (dependencyChain.length === 0)
2871
+ throw new InconclusiveMatchError(`Circular dependency detected for flag '${targetFlagKey}' (empty dependency chain)`);
2872
+ for (const depFlagKey of dependencyChain) {
2873
+ if (!(depFlagKey in evaluationCache)) {
2874
+ const depFlag = this.featureFlagsByKey[depFlagKey];
2875
+ if (depFlag)
2876
+ if (depFlag.active)
2877
+ try {
2878
+ const depResult = await this.computeFlagValueLocally(depFlag, evaluationContext);
2879
+ evaluationCache[depFlagKey] = depResult;
2880
+ } catch (error) {
2881
+ throw new InconclusiveMatchError(`Error evaluating flag dependency '${depFlagKey}' for flag '${targetFlagKey}': ${error}`);
2882
+ }
2883
+ else
2884
+ evaluationCache[depFlagKey] = false;
2885
+ else
2886
+ throw new InconclusiveMatchError(`Missing flag dependency '${depFlagKey}' for flag '${targetFlagKey}'`);
2887
+ }
2888
+ const cachedResult = evaluationCache[depFlagKey];
2889
+ if (cachedResult == null)
2890
+ throw new InconclusiveMatchError(`Dependency '${depFlagKey}' could not be evaluated`);
2891
+ }
2892
+ const targetFlagValue = evaluationCache[targetFlagKey];
2893
+ return this.flagEvaluatesToExpectedValue(property.value, targetFlagValue);
2894
+ }
2895
+ flagEvaluatesToExpectedValue(expectedValue, flagValue) {
2896
+ if (typeof expectedValue == "boolean")
2897
+ return expectedValue === flagValue || typeof flagValue == "string" && flagValue !== "" && expectedValue === true;
2898
+ if (typeof expectedValue == "string")
2899
+ return flagValue === expectedValue;
2900
+ return false;
2901
+ }
2902
+ async matchFeatureFlagProperties(flag, bucketingValue, properties, evaluationContext) {
2903
+ const flagFilters = flag.filters || {};
2904
+ const flagConditions = flagFilters.groups || [];
2905
+ let isInconclusive = false;
2906
+ let result;
2907
+ for (const condition of flagConditions)
2908
+ try {
2909
+ if (await this.isConditionMatch(flag, bucketingValue, condition, properties, evaluationContext)) {
2910
+ const variantOverride = condition.variant;
2911
+ const flagVariants = flagFilters.multivariate?.variants || [];
2912
+ result = variantOverride && flagVariants.some((variant) => variant.key === variantOverride) ? variantOverride : await this.getMatchingVariant(flag, bucketingValue) || true;
2913
+ break;
2914
+ }
2915
+ } catch (e) {
2916
+ if (e instanceof RequiresServerEvaluation)
2917
+ throw e;
2918
+ if (e instanceof InconclusiveMatchError)
2919
+ isInconclusive = true;
2920
+ else
2921
+ throw e;
2922
+ }
2923
+ if (result !== undefined)
2924
+ return result;
2925
+ if (isInconclusive)
2926
+ throw new InconclusiveMatchError("Can't determine if feature flag is enabled or not with given properties");
2927
+ return false;
2928
+ }
2929
+ async isConditionMatch(flag, bucketingValue, condition, properties, evaluationContext) {
2930
+ const rolloutPercentage = condition.rollout_percentage;
2931
+ const warnFunction = (msg) => {
2932
+ this.logMsgIfDebug(() => console.warn(msg));
2933
+ };
2934
+ if ((condition.properties || []).length > 0) {
2935
+ for (const prop of condition.properties) {
2936
+ const propertyType = prop.type;
2937
+ let matches = false;
2938
+ matches = propertyType === "cohort" ? matchCohort(prop, properties, this.cohorts, this.debugMode) : propertyType === "flag" ? await this.evaluateFlagDependency(prop, properties, evaluationContext) : matchProperty(prop, properties, warnFunction);
2939
+ if (!matches)
2940
+ return false;
2941
+ }
2942
+ if (rolloutPercentage == undefined)
2943
+ return true;
2944
+ }
2945
+ if (rolloutPercentage != null && await _hash(flag.key, bucketingValue) > rolloutPercentage / 100)
2946
+ return false;
2947
+ return true;
2948
+ }
2949
+ async getMatchingVariant(flag, bucketingValue) {
2950
+ const hashValue = await _hash(flag.key, bucketingValue, "variant");
2951
+ const matchingVariant = this.variantLookupTable(flag).find((variant) => hashValue >= variant.valueMin && hashValue < variant.valueMax);
2952
+ if (matchingVariant)
2953
+ return matchingVariant.key;
2954
+ }
2955
+ variantLookupTable(flag) {
2956
+ const lookupTable = [];
2957
+ let valueMin = 0;
2958
+ let valueMax = 0;
2959
+ const flagFilters = flag.filters || {};
2960
+ const multivariates = flagFilters.multivariate?.variants || [];
2961
+ multivariates.forEach((variant) => {
2962
+ valueMax = valueMin + variant.rollout_percentage / 100;
2963
+ lookupTable.push({
2964
+ valueMin,
2965
+ valueMax,
2966
+ key: variant.key
2967
+ });
2968
+ valueMin = valueMax;
2969
+ });
2970
+ return lookupTable;
2971
+ }
2972
+ updateFlagState(flagData) {
2973
+ this.featureFlags = flagData.flags;
2974
+ this.featureFlagsByKey = flagData.flags.reduce((acc, curr) => (acc[curr.key] = curr, acc), {});
2975
+ this.groupTypeMapping = flagData.groupTypeMapping;
2976
+ this.cohorts = flagData.cohorts;
2977
+ this.loadedSuccessfullyOnce = true;
2978
+ }
2979
+ warnAboutExperienceContinuityFlags(flags) {
2980
+ if (this.strictLocalEvaluation)
2981
+ return;
2982
+ const experienceContinuityFlags = flags.filter((f) => f.ensure_experience_continuity);
2983
+ if (experienceContinuityFlags.length > 0)
2984
+ 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).`);
2985
+ }
2986
+ async loadFromCache(debugMessage) {
2987
+ if (!this.cacheProvider)
2988
+ return false;
2989
+ try {
2990
+ const cached = await this.cacheProvider.getFlagDefinitions();
2991
+ if (cached) {
2992
+ this.updateFlagState(cached);
2993
+ this.logMsgIfDebug(() => console.debug(`[FEATURE FLAGS] ${debugMessage} (${cached.flags.length} flags)`));
2994
+ this.onLoad?.(this.featureFlags.length);
2995
+ this.warnAboutExperienceContinuityFlags(cached.flags);
2996
+ return true;
2997
+ }
2998
+ return false;
2999
+ } catch (err) {
3000
+ this.onError?.(new Error(`Failed to load from cache: ${err}`));
3001
+ return false;
3002
+ }
3003
+ }
3004
+ async loadFeatureFlags(forceReload = false) {
3005
+ if (this.loadedSuccessfullyOnce && !forceReload)
3006
+ return;
3007
+ if (!forceReload && this.nextFetchAllowedAt && Date.now() < this.nextFetchAllowedAt)
3008
+ return void this.logMsgIfDebug(() => console.debug("[FEATURE FLAGS] Skipping fetch, in backoff period"));
3009
+ if (!this.loadingPromise)
3010
+ this.loadingPromise = this._loadFeatureFlags().catch((err) => this.logMsgIfDebug(() => console.debug(`[FEATURE FLAGS] Failed to load feature flags: ${err}`))).finally(() => {
3011
+ this.loadingPromise = undefined;
3012
+ });
3013
+ return this.loadingPromise;
3014
+ }
3015
+ isLocalEvaluationReady() {
3016
+ return (this.loadedSuccessfullyOnce ?? false) && (this.featureFlags?.length ?? 0) > 0;
3017
+ }
3018
+ getFlagDefinitionsLoadedAt() {
3019
+ return this.flagDefinitionsLoadedAt;
3020
+ }
3021
+ getPollingInterval() {
3022
+ if (!this.shouldBeginExponentialBackoff)
3023
+ return this.pollingInterval;
3024
+ return Math.min(SIXTY_SECONDS, this.pollingInterval * 2 ** this.backOffCount);
3025
+ }
3026
+ beginBackoff() {
3027
+ this.shouldBeginExponentialBackoff = true;
3028
+ this.backOffCount += 1;
3029
+ this.nextFetchAllowedAt = Date.now() + this.getPollingInterval();
3030
+ }
3031
+ clearBackoff() {
3032
+ this.shouldBeginExponentialBackoff = false;
3033
+ this.backOffCount = 0;
3034
+ this.nextFetchAllowedAt = undefined;
3035
+ }
3036
+ async _loadFeatureFlags() {
3037
+ if (this.poller) {
3038
+ clearTimeout(this.poller);
3039
+ this.poller = undefined;
3040
+ }
3041
+ this.poller = setTimeout(() => this.loadFeatureFlags(true), this.getPollingInterval());
3042
+ try {
3043
+ let shouldFetch = true;
3044
+ if (this.cacheProvider)
3045
+ try {
3046
+ shouldFetch = await this.cacheProvider.shouldFetchFlagDefinitions();
3047
+ } catch (err) {
3048
+ this.onError?.(new Error(`Error in shouldFetchFlagDefinitions: ${err}`));
3049
+ }
3050
+ if (!shouldFetch) {
3051
+ const loaded = await this.loadFromCache("Loaded flags from cache (skipped fetch)");
3052
+ if (loaded)
3053
+ return;
3054
+ if (this.loadedSuccessfullyOnce)
3055
+ return;
3056
+ }
3057
+ const res = await this._requestFeatureFlagDefinitions();
3058
+ if (!res)
3059
+ return;
3060
+ switch (res.status) {
3061
+ case 304:
3062
+ this.logMsgIfDebug(() => console.debug("[FEATURE FLAGS] Flags not modified (304), using cached data"));
3063
+ this.flagsEtag = res.headers?.get("ETag") ?? this.flagsEtag;
3064
+ this.loadedSuccessfullyOnce = true;
3065
+ this.clearBackoff();
3066
+ return;
3067
+ case 401:
3068
+ this.beginBackoff();
3069
+ 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`);
3070
+ case 402:
3071
+ 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");
3072
+ this.featureFlags = [];
3073
+ this.featureFlagsByKey = {};
3074
+ this.groupTypeMapping = {};
3075
+ this.cohorts = {};
3076
+ return;
3077
+ case 403:
3078
+ this.beginBackoff();
3079
+ 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`);
3080
+ case 429:
3081
+ this.beginBackoff();
3082
+ 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`);
3083
+ case 200: {
3084
+ const responseJson = await res.json() ?? {};
3085
+ if (!("flags" in responseJson))
3086
+ return void this.onError?.(new Error(`Invalid response when getting feature flags: ${JSON.stringify(responseJson)}`));
3087
+ this.flagsEtag = res.headers?.get("ETag") ?? undefined;
3088
+ const flagData = {
3089
+ flags: responseJson.flags ?? [],
3090
+ groupTypeMapping: responseJson.group_type_mapping || {},
3091
+ cohorts: responseJson.cohorts || {}
3092
+ };
3093
+ this.updateFlagState(flagData);
3094
+ this.flagDefinitionsLoadedAt = Date.now();
3095
+ this.clearBackoff();
3096
+ if (this.cacheProvider && shouldFetch)
3097
+ try {
3098
+ await this.cacheProvider.onFlagDefinitionsReceived(flagData);
3099
+ } catch (err) {
3100
+ this.onError?.(new Error(`Failed to store in cache: ${err}`));
3101
+ }
3102
+ this.onLoad?.(this.featureFlags.length);
3103
+ this.warnAboutExperienceContinuityFlags(flagData.flags);
3104
+ break;
3105
+ }
3106
+ default:
3107
+ return;
3108
+ }
3109
+ } catch (err) {
3110
+ if (err instanceof ClientError)
3111
+ this.onError?.(err);
3112
+ }
3113
+ }
3114
+ getPersonalApiKeyRequestOptions(method = "GET", etag) {
3115
+ const headers = {
3116
+ ...this.customHeaders,
3117
+ "Content-Type": "application/json",
3118
+ Authorization: `Bearer ${this.personalApiKey}`
3119
+ };
3120
+ if (etag)
3121
+ headers["If-None-Match"] = etag;
3122
+ return {
3123
+ method,
3124
+ headers
3125
+ };
3126
+ }
3127
+ _requestFeatureFlagDefinitions() {
3128
+ const url = `${this.host}/api/feature_flag/local_evaluation?token=${this.projectApiKey}&send_cohorts`;
3129
+ const options = this.getPersonalApiKeyRequestOptions("GET", this.flagsEtag);
3130
+ let abortTimeout = null;
3131
+ if (this.timeout && typeof this.timeout == "number") {
3132
+ const controller = new AbortController;
3133
+ abortTimeout = safeSetTimeout(() => {
3134
+ controller.abort();
3135
+ }, this.timeout);
3136
+ options.signal = controller.signal;
3137
+ }
3138
+ try {
3139
+ const fetch1 = this.fetch;
3140
+ return fetch1(url, options);
3141
+ } finally {
3142
+ clearTimeout(abortTimeout);
3143
+ }
3144
+ }
3145
+ async stopPoller(timeoutMs = 30000) {
3146
+ clearTimeout(this.poller);
3147
+ if (this.cacheProvider)
3148
+ try {
3149
+ const shutdownResult = this.cacheProvider.shutdown();
3150
+ if (shutdownResult instanceof Promise)
3151
+ await Promise.race([
3152
+ shutdownResult,
3153
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`Cache shutdown timeout after ${timeoutMs}ms`)), timeoutMs))
3154
+ ]);
3155
+ } catch (err) {
3156
+ this.onError?.(new Error(`Error during cache shutdown: ${err}`));
3157
+ }
3158
+ }
3159
+ }
3160
+ async function _hash(key, bucketingValue, salt = "") {
3161
+ const hashString = await hashSHA1(`${key}.${bucketingValue}${salt}`);
3162
+ return parseInt(hashString.slice(0, 15), 16) / LONG_SCALE;
3163
+ }
3164
+ function matchProperty(property, propertyValues, warnFunction) {
3165
+ const key = property.key;
3166
+ const value = property.value;
3167
+ const operator = property.operator || "exact";
3168
+ if (key in propertyValues) {
3169
+ if (operator === "is_not_set")
3170
+ throw new InconclusiveMatchError("Operator is_not_set is not supported");
3171
+ } else
3172
+ throw new InconclusiveMatchError(`Property ${key} not found in propertyValues`);
3173
+ const overrideValue = propertyValues[key];
3174
+ if (overrideValue == null && !NULL_VALUES_ALLOWED_OPERATORS.includes(operator)) {
3175
+ if (warnFunction)
3176
+ warnFunction(`Property ${key} cannot have a value of null/undefined with the ${operator} operator`);
3177
+ return false;
3178
+ }
3179
+ function computeExactMatch(value2, overrideValue2) {
3180
+ if (Array.isArray(value2))
3181
+ return value2.map((val) => String(val).toLowerCase()).includes(String(overrideValue2).toLowerCase());
3182
+ return String(value2).toLowerCase() === String(overrideValue2).toLowerCase();
3183
+ }
3184
+ function compare(lhs, rhs, operator2) {
3185
+ if (operator2 === "gt")
3186
+ return lhs > rhs;
3187
+ if (operator2 === "gte")
3188
+ return lhs >= rhs;
3189
+ if (operator2 === "lt")
3190
+ return lhs < rhs;
3191
+ if (operator2 === "lte")
3192
+ return lhs <= rhs;
3193
+ throw new Error(`Invalid operator: ${operator2}`);
3194
+ }
3195
+ switch (operator) {
3196
+ case "exact":
3197
+ return computeExactMatch(value, overrideValue);
3198
+ case "is_not":
3199
+ return !computeExactMatch(value, overrideValue);
3200
+ case "is_set":
3201
+ return key in propertyValues;
3202
+ case "icontains":
3203
+ return String(overrideValue).toLowerCase().includes(String(value).toLowerCase());
3204
+ case "not_icontains":
3205
+ return !String(overrideValue).toLowerCase().includes(String(value).toLowerCase());
3206
+ case "regex":
3207
+ return isValidRegex(String(value)) && String(overrideValue).match(String(value)) !== null;
3208
+ case "not_regex":
3209
+ return isValidRegex(String(value)) && String(overrideValue).match(String(value)) === null;
3210
+ case "gt":
3211
+ case "gte":
3212
+ case "lt":
3213
+ case "lte": {
3214
+ let parsedValue = typeof value == "number" ? value : null;
3215
+ if (typeof value == "string")
3216
+ try {
3217
+ parsedValue = parseFloat(value);
3218
+ } catch (err) {}
3219
+ if (parsedValue == null || overrideValue == null)
3220
+ return compare(String(overrideValue), String(value), operator);
3221
+ if (typeof overrideValue == "string")
3222
+ return compare(overrideValue, String(value), operator);
3223
+ return compare(overrideValue, parsedValue, operator);
3224
+ }
3225
+ case "is_date_after":
3226
+ case "is_date_before": {
3227
+ if (typeof value == "boolean")
3228
+ throw new InconclusiveMatchError("Date operations cannot be performed on boolean values");
3229
+ let parsedDate = relativeDateParseForFeatureFlagMatching(String(value));
3230
+ if (parsedDate == null)
3231
+ parsedDate = convertToDateTime(value);
3232
+ if (parsedDate == null)
3233
+ throw new InconclusiveMatchError(`Invalid date: ${value}`);
3234
+ const overrideDate = convertToDateTime(overrideValue);
3235
+ if ([
3236
+ "is_date_before"
3237
+ ].includes(operator))
3238
+ return overrideDate < parsedDate;
3239
+ return overrideDate > parsedDate;
3240
+ }
3241
+ case "semver_eq": {
3242
+ const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
3243
+ return cmp === 0;
3244
+ }
3245
+ case "semver_neq": {
3246
+ const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
3247
+ return cmp !== 0;
3248
+ }
3249
+ case "semver_gt": {
3250
+ const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
3251
+ return cmp > 0;
3252
+ }
3253
+ case "semver_gte": {
3254
+ const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
3255
+ return cmp >= 0;
3256
+ }
3257
+ case "semver_lt": {
3258
+ const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
3259
+ return cmp < 0;
3260
+ }
3261
+ case "semver_lte": {
3262
+ const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
3263
+ return cmp <= 0;
3264
+ }
3265
+ case "semver_tilde": {
3266
+ const overrideParsed = parseSemver(String(overrideValue));
3267
+ const { lower, upper } = computeTildeBounds(String(value));
3268
+ return compareSemverTuples(overrideParsed, lower) >= 0 && compareSemverTuples(overrideParsed, upper) < 0;
3269
+ }
3270
+ case "semver_caret": {
3271
+ const overrideParsed = parseSemver(String(overrideValue));
3272
+ const { lower, upper } = computeCaretBounds(String(value));
3273
+ return compareSemverTuples(overrideParsed, lower) >= 0 && compareSemverTuples(overrideParsed, upper) < 0;
3274
+ }
3275
+ case "semver_wildcard": {
3276
+ const overrideParsed = parseSemver(String(overrideValue));
3277
+ const { lower, upper } = computeWildcardBounds(String(value));
3278
+ return compareSemverTuples(overrideParsed, lower) >= 0 && compareSemverTuples(overrideParsed, upper) < 0;
3279
+ }
3280
+ default:
3281
+ throw new InconclusiveMatchError(`Unknown operator: ${operator}`);
3282
+ }
3283
+ }
3284
+ function checkCohortExists(cohortId, cohortProperties) {
3285
+ if (!(cohortId in cohortProperties))
3286
+ throw new RequiresServerEvaluation(`cohort ${cohortId} not found in local cohorts - likely a static cohort that requires server evaluation`);
3287
+ }
3288
+ function matchCohort(property, propertyValues, cohortProperties, debugMode = false) {
3289
+ const cohortId = String(property.value);
3290
+ checkCohortExists(cohortId, cohortProperties);
3291
+ const propertyGroup = cohortProperties[cohortId];
3292
+ return matchPropertyGroup(propertyGroup, propertyValues, cohortProperties, debugMode);
3293
+ }
3294
+ function matchPropertyGroup(propertyGroup, propertyValues, cohortProperties, debugMode = false) {
3295
+ if (!propertyGroup)
3296
+ return true;
3297
+ const propertyGroupType = propertyGroup.type;
3298
+ const properties = propertyGroup.values;
3299
+ if (!properties || properties.length === 0)
3300
+ return true;
3301
+ let errorMatchingLocally = false;
3302
+ if ("values" in properties[0]) {
3303
+ for (const prop of properties)
3304
+ try {
3305
+ const matches = matchPropertyGroup(prop, propertyValues, cohortProperties, debugMode);
3306
+ if (propertyGroupType === "AND") {
3307
+ if (!matches)
3308
+ return false;
3309
+ } else if (matches)
3310
+ return true;
3311
+ } catch (err) {
3312
+ if (err instanceof RequiresServerEvaluation)
3313
+ throw err;
3314
+ if (err instanceof InconclusiveMatchError) {
3315
+ if (debugMode)
3316
+ console.debug(`Failed to compute property ${prop} locally: ${err}`);
3317
+ errorMatchingLocally = true;
3318
+ } else
3319
+ throw err;
3320
+ }
3321
+ if (errorMatchingLocally)
3322
+ throw new InconclusiveMatchError("Can't match cohort without a given cohort property value");
3323
+ return propertyGroupType === "AND";
3324
+ }
3325
+ for (const prop of properties)
3326
+ try {
3327
+ let matches;
3328
+ if (prop.type === "cohort")
3329
+ matches = matchCohort(prop, propertyValues, cohortProperties, debugMode);
3330
+ else if (prop.type === "flag") {
3331
+ if (debugMode)
3332
+ console.warn(`[FEATURE FLAGS] Flag dependency filters are not supported in local evaluation. Skipping condition with dependency on flag '${prop.key || "unknown"}'`);
3333
+ continue;
3334
+ } else
3335
+ matches = matchProperty(prop, propertyValues);
3336
+ const negation = prop.negation || false;
3337
+ if (propertyGroupType === "AND") {
3338
+ if (!matches && !negation)
3339
+ return false;
3340
+ if (matches && negation)
3341
+ return false;
3342
+ } else {
3343
+ if (matches && !negation)
3344
+ return true;
3345
+ if (!matches && negation)
3346
+ return true;
3347
+ }
3348
+ } catch (err) {
3349
+ if (err instanceof RequiresServerEvaluation)
3350
+ throw err;
3351
+ if (err instanceof InconclusiveMatchError) {
3352
+ if (debugMode)
3353
+ console.debug(`Failed to compute property ${prop} locally: ${err}`);
3354
+ errorMatchingLocally = true;
3355
+ } else
3356
+ throw err;
3357
+ }
3358
+ if (errorMatchingLocally)
3359
+ throw new InconclusiveMatchError("can't match cohort without a given cohort property value");
3360
+ return propertyGroupType === "AND";
3361
+ }
3362
+ function isValidRegex(regex) {
3363
+ try {
3364
+ new RegExp(regex);
3365
+ return true;
3366
+ } catch (err) {
3367
+ return false;
3368
+ }
3369
+ }
3370
+ function parseSemver(value) {
3371
+ const text = String(value).trim().replace(/^[vV]/, "");
3372
+ const baseVersion = text.split("-")[0].split("+")[0];
3373
+ if (!baseVersion || baseVersion.startsWith("."))
3374
+ throw new InconclusiveMatchError(`Invalid semver: ${value}`);
3375
+ const parts = baseVersion.split(".");
3376
+ const parsePart = (part) => {
3377
+ if (part === undefined || part === "")
3378
+ return 0;
3379
+ if (!/^\d+$/.test(part))
3380
+ throw new InconclusiveMatchError(`Invalid semver: ${value}`);
3381
+ return parseInt(part, 10);
3382
+ };
3383
+ const major = parsePart(parts[0]);
3384
+ const minor = parsePart(parts[1]);
3385
+ const patch = parsePart(parts[2]);
3386
+ return [
3387
+ major,
3388
+ minor,
3389
+ patch
3390
+ ];
3391
+ }
3392
+ function compareSemverTuples(a, b) {
3393
+ for (let i = 0;i < 3; i++) {
3394
+ if (a[i] < b[i])
3395
+ return -1;
3396
+ if (a[i] > b[i])
3397
+ return 1;
3398
+ }
3399
+ return 0;
3400
+ }
3401
+ function computeTildeBounds(value) {
3402
+ const parsed = parseSemver(value);
3403
+ const lower = [
3404
+ parsed[0],
3405
+ parsed[1],
3406
+ parsed[2]
3407
+ ];
3408
+ const upper = [
3409
+ parsed[0],
3410
+ parsed[1] + 1,
3411
+ 0
3412
+ ];
3413
+ return {
3414
+ lower,
3415
+ upper
3416
+ };
3417
+ }
3418
+ function computeCaretBounds(value) {
3419
+ const parsed = parseSemver(value);
3420
+ const [major, minor, patch] = parsed;
3421
+ const lower = [
3422
+ major,
3423
+ minor,
3424
+ patch
3425
+ ];
3426
+ let upper;
3427
+ upper = major > 0 ? [
3428
+ major + 1,
3429
+ 0,
3430
+ 0
3431
+ ] : minor > 0 ? [
3432
+ 0,
3433
+ minor + 1,
3434
+ 0
3435
+ ] : [
3436
+ 0,
3437
+ 0,
3438
+ patch + 1
3439
+ ];
3440
+ return {
3441
+ lower,
3442
+ upper
3443
+ };
3444
+ }
3445
+ function computeWildcardBounds(value) {
3446
+ const text = String(value).trim().replace(/^[vV]/, "");
3447
+ const cleanedText = text.replace(/\.\*$/, "").replace(/\*$/, "");
3448
+ if (!cleanedText)
3449
+ throw new InconclusiveMatchError(`Invalid wildcard semver: ${value}`);
3450
+ const parts = cleanedText.split(".");
3451
+ const major = parseInt(parts[0], 10);
3452
+ if (isNaN(major))
3453
+ throw new InconclusiveMatchError(`Invalid wildcard semver: ${value}`);
3454
+ let lower;
3455
+ let upper;
3456
+ if (parts.length === 1) {
3457
+ lower = [
3458
+ major,
3459
+ 0,
3460
+ 0
3461
+ ];
3462
+ upper = [
3463
+ major + 1,
3464
+ 0,
3465
+ 0
3466
+ ];
3467
+ } else {
3468
+ const minor = parseInt(parts[1], 10);
3469
+ if (isNaN(minor))
3470
+ throw new InconclusiveMatchError(`Invalid wildcard semver: ${value}`);
3471
+ lower = [
3472
+ major,
3473
+ minor,
3474
+ 0
3475
+ ];
3476
+ upper = [
3477
+ major,
3478
+ minor + 1,
3479
+ 0
3480
+ ];
3481
+ }
3482
+ return {
3483
+ lower,
3484
+ upper
3485
+ };
3486
+ }
3487
+ function convertToDateTime(value) {
3488
+ if (value instanceof Date)
3489
+ return value;
3490
+ if (typeof value == "string" || typeof value == "number") {
3491
+ const date = new Date(value);
3492
+ if (!isNaN(date.valueOf()))
3493
+ return date;
3494
+ throw new InconclusiveMatchError(`${value} is in an invalid date format`);
3495
+ }
3496
+ throw new InconclusiveMatchError(`The date provided ${value} must be a string, number, or date object`);
3497
+ }
3498
+ function relativeDateParseForFeatureFlagMatching(value) {
3499
+ const regex = /^-?(?<number>[0-9]+)(?<interval>[a-z])$/;
3500
+ const match = value.match(regex);
3501
+ const parsedDt = new Date(new Date().toISOString());
3502
+ if (!match)
3503
+ return null;
3504
+ {
3505
+ if (!match.groups)
3506
+ return null;
3507
+ const number = parseInt(match.groups["number"]);
3508
+ if (number >= 1e4)
3509
+ return null;
3510
+ const interval = match.groups["interval"];
3511
+ if (interval == "h")
3512
+ parsedDt.setUTCHours(parsedDt.getUTCHours() - number);
3513
+ else if (interval == "d")
3514
+ parsedDt.setUTCDate(parsedDt.getUTCDate() - number);
3515
+ else if (interval == "w")
3516
+ parsedDt.setUTCDate(parsedDt.getUTCDate() - 7 * number);
3517
+ else if (interval == "m")
3518
+ parsedDt.setUTCMonth(parsedDt.getUTCMonth() - number);
3519
+ else {
3520
+ if (interval != "y")
3521
+ return null;
3522
+ parsedDt.setUTCFullYear(parsedDt.getUTCFullYear() - number);
3523
+ }
3524
+ return parsedDt;
3525
+ }
3526
+ }
3527
+
3528
+ // node_modules/posthog-node/dist/storage-memory.mjs
3529
+ class PostHogMemoryStorage {
3530
+ getProperty(key) {
3531
+ return this._memoryStorage[key];
3532
+ }
3533
+ setProperty(key, value) {
3534
+ this._memoryStorage[key] = value !== null ? value : undefined;
3535
+ }
3536
+ constructor() {
3537
+ this._memoryStorage = {};
3538
+ }
3539
+ }
3540
+
3541
+ // node_modules/posthog-node/dist/client.mjs
3542
+ var MINIMUM_POLLING_INTERVAL = 100;
3543
+ var THIRTY_SECONDS = 30000;
3544
+ var MAX_CACHE_SIZE = 50000;
3545
+ var WAITUNTIL_DEBOUNCE_MS = 50;
3546
+ var WAITUNTIL_MAX_WAIT_MS = 500;
3547
+
3548
+ class PostHogBackendClient extends PostHogCoreStateless {
3549
+ constructor(apiKey, options = {}) {
3550
+ super(apiKey, options), this._memoryStorage = new PostHogMemoryStorage;
3551
+ this.options = options;
3552
+ this.context = this.initializeContext();
3553
+ this.options.featureFlagsPollingInterval = typeof options.featureFlagsPollingInterval == "number" ? Math.max(options.featureFlagsPollingInterval, MINIMUM_POLLING_INTERVAL) : THIRTY_SECONDS;
3554
+ if (typeof options.waitUntilDebounceMs == "number")
3555
+ this.options.waitUntilDebounceMs = Math.max(options.waitUntilDebounceMs, 0);
3556
+ if (typeof options.waitUntilMaxWaitMs == "number")
3557
+ this.options.waitUntilMaxWaitMs = Math.max(options.waitUntilMaxWaitMs, 0);
3558
+ if (options.personalApiKey) {
3559
+ if (options.personalApiKey.includes("phc_"))
3560
+ throw new Error('Your Personal API key is invalid. These keys are prefixed with "phx_" and can be created in PostHog project settings.');
3561
+ const shouldEnableLocalEvaluation = options.enableLocalEvaluation !== false;
3562
+ if (shouldEnableLocalEvaluation)
3563
+ this.featureFlagsPoller = new FeatureFlagsPoller({
3564
+ pollingInterval: this.options.featureFlagsPollingInterval,
3565
+ personalApiKey: options.personalApiKey,
3566
+ projectApiKey: apiKey,
3567
+ timeout: options.requestTimeout ?? 1e4,
3568
+ host: this.host,
3569
+ fetch: options.fetch,
3570
+ onError: (err) => {
3571
+ this._events.emit("error", err);
3572
+ },
3573
+ onLoad: (count) => {
3574
+ this._events.emit("localEvaluationFlagsLoaded", count);
3575
+ },
3576
+ customHeaders: this.getCustomHeaders(),
3577
+ cacheProvider: options.flagDefinitionCacheProvider,
3578
+ strictLocalEvaluation: options.strictLocalEvaluation
3579
+ });
3580
+ }
3581
+ this.errorTracking = new ErrorTracking(this, options, this._logger);
3582
+ this.distinctIdHasSentFlagCalls = {};
3583
+ this.maxCacheSize = options.maxCacheSize || MAX_CACHE_SIZE;
3584
+ }
3585
+ enqueue(type, message, options) {
3586
+ super.enqueue(type, message, options);
3587
+ this.scheduleDebouncedFlush();
3588
+ }
3589
+ async flush() {
3590
+ const flushPromise = super.flush();
3591
+ const waitUntil = this.options.waitUntil;
3592
+ if (waitUntil && !this._waitUntilCycle)
3593
+ try {
3594
+ waitUntil(flushPromise.catch(() => {}));
3595
+ } catch {}
3596
+ return flushPromise;
3597
+ }
3598
+ scheduleDebouncedFlush() {
3599
+ const waitUntil = this.options.waitUntil;
3600
+ if (!waitUntil)
3601
+ return;
3602
+ if (this.disabled || this.optedOut)
3603
+ return;
3604
+ if (!this._waitUntilCycle) {
3605
+ let resolve;
3606
+ const promise = new Promise((r) => {
3607
+ resolve = r;
3608
+ });
3609
+ try {
3610
+ waitUntil(promise);
3611
+ } catch {
3612
+ return;
3613
+ }
3614
+ this._waitUntilCycle = {
3615
+ resolve,
3616
+ startedAt: Date.now(),
3617
+ timer: undefined
3618
+ };
3619
+ }
3620
+ const elapsed = Date.now() - this._waitUntilCycle.startedAt;
3621
+ const maxWaitMs = this.options.waitUntilMaxWaitMs ?? WAITUNTIL_MAX_WAIT_MS;
3622
+ const flushNow = elapsed >= maxWaitMs;
3623
+ if (this._waitUntilCycle.timer !== undefined)
3624
+ clearTimeout(this._waitUntilCycle.timer);
3625
+ if (flushNow)
3626
+ return void this.resolveWaitUntilFlush();
3627
+ const debounceMs = this.options.waitUntilDebounceMs ?? WAITUNTIL_DEBOUNCE_MS;
3628
+ this._waitUntilCycle.timer = safeSetTimeout(() => {
3629
+ this.resolveWaitUntilFlush();
3630
+ }, debounceMs);
3631
+ }
3632
+ _consumeWaitUntilCycle() {
3633
+ const cycle = this._waitUntilCycle;
3634
+ if (cycle) {
3635
+ clearTimeout(cycle.timer);
3636
+ this._waitUntilCycle = undefined;
3637
+ }
3638
+ return cycle?.resolve;
3639
+ }
3640
+ async resolveWaitUntilFlush() {
3641
+ const resolve = this._consumeWaitUntilCycle();
3642
+ try {
3643
+ await super.flush();
3644
+ } catch {} finally {
3645
+ resolve?.();
3646
+ }
3647
+ }
3648
+ getPersistedProperty(key) {
3649
+ return this._memoryStorage.getProperty(key);
3650
+ }
3651
+ setPersistedProperty(key, value) {
3652
+ return this._memoryStorage.setProperty(key, value);
3653
+ }
3654
+ fetch(url, options) {
3655
+ return this.options.fetch ? this.options.fetch(url, options) : fetch(url, options);
3656
+ }
3657
+ getLibraryVersion() {
3658
+ return version;
3659
+ }
3660
+ getCustomUserAgent() {
3661
+ return `${this.getLibraryId()}/${this.getLibraryVersion()}`;
3662
+ }
3663
+ enable() {
3664
+ return super.optIn();
3665
+ }
3666
+ disable() {
3667
+ return super.optOut();
3668
+ }
3669
+ debug(enabled = true) {
3670
+ super.debug(enabled);
3671
+ this.featureFlagsPoller?.debug(enabled);
3672
+ }
3673
+ capture(props) {
3674
+ if (typeof props == "string")
3675
+ this._logger.warn("Called capture() with a string as the first argument when an object was expected.");
3676
+ if (props.event === "$exception" && !props._originatedFromCaptureException)
3677
+ 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.");
3678
+ this.addPendingPromise(this.prepareEventMessage(props).then(({ distinctId, event, properties, options }) => super.captureStateless(distinctId, event, properties, {
3679
+ timestamp: options.timestamp,
3680
+ disableGeoip: options.disableGeoip,
3681
+ uuid: options.uuid
3682
+ })).catch((err) => {
3683
+ if (err)
3684
+ console.error(err);
3685
+ }));
3686
+ }
3687
+ async captureImmediate(props) {
3688
+ if (typeof props == "string")
3689
+ this._logger.warn("Called captureImmediate() with a string as the first argument when an object was expected.");
3690
+ if (props.event === "$exception" && !props._originatedFromCaptureException)
3691
+ 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.");
3692
+ return this.addPendingPromise(this.prepareEventMessage(props).then(({ distinctId, event, properties, options }) => super.captureStatelessImmediate(distinctId, event, properties, {
3693
+ timestamp: options.timestamp,
3694
+ disableGeoip: options.disableGeoip,
3695
+ uuid: options.uuid
3696
+ })).catch((err) => {
3697
+ if (err)
3698
+ console.error(err);
3699
+ }));
3700
+ }
3701
+ identify({ distinctId, properties = {}, disableGeoip }) {
3702
+ const { $set, $set_once, $anon_distinct_id, ...rest } = properties;
3703
+ const setProps = $set || rest;
3704
+ const setOnceProps = $set_once || {};
3705
+ const eventProperties = {
3706
+ $set: setProps,
3707
+ $set_once: setOnceProps,
3708
+ $anon_distinct_id: $anon_distinct_id ?? undefined
3709
+ };
3710
+ super.identifyStateless(distinctId, eventProperties, {
3711
+ disableGeoip
3712
+ });
3713
+ }
3714
+ async identifyImmediate({ distinctId, properties = {}, disableGeoip }) {
3715
+ const { $set, $set_once, $anon_distinct_id, ...rest } = properties;
3716
+ const setProps = $set || rest;
3717
+ const setOnceProps = $set_once || {};
3718
+ const eventProperties = {
3719
+ $set: setProps,
3720
+ $set_once: setOnceProps,
3721
+ $anon_distinct_id: $anon_distinct_id ?? undefined
3722
+ };
3723
+ super.identifyStatelessImmediate(distinctId, eventProperties, {
3724
+ disableGeoip
3725
+ });
3726
+ }
3727
+ alias(data) {
3728
+ super.aliasStateless(data.alias, data.distinctId, undefined, {
3729
+ disableGeoip: data.disableGeoip
3730
+ });
3731
+ }
3732
+ async aliasImmediate(data) {
3733
+ await super.aliasStatelessImmediate(data.alias, data.distinctId, undefined, {
3734
+ disableGeoip: data.disableGeoip
3735
+ });
3736
+ }
3737
+ isLocalEvaluationReady() {
3738
+ return this.featureFlagsPoller?.isLocalEvaluationReady() ?? false;
3739
+ }
3740
+ async waitForLocalEvaluationReady(timeoutMs = THIRTY_SECONDS) {
3741
+ if (this.isLocalEvaluationReady())
3742
+ return true;
3743
+ if (this.featureFlagsPoller === undefined)
3744
+ return false;
3745
+ return new Promise((resolve) => {
3746
+ const timeout = setTimeout(() => {
3747
+ cleanup();
3748
+ resolve(false);
3749
+ }, timeoutMs);
3750
+ const cleanup = this._events.on("localEvaluationFlagsLoaded", (count) => {
3751
+ clearTimeout(timeout);
3752
+ cleanup();
3753
+ resolve(count > 0);
3754
+ });
3755
+ });
3756
+ }
3757
+ _resolveDistinctId(distinctIdOrOptions, options) {
3758
+ if (typeof distinctIdOrOptions == "string")
3759
+ return {
3760
+ distinctId: distinctIdOrOptions,
3761
+ options
3762
+ };
3763
+ return {
3764
+ distinctId: this.context?.get()?.distinctId,
3765
+ options: distinctIdOrOptions
3766
+ };
3767
+ }
3768
+ async _getFeatureFlagResult(key, distinctId, options = {}, matchValue) {
3769
+ const sendFeatureFlagEvents = options.sendFeatureFlagEvents ?? true;
3770
+ if (this._flagOverrides !== undefined && key in this._flagOverrides) {
3771
+ const overrideValue = this._flagOverrides[key];
3772
+ if (overrideValue === undefined)
3773
+ return;
3774
+ const overridePayload = this._payloadOverrides?.[key];
3775
+ return {
3776
+ key,
3777
+ enabled: overrideValue !== false,
3778
+ variant: typeof overrideValue == "string" ? overrideValue : undefined,
3779
+ payload: overridePayload
3780
+ };
3781
+ }
3782
+ const { groups, disableGeoip } = options;
3783
+ let { onlyEvaluateLocally, personProperties, groupProperties } = options;
3784
+ const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
3785
+ personProperties = adjustedProperties.allPersonProperties;
3786
+ groupProperties = adjustedProperties.allGroupProperties;
3787
+ const evaluationContext = this.createFeatureFlagEvaluationContext(distinctId, groups, personProperties, groupProperties);
3788
+ if (onlyEvaluateLocally == undefined)
3789
+ onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false;
3790
+ let result;
3791
+ let flagWasLocallyEvaluated = false;
3792
+ let requestId;
3793
+ let evaluatedAt;
3794
+ let featureFlagError;
3795
+ let flagId;
3796
+ let flagVersion;
3797
+ let flagReason;
3798
+ const localEvaluationEnabled = this.featureFlagsPoller !== undefined;
3799
+ if (localEvaluationEnabled) {
3800
+ await this.featureFlagsPoller?.loadFeatureFlags();
3801
+ const flag = this.featureFlagsPoller?.featureFlagsByKey[key];
3802
+ if (flag)
3803
+ try {
3804
+ const localResult = await this.featureFlagsPoller?.computeFlagAndPayloadLocally(flag, evaluationContext, {
3805
+ matchValue
3806
+ });
3807
+ if (localResult) {
3808
+ flagWasLocallyEvaluated = true;
3809
+ const value = localResult.value;
3810
+ flagId = flag.id;
3811
+ flagReason = "Evaluated locally";
3812
+ result = {
3813
+ key,
3814
+ enabled: value !== false,
3815
+ variant: typeof value == "string" ? value : undefined,
3816
+ payload: localResult.payload ?? undefined
3817
+ };
3818
+ }
3819
+ } catch (e) {
3820
+ if (e instanceof RequiresServerEvaluation || e instanceof InconclusiveMatchError)
3821
+ this._logger?.info(`${e.name} when computing flag locally: ${key}: ${e.message}`);
3822
+ else
3823
+ throw e;
3824
+ }
3825
+ }
3826
+ if (!flagWasLocallyEvaluated && !onlyEvaluateLocally) {
3827
+ const flagsResponse = await super.getFeatureFlagDetailsStateless(evaluationContext.distinctId, evaluationContext.groups, evaluationContext.personProperties, evaluationContext.groupProperties, disableGeoip, [
3828
+ key
3829
+ ]);
3830
+ if (flagsResponse === undefined)
3831
+ featureFlagError = FeatureFlagError2.UNKNOWN_ERROR;
3832
+ else {
3833
+ requestId = flagsResponse.requestId;
3834
+ evaluatedAt = flagsResponse.evaluatedAt;
3835
+ const errors = [];
3836
+ if (flagsResponse.errorsWhileComputingFlags)
3837
+ errors.push(FeatureFlagError2.ERRORS_WHILE_COMPUTING);
3838
+ if (flagsResponse.quotaLimited?.includes("feature_flags"))
3839
+ errors.push(FeatureFlagError2.QUOTA_LIMITED);
3840
+ const flagDetail = flagsResponse.flags[key];
3841
+ if (flagDetail === undefined)
3842
+ errors.push(FeatureFlagError2.FLAG_MISSING);
3843
+ else {
3844
+ flagId = flagDetail.metadata?.id;
3845
+ flagVersion = flagDetail.metadata?.version;
3846
+ flagReason = flagDetail.reason?.description ?? flagDetail.reason?.code;
3847
+ let parsedPayload;
3848
+ if (flagDetail.metadata?.payload !== undefined)
3849
+ try {
3850
+ parsedPayload = JSON.parse(flagDetail.metadata.payload);
3851
+ } catch {
3852
+ parsedPayload = flagDetail.metadata.payload;
3853
+ }
3854
+ result = {
3855
+ key,
3856
+ enabled: flagDetail.enabled,
3857
+ variant: flagDetail.variant,
3858
+ payload: parsedPayload
3859
+ };
3860
+ }
3861
+ if (errors.length > 0)
3862
+ featureFlagError = errors.join(",");
3863
+ }
3864
+ }
3865
+ if (sendFeatureFlagEvents) {
3866
+ const response = result === undefined ? undefined : result.enabled === false ? false : result.variant ?? true;
3867
+ const featureFlagReportedKey = `${key}_${response}`;
3868
+ if (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey)) {
3869
+ if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize)
3870
+ this.distinctIdHasSentFlagCalls = {};
3871
+ if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId]))
3872
+ this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
3873
+ else
3874
+ this.distinctIdHasSentFlagCalls[distinctId] = [
3875
+ featureFlagReportedKey
3876
+ ];
3877
+ const properties = {
3878
+ $feature_flag: key,
3879
+ $feature_flag_response: response,
3880
+ $feature_flag_id: flagId,
3881
+ $feature_flag_version: flagVersion,
3882
+ $feature_flag_reason: flagReason,
3883
+ locally_evaluated: flagWasLocallyEvaluated,
3884
+ [`$feature/${key}`]: response,
3885
+ $feature_flag_request_id: requestId,
3886
+ $feature_flag_evaluated_at: flagWasLocallyEvaluated ? Date.now() : evaluatedAt
3887
+ };
3888
+ if (flagWasLocallyEvaluated && this.featureFlagsPoller) {
3889
+ const flagDefinitionsLoadedAt = this.featureFlagsPoller.getFlagDefinitionsLoadedAt();
3890
+ if (flagDefinitionsLoadedAt !== undefined)
3891
+ properties.$feature_flag_definitions_loaded_at = flagDefinitionsLoadedAt;
3892
+ }
3893
+ if (featureFlagError)
3894
+ properties.$feature_flag_error = featureFlagError;
3895
+ this.capture({
3896
+ distinctId,
3897
+ event: "$feature_flag_called",
3898
+ properties,
3899
+ groups,
3900
+ disableGeoip
3901
+ });
3902
+ }
3903
+ }
3904
+ if (result !== undefined && this._payloadOverrides !== undefined && key in this._payloadOverrides)
3905
+ result = {
3906
+ ...result,
3907
+ payload: this._payloadOverrides[key]
3908
+ };
3909
+ return result;
3910
+ }
3911
+ async getFeatureFlag(key, distinctId, options) {
3912
+ const result = await this._getFeatureFlagResult(key, distinctId, {
3913
+ ...options,
3914
+ sendFeatureFlagEvents: options?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true
3915
+ });
3916
+ if (result === undefined)
3917
+ return;
3918
+ if (result.enabled === false)
3919
+ return false;
3920
+ return result.variant ?? true;
3921
+ }
3922
+ async getFeatureFlagPayload(key, distinctId, matchValue, options) {
3923
+ if (this._payloadOverrides !== undefined && key in this._payloadOverrides)
3924
+ return this._payloadOverrides[key];
3925
+ const result = await this._getFeatureFlagResult(key, distinctId, {
3926
+ ...options,
3927
+ sendFeatureFlagEvents: false
3928
+ }, matchValue);
3929
+ if (result === undefined)
3930
+ return;
3931
+ return result.payload ?? null;
3932
+ }
3933
+ async getFeatureFlagResult(key, distinctIdOrOptions, options) {
3934
+ const { distinctId: resolvedDistinctId, options: resolvedOptions } = this._resolveDistinctId(distinctIdOrOptions, options);
3935
+ if (!resolvedDistinctId)
3936
+ return void this._logger.warn("[PostHog] distinctId is required — pass it explicitly or use withContext()");
3937
+ return this._getFeatureFlagResult(key, resolvedDistinctId, {
3938
+ ...resolvedOptions,
3939
+ sendFeatureFlagEvents: resolvedOptions?.sendFeatureFlagEvents ?? this.options.sendFeatureFlagEvent ?? true
3940
+ });
3941
+ }
3942
+ async getRemoteConfigPayload(flagKey) {
3943
+ if (!this.options.personalApiKey)
3944
+ throw new Error("Personal API key is required for remote config payload decryption");
3945
+ const response = await this._requestRemoteConfigPayload(flagKey);
3946
+ if (!response)
3947
+ return;
3948
+ const parsed = await response.json();
3949
+ if (typeof parsed == "string")
3950
+ try {
3951
+ return JSON.parse(parsed);
3952
+ } catch (e) {}
3953
+ return parsed;
3954
+ }
3955
+ async isFeatureEnabled(key, distinctId, options) {
3956
+ const feat = await this.getFeatureFlag(key, distinctId, options);
3957
+ if (feat === undefined)
3958
+ return;
3959
+ return !!feat || false;
3960
+ }
3961
+ async getAllFlags(distinctIdOrOptions, options) {
3962
+ const { distinctId: resolvedDistinctId, options: resolvedOptions } = this._resolveDistinctId(distinctIdOrOptions, options);
3963
+ if (!resolvedDistinctId) {
3964
+ this._logger.warn("[PostHog] distinctId is required to get feature flags — pass it explicitly or use withContext()");
3965
+ return {};
3966
+ }
3967
+ const response = await this.getAllFlagsAndPayloads(resolvedDistinctId, resolvedOptions);
3968
+ return response.featureFlags || {};
3969
+ }
3970
+ async getAllFlagsAndPayloads(distinctIdOrOptions, options) {
3971
+ const { distinctId: resolvedDistinctId, options: resolvedOptions } = this._resolveDistinctId(distinctIdOrOptions, options);
3972
+ if (!resolvedDistinctId) {
3973
+ this._logger.warn("[PostHog] distinctId is required to get feature flags and payloads — pass it explicitly or use withContext()");
3974
+ return {
3975
+ featureFlags: {},
3976
+ featureFlagPayloads: {}
3977
+ };
3978
+ }
3979
+ const { groups, disableGeoip, flagKeys } = resolvedOptions || {};
3980
+ let { onlyEvaluateLocally, personProperties, groupProperties } = resolvedOptions || {};
3981
+ const adjustedProperties = this.addLocalPersonAndGroupProperties(resolvedDistinctId, groups, personProperties, groupProperties);
3982
+ personProperties = adjustedProperties.allPersonProperties;
3983
+ groupProperties = adjustedProperties.allGroupProperties;
3984
+ const evaluationContext = this.createFeatureFlagEvaluationContext(resolvedDistinctId, groups, personProperties, groupProperties);
3985
+ if (onlyEvaluateLocally == undefined)
3986
+ onlyEvaluateLocally = this.options.strictLocalEvaluation ?? false;
3987
+ const localEvaluationResult = await this.featureFlagsPoller?.getAllFlagsAndPayloads(evaluationContext, flagKeys);
3988
+ let featureFlags = {};
3989
+ let featureFlagPayloads = {};
3990
+ let fallbackToFlags = true;
3991
+ if (localEvaluationResult) {
3992
+ featureFlags = localEvaluationResult.response;
3993
+ featureFlagPayloads = localEvaluationResult.payloads;
3994
+ fallbackToFlags = localEvaluationResult.fallbackToFlags;
3995
+ }
3996
+ if (fallbackToFlags && !onlyEvaluateLocally) {
3997
+ const remoteEvaluationResult = await super.getFeatureFlagsAndPayloadsStateless(evaluationContext.distinctId, evaluationContext.groups, evaluationContext.personProperties, evaluationContext.groupProperties, disableGeoip, flagKeys);
3998
+ featureFlags = {
3999
+ ...featureFlags,
4000
+ ...remoteEvaluationResult.flags || {}
4001
+ };
4002
+ featureFlagPayloads = {
4003
+ ...featureFlagPayloads,
4004
+ ...remoteEvaluationResult.payloads || {}
4005
+ };
4006
+ }
4007
+ if (this._flagOverrides !== undefined)
4008
+ featureFlags = {
4009
+ ...featureFlags,
4010
+ ...this._flagOverrides
4011
+ };
4012
+ if (this._payloadOverrides !== undefined)
4013
+ featureFlagPayloads = {
4014
+ ...featureFlagPayloads,
4015
+ ...this._payloadOverrides
4016
+ };
4017
+ return {
4018
+ featureFlags,
4019
+ featureFlagPayloads
4020
+ };
4021
+ }
4022
+ groupIdentify({ groupType, groupKey, properties, distinctId, disableGeoip }) {
4023
+ super.groupIdentifyStateless(groupType, groupKey, properties, {
4024
+ disableGeoip
4025
+ }, distinctId);
4026
+ }
4027
+ async reloadFeatureFlags() {
4028
+ await this.featureFlagsPoller?.loadFeatureFlags(true);
4029
+ }
4030
+ overrideFeatureFlags(overrides) {
4031
+ const flagArrayToRecord = (flags) => Object.fromEntries(flags.map((f) => [
4032
+ f,
4033
+ true
4034
+ ]));
4035
+ if (overrides === false) {
4036
+ this._flagOverrides = undefined;
4037
+ this._payloadOverrides = undefined;
4038
+ return;
4039
+ }
4040
+ if (Array.isArray(overrides)) {
4041
+ this._flagOverrides = flagArrayToRecord(overrides);
4042
+ return;
4043
+ }
4044
+ if (this._isFeatureFlagOverrideOptions(overrides)) {
4045
+ if ("flags" in overrides) {
4046
+ if (overrides.flags === false)
4047
+ this._flagOverrides = undefined;
4048
+ else if (Array.isArray(overrides.flags))
4049
+ this._flagOverrides = flagArrayToRecord(overrides.flags);
4050
+ else if (overrides.flags !== undefined)
4051
+ this._flagOverrides = {
4052
+ ...overrides.flags
4053
+ };
4054
+ }
4055
+ if ("payloads" in overrides) {
4056
+ if (overrides.payloads === false)
4057
+ this._payloadOverrides = undefined;
4058
+ else if (overrides.payloads !== undefined)
4059
+ this._payloadOverrides = {
4060
+ ...overrides.payloads
4061
+ };
4062
+ }
4063
+ return;
4064
+ }
4065
+ this._flagOverrides = {
4066
+ ...overrides
4067
+ };
4068
+ }
4069
+ _isFeatureFlagOverrideOptions(overrides) {
4070
+ if (typeof overrides != "object" || overrides === null || Array.isArray(overrides))
4071
+ return false;
4072
+ const obj = overrides;
4073
+ if ("flags" in obj) {
4074
+ const flagsValue = obj["flags"];
4075
+ if (flagsValue === false || Array.isArray(flagsValue) || typeof flagsValue == "object" && flagsValue !== null)
4076
+ return true;
4077
+ }
4078
+ if ("payloads" in obj) {
4079
+ const payloadsValue = obj["payloads"];
4080
+ if (payloadsValue === false || typeof payloadsValue == "object" && payloadsValue !== null)
4081
+ return true;
4082
+ }
4083
+ return false;
4084
+ }
4085
+ withContext(data, fn, options) {
4086
+ if (!this.context)
4087
+ return fn();
4088
+ return this.context.run(data, fn, options);
4089
+ }
4090
+ getContext() {
4091
+ return this.context?.get();
4092
+ }
4093
+ enterContext(data, options) {
4094
+ this.context?.enter(data, options);
4095
+ }
4096
+ async _shutdown(shutdownTimeoutMs) {
4097
+ const resolve = this._consumeWaitUntilCycle();
4098
+ await this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
4099
+ this.errorTracking.shutdown();
4100
+ try {
4101
+ return await super._shutdown(shutdownTimeoutMs);
4102
+ } finally {
4103
+ resolve?.();
4104
+ }
4105
+ }
4106
+ async _requestRemoteConfigPayload(flagKey) {
4107
+ if (!this.options.personalApiKey)
4108
+ return;
4109
+ const url = `${this.host}/api/projects/@current/feature_flags/${flagKey}/remote_config?token=${encodeURIComponent(this.apiKey)}`;
4110
+ const options = {
4111
+ method: "GET",
4112
+ headers: {
4113
+ ...this.getCustomHeaders(),
4114
+ "Content-Type": "application/json",
4115
+ Authorization: `Bearer ${this.options.personalApiKey}`
4116
+ }
4117
+ };
4118
+ let abortTimeout = null;
4119
+ if (this.options.requestTimeout && typeof this.options.requestTimeout == "number") {
4120
+ const controller = new AbortController;
4121
+ abortTimeout = safeSetTimeout(() => {
4122
+ controller.abort();
4123
+ }, this.options.requestTimeout);
4124
+ options.signal = controller.signal;
4125
+ }
4126
+ try {
4127
+ return await this.fetch(url, options);
4128
+ } catch (error) {
4129
+ this._events.emit("error", error);
4130
+ return;
4131
+ } finally {
4132
+ if (abortTimeout)
4133
+ clearTimeout(abortTimeout);
4134
+ }
4135
+ }
4136
+ extractPropertiesFromEvent(eventProperties, groups) {
4137
+ if (!eventProperties)
4138
+ return {
4139
+ personProperties: {},
4140
+ groupProperties: {}
4141
+ };
4142
+ const personProperties = {};
4143
+ const groupProperties = {};
4144
+ for (const [key, value] of Object.entries(eventProperties))
4145
+ if (isPlainObject(value) && groups && key in groups) {
4146
+ const groupProps = {};
4147
+ for (const [groupKey, groupValue] of Object.entries(value))
4148
+ groupProps[String(groupKey)] = String(groupValue);
4149
+ groupProperties[String(key)] = groupProps;
4150
+ } else
4151
+ personProperties[String(key)] = String(value);
4152
+ return {
4153
+ personProperties,
4154
+ groupProperties
4155
+ };
4156
+ }
4157
+ async getFeatureFlagsForEvent(distinctId, groups, disableGeoip, sendFeatureFlagsOptions) {
4158
+ const finalPersonProperties = sendFeatureFlagsOptions?.personProperties || {};
4159
+ const finalGroupProperties = sendFeatureFlagsOptions?.groupProperties || {};
4160
+ const flagKeys = sendFeatureFlagsOptions?.flagKeys;
4161
+ const onlyEvaluateLocally = sendFeatureFlagsOptions?.onlyEvaluateLocally ?? this.options.strictLocalEvaluation ?? false;
4162
+ if (onlyEvaluateLocally)
4163
+ if (!((this.featureFlagsPoller?.featureFlags?.length || 0) > 0))
4164
+ return {};
4165
+ else {
4166
+ const groupsWithStringValues = {};
4167
+ for (const [key, value] of Object.entries(groups || {}))
4168
+ groupsWithStringValues[key] = String(value);
4169
+ return await this.getAllFlags(distinctId, {
4170
+ groups: groupsWithStringValues,
4171
+ personProperties: finalPersonProperties,
4172
+ groupProperties: finalGroupProperties,
4173
+ disableGeoip,
4174
+ onlyEvaluateLocally: true,
4175
+ flagKeys
4176
+ });
4177
+ }
4178
+ if ((this.featureFlagsPoller?.featureFlags?.length || 0) > 0) {
4179
+ const groupsWithStringValues = {};
4180
+ for (const [key, value] of Object.entries(groups || {}))
4181
+ groupsWithStringValues[key] = String(value);
4182
+ return await this.getAllFlags(distinctId, {
4183
+ groups: groupsWithStringValues,
4184
+ personProperties: finalPersonProperties,
4185
+ groupProperties: finalGroupProperties,
4186
+ disableGeoip,
4187
+ onlyEvaluateLocally: true,
4188
+ flagKeys
4189
+ });
4190
+ }
4191
+ return (await super.getFeatureFlagsStateless(distinctId, groups, finalPersonProperties, finalGroupProperties, disableGeoip)).flags;
4192
+ }
4193
+ addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties) {
4194
+ const allPersonProperties = {
4195
+ distinct_id: distinctId,
4196
+ ...personProperties || {}
4197
+ };
4198
+ const allGroupProperties = {};
4199
+ if (groups)
4200
+ for (const groupName of Object.keys(groups))
4201
+ allGroupProperties[groupName] = {
4202
+ $group_key: groups[groupName],
4203
+ ...groupProperties?.[groupName] || {}
4204
+ };
4205
+ return {
4206
+ allPersonProperties,
4207
+ allGroupProperties
4208
+ };
4209
+ }
4210
+ createFeatureFlagEvaluationContext(distinctId, groups, personProperties, groupProperties) {
4211
+ return {
4212
+ distinctId,
4213
+ groups: groups || {},
4214
+ personProperties: personProperties || {},
4215
+ groupProperties: groupProperties || {},
4216
+ evaluationCache: {}
4217
+ };
4218
+ }
4219
+ captureException(error, distinctId, additionalProperties, uuid) {
4220
+ if (!ErrorTracking.isPreviouslyCapturedError(error)) {
4221
+ const syntheticException = new Error("PostHog syntheticException");
4222
+ this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
4223
+ syntheticException
4224
+ }, distinctId, additionalProperties).then((msg) => this.capture({
4225
+ ...msg,
4226
+ uuid
4227
+ })));
4228
+ }
4229
+ }
4230
+ async captureExceptionImmediate(error, distinctId, additionalProperties) {
4231
+ if (!ErrorTracking.isPreviouslyCapturedError(error)) {
4232
+ const syntheticException = new Error("PostHog syntheticException");
4233
+ return this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
4234
+ syntheticException
4235
+ }, distinctId, additionalProperties).then((msg) => this.captureImmediate(msg)));
4236
+ }
4237
+ }
4238
+ async prepareEventMessage(props) {
4239
+ const { distinctId, event, properties, groups, sendFeatureFlags, timestamp, disableGeoip, uuid } = props;
4240
+ const contextData = this.context?.get();
4241
+ let mergedDistinctId = distinctId || contextData?.distinctId;
4242
+ const mergedProperties = {
4243
+ ...this.props,
4244
+ ...contextData?.properties || {},
4245
+ ...properties || {}
4246
+ };
4247
+ if (!mergedDistinctId) {
4248
+ mergedDistinctId = uuidv7();
4249
+ mergedProperties.$process_person_profile = false;
4250
+ }
4251
+ if (contextData?.sessionId && !mergedProperties.$session_id)
4252
+ mergedProperties.$session_id = contextData.sessionId;
4253
+ const eventMessage = this._runBeforeSend({
4254
+ distinctId: mergedDistinctId,
4255
+ event,
4256
+ properties: mergedProperties,
4257
+ groups,
4258
+ sendFeatureFlags,
4259
+ timestamp,
4260
+ disableGeoip,
4261
+ uuid
4262
+ });
4263
+ if (!eventMessage)
4264
+ return Promise.reject(null);
4265
+ const eventProperties = await Promise.resolve().then(async () => {
4266
+ if (sendFeatureFlags) {
4267
+ const sendFeatureFlagsOptions = typeof sendFeatureFlags == "object" ? sendFeatureFlags : undefined;
4268
+ return await this.getFeatureFlagsForEvent(eventMessage.distinctId, groups, disableGeoip, sendFeatureFlagsOptions);
4269
+ }
4270
+ eventMessage.event;
4271
+ return {};
4272
+ }).then((flags) => {
4273
+ const additionalProperties = {};
4274
+ if (flags)
4275
+ for (const [feature, variant] of Object.entries(flags))
4276
+ additionalProperties[`$feature/${feature}`] = variant;
4277
+ const activeFlags = Object.keys(flags || {}).filter((flag) => flags?.[flag] !== false).sort();
4278
+ if (activeFlags.length > 0)
4279
+ additionalProperties["$active_feature_flags"] = activeFlags;
4280
+ return additionalProperties;
4281
+ }).catch(() => ({})).then((additionalProperties) => {
4282
+ const props2 = {
4283
+ ...additionalProperties,
4284
+ ...eventMessage.properties || {},
4285
+ $groups: eventMessage.groups || groups
4286
+ };
4287
+ return props2;
4288
+ });
4289
+ if (eventMessage.event === "$pageview" && this.options.__preview_capture_bot_pageviews && typeof eventProperties.$raw_user_agent == "string") {
4290
+ if (isBlockedUA(eventProperties.$raw_user_agent, this.options.custom_blocked_useragents || [])) {
4291
+ eventMessage.event = "$bot_pageview";
4292
+ eventProperties.$browser_type = "bot";
4293
+ }
4294
+ }
4295
+ return {
4296
+ distinctId: eventMessage.distinctId,
4297
+ event: eventMessage.event,
4298
+ properties: eventProperties,
4299
+ options: {
4300
+ timestamp: eventMessage.timestamp,
4301
+ disableGeoip: eventMessage.disableGeoip,
4302
+ uuid: eventMessage.uuid
4303
+ }
4304
+ };
4305
+ }
4306
+ _runBeforeSend(eventMessage) {
4307
+ const beforeSend = this.options.before_send;
4308
+ if (!beforeSend)
4309
+ return eventMessage;
4310
+ const fns = Array.isArray(beforeSend) ? beforeSend : [
4311
+ beforeSend
4312
+ ];
4313
+ let result = eventMessage;
4314
+ for (const fn of fns) {
4315
+ result = fn(result);
4316
+ if (!result) {
4317
+ this._logger.info(`Event '${eventMessage.event}' was rejected in beforeSend function`);
4318
+ return null;
4319
+ }
4320
+ if (!result.properties || Object.keys(result.properties).length === 0) {
4321
+ const message = `Event '${result.event}' has no properties after beforeSend function, this is likely an error.`;
4322
+ this._logger.warn(message);
4323
+ }
4324
+ }
4325
+ return result;
4326
+ }
4327
+ }
4328
+
4329
+ // node_modules/posthog-node/dist/extensions/context/context.mjs
4330
+ import { AsyncLocalStorage } from "node:async_hooks";
4331
+
4332
+ class PostHogContext {
4333
+ constructor() {
4334
+ this.storage = new AsyncLocalStorage;
4335
+ }
4336
+ get() {
4337
+ return this.storage.getStore();
4338
+ }
4339
+ run(context, fn, options) {
4340
+ return this.storage.run(this.resolve(context, options), fn);
4341
+ }
4342
+ enter(context, options) {
4343
+ this.storage.enterWith(this.resolve(context, options));
4344
+ }
4345
+ resolve(context, options) {
4346
+ if (options?.fresh === true)
4347
+ return context;
4348
+ const current = this.get() || {};
4349
+ return {
4350
+ distinctId: context.distinctId ?? current.distinctId,
4351
+ sessionId: context.sessionId ?? current.sessionId,
4352
+ properties: {
4353
+ ...current.properties || {},
4354
+ ...context.properties || {}
4355
+ }
4356
+ };
4357
+ }
4358
+ }
4359
+
4360
+ // node_modules/posthog-node/dist/extensions/sentry-integration.mjs
4361
+ var NAME = "posthog-node";
4362
+ function createEventProcessor(_posthog, { organization, projectId, prefix, severityAllowList = [
4363
+ "error"
4364
+ ], sendExceptionsToPostHog = true } = {}) {
4365
+ return (event) => {
4366
+ const shouldProcessLevel = severityAllowList === "*" || severityAllowList.includes(event.level);
4367
+ if (!shouldProcessLevel)
4368
+ return event;
4369
+ if (!event.tags)
4370
+ event.tags = {};
4371
+ const userId = event.tags[PostHogSentryIntegration.POSTHOG_ID_TAG];
4372
+ if (userId === undefined)
4373
+ return event;
4374
+ const uiHost = _posthog.options.host ?? "https://us.i.posthog.com";
4375
+ const personUrl = new URL(`/project/${_posthog.apiKey}/person/${userId}`, uiHost).toString();
4376
+ event.tags["PostHog Person URL"] = personUrl;
4377
+ const exceptions = event.exception?.values || [];
4378
+ const exceptionList = exceptions.map((exception) => ({
4379
+ ...exception,
4380
+ stacktrace: exception.stacktrace ? {
4381
+ ...exception.stacktrace,
4382
+ type: "raw",
4383
+ frames: (exception.stacktrace.frames || []).map((frame) => ({
4384
+ ...frame,
4385
+ platform: "node:javascript"
4386
+ }))
4387
+ } : undefined
4388
+ }));
4389
+ const properties = {
4390
+ $exception_message: exceptions[0]?.value || event.message,
4391
+ $exception_type: exceptions[0]?.type,
4392
+ $exception_level: event.level,
4393
+ $exception_list: exceptionList,
4394
+ $sentry_event_id: event.event_id,
4395
+ $sentry_exception: event.exception,
4396
+ $sentry_exception_message: exceptions[0]?.value || event.message,
4397
+ $sentry_exception_type: exceptions[0]?.type,
4398
+ $sentry_tags: event.tags
4399
+ };
4400
+ if (organization && projectId)
4401
+ properties["$sentry_url"] = (prefix || "https://sentry.io/organizations/") + organization + "/issues/?project=" + projectId + "&query=" + event.event_id;
4402
+ if (sendExceptionsToPostHog)
4403
+ _posthog.capture({
4404
+ event: "$exception",
4405
+ distinctId: userId,
4406
+ properties
4407
+ });
4408
+ return event;
4409
+ };
4410
+ }
4411
+ class PostHogSentryIntegration {
4412
+ static #_ = this.POSTHOG_ID_TAG = "posthog_distinct_id";
4413
+ constructor(_posthog, organization, prefix, severityAllowList, sendExceptionsToPostHog) {
4414
+ this.name = NAME;
4415
+ this.name = NAME;
4416
+ this.setupOnce = function(addGlobalEventProcessor, getCurrentHub) {
4417
+ const projectId = getCurrentHub()?.getClient()?.getDsn()?.projectId;
4418
+ addGlobalEventProcessor(createEventProcessor(_posthog, {
4419
+ organization,
4420
+ projectId,
4421
+ prefix,
4422
+ severityAllowList,
4423
+ sendExceptionsToPostHog: sendExceptionsToPostHog ?? true
4424
+ }));
4425
+ };
4426
+ }
4427
+ }
4428
+ // node_modules/posthog-node/dist/entrypoints/index.node.mjs
4429
+ ErrorTracking.errorPropertiesBuilder = new exports_error_tracking.ErrorPropertiesBuilder([
4430
+ new exports_error_tracking.EventCoercer,
4431
+ new exports_error_tracking.ErrorCoercer,
4432
+ new exports_error_tracking.ObjectCoercer,
4433
+ new exports_error_tracking.StringCoercer,
4434
+ new exports_error_tracking.PrimitiveCoercer
4435
+ ], exports_error_tracking.createStackParser("node:javascript", exports_error_tracking.nodeStackLineParser), [
4436
+ createModulerModifier(),
4437
+ addSourceContext
4438
+ ]);
4439
+
4440
+ class PostHog extends PostHogBackendClient {
4441
+ getLibraryId() {
4442
+ return "posthog-node";
4443
+ }
4444
+ initializeContext() {
4445
+ return new PostHogContext;
4446
+ }
4447
+ }
4448
+
4449
+ // src/index.ts
4450
+ import { randomUUID as randomUUID2 } from "node:crypto";
4451
+
4452
+ // src/utils.ts
4453
+ import { hostname } from "node:os";
4454
+ import { basename } from "node:path";
4455
+ function loadConfig() {
4456
+ const tags = {};
4457
+ const tagsEnv = process.env.POSTHOG_TAGS;
4458
+ if (tagsEnv) {
4459
+ for (const pair of tagsEnv.split(",")) {
4460
+ const colonIdx = pair.indexOf(":");
4461
+ if (colonIdx > 0) {
4462
+ const key = pair.slice(0, colonIdx).trim();
4463
+ const val = pair.slice(colonIdx + 1).trim();
4464
+ if (key.length > 0 && val.length > 0) {
4465
+ tags[key] = val;
4466
+ }
4467
+ }
4468
+ }
4469
+ }
4470
+ let distinctId = process.env.POSTHOG_DISTINCT_ID;
4471
+ if (!distinctId) {
4472
+ try {
4473
+ distinctId = hostname();
4474
+ } catch {
4475
+ distinctId = "opencode-user";
4476
+ }
4477
+ }
4478
+ return {
4479
+ apiKey: process.env.POSTHOG_API_KEY ?? "",
4480
+ host: process.env.POSTHOG_HOST ?? "https://us.i.posthog.com",
4481
+ privacyMode: process.env.POSTHOG_PRIVACY_MODE === "true",
4482
+ enabled: process.env.POSTHOG_ENABLED !== "false",
4483
+ distinctId,
4484
+ projectName: process.env.POSTHOG_PROJECT_NAME || basename(process.cwd()) || "opencode-project",
4485
+ tags,
4486
+ maxAttributeLength: parseInt(process.env.POSTHOG_MAX_ATTRIBUTE_LENGTH ?? "12000", 10) || 12000
4487
+ };
4488
+ }
4489
+ var SENSITIVE_KEY_PATTERN = /api[-_]?key|token|secret|password|authorization|credential|private[-_]?key/i;
4490
+ var SENSITIVE_JSON_PATTERN = /"(?:api[-_]?key|token|secret|password|authorization|credential|private[-_]?key)"\s*:\s*"[^"]*"/gi;
4491
+ var SENSITIVE_KV_PATTERN = /(?:api[-_]?key|token|secret|password|authorization|credential|private[-_]?key)\s*[=:]\s*[^\n,;]*/gi;
4492
+ function redactStringValues(str) {
4493
+ return str.replace(SENSITIVE_JSON_PATTERN, "[REDACTED]").replace(SENSITIVE_KV_PATTERN, "[REDACTED]");
4494
+ }
4495
+ function redactSensitive(value, seen, depth) {
4496
+ if (depth > 8)
4497
+ return "[DepthLimit]";
4498
+ if (value === null || value === undefined)
4499
+ return value;
4500
+ if (typeof value === "string")
4501
+ return redactStringValues(value);
4502
+ if (typeof value !== "object")
4503
+ return value;
4504
+ if (seen.has(value))
4505
+ return "[Circular]";
4506
+ seen.add(value);
4507
+ if (Array.isArray(value)) {
4508
+ return value.map((item) => redactSensitive(item, seen, depth + 1));
4509
+ }
4510
+ const output = {};
4511
+ for (const [key, nested] of Object.entries(value)) {
4512
+ if (SENSITIVE_KEY_PATTERN.test(key)) {
4513
+ output[key] = "[REDACTED]";
4514
+ } else {
4515
+ output[key] = redactSensitive(nested, seen, depth + 1);
4516
+ }
4517
+ }
4518
+ return output;
4519
+ }
4520
+ function truncate(value, maxLength) {
4521
+ if (maxLength <= 0)
4522
+ return "";
4523
+ if (value.length <= maxLength)
4524
+ return value;
4525
+ const omitted = value.length - maxLength;
4526
+ return `${value.slice(0, maxLength)}...[truncated ${omitted} chars]`;
4527
+ }
4528
+ function serializeAttribute(value, maxLength) {
4529
+ if (value === undefined || value === null)
4530
+ return null;
4531
+ const redacted = redactSensitive(value, new WeakSet, 0);
4532
+ if (typeof redacted === "string") {
4533
+ return truncate(redacted, maxLength);
4534
+ }
4535
+ try {
4536
+ const json = JSON.stringify(redacted);
4537
+ if (json === undefined)
4538
+ return null;
4539
+ return truncate(json, maxLength);
4540
+ } catch {
4541
+ return "[Unserializable]";
4542
+ }
4543
+ }
4544
+ function redactForPrivacy(value, privacyMode) {
4545
+ return privacyMode ? null : value;
4546
+ }
4547
+ function serializeError(error, maxLength = 12000) {
4548
+ if (!error)
4549
+ return null;
4550
+ return serializeAttribute(error, maxLength);
4551
+ }
4552
+
4553
+ // src/events.ts
4554
+ import { randomUUID } from "node:crypto";
4555
+ // package.json
4556
+ var package_default = {
4557
+ name: "opencode-posthog",
4558
+ version: "0.0.1",
4559
+ description: "PostHog LLM Analytics plugin for OpenCode",
4560
+ author: "Nejc Drobnič <nejc@nejc.dev>",
4561
+ license: "MIT",
4562
+ type: "module",
4563
+ main: "./dist/index.js",
4564
+ module: "./dist/index.js",
4565
+ types: "./dist/index.d.ts",
4566
+ exports: {
4567
+ ".": {
4568
+ import: "./dist/index.js",
4569
+ require: "./dist/index.js",
4570
+ types: "./dist/index.d.ts"
4571
+ }
4572
+ },
4573
+ files: [
4574
+ "dist"
4575
+ ],
4576
+ keywords: [
4577
+ "opencode-plugin",
4578
+ "posthog",
4579
+ "ai",
4580
+ "llm",
4581
+ "observability",
4582
+ "tracing",
4583
+ "analytics"
4584
+ ],
4585
+ repository: {
4586
+ type: "git",
4587
+ url: "git+https://github.com/Quantumlyy/opencode-posthog.git"
4588
+ },
4589
+ bugs: {
4590
+ url: "https://github.com/Quantumlyy/opencode-posthog/issues"
4591
+ },
4592
+ homepage: "https://github.com/Quantumlyy/opencode-posthog#readme",
4593
+ scripts: {
4594
+ build: "bun build src/index.ts --outdir dist --target node",
4595
+ prepublishOnly: "bun run build",
4596
+ test: "vitest run",
4597
+ "test:watch": "vitest",
4598
+ typecheck: "tsc --noEmit",
4599
+ lint: "oxlint src/ && oxfmt --check .",
4600
+ "lint:fix": "oxlint --fix src/ && oxfmt --write ."
4601
+ },
4602
+ dependencies: {
4603
+ "posthog-node": "^5.0.0"
4604
+ },
4605
+ peerDependencies: {
4606
+ "@opencode-ai/plugin": "*"
4607
+ },
4608
+ devDependencies: {
4609
+ "@opencode-ai/plugin": "*",
4610
+ "@opencode-ai/sdk": "*",
4611
+ "@types/bun": "^1.3.0",
4612
+ oxfmt: "^0.40.0",
4613
+ oxlint: "^1.55.0",
4614
+ typescript: "^5.8.0",
4615
+ vitest: "^3.0.0"
4616
+ }
4617
+ };
4618
+
4619
+ // src/version.ts
4620
+ var VERSION = package_default.version;
4621
+
4622
+ // src/events.ts
4623
+ var STOP_REASON_MAP = {
4624
+ stop: "stop",
4625
+ length: "length",
4626
+ "tool-calls": "tool_calls",
4627
+ error: "error"
4628
+ };
4629
+ function mapStopReason(reason) {
4630
+ if (!reason)
4631
+ return null;
4632
+ return STOP_REASON_MAP[reason] ?? reason;
4633
+ }
4634
+ function buildAiGeneration(part, assistantInfo, trace, config) {
4635
+ const spanId = trace.currentGenerationSpanId ?? randomUUID();
4636
+ const inputMessages = redactForPrivacy(trace.stepInputSnapshot.length > 0 ? trace.stepInputSnapshot : null, config.privacyMode);
4637
+ const outputChoices = redactForPrivacy(trace.stepAssistantText ? [{ role: "assistant", content: trace.stepAssistantText }] : null, config.privacyMode);
4638
+ return {
4639
+ event: "$ai_generation",
4640
+ distinctId: config.distinctId,
4641
+ properties: {
4642
+ $ai_trace_id: trace.traceId,
4643
+ $ai_session_id: trace.sessionId,
4644
+ $ai_span_id: spanId,
4645
+ $ai_model: assistantInfo?.modelID ?? "unknown",
4646
+ $ai_provider: assistantInfo?.providerID ?? "unknown",
4647
+ $ai_input_tokens: part.tokens.input,
4648
+ $ai_output_tokens: part.tokens.output,
4649
+ $ai_reasoning_tokens: part.tokens.reasoning,
4650
+ cache_read_input_tokens: part.tokens.cache.read,
4651
+ cache_creation_input_tokens: part.tokens.cache.write,
4652
+ $ai_total_cost_usd: part.cost,
4653
+ $ai_stop_reason: mapStopReason(part.reason),
4654
+ $ai_input: inputMessages,
4655
+ $ai_output_choices: outputChoices,
4656
+ $ai_is_error: !!assistantInfo?.error,
4657
+ $ai_error: serializeError(assistantInfo?.error, config.maxAttributeLength),
4658
+ $ai_lib: "opencode-posthog",
4659
+ $ai_lib_version: VERSION,
4660
+ $ai_framework: "opencode",
4661
+ $ai_project_name: config.projectName,
4662
+ $ai_agent_name: trace.agentName ?? config.projectName,
4663
+ ...config.tags
4664
+ }
4665
+ };
4666
+ }
4667
+ function buildAiSpan(toolName, toolState, trace, config) {
4668
+ const spanId = randomUUID();
4669
+ const latency = (toolState.time.end - toolState.time.start) / 1000;
4670
+ const isError2 = toolState.status === "error";
4671
+ const inputState = redactForPrivacy(serializeAttribute(toolState.input, config.maxAttributeLength), config.privacyMode);
4672
+ let outputState = null;
4673
+ if (!config.privacyMode) {
4674
+ if (toolState.status === "completed") {
4675
+ outputState = serializeAttribute(toolState.output, config.maxAttributeLength);
4676
+ } else {
4677
+ outputState = serializeAttribute(toolState.error, config.maxAttributeLength);
4678
+ }
4679
+ }
4680
+ return {
4681
+ event: "$ai_span",
4682
+ distinctId: config.distinctId,
4683
+ properties: {
4684
+ $ai_trace_id: trace.traceId,
4685
+ $ai_session_id: trace.sessionId,
4686
+ $ai_span_id: spanId,
4687
+ $ai_parent_id: trace.currentGenerationSpanId ?? null,
4688
+ $ai_span_name: toolName,
4689
+ $ai_latency: latency,
4690
+ $ai_input_state: inputState,
4691
+ $ai_output_state: outputState,
4692
+ $ai_is_error: isError2,
4693
+ $ai_error: isError2 ? serializeAttribute(toolState.error, config.maxAttributeLength) : null,
4694
+ $ai_lib: "opencode-posthog",
4695
+ $ai_lib_version: VERSION,
4696
+ $ai_framework: "opencode",
4697
+ $ai_project_name: config.projectName,
4698
+ $ai_agent_name: trace.agentName ?? config.projectName,
4699
+ ...config.tags
4700
+ }
4701
+ };
4702
+ }
4703
+ function buildAiTrace(trace, config) {
4704
+ const latency = (Date.now() - trace.startTime) / 1000;
4705
+ return {
4706
+ event: "$ai_trace",
4707
+ distinctId: config.distinctId,
4708
+ properties: {
4709
+ $ai_trace_id: trace.traceId,
4710
+ $ai_session_id: trace.sessionId,
4711
+ $ai_latency: latency,
4712
+ $ai_span_name: config.projectName,
4713
+ $ai_input_state: redactForPrivacy(trace.userPrompt ?? null, config.privacyMode),
4714
+ $ai_output_state: redactForPrivacy(trace.lastAssistantText ?? null, config.privacyMode),
4715
+ $ai_total_input_tokens: trace.totalInputTokens,
4716
+ $ai_total_output_tokens: trace.totalOutputTokens,
4717
+ $ai_is_error: trace.hadError,
4718
+ $ai_error: trace.lastError ? serializeAttribute(trace.lastError, config.maxAttributeLength) : null,
4719
+ $ai_lib: "opencode-posthog",
4720
+ $ai_lib_version: VERSION,
4721
+ $ai_framework: "opencode",
4722
+ $ai_project_name: config.projectName,
4723
+ $ai_agent_name: trace.agentName ?? config.projectName,
4724
+ ...config.tags
4725
+ }
4726
+ };
4727
+ }
4728
+
4729
+ // src/index.ts
4730
+ var PostHogPlugin = async () => {
4731
+ const config = loadConfig();
4732
+ if (!config.enabled || !config.apiKey)
4733
+ return {};
4734
+ const client = new PostHog(config.apiKey, {
4735
+ host: config.host,
4736
+ flushAt: 20,
4737
+ flushInterval: 1e4
4738
+ });
4739
+ function safeCapture(event) {
4740
+ try {
4741
+ client.capture({
4742
+ distinctId: event.distinctId,
4743
+ event: event.event,
4744
+ properties: event.properties
4745
+ });
4746
+ } catch {}
4747
+ }
4748
+ const traces = new Map;
4749
+ const messageRoles = new Map;
4750
+ const assistantMessages = new Map;
4751
+ function getOrCreateTrace(sessionId) {
4752
+ let trace = traces.get(sessionId);
4753
+ if (!trace) {
4754
+ trace = {
4755
+ traceId: randomUUID2(),
4756
+ sessionId,
4757
+ startTime: Date.now(),
4758
+ totalInputTokens: 0,
4759
+ totalOutputTokens: 0,
4760
+ totalCost: 0,
4761
+ hadError: false,
4762
+ stepInputMessages: [],
4763
+ stepInputSnapshot: [],
4764
+ messageIds: new Set
4765
+ };
4766
+ traces.set(sessionId, trace);
4767
+ }
4768
+ return trace;
4769
+ }
4770
+ function handleMessageUpdated(event) {
4771
+ if (event.type !== "message.updated")
4772
+ return;
4773
+ const msg = event.properties.info;
4774
+ if (msg.role === "user") {
4775
+ const trace = {
4776
+ traceId: randomUUID2(),
4777
+ sessionId: msg.sessionID,
4778
+ startTime: msg.time.created,
4779
+ totalInputTokens: 0,
4780
+ totalOutputTokens: 0,
4781
+ totalCost: 0,
4782
+ hadError: false,
4783
+ agentName: msg.agent,
4784
+ stepInputMessages: [],
4785
+ stepInputSnapshot: [],
4786
+ messageIds: new Set([msg.id])
4787
+ };
4788
+ traces.set(msg.sessionID, trace);
4789
+ messageRoles.set(msg.id, "user");
4790
+ } else if (msg.role === "assistant") {
4791
+ const assistant = msg;
4792
+ messageRoles.set(assistant.id, "assistant");
4793
+ const info = {
4794
+ messageID: assistant.id,
4795
+ modelID: assistant.modelID,
4796
+ providerID: assistant.providerID,
4797
+ error: assistant.error
4798
+ };
4799
+ assistantMessages.set(assistant.id, info);
4800
+ const trace = getOrCreateTrace(assistant.sessionID);
4801
+ trace.messageIds.add(assistant.id);
4802
+ trace.currentAssistantMsg = info;
4803
+ if (assistant.error) {
4804
+ trace.hadError = true;
4805
+ trace.lastError = serializeAttribute(assistant.error, config.maxAttributeLength) ?? assistant.error.name;
4806
+ }
4807
+ }
4808
+ }
4809
+ function handlePartUpdated(event) {
4810
+ if (event.type !== "message.part.updated")
4811
+ return;
4812
+ const part = event.properties.part;
4813
+ switch (part.type) {
4814
+ case "text":
4815
+ handleTextPart(part);
4816
+ break;
4817
+ case "step-start":
4818
+ handleStepStart(part);
4819
+ break;
4820
+ case "step-finish":
4821
+ handleStepFinish(part);
4822
+ break;
4823
+ case "tool":
4824
+ handleToolPart(part);
4825
+ break;
4826
+ }
4827
+ }
4828
+ function handleTextPart(part) {
4829
+ const role = messageRoles.get(part.messageID);
4830
+ if (!role)
4831
+ return;
4832
+ const trace = traces.get(part.sessionID);
4833
+ if (!trace)
4834
+ return;
4835
+ if (role === "user") {
4836
+ trace.userPrompt = part.text;
4837
+ trace.stepInputMessages.push({ role: "user", content: part.text });
4838
+ } else if (role === "assistant") {
4839
+ trace.lastAssistantText = part.text;
4840
+ trace.stepAssistantText = part.text;
4841
+ }
4842
+ }
4843
+ function handleStepStart(part) {
4844
+ const trace = traces.get(part.sessionID);
4845
+ if (!trace)
4846
+ return;
4847
+ trace.currentGenerationSpanId = randomUUID2();
4848
+ trace.stepInputSnapshot = [...trace.stepInputMessages];
4849
+ trace.stepAssistantText = undefined;
4850
+ }
4851
+ function handleStepFinish(part) {
4852
+ const trace = traces.get(part.sessionID);
4853
+ if (!trace)
4854
+ return;
4855
+ const assistantInfo = trace.currentAssistantMsg;
4856
+ trace.totalInputTokens += part.tokens.input;
4857
+ trace.totalOutputTokens += part.tokens.output;
4858
+ trace.totalCost += part.cost;
4859
+ const generation = buildAiGeneration(part, assistantInfo, trace, config);
4860
+ safeCapture(generation);
4861
+ }
4862
+ function handleToolPart(part) {
4863
+ if (part.state.status !== "completed" && part.state.status !== "error")
4864
+ return;
4865
+ const trace = traces.get(part.sessionID);
4866
+ if (!trace)
4867
+ return;
4868
+ const toolState = part.state;
4869
+ const span = buildAiSpan(part.tool, toolState, trace, config);
4870
+ safeCapture(span);
4871
+ if (toolState.status === "completed") {
4872
+ const redacted = serializeAttribute(toolState.output, config.maxAttributeLength) ?? "";
4873
+ trace.stepInputMessages.push({
4874
+ role: "tool",
4875
+ content: `[${part.tool}] ${redacted}`
4876
+ });
4877
+ } else {
4878
+ const redacted = serializeAttribute(toolState.error, config.maxAttributeLength) ?? "";
4879
+ trace.stepInputMessages.push({
4880
+ role: "tool",
4881
+ content: `[${part.tool}] ERROR: ${redacted}`
4882
+ });
4883
+ trace.hadError = true;
4884
+ trace.lastError = toolState.error;
4885
+ }
4886
+ }
4887
+ async function handleSessionIdle(event) {
4888
+ if (event.type !== "session.idle")
4889
+ return;
4890
+ const sessionId = event.properties.sessionID;
4891
+ const trace = traces.get(sessionId);
4892
+ if (!trace)
4893
+ return;
4894
+ const traceEvent = buildAiTrace(trace, config);
4895
+ safeCapture(traceEvent);
4896
+ try {
4897
+ await client.flush();
4898
+ } catch {}
4899
+ for (const msgId of trace.messageIds) {
4900
+ messageRoles.delete(msgId);
4901
+ assistantMessages.delete(msgId);
4902
+ }
4903
+ traces.delete(sessionId);
4904
+ }
4905
+ function handleSessionError(event) {
4906
+ if (event.type !== "session.error")
4907
+ return;
4908
+ const sessionId = event.properties.sessionID;
4909
+ if (!sessionId)
4910
+ return;
4911
+ const trace = traces.get(sessionId);
4912
+ if (trace) {
4913
+ trace.hadError = true;
4914
+ if (event.properties.error) {
4915
+ trace.lastError = serializeAttribute(event.properties.error, config.maxAttributeLength) ?? "unknown error";
4916
+ }
4917
+ }
4918
+ }
4919
+ return {
4920
+ event: async ({ event }) => {
4921
+ try {
4922
+ switch (event.type) {
4923
+ case "message.updated":
4924
+ handleMessageUpdated(event);
4925
+ break;
4926
+ case "message.part.updated":
4927
+ handlePartUpdated(event);
4928
+ break;
4929
+ case "session.idle":
4930
+ await handleSessionIdle(event);
4931
+ break;
4932
+ case "session.error":
4933
+ handleSessionError(event);
4934
+ break;
4935
+ }
4936
+ } catch {}
4937
+ }
4938
+ };
4939
+ };
4940
+ export {
4941
+ PostHogPlugin
4942
+ };