@rpcbase/server 0.546.0 → 0.548.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,7 +5,8 @@ import { createClient } from "redis";
5
5
  import { MongoClient } from "mongodb";
6
6
  import env from "@rpcbase/env";
7
7
  import { initApiClient, STATIC_RPCBASE_RTS_HYDRATION_DATA_KEY, RtsSsrRuntimeProvider, SsrErrorFallback, SSR_ERROR_STATE_GLOBAL_KEY, serializeSsrErrorState } from "@rpcbase/client";
8
- import { posix, dirname, sep } from "path";
8
+ import { getMongoUrl } from "@rpcbase/db/mongo";
9
+ import { posix, dirname, sep, isAbsolute, relative } from "path";
9
10
  import fs, { createReadStream, readFileSync } from "node:fs";
10
11
  import { createInterface } from "node:readline";
11
12
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -290,194 +291,23 @@ const parsePayload = (response) => {
290
291
  return response;
291
292
  }
292
293
  };
293
- const DIGITS = "0123456789abcdef";
294
- class UUID {
295
- constructor(bytes) {
296
- this.bytes = bytes;
297
- }
298
- static ofInner(bytes) {
299
- if (16 === bytes.length) return new UUID(bytes);
300
- throw new TypeError("not 128-bit length");
301
- }
302
- static fromFieldsV7(unixTsMs, randA, randBHi, randBLo) {
303
- if (!Number.isInteger(unixTsMs) || !Number.isInteger(randA) || !Number.isInteger(randBHi) || !Number.isInteger(randBLo) || unixTsMs < 0 || randA < 0 || randBHi < 0 || randBLo < 0 || unixTsMs > 281474976710655 || randA > 4095 || randBHi > 1073741823 || randBLo > 4294967295) throw new RangeError("invalid field value");
304
- const bytes = new Uint8Array(16);
305
- bytes[0] = unixTsMs / 2 ** 40;
306
- bytes[1] = unixTsMs / 2 ** 32;
307
- bytes[2] = unixTsMs / 2 ** 24;
308
- bytes[3] = unixTsMs / 2 ** 16;
309
- bytes[4] = unixTsMs / 256;
310
- bytes[5] = unixTsMs;
311
- bytes[6] = 112 | randA >>> 8;
312
- bytes[7] = randA;
313
- bytes[8] = 128 | randBHi >>> 24;
314
- bytes[9] = randBHi >>> 16;
315
- bytes[10] = randBHi >>> 8;
316
- bytes[11] = randBHi;
317
- bytes[12] = randBLo >>> 24;
318
- bytes[13] = randBLo >>> 16;
319
- bytes[14] = randBLo >>> 8;
320
- bytes[15] = randBLo;
321
- return new UUID(bytes);
322
- }
323
- static parse(uuid) {
324
- let hex;
325
- switch (uuid.length) {
326
- case 32:
327
- hex = /^[0-9a-f]{32}$/i.exec(uuid)?.[0];
328
- break;
329
- case 36:
330
- 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("");
331
- break;
332
- case 38:
333
- 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("");
334
- break;
335
- case 45:
336
- 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("");
337
- break;
338
- }
339
- if (hex) {
340
- const inner = new Uint8Array(16);
341
- for (let i = 0; i < 16; i += 4) {
342
- const n = parseInt(hex.substring(2 * i, 2 * i + 8), 16);
343
- inner[i + 0] = n >>> 24;
344
- inner[i + 1] = n >>> 16;
345
- inner[i + 2] = n >>> 8;
346
- inner[i + 3] = n;
347
- }
348
- return new UUID(inner);
349
- }
350
- throw new SyntaxError("could not parse UUID string");
351
- }
352
- toString() {
353
- let text = "";
354
- for (let i = 0; i < this.bytes.length; i++) {
355
- text += DIGITS.charAt(this.bytes[i] >>> 4);
356
- text += DIGITS.charAt(15 & this.bytes[i]);
357
- if (3 === i || 5 === i || 7 === i || 9 === i) text += "-";
358
- }
359
- return text;
360
- }
361
- toHex() {
362
- let text = "";
363
- for (let i = 0; i < this.bytes.length; i++) {
364
- text += DIGITS.charAt(this.bytes[i] >>> 4);
365
- text += DIGITS.charAt(15 & this.bytes[i]);
366
- }
367
- return text;
368
- }
369
- toJSON() {
370
- return this.toString();
371
- }
372
- getVariant() {
373
- const n = this.bytes[8] >>> 4;
374
- if (n < 0) throw new Error("unreachable");
375
- if (n <= 7) return this.bytes.every((e) => 0 === e) ? "NIL" : "VAR_0";
376
- if (n <= 11) return "VAR_10";
377
- if (n <= 13) return "VAR_110";
378
- if (n <= 15) return this.bytes.every((e) => 255 === e) ? "MAX" : "VAR_RESERVED";
379
- else throw new Error("unreachable");
380
- }
381
- getVersion() {
382
- return "VAR_10" === this.getVariant() ? this.bytes[6] >>> 4 : void 0;
383
- }
384
- clone() {
385
- return new UUID(this.bytes.slice(0));
386
- }
387
- equals(other) {
388
- return 0 === this.compareTo(other);
389
- }
390
- compareTo(other) {
391
- for (let i = 0; i < 16; i++) {
392
- const diff = this.bytes[i] - other.bytes[i];
393
- if (0 !== diff) return Math.sign(diff);
394
- }
395
- return 0;
396
- }
294
+ function isGzipSupported() {
295
+ return "CompressionStream" in globalThis;
397
296
  }
398
- class V7Generator {
399
- constructor(randomNumberGenerator) {
400
- this.timestamp = 0;
401
- this.counter = 0;
402
- this.random = randomNumberGenerator ?? getDefaultRandom();
403
- }
404
- generate() {
405
- return this.generateOrResetCore(Date.now(), 1e4);
406
- }
407
- generateOrAbort() {
408
- return this.generateOrAbortCore(Date.now(), 1e4);
409
- }
410
- generateOrResetCore(unixTsMs, rollbackAllowance) {
411
- let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
412
- if (void 0 === value) {
413
- this.timestamp = 0;
414
- value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
415
- }
416
- return value;
417
- }
418
- generateOrAbortCore(unixTsMs, rollbackAllowance) {
419
- const MAX_COUNTER = 4398046511103;
420
- if (!Number.isInteger(unixTsMs) || unixTsMs < 1 || unixTsMs > 281474976710655) throw new RangeError("`unixTsMs` must be a 48-bit positive integer");
421
- if (rollbackAllowance < 0 || rollbackAllowance > 281474976710655) throw new RangeError("`rollbackAllowance` out of reasonable range");
422
- if (unixTsMs > this.timestamp) {
423
- this.timestamp = unixTsMs;
424
- this.resetCounter();
425
- } else {
426
- if (!(unixTsMs + rollbackAllowance >= this.timestamp)) return;
427
- this.counter++;
428
- if (this.counter > MAX_COUNTER) {
429
- this.timestamp++;
430
- this.resetCounter();
431
- }
432
- }
433
- return UUID.fromFieldsV7(this.timestamp, Math.trunc(this.counter / 2 ** 30), this.counter & 2 ** 30 - 1, this.random.nextUint32());
434
- }
435
- resetCounter() {
436
- this.counter = 1024 * this.random.nextUint32() + (1023 & this.random.nextUint32());
437
- }
438
- generateV4() {
439
- const bytes = new Uint8Array(Uint32Array.of(this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32()).buffer);
440
- bytes[6] = 64 | bytes[6] >>> 4;
441
- bytes[8] = 128 | bytes[8] >>> 2;
442
- return UUID.ofInner(bytes);
297
+ async function gzipCompress(input, isDebug = true, options) {
298
+ try {
299
+ const dataStream = new Blob([
300
+ input
301
+ ], {
302
+ type: "text/plain"
303
+ }).stream();
304
+ const compressedStream = dataStream.pipeThrough(new CompressionStream("gzip"));
305
+ return await new Response(compressedStream).blob();
306
+ } catch (error) {
307
+ if (isDebug) console.error("Failed to gzip compress data", error);
308
+ return null;
443
309
  }
444
310
  }
445
- const getDefaultRandom = () => ({
446
- nextUint32: () => 65536 * Math.trunc(65536 * Math.random()) + Math.trunc(65536 * Math.random())
447
- });
448
- let defaultGenerator;
449
- const uuidv7 = () => uuidv7obj().toString();
450
- const uuidv7obj = () => (defaultGenerator || (defaultGenerator = new V7Generator())).generate();
451
- var types_PostHogPersistedProperty = /* @__PURE__ */ (function(PostHogPersistedProperty) {
452
- PostHogPersistedProperty["AnonymousId"] = "anonymous_id";
453
- PostHogPersistedProperty["DistinctId"] = "distinct_id";
454
- PostHogPersistedProperty["Props"] = "props";
455
- PostHogPersistedProperty["EnablePersonProcessing"] = "enable_person_processing";
456
- PostHogPersistedProperty["PersonMode"] = "person_mode";
457
- PostHogPersistedProperty["FeatureFlagDetails"] = "feature_flag_details";
458
- PostHogPersistedProperty["FeatureFlags"] = "feature_flags";
459
- PostHogPersistedProperty["FeatureFlagPayloads"] = "feature_flag_payloads";
460
- PostHogPersistedProperty["BootstrapFeatureFlagDetails"] = "bootstrap_feature_flag_details";
461
- PostHogPersistedProperty["BootstrapFeatureFlags"] = "bootstrap_feature_flags";
462
- PostHogPersistedProperty["BootstrapFeatureFlagPayloads"] = "bootstrap_feature_flag_payloads";
463
- PostHogPersistedProperty["OverrideFeatureFlags"] = "override_feature_flags";
464
- PostHogPersistedProperty["Queue"] = "queue";
465
- PostHogPersistedProperty["OptedOut"] = "opted_out";
466
- PostHogPersistedProperty["SessionId"] = "session_id";
467
- PostHogPersistedProperty["SessionStartTimestamp"] = "session_start_timestamp";
468
- PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
469
- PostHogPersistedProperty["PersonProperties"] = "person_properties";
470
- PostHogPersistedProperty["GroupProperties"] = "group_properties";
471
- PostHogPersistedProperty["InstalledAppBuild"] = "installed_app_build";
472
- PostHogPersistedProperty["InstalledAppVersion"] = "installed_app_version";
473
- PostHogPersistedProperty["SessionReplay"] = "session_replay";
474
- PostHogPersistedProperty["SurveyLastSeenDate"] = "survey_last_seen_date";
475
- PostHogPersistedProperty["SurveysSeen"] = "surveys_seen";
476
- PostHogPersistedProperty["Surveys"] = "surveys";
477
- PostHogPersistedProperty["RemoteConfig"] = "remote_config";
478
- PostHogPersistedProperty["FlagsEndpointWasHit"] = "flags_endpoint_was_hit";
479
- return PostHogPersistedProperty;
480
- })({});
481
311
  const DEFAULT_BLOCKED_UA_STRS = [
482
312
  "amazonbot",
483
313
  "amazonproductbot",
@@ -565,6 +395,37 @@ const isBlockedUA = function(ua, customBlockedUserAgents = []) {
565
395
  return -1 !== uaLower.indexOf(blockedUaLower);
566
396
  });
567
397
  };
398
+ var types_PostHogPersistedProperty = /* @__PURE__ */ (function(PostHogPersistedProperty) {
399
+ PostHogPersistedProperty["AnonymousId"] = "anonymous_id";
400
+ PostHogPersistedProperty["DistinctId"] = "distinct_id";
401
+ PostHogPersistedProperty["Props"] = "props";
402
+ PostHogPersistedProperty["EnablePersonProcessing"] = "enable_person_processing";
403
+ PostHogPersistedProperty["PersonMode"] = "person_mode";
404
+ PostHogPersistedProperty["FeatureFlagDetails"] = "feature_flag_details";
405
+ PostHogPersistedProperty["FeatureFlags"] = "feature_flags";
406
+ PostHogPersistedProperty["FeatureFlagPayloads"] = "feature_flag_payloads";
407
+ PostHogPersistedProperty["BootstrapFeatureFlagDetails"] = "bootstrap_feature_flag_details";
408
+ PostHogPersistedProperty["BootstrapFeatureFlags"] = "bootstrap_feature_flags";
409
+ PostHogPersistedProperty["BootstrapFeatureFlagPayloads"] = "bootstrap_feature_flag_payloads";
410
+ PostHogPersistedProperty["OverrideFeatureFlags"] = "override_feature_flags";
411
+ PostHogPersistedProperty["Queue"] = "queue";
412
+ PostHogPersistedProperty["OptedOut"] = "opted_out";
413
+ PostHogPersistedProperty["SessionId"] = "session_id";
414
+ PostHogPersistedProperty["SessionStartTimestamp"] = "session_start_timestamp";
415
+ PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
416
+ PostHogPersistedProperty["PersonProperties"] = "person_properties";
417
+ PostHogPersistedProperty["GroupProperties"] = "group_properties";
418
+ PostHogPersistedProperty["InstalledAppBuild"] = "installed_app_build";
419
+ PostHogPersistedProperty["InstalledAppVersion"] = "installed_app_version";
420
+ PostHogPersistedProperty["SessionReplay"] = "session_replay";
421
+ PostHogPersistedProperty["SurveyLastSeenDate"] = "survey_last_seen_date";
422
+ PostHogPersistedProperty["SurveysSeen"] = "surveys_seen";
423
+ PostHogPersistedProperty["Surveys"] = "surveys";
424
+ PostHogPersistedProperty["RemoteConfig"] = "remote_config";
425
+ PostHogPersistedProperty["FlagsEndpointWasHit"] = "flags_endpoint_was_hit";
426
+ PostHogPersistedProperty["DeviceId"] = "device_id";
427
+ return PostHogPersistedProperty;
428
+ })({});
568
429
  const nativeIsArray = Array.isArray;
569
430
  const ObjProto = Object.prototype;
570
431
  const type_utils_toString = ObjProto.toString;
@@ -572,7 +433,6 @@ const isArray = nativeIsArray || function(obj) {
572
433
  return "[object Array]" === type_utils_toString.call(obj);
573
434
  };
574
435
  const isObject = (x) => x === Object(x) && !isArray(x);
575
- const isUndefined = (x) => void 0 === x;
576
436
  const isString = (x) => "[object String]" == type_utils_toString.call(x);
577
437
  const isEmptyString = (x) => isString(x) && 0 === x.trim().length;
578
438
  const isNumber = (x) => "[object Number]" == type_utils_toString.call(x) && x === x;
@@ -584,7 +444,7 @@ function isBuiltin(candidate, className) {
584
444
  return Object.prototype.toString.call(candidate) === `[object ${className}]`;
585
445
  }
586
446
  function isEvent(candidate) {
587
- return !isUndefined(Event) && isInstanceOf(candidate, Event);
447
+ return "undefined" != typeof Event && isInstanceOf(candidate, Event);
588
448
  }
589
449
  function isPlainObject(candidate) {
590
450
  return isBuiltin(candidate, "Object");
@@ -651,6 +511,164 @@ class BucketedRateLimiter {
651
511
  this._buckets = {};
652
512
  }
653
513
  }
514
+ const DIGITS = "0123456789abcdef";
515
+ class UUID {
516
+ constructor(bytes) {
517
+ this.bytes = bytes;
518
+ }
519
+ static ofInner(bytes) {
520
+ if (16 === bytes.length) return new UUID(bytes);
521
+ throw new TypeError("not 128-bit length");
522
+ }
523
+ static fromFieldsV7(unixTsMs, randA, randBHi, randBLo) {
524
+ if (!Number.isInteger(unixTsMs) || !Number.isInteger(randA) || !Number.isInteger(randBHi) || !Number.isInteger(randBLo) || unixTsMs < 0 || randA < 0 || randBHi < 0 || randBLo < 0 || unixTsMs > 281474976710655 || randA > 4095 || randBHi > 1073741823 || randBLo > 4294967295) throw new RangeError("invalid field value");
525
+ const bytes = new Uint8Array(16);
526
+ bytes[0] = unixTsMs / 2 ** 40;
527
+ bytes[1] = unixTsMs / 2 ** 32;
528
+ bytes[2] = unixTsMs / 2 ** 24;
529
+ bytes[3] = unixTsMs / 2 ** 16;
530
+ bytes[4] = unixTsMs / 256;
531
+ bytes[5] = unixTsMs;
532
+ bytes[6] = 112 | randA >>> 8;
533
+ bytes[7] = randA;
534
+ bytes[8] = 128 | randBHi >>> 24;
535
+ bytes[9] = randBHi >>> 16;
536
+ bytes[10] = randBHi >>> 8;
537
+ bytes[11] = randBHi;
538
+ bytes[12] = randBLo >>> 24;
539
+ bytes[13] = randBLo >>> 16;
540
+ bytes[14] = randBLo >>> 8;
541
+ bytes[15] = randBLo;
542
+ return new UUID(bytes);
543
+ }
544
+ static parse(uuid) {
545
+ let hex;
546
+ switch (uuid.length) {
547
+ case 32:
548
+ hex = /^[0-9a-f]{32}$/i.exec(uuid)?.[0];
549
+ break;
550
+ case 36:
551
+ 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("");
552
+ break;
553
+ case 38:
554
+ 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("");
555
+ break;
556
+ case 45:
557
+ 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("");
558
+ break;
559
+ }
560
+ if (hex) {
561
+ const inner = new Uint8Array(16);
562
+ for (let i = 0; i < 16; i += 4) {
563
+ const n = parseInt(hex.substring(2 * i, 2 * i + 8), 16);
564
+ inner[i + 0] = n >>> 24;
565
+ inner[i + 1] = n >>> 16;
566
+ inner[i + 2] = n >>> 8;
567
+ inner[i + 3] = n;
568
+ }
569
+ return new UUID(inner);
570
+ }
571
+ throw new SyntaxError("could not parse UUID string");
572
+ }
573
+ toString() {
574
+ let text = "";
575
+ for (let i = 0; i < this.bytes.length; i++) {
576
+ text += DIGITS.charAt(this.bytes[i] >>> 4);
577
+ text += DIGITS.charAt(15 & this.bytes[i]);
578
+ if (3 === i || 5 === i || 7 === i || 9 === i) text += "-";
579
+ }
580
+ return text;
581
+ }
582
+ toHex() {
583
+ let text = "";
584
+ for (let i = 0; i < this.bytes.length; i++) {
585
+ text += DIGITS.charAt(this.bytes[i] >>> 4);
586
+ text += DIGITS.charAt(15 & this.bytes[i]);
587
+ }
588
+ return text;
589
+ }
590
+ toJSON() {
591
+ return this.toString();
592
+ }
593
+ getVariant() {
594
+ const n = this.bytes[8] >>> 4;
595
+ if (n < 0) throw new Error("unreachable");
596
+ if (n <= 7) return this.bytes.every((e) => 0 === e) ? "NIL" : "VAR_0";
597
+ if (n <= 11) return "VAR_10";
598
+ if (n <= 13) return "VAR_110";
599
+ if (n <= 15) return this.bytes.every((e) => 255 === e) ? "MAX" : "VAR_RESERVED";
600
+ else throw new Error("unreachable");
601
+ }
602
+ getVersion() {
603
+ return "VAR_10" === this.getVariant() ? this.bytes[6] >>> 4 : void 0;
604
+ }
605
+ clone() {
606
+ return new UUID(this.bytes.slice(0));
607
+ }
608
+ equals(other) {
609
+ return 0 === this.compareTo(other);
610
+ }
611
+ compareTo(other) {
612
+ for (let i = 0; i < 16; i++) {
613
+ const diff = this.bytes[i] - other.bytes[i];
614
+ if (0 !== diff) return Math.sign(diff);
615
+ }
616
+ return 0;
617
+ }
618
+ }
619
+ class V7Generator {
620
+ constructor(randomNumberGenerator) {
621
+ this.timestamp = 0;
622
+ this.counter = 0;
623
+ this.random = randomNumberGenerator ?? getDefaultRandom();
624
+ }
625
+ generate() {
626
+ return this.generateOrResetCore(Date.now(), 1e4);
627
+ }
628
+ generateOrAbort() {
629
+ return this.generateOrAbortCore(Date.now(), 1e4);
630
+ }
631
+ generateOrResetCore(unixTsMs, rollbackAllowance) {
632
+ let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
633
+ if (void 0 === value) {
634
+ this.timestamp = 0;
635
+ value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
636
+ }
637
+ return value;
638
+ }
639
+ generateOrAbortCore(unixTsMs, rollbackAllowance) {
640
+ const MAX_COUNTER = 4398046511103;
641
+ if (!Number.isInteger(unixTsMs) || unixTsMs < 1 || unixTsMs > 281474976710655) throw new RangeError("`unixTsMs` must be a 48-bit positive integer");
642
+ if (rollbackAllowance < 0 || rollbackAllowance > 281474976710655) throw new RangeError("`rollbackAllowance` out of reasonable range");
643
+ if (unixTsMs > this.timestamp) {
644
+ this.timestamp = unixTsMs;
645
+ this.resetCounter();
646
+ } else {
647
+ if (!(unixTsMs + rollbackAllowance >= this.timestamp)) return;
648
+ this.counter++;
649
+ if (this.counter > MAX_COUNTER) {
650
+ this.timestamp++;
651
+ this.resetCounter();
652
+ }
653
+ }
654
+ return UUID.fromFieldsV7(this.timestamp, Math.trunc(this.counter / 2 ** 30), this.counter & 2 ** 30 - 1, this.random.nextUint32());
655
+ }
656
+ resetCounter() {
657
+ this.counter = 1024 * this.random.nextUint32() + (1023 & this.random.nextUint32());
658
+ }
659
+ generateV4() {
660
+ const bytes = new Uint8Array(Uint32Array.of(this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32()).buffer);
661
+ bytes[6] = 64 | bytes[6] >>> 4;
662
+ bytes[8] = 128 | bytes[8] >>> 2;
663
+ return UUID.ofInner(bytes);
664
+ }
665
+ }
666
+ const getDefaultRandom = () => ({
667
+ nextUint32: () => 65536 * Math.trunc(65536 * Math.random()) + Math.trunc(65536 * Math.random())
668
+ });
669
+ let defaultGenerator;
670
+ const uuidv7 = () => uuidv7obj().toString();
671
+ const uuidv7obj = () => (defaultGenerator || (defaultGenerator = new V7Generator())).generate();
654
672
  class PromiseQueue {
655
673
  add(promise) {
656
674
  const promiseUUID = uuidv7();
@@ -715,13 +733,6 @@ function createLogger(prefix, maybeCall = passThrough) {
715
733
  return _createLogger(prefix, maybeCall, createConsole());
716
734
  }
717
735
  const STRING_FORMAT = "utf8";
718
- function assert(truthyValue, message) {
719
- if (!truthyValue || "string" != typeof truthyValue || isEmpty(truthyValue)) throw new Error(message);
720
- }
721
- function isEmpty(truthyValue) {
722
- if (0 === truthyValue.trim().length) return true;
723
- return false;
724
- }
725
736
  function removeTrailingSlash(url) {
726
737
  return url?.replace(/\/+$/, "");
727
738
  }
@@ -774,23 +785,6 @@ class SimpleEventEmitter {
774
785
  for (const listener of this.events["*"] || []) listener(event, payload);
775
786
  }
776
787
  }
777
- function isGzipSupported() {
778
- return "CompressionStream" in globalThis;
779
- }
780
- async function gzipCompress(input, isDebug = true) {
781
- try {
782
- const dataStream = new Blob([
783
- input
784
- ], {
785
- type: "text/plain"
786
- }).stream();
787
- const compressedStream = dataStream.pipeThrough(new CompressionStream("gzip"));
788
- return await new Response(compressedStream).blob();
789
- } catch (error) {
790
- if (isDebug) console.error("Failed to gzip compress data", error);
791
- return null;
792
- }
793
- }
794
788
  class PostHogFetchHttpError extends Error {
795
789
  constructor(response, reqByteLength) {
796
790
  super("HTTP error while fetching PostHog: status=" + response.status + ", reqByteLength=" + reqByteLength), this.response = response, this.reqByteLength = reqByteLength, this.name = "PostHogFetchHttpError";
@@ -836,9 +830,13 @@ class PostHogCoreStateless {
836
830
  this.promiseQueue = new PromiseQueue();
837
831
  this._events = new SimpleEventEmitter();
838
832
  this._isInitialized = false;
839
- assert(apiKey, "You must pass your PostHog project's api key.");
840
- this.apiKey = apiKey;
841
- this.host = removeTrailingSlash(options.host || "https://us.i.posthog.com");
833
+ const normalizedApiKey = "string" == typeof apiKey ? apiKey.trim() : "";
834
+ const normalizedHost = "string" == typeof options.host ? options.host.trim() : "";
835
+ const missingApiKey = !normalizedApiKey;
836
+ this._logger = createLogger("[PostHog]", this.logMsgIfDebug.bind(this));
837
+ if (missingApiKey) this._logger.error("You must pass your PostHog project's api key. The client will be disabled.");
838
+ this.apiKey = normalizedApiKey;
839
+ this.host = removeTrailingSlash(normalizedHost || "https://us.i.posthog.com");
842
840
  this.flushAt = options.flushAt ? Math.max(options.flushAt, 1) : 20;
843
841
  this.maxBatchSize = Math.max(this.flushAt, options.maxBatchSize ?? 100);
844
842
  this.maxQueueSize = Math.max(this.flushAt, options.maxQueueSize ?? 1e3);
@@ -855,11 +853,10 @@ class PostHogCoreStateless {
855
853
  this.featureFlagsRequestTimeoutMs = options.featureFlagsRequestTimeoutMs ?? 3e3;
856
854
  this.remoteConfigRequestTimeoutMs = options.remoteConfigRequestTimeoutMs ?? 3e3;
857
855
  this.disableGeoip = options.disableGeoip ?? true;
858
- this.disabled = options.disabled ?? false;
856
+ this.disabled = (options.disabled ?? false) || missingApiKey;
859
857
  this.historicalMigration = options?.historicalMigration ?? false;
860
858
  this._initPromise = Promise.resolve();
861
859
  this._isInitialized = true;
862
- this._logger = createLogger("[PostHog]", this.logMsgIfDebug.bind(this));
863
860
  this.evaluationContexts = options?.evaluationContexts ?? options?.evaluationEnvironments;
864
861
  if (options?.evaluationEnvironments && !options?.evaluationContexts) this._logger.warn("evaluationEnvironments is deprecated. Use evaluationContexts instead. This property will be removed in a future version.");
865
862
  this.disableCompression = !isGzipSupported() || (options?.disableCompression ?? false);
@@ -1024,7 +1021,7 @@ class PostHogCoreStateless {
1024
1021
  this._events.emit("error", error);
1025
1022
  });
1026
1023
  }
1027
- async getFlags(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}, fetchConfig = true) {
1024
+ async getFlags(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}, fetchConfig = false) {
1028
1025
  await this._initPromise;
1029
1026
  const configParam = fetchConfig ? "&config=true" : "";
1030
1027
  const url = `${this.host}/flags/?v=2${configParam}`;
@@ -1036,6 +1033,7 @@ class PostHogCoreStateless {
1036
1033
  group_properties: groupProperties,
1037
1034
  ...extraPayload
1038
1035
  };
1036
+ if (personProperties.$device_id) requestData.$device_id = personProperties.$device_id;
1039
1037
  if (this.evaluationContexts && this.evaluationContexts.length > 0) requestData.evaluation_contexts = this.evaluationContexts;
1040
1038
  const fetchOptions = {
1041
1039
  method: "POST",
@@ -1383,11 +1381,6 @@ class PostHogCoreStateless {
1383
1381
  this._events.emit("flush", sentMessages);
1384
1382
  }
1385
1383
  async fetchWithRetry(url, options, retryOptions, requestTimeout) {
1386
- AbortSignal.timeout ??= function(ms) {
1387
- const ctrl = new AbortController();
1388
- setTimeout(() => ctrl.abort(), ms);
1389
- return ctrl.signal;
1390
- };
1391
1384
  const body = options.body ? options.body : "";
1392
1385
  let reqByteLength = -1;
1393
1386
  try {
@@ -1400,14 +1393,19 @@ class PostHogCoreStateless {
1400
1393
  }
1401
1394
  }
1402
1395
  return await retriable(async () => {
1396
+ const ctrl = new AbortController();
1397
+ const timeoutMs = requestTimeout ?? this.requestTimeout;
1398
+ const timer = safeSetTimeout(() => ctrl.abort(), timeoutMs);
1403
1399
  let res = null;
1404
1400
  try {
1405
1401
  res = await this.fetch(url, {
1406
- signal: AbortSignal.timeout(requestTimeout ?? this.requestTimeout),
1402
+ signal: ctrl.signal,
1407
1403
  ...options
1408
1404
  });
1409
1405
  } catch (e) {
1410
1406
  throw new PostHogFetchNetworkError(e);
1407
+ } finally {
1408
+ clearTimeout(timer);
1411
1409
  }
1412
1410
  const isNoCors = "no-cors" === options.mode;
1413
1411
  if (!isNoCors && (res.status < 200 || res.status >= 400)) throw new PostHogFetchHttpError(res, reqByteLength);
@@ -1435,16 +1433,21 @@ class PostHogCoreStateless {
1435
1433
  await logFlushError(e);
1436
1434
  }
1437
1435
  };
1438
- return Promise.race([
1439
- new Promise((_, reject) => {
1440
- safeSetTimeout(() => {
1441
- this._logger.error("Timed out while shutting down PostHog");
1442
- hasTimedOut = true;
1443
- reject("Timeout while shutting down PostHog. Some events may not have been sent.");
1444
- }, shutdownTimeoutMs);
1445
- }),
1446
- doShutdown()
1447
- ]);
1436
+ let timeoutHandle;
1437
+ try {
1438
+ return await Promise.race([
1439
+ new Promise((_, reject) => {
1440
+ timeoutHandle = safeSetTimeout(() => {
1441
+ this._logger.error("Timed out while shutting down PostHog");
1442
+ hasTimedOut = true;
1443
+ reject("Timeout while shutting down PostHog. Some events may not have been sent.");
1444
+ }, shutdownTimeoutMs);
1445
+ }),
1446
+ doShutdown()
1447
+ ]);
1448
+ } finally {
1449
+ clearTimeout(timeoutHandle);
1450
+ }
1448
1451
  }
1449
1452
  async shutdown(shutdownTimeoutMs = 3e4) {
1450
1453
  if (this.shutdownPromise) this._logger.warn("shutdown() called while already shutting down. shutdown() is meant to be called once before process exit - use flush() for per-request cleanup");
@@ -2051,6 +2054,17 @@ function snipLine(line, colno) {
2051
2054
  if (end < lineLength) newLine += "...";
2052
2055
  return newLine;
2053
2056
  }
2057
+ function createRelativePathModifier(basePath = process.cwd()) {
2058
+ const isWindows = "\\" === sep;
2059
+ const toUnix = (p) => isWindows ? p.replace(/\\/g, "/") : p;
2060
+ const normalizedBase = toUnix(basePath);
2061
+ return async (frames) => {
2062
+ for (const frame of frames) if (!(!frame.filename || frame.filename.startsWith("node:") || frame.filename.startsWith("data:"))) {
2063
+ if (isAbsolute(frame.filename)) frame.filename = toUnix(relative(normalizedBase, toUnix(frame.filename)));
2064
+ }
2065
+ return frames;
2066
+ };
2067
+ }
2054
2068
  function makeUncaughtExceptionHandler(captureFn, onFatalFn) {
2055
2069
  let calledFatalError = false;
2056
2070
  return Object.assign((error) => {
@@ -2102,12 +2116,11 @@ class ErrorTracking {
2102
2116
  const properties = {
2103
2117
  ...additionalProperties
2104
2118
  };
2105
- if (!distinctId) properties.$process_person_profile = false;
2106
2119
  const exceptionProperties = this.errorPropertiesBuilder.buildFromUnknown(error, hint);
2107
2120
  exceptionProperties.$exception_list = await this.errorPropertiesBuilder.modifyFrames(exceptionProperties.$exception_list);
2108
2121
  return {
2109
2122
  event: "$exception",
2110
- distinctId: distinctId || uuidv7(),
2123
+ distinctId,
2111
2124
  properties: {
2112
2125
  ...exceptionProperties,
2113
2126
  ...properties
@@ -2147,7 +2160,7 @@ class ErrorTracking {
2147
2160
  this._rateLimiter.stop();
2148
2161
  }
2149
2162
  }
2150
- const version = "5.26.0";
2163
+ const version = "5.30.1";
2151
2164
  const FeatureFlagError = {
2152
2165
  ERRORS_WHILE_COMPUTING: "errors_while_computing_flags",
2153
2166
  FLAG_MISSING: "flag_missing",
@@ -2476,6 +2489,9 @@ class FeatureFlagsPoller {
2476
2489
  isLocalEvaluationReady() {
2477
2490
  return (this.loadedSuccessfullyOnce ?? false) && (this.featureFlags?.length ?? 0) > 0;
2478
2491
  }
2492
+ getFlagDefinitionsLoadedAt() {
2493
+ return this.flagDefinitionsLoadedAt;
2494
+ }
2479
2495
  getPollingInterval() {
2480
2496
  if (!this.shouldBeginExponentialBackoff) return this.pollingInterval;
2481
2497
  return Math.min(SIXTY_SECONDS, this.pollingInterval * 2 ** this.backOffCount);
@@ -2543,6 +2559,7 @@ class FeatureFlagsPoller {
2543
2559
  cohorts: responseJson.cohorts || {}
2544
2560
  };
2545
2561
  this.updateFlagState(flagData);
2562
+ this.flagDefinitionsLoadedAt = Date.now();
2546
2563
  this.clearBackoff();
2547
2564
  if (this.cacheProvider && shouldFetch) try {
2548
2565
  await this.cacheProvider.onFlagDefinitionsReceived(flagData);
@@ -2573,7 +2590,7 @@ class FeatureFlagsPoller {
2573
2590
  };
2574
2591
  }
2575
2592
  _requestFeatureFlagDefinitions() {
2576
- const url = `${this.host}/api/feature_flag/local_evaluation?token=${this.projectApiKey}&send_cohorts`;
2593
+ const url = `${this.host}/flags/definitions?token=${this.projectApiKey}&send_cohorts`;
2577
2594
  const options = this.getPersonalApiKeyRequestOptions("GET", this.flagsEtag);
2578
2595
  let abortTimeout = null;
2579
2596
  if (this.timeout && "number" == typeof this.timeout) {
@@ -2670,6 +2687,45 @@ function matchProperty(property, propertyValues, warnFunction) {
2670
2687
  ].includes(operator)) return overrideDate < parsedDate;
2671
2688
  return overrideDate > parsedDate;
2672
2689
  }
2690
+ case "semver_eq": {
2691
+ const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
2692
+ return 0 === cmp;
2693
+ }
2694
+ case "semver_neq": {
2695
+ const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
2696
+ return 0 !== cmp;
2697
+ }
2698
+ case "semver_gt": {
2699
+ const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
2700
+ return cmp > 0;
2701
+ }
2702
+ case "semver_gte": {
2703
+ const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
2704
+ return cmp >= 0;
2705
+ }
2706
+ case "semver_lt": {
2707
+ const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
2708
+ return cmp < 0;
2709
+ }
2710
+ case "semver_lte": {
2711
+ const cmp = compareSemverTuples(parseSemver(String(overrideValue)), parseSemver(String(value)));
2712
+ return cmp <= 0;
2713
+ }
2714
+ case "semver_tilde": {
2715
+ const overrideParsed = parseSemver(String(overrideValue));
2716
+ const { lower, upper } = computeTildeBounds(String(value));
2717
+ return compareSemverTuples(overrideParsed, lower) >= 0 && compareSemverTuples(overrideParsed, upper) < 0;
2718
+ }
2719
+ case "semver_caret": {
2720
+ const overrideParsed = parseSemver(String(overrideValue));
2721
+ const { lower, upper } = computeCaretBounds(String(value));
2722
+ return compareSemverTuples(overrideParsed, lower) >= 0 && compareSemverTuples(overrideParsed, upper) < 0;
2723
+ }
2724
+ case "semver_wildcard": {
2725
+ const overrideParsed = parseSemver(String(overrideValue));
2726
+ const { lower, upper } = computeWildcardBounds(String(value));
2727
+ return compareSemverTuples(overrideParsed, lower) >= 0 && compareSemverTuples(overrideParsed, upper) < 0;
2728
+ }
2673
2729
  default:
2674
2730
  throw new InconclusiveMatchError(`Unknown operator: ${operator}`);
2675
2731
  }
@@ -2738,6 +2794,115 @@ function isValidRegex(regex) {
2738
2794
  return false;
2739
2795
  }
2740
2796
  }
2797
+ function parseSemver(value) {
2798
+ const text = String(value).trim().replace(/^[vV]/, "");
2799
+ const baseVersion = text.split("-")[0].split("+")[0];
2800
+ if (!baseVersion || baseVersion.startsWith(".")) throw new InconclusiveMatchError(`Invalid semver: ${value}`);
2801
+ const parts = baseVersion.split(".");
2802
+ const parsePart = (part) => {
2803
+ if (void 0 === part || "" === part) return 0;
2804
+ if (!/^\d+$/.test(part)) throw new InconclusiveMatchError(`Invalid semver: ${value}`);
2805
+ return parseInt(part, 10);
2806
+ };
2807
+ const major = parsePart(parts[0]);
2808
+ const minor = parsePart(parts[1]);
2809
+ const patch = parsePart(parts[2]);
2810
+ return [
2811
+ major,
2812
+ minor,
2813
+ patch
2814
+ ];
2815
+ }
2816
+ function compareSemverTuples(a, b) {
2817
+ for (let i = 0; i < 3; i++) {
2818
+ if (a[i] < b[i]) return -1;
2819
+ if (a[i] > b[i]) return 1;
2820
+ }
2821
+ return 0;
2822
+ }
2823
+ function computeTildeBounds(value) {
2824
+ const parsed = parseSemver(value);
2825
+ const lower = [
2826
+ parsed[0],
2827
+ parsed[1],
2828
+ parsed[2]
2829
+ ];
2830
+ const upper = [
2831
+ parsed[0],
2832
+ parsed[1] + 1,
2833
+ 0
2834
+ ];
2835
+ return {
2836
+ lower,
2837
+ upper
2838
+ };
2839
+ }
2840
+ function computeCaretBounds(value) {
2841
+ const parsed = parseSemver(value);
2842
+ const [major, minor, patch] = parsed;
2843
+ const lower = [
2844
+ major,
2845
+ minor,
2846
+ patch
2847
+ ];
2848
+ let upper;
2849
+ upper = major > 0 ? [
2850
+ major + 1,
2851
+ 0,
2852
+ 0
2853
+ ] : minor > 0 ? [
2854
+ 0,
2855
+ minor + 1,
2856
+ 0
2857
+ ] : [
2858
+ 0,
2859
+ 0,
2860
+ patch + 1
2861
+ ];
2862
+ return {
2863
+ lower,
2864
+ upper
2865
+ };
2866
+ }
2867
+ function computeWildcardBounds(value) {
2868
+ const text = String(value).trim().replace(/^[vV]/, "");
2869
+ const cleanedText = text.replace(/\.\*$/, "").replace(/\*$/, "");
2870
+ if (!cleanedText) throw new InconclusiveMatchError(`Invalid wildcard semver: ${value}`);
2871
+ const parts = cleanedText.split(".");
2872
+ const major = parseInt(parts[0], 10);
2873
+ if (isNaN(major)) throw new InconclusiveMatchError(`Invalid wildcard semver: ${value}`);
2874
+ let lower;
2875
+ let upper;
2876
+ if (1 === parts.length) {
2877
+ lower = [
2878
+ major,
2879
+ 0,
2880
+ 0
2881
+ ];
2882
+ upper = [
2883
+ major + 1,
2884
+ 0,
2885
+ 0
2886
+ ];
2887
+ } else {
2888
+ const minor = parseInt(parts[1], 10);
2889
+ if (isNaN(minor)) throw new InconclusiveMatchError(`Invalid wildcard semver: ${value}`);
2890
+ lower = [
2891
+ major,
2892
+ minor,
2893
+ 0
2894
+ ];
2895
+ upper = [
2896
+ major,
2897
+ minor + 1,
2898
+ 0
2899
+ ];
2900
+ }
2901
+ return {
2902
+ lower,
2903
+ upper
2904
+ };
2905
+ }
2741
2906
  function convertToDateTime(value) {
2742
2907
  if (value instanceof Date) return value;
2743
2908
  if ("string" == typeof value || "number" == typeof value) {
@@ -2782,22 +2947,44 @@ class PostHogMemoryStorage {
2782
2947
  const MINIMUM_POLLING_INTERVAL = 100;
2783
2948
  const THIRTY_SECONDS = 3e4;
2784
2949
  const MAX_CACHE_SIZE = 5e4;
2950
+ const WAITUNTIL_DEBOUNCE_MS = 50;
2951
+ const WAITUNTIL_MAX_WAIT_MS = 500;
2952
+ const DEFAULT_NODE_HOST = "https://us.i.posthog.com";
2953
+ function normalizeApiKey(value) {
2954
+ return "string" == typeof value ? value.trim() : "";
2955
+ }
2956
+ function normalizePersonalApiKey(value) {
2957
+ const normalizedValue = "string" == typeof value ? value.trim() : "";
2958
+ return normalizedValue || void 0;
2959
+ }
2960
+ function normalizeHost(value) {
2961
+ const normalizedValue = "string" == typeof value ? value.trim() : "";
2962
+ return normalizedValue || DEFAULT_NODE_HOST;
2963
+ }
2785
2964
  class PostHogBackendClient extends PostHogCoreStateless {
2786
2965
  constructor(apiKey, options = {}) {
2787
- super(apiKey, options), this._memoryStorage = new PostHogMemoryStorage();
2788
- this.options = options;
2966
+ const normalizedApiKey = normalizeApiKey(apiKey);
2967
+ const normalizedOptions = {
2968
+ ...options,
2969
+ host: normalizeHost(options.host),
2970
+ personalApiKey: normalizePersonalApiKey(options.personalApiKey)
2971
+ };
2972
+ super(normalizedApiKey, normalizedOptions), this._memoryStorage = new PostHogMemoryStorage();
2973
+ this.options = normalizedOptions;
2789
2974
  this.context = this.initializeContext();
2790
- this.options.featureFlagsPollingInterval = "number" == typeof options.featureFlagsPollingInterval ? Math.max(options.featureFlagsPollingInterval, MINIMUM_POLLING_INTERVAL) : THIRTY_SECONDS;
2791
- if (options.personalApiKey) {
2792
- if (options.personalApiKey.includes("phc_")) throw new Error('Your Personal API key is invalid. These keys are prefixed with "phx_" and can be created in PostHog project settings.');
2793
- const shouldEnableLocalEvaluation = false !== options.enableLocalEvaluation;
2975
+ this.options.featureFlagsPollingInterval = "number" == typeof normalizedOptions.featureFlagsPollingInterval ? Math.max(normalizedOptions.featureFlagsPollingInterval, MINIMUM_POLLING_INTERVAL) : THIRTY_SECONDS;
2976
+ if ("number" == typeof normalizedOptions.waitUntilDebounceMs) this.options.waitUntilDebounceMs = Math.max(normalizedOptions.waitUntilDebounceMs, 0);
2977
+ if ("number" == typeof normalizedOptions.waitUntilMaxWaitMs) this.options.waitUntilMaxWaitMs = Math.max(normalizedOptions.waitUntilMaxWaitMs, 0);
2978
+ if (normalizedOptions.personalApiKey) {
2979
+ if (normalizedOptions.personalApiKey.includes("phc_")) throw new Error('Your Personal API key is invalid. These keys are prefixed with "phx_" and can be created in PostHog project settings.');
2980
+ const shouldEnableLocalEvaluation = false !== normalizedOptions.enableLocalEvaluation;
2794
2981
  if (shouldEnableLocalEvaluation) this.featureFlagsPoller = new FeatureFlagsPoller({
2795
2982
  pollingInterval: this.options.featureFlagsPollingInterval,
2796
- personalApiKey: options.personalApiKey,
2797
- projectApiKey: apiKey,
2798
- timeout: options.requestTimeout ?? 1e4,
2983
+ personalApiKey: normalizedOptions.personalApiKey,
2984
+ projectApiKey: normalizedApiKey,
2985
+ timeout: normalizedOptions.requestTimeout ?? 1e4,
2799
2986
  host: this.host,
2800
- fetch: options.fetch,
2987
+ fetch: normalizedOptions.fetch,
2801
2988
  onError: (err) => {
2802
2989
  this._events.emit("error", err);
2803
2990
  },
@@ -2805,13 +2992,74 @@ class PostHogBackendClient extends PostHogCoreStateless {
2805
2992
  this._events.emit("localEvaluationFlagsLoaded", count);
2806
2993
  },
2807
2994
  customHeaders: this.getCustomHeaders(),
2808
- cacheProvider: options.flagDefinitionCacheProvider,
2809
- strictLocalEvaluation: options.strictLocalEvaluation
2995
+ cacheProvider: normalizedOptions.flagDefinitionCacheProvider,
2996
+ strictLocalEvaluation: normalizedOptions.strictLocalEvaluation
2810
2997
  });
2811
2998
  }
2812
- this.errorTracking = new ErrorTracking(this, options, this._logger);
2999
+ this.errorTracking = new ErrorTracking(this, normalizedOptions, this._logger);
2813
3000
  this.distinctIdHasSentFlagCalls = {};
2814
- this.maxCacheSize = options.maxCacheSize || MAX_CACHE_SIZE;
3001
+ this.maxCacheSize = normalizedOptions.maxCacheSize || MAX_CACHE_SIZE;
3002
+ }
3003
+ enqueue(type, message, options) {
3004
+ super.enqueue(type, message, options);
3005
+ this.scheduleDebouncedFlush();
3006
+ }
3007
+ async flush() {
3008
+ const flushPromise = super.flush();
3009
+ const waitUntil = this.options.waitUntil;
3010
+ if (waitUntil && !this._waitUntilCycle) try {
3011
+ waitUntil(flushPromise.catch(() => {
3012
+ }));
3013
+ } catch {
3014
+ }
3015
+ return flushPromise;
3016
+ }
3017
+ scheduleDebouncedFlush() {
3018
+ const waitUntil = this.options.waitUntil;
3019
+ if (!waitUntil) return;
3020
+ if (this.disabled || this.optedOut) return;
3021
+ if (!this._waitUntilCycle) {
3022
+ let resolve;
3023
+ const promise = new Promise((r) => {
3024
+ resolve = r;
3025
+ });
3026
+ try {
3027
+ waitUntil(promise);
3028
+ } catch {
3029
+ return;
3030
+ }
3031
+ this._waitUntilCycle = {
3032
+ resolve,
3033
+ startedAt: Date.now(),
3034
+ timer: void 0
3035
+ };
3036
+ }
3037
+ const elapsed = Date.now() - this._waitUntilCycle.startedAt;
3038
+ const maxWaitMs = this.options.waitUntilMaxWaitMs ?? WAITUNTIL_MAX_WAIT_MS;
3039
+ const flushNow = elapsed >= maxWaitMs;
3040
+ if (void 0 !== this._waitUntilCycle.timer) clearTimeout(this._waitUntilCycle.timer);
3041
+ if (flushNow) return void this.resolveWaitUntilFlush();
3042
+ const debounceMs = this.options.waitUntilDebounceMs ?? WAITUNTIL_DEBOUNCE_MS;
3043
+ this._waitUntilCycle.timer = safeSetTimeout(() => {
3044
+ this.resolveWaitUntilFlush();
3045
+ }, debounceMs);
3046
+ }
3047
+ _consumeWaitUntilCycle() {
3048
+ const cycle = this._waitUntilCycle;
3049
+ if (cycle) {
3050
+ clearTimeout(cycle.timer);
3051
+ this._waitUntilCycle = void 0;
3052
+ }
3053
+ return cycle?.resolve;
3054
+ }
3055
+ async resolveWaitUntilFlush() {
3056
+ const resolve = this._consumeWaitUntilCycle();
3057
+ try {
3058
+ await super.flush();
3059
+ } catch {
3060
+ } finally {
3061
+ resolve?.();
3062
+ }
2815
3063
  }
2816
3064
  getPersistedProperty(key) {
2817
3065
  return this._memoryStorage.getProperty(key);
@@ -3028,8 +3276,12 @@ class PostHogBackendClient extends PostHogCoreStateless {
3028
3276
  locally_evaluated: flagWasLocallyEvaluated,
3029
3277
  [`$feature/${key}`]: response,
3030
3278
  $feature_flag_request_id: requestId,
3031
- $feature_flag_evaluated_at: evaluatedAt
3279
+ $feature_flag_evaluated_at: flagWasLocallyEvaluated ? Date.now() : evaluatedAt
3032
3280
  };
3281
+ if (flagWasLocallyEvaluated && this.featureFlagsPoller) {
3282
+ const flagDefinitionsLoadedAt = this.featureFlagsPoller.getFlagDefinitionsLoadedAt();
3283
+ if (void 0 !== flagDefinitionsLoadedAt) properties.$feature_flag_definitions_loaded_at = flagDefinitionsLoadedAt;
3284
+ }
3033
3285
  if (featureFlagError) properties.$feature_flag_error = featureFlagError;
3034
3286
  this.capture({
3035
3287
  distinctId,
@@ -3212,9 +3464,14 @@ class PostHogBackendClient extends PostHogCoreStateless {
3212
3464
  this.context?.enter(data, options);
3213
3465
  }
3214
3466
  async _shutdown(shutdownTimeoutMs) {
3215
- this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
3467
+ const resolve = this._consumeWaitUntilCycle();
3468
+ await this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
3216
3469
  this.errorTracking.shutdown();
3217
- return super._shutdown(shutdownTimeoutMs);
3470
+ try {
3471
+ return await super._shutdown(shutdownTimeoutMs);
3472
+ } finally {
3473
+ resolve?.();
3474
+ }
3218
3475
  }
3219
3476
  async _requestRemoteConfigPayload(flagKey) {
3220
3477
  if (!this.options.personalApiKey) return;
@@ -3331,7 +3588,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
3331
3588
  async captureExceptionImmediate(error, distinctId, additionalProperties) {
3332
3589
  if (!ErrorTracking.isPreviouslyCapturedError(error)) {
3333
3590
  const syntheticException = new Error("PostHog syntheticException");
3334
- this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
3591
+ return this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
3335
3592
  syntheticException
3336
3593
  }, distinctId, additionalProperties).then((msg) => this.captureImmediate(msg)));
3337
3594
  }
@@ -3484,7 +3741,8 @@ ErrorTracking.errorPropertiesBuilder = new ErrorPropertiesBuilder([
3484
3741
  new PrimitiveCoercer()
3485
3742
  ], createStackParser("node:javascript", nodeStackLineParser), [
3486
3743
  createModulerModifier(),
3487
- addSourceContext
3744
+ addSourceContext,
3745
+ createRelativePathModifier()
3488
3746
  ]);
3489
3747
  class PostHog extends PostHogBackendClient {
3490
3748
  getLibraryId() {
@@ -3815,30 +4073,30 @@ const shutdownSession = async (session2) => {
3815
4073
  };
3816
4074
  const toPosixPath = (input) => input.split(path.sep).join("/");
3817
4075
  const isSubpath = (candidate, root) => {
3818
- const relative = path.relative(root, candidate);
3819
- return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
4076
+ const relative2 = path.relative(root, candidate);
4077
+ return relative2 === "" || !relative2.startsWith("..") && !path.isAbsolute(relative2);
3820
4078
  };
3821
4079
  const classifyServerTarget = (absolutePath, projectRoot) => {
3822
4080
  if (!isSubpath(absolutePath, projectRoot)) {
3823
4081
  return "ssr";
3824
4082
  }
3825
- const relative = toPosixPath(path.relative(projectRoot, absolutePath));
3826
- if (relative.startsWith("src/api/") || relative.includes("/src/api/")) {
4083
+ const relative2 = toPosixPath(path.relative(projectRoot, absolutePath));
4084
+ if (relative2.startsWith("src/api/") || relative2.includes("/src/api/")) {
3827
4085
  return "api";
3828
4086
  }
3829
- if (relative.startsWith("src/worker/") || relative.includes("/src/worker/")) {
4087
+ if (relative2.startsWith("src/worker/") || relative2.includes("/src/worker/")) {
3830
4088
  return "worker";
3831
4089
  }
3832
- if (relative.startsWith("src/server/") || relative.includes("/src/server/")) {
4090
+ if (relative2.startsWith("src/server/") || relative2.includes("/src/server/")) {
3833
4091
  return "ssr";
3834
4092
  }
3835
- if (relative.startsWith("build/dist/api/") || relative.includes("/build/dist/api/")) {
4093
+ if (relative2.startsWith("build/dist/api/") || relative2.includes("/build/dist/api/")) {
3836
4094
  return "api";
3837
4095
  }
3838
- if (relative.startsWith("build/dist/worker/") || relative.includes("/build/dist/worker/")) {
4096
+ if (relative2.startsWith("build/dist/worker/") || relative2.includes("/build/dist/worker/")) {
3839
4097
  return "worker";
3840
4098
  }
3841
- if (relative.startsWith("build/dist/ssr/") || relative.includes("/build/dist/ssr/")) {
4099
+ if (relative2.startsWith("build/dist/ssr/") || relative2.includes("/build/dist/ssr/")) {
3842
4100
  return "ssr";
3843
4101
  }
3844
4102
  return "ssr";
@@ -3981,26 +4239,17 @@ process.env = {
3981
4239
  };
3982
4240
  const isProduction$1 = process.env.NODE_ENV === "production";
3983
4241
  const SESSION_MAX_AGE_S = 3600 * 24 * 60;
3984
- const getMongoUrl = (serverEnv) => {
3985
- const explicitUrl = serverEnv.MONGODB_URL || serverEnv.MONGO_URL || serverEnv.MONGODB_URI || serverEnv.DB_URL;
3986
- if (explicitUrl) {
3987
- return explicitUrl;
3988
- }
3989
- if (serverEnv.DB_PORT) {
3990
- const host = serverEnv.DB_HOST ?? "localhost";
3991
- const appName = serverEnv.APP_NAME?.trim();
3992
- if (!appName) {
3993
- throw new Error("Missing APP_NAME (required to build MongoDB session store DB name)");
3994
- }
3995
- return `mongodb://${host}:${serverEnv.DB_PORT}/${appName}-sessions`;
4242
+ const getMongoSessionUrl = (serverEnv) => {
4243
+ const appName = serverEnv.APP_NAME?.trim();
4244
+ if (!appName) {
4245
+ throw new Error("Missing APP_NAME (required to build MongoDB session store DB name)");
3996
4246
  }
3997
- return void 0;
4247
+ return getMongoUrl(serverEnv, {
4248
+ dbName: `${appName}-sessions`
4249
+ });
3998
4250
  };
3999
4251
  const createMongoSessionStore = async (serverEnv) => {
4000
- const mongoUrl = getMongoUrl(serverEnv);
4001
- if (!mongoUrl) {
4002
- throw new Error("Missing REDIS_URL and Mongo connection details (MONGODB_URL/MONGO_URL/MONGODB_URI/DB_PORT)");
4003
- }
4252
+ const mongoUrl = getMongoSessionUrl(serverEnv);
4004
4253
  console.log("Using MongoDB session store");
4005
4254
  const client2 = await MongoClient.connect(mongoUrl, {
4006
4255
  family: 4,