@rpcbase/server 0.547.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
@@ -6,7 +6,7 @@ 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
8
  import { getMongoUrl } from "@rpcbase/db/mongo";
9
- import { posix, dirname, sep } from "path";
9
+ import { posix, dirname, sep, isAbsolute, relative } from "path";
10
10
  import fs, { createReadStream, readFileSync } from "node:fs";
11
11
  import { createInterface } from "node:readline";
12
12
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -291,194 +291,23 @@ const parsePayload = (response) => {
291
291
  return response;
292
292
  }
293
293
  };
294
- const DIGITS = "0123456789abcdef";
295
- class UUID {
296
- constructor(bytes) {
297
- this.bytes = bytes;
298
- }
299
- static ofInner(bytes) {
300
- if (16 === bytes.length) return new UUID(bytes);
301
- throw new TypeError("not 128-bit length");
302
- }
303
- static fromFieldsV7(unixTsMs, randA, randBHi, randBLo) {
304
- 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");
305
- const bytes = new Uint8Array(16);
306
- bytes[0] = unixTsMs / 2 ** 40;
307
- bytes[1] = unixTsMs / 2 ** 32;
308
- bytes[2] = unixTsMs / 2 ** 24;
309
- bytes[3] = unixTsMs / 2 ** 16;
310
- bytes[4] = unixTsMs / 256;
311
- bytes[5] = unixTsMs;
312
- bytes[6] = 112 | randA >>> 8;
313
- bytes[7] = randA;
314
- bytes[8] = 128 | randBHi >>> 24;
315
- bytes[9] = randBHi >>> 16;
316
- bytes[10] = randBHi >>> 8;
317
- bytes[11] = randBHi;
318
- bytes[12] = randBLo >>> 24;
319
- bytes[13] = randBLo >>> 16;
320
- bytes[14] = randBLo >>> 8;
321
- bytes[15] = randBLo;
322
- return new UUID(bytes);
323
- }
324
- static parse(uuid) {
325
- let hex;
326
- switch (uuid.length) {
327
- case 32:
328
- hex = /^[0-9a-f]{32}$/i.exec(uuid)?.[0];
329
- break;
330
- case 36:
331
- 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("");
332
- break;
333
- case 38:
334
- 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("");
335
- break;
336
- case 45:
337
- 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("");
338
- break;
339
- }
340
- if (hex) {
341
- const inner = new Uint8Array(16);
342
- for (let i = 0; i < 16; i += 4) {
343
- const n = parseInt(hex.substring(2 * i, 2 * i + 8), 16);
344
- inner[i + 0] = n >>> 24;
345
- inner[i + 1] = n >>> 16;
346
- inner[i + 2] = n >>> 8;
347
- inner[i + 3] = n;
348
- }
349
- return new UUID(inner);
350
- }
351
- throw new SyntaxError("could not parse UUID string");
352
- }
353
- toString() {
354
- let text = "";
355
- for (let i = 0; i < this.bytes.length; i++) {
356
- text += DIGITS.charAt(this.bytes[i] >>> 4);
357
- text += DIGITS.charAt(15 & this.bytes[i]);
358
- if (3 === i || 5 === i || 7 === i || 9 === i) text += "-";
359
- }
360
- return text;
361
- }
362
- toHex() {
363
- let text = "";
364
- for (let i = 0; i < this.bytes.length; i++) {
365
- text += DIGITS.charAt(this.bytes[i] >>> 4);
366
- text += DIGITS.charAt(15 & this.bytes[i]);
367
- }
368
- return text;
369
- }
370
- toJSON() {
371
- return this.toString();
372
- }
373
- getVariant() {
374
- const n = this.bytes[8] >>> 4;
375
- if (n < 0) throw new Error("unreachable");
376
- if (n <= 7) return this.bytes.every((e) => 0 === e) ? "NIL" : "VAR_0";
377
- if (n <= 11) return "VAR_10";
378
- if (n <= 13) return "VAR_110";
379
- if (n <= 15) return this.bytes.every((e) => 255 === e) ? "MAX" : "VAR_RESERVED";
380
- else throw new Error("unreachable");
381
- }
382
- getVersion() {
383
- return "VAR_10" === this.getVariant() ? this.bytes[6] >>> 4 : void 0;
384
- }
385
- clone() {
386
- return new UUID(this.bytes.slice(0));
387
- }
388
- equals(other) {
389
- return 0 === this.compareTo(other);
390
- }
391
- compareTo(other) {
392
- for (let i = 0; i < 16; i++) {
393
- const diff = this.bytes[i] - other.bytes[i];
394
- if (0 !== diff) return Math.sign(diff);
395
- }
396
- return 0;
397
- }
294
+ function isGzipSupported() {
295
+ return "CompressionStream" in globalThis;
398
296
  }
399
- class V7Generator {
400
- constructor(randomNumberGenerator) {
401
- this.timestamp = 0;
402
- this.counter = 0;
403
- this.random = randomNumberGenerator ?? getDefaultRandom();
404
- }
405
- generate() {
406
- return this.generateOrResetCore(Date.now(), 1e4);
407
- }
408
- generateOrAbort() {
409
- return this.generateOrAbortCore(Date.now(), 1e4);
410
- }
411
- generateOrResetCore(unixTsMs, rollbackAllowance) {
412
- let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
413
- if (void 0 === value) {
414
- this.timestamp = 0;
415
- value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
416
- }
417
- return value;
418
- }
419
- generateOrAbortCore(unixTsMs, rollbackAllowance) {
420
- const MAX_COUNTER = 4398046511103;
421
- if (!Number.isInteger(unixTsMs) || unixTsMs < 1 || unixTsMs > 281474976710655) throw new RangeError("`unixTsMs` must be a 48-bit positive integer");
422
- if (rollbackAllowance < 0 || rollbackAllowance > 281474976710655) throw new RangeError("`rollbackAllowance` out of reasonable range");
423
- if (unixTsMs > this.timestamp) {
424
- this.timestamp = unixTsMs;
425
- this.resetCounter();
426
- } else {
427
- if (!(unixTsMs + rollbackAllowance >= this.timestamp)) return;
428
- this.counter++;
429
- if (this.counter > MAX_COUNTER) {
430
- this.timestamp++;
431
- this.resetCounter();
432
- }
433
- }
434
- return UUID.fromFieldsV7(this.timestamp, Math.trunc(this.counter / 2 ** 30), this.counter & 2 ** 30 - 1, this.random.nextUint32());
435
- }
436
- resetCounter() {
437
- this.counter = 1024 * this.random.nextUint32() + (1023 & this.random.nextUint32());
438
- }
439
- generateV4() {
440
- const bytes = new Uint8Array(Uint32Array.of(this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32()).buffer);
441
- bytes[6] = 64 | bytes[6] >>> 4;
442
- bytes[8] = 128 | bytes[8] >>> 2;
443
- 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;
444
309
  }
445
310
  }
446
- const getDefaultRandom = () => ({
447
- nextUint32: () => 65536 * Math.trunc(65536 * Math.random()) + Math.trunc(65536 * Math.random())
448
- });
449
- let defaultGenerator;
450
- const uuidv7 = () => uuidv7obj().toString();
451
- const uuidv7obj = () => (defaultGenerator || (defaultGenerator = new V7Generator())).generate();
452
- var types_PostHogPersistedProperty = /* @__PURE__ */ (function(PostHogPersistedProperty) {
453
- PostHogPersistedProperty["AnonymousId"] = "anonymous_id";
454
- PostHogPersistedProperty["DistinctId"] = "distinct_id";
455
- PostHogPersistedProperty["Props"] = "props";
456
- PostHogPersistedProperty["EnablePersonProcessing"] = "enable_person_processing";
457
- PostHogPersistedProperty["PersonMode"] = "person_mode";
458
- PostHogPersistedProperty["FeatureFlagDetails"] = "feature_flag_details";
459
- PostHogPersistedProperty["FeatureFlags"] = "feature_flags";
460
- PostHogPersistedProperty["FeatureFlagPayloads"] = "feature_flag_payloads";
461
- PostHogPersistedProperty["BootstrapFeatureFlagDetails"] = "bootstrap_feature_flag_details";
462
- PostHogPersistedProperty["BootstrapFeatureFlags"] = "bootstrap_feature_flags";
463
- PostHogPersistedProperty["BootstrapFeatureFlagPayloads"] = "bootstrap_feature_flag_payloads";
464
- PostHogPersistedProperty["OverrideFeatureFlags"] = "override_feature_flags";
465
- PostHogPersistedProperty["Queue"] = "queue";
466
- PostHogPersistedProperty["OptedOut"] = "opted_out";
467
- PostHogPersistedProperty["SessionId"] = "session_id";
468
- PostHogPersistedProperty["SessionStartTimestamp"] = "session_start_timestamp";
469
- PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
470
- PostHogPersistedProperty["PersonProperties"] = "person_properties";
471
- PostHogPersistedProperty["GroupProperties"] = "group_properties";
472
- PostHogPersistedProperty["InstalledAppBuild"] = "installed_app_build";
473
- PostHogPersistedProperty["InstalledAppVersion"] = "installed_app_version";
474
- PostHogPersistedProperty["SessionReplay"] = "session_replay";
475
- PostHogPersistedProperty["SurveyLastSeenDate"] = "survey_last_seen_date";
476
- PostHogPersistedProperty["SurveysSeen"] = "surveys_seen";
477
- PostHogPersistedProperty["Surveys"] = "surveys";
478
- PostHogPersistedProperty["RemoteConfig"] = "remote_config";
479
- PostHogPersistedProperty["FlagsEndpointWasHit"] = "flags_endpoint_was_hit";
480
- return PostHogPersistedProperty;
481
- })({});
482
311
  const DEFAULT_BLOCKED_UA_STRS = [
483
312
  "amazonbot",
484
313
  "amazonproductbot",
@@ -566,6 +395,37 @@ const isBlockedUA = function(ua, customBlockedUserAgents = []) {
566
395
  return -1 !== uaLower.indexOf(blockedUaLower);
567
396
  });
568
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
+ })({});
569
429
  const nativeIsArray = Array.isArray;
570
430
  const ObjProto = Object.prototype;
571
431
  const type_utils_toString = ObjProto.toString;
@@ -573,7 +433,6 @@ const isArray = nativeIsArray || function(obj) {
573
433
  return "[object Array]" === type_utils_toString.call(obj);
574
434
  };
575
435
  const isObject = (x) => x === Object(x) && !isArray(x);
576
- const isUndefined = (x) => void 0 === x;
577
436
  const isString = (x) => "[object String]" == type_utils_toString.call(x);
578
437
  const isEmptyString = (x) => isString(x) && 0 === x.trim().length;
579
438
  const isNumber = (x) => "[object Number]" == type_utils_toString.call(x) && x === x;
@@ -585,7 +444,7 @@ function isBuiltin(candidate, className) {
585
444
  return Object.prototype.toString.call(candidate) === `[object ${className}]`;
586
445
  }
587
446
  function isEvent(candidate) {
588
- return !isUndefined(Event) && isInstanceOf(candidate, Event);
447
+ return "undefined" != typeof Event && isInstanceOf(candidate, Event);
589
448
  }
590
449
  function isPlainObject(candidate) {
591
450
  return isBuiltin(candidate, "Object");
@@ -652,6 +511,164 @@ class BucketedRateLimiter {
652
511
  this._buckets = {};
653
512
  }
654
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();
655
672
  class PromiseQueue {
656
673
  add(promise) {
657
674
  const promiseUUID = uuidv7();
@@ -716,13 +733,6 @@ function createLogger(prefix, maybeCall = passThrough) {
716
733
  return _createLogger(prefix, maybeCall, createConsole());
717
734
  }
718
735
  const STRING_FORMAT = "utf8";
719
- function assert(truthyValue, message) {
720
- if (!truthyValue || "string" != typeof truthyValue || isEmpty(truthyValue)) throw new Error(message);
721
- }
722
- function isEmpty(truthyValue) {
723
- if (0 === truthyValue.trim().length) return true;
724
- return false;
725
- }
726
736
  function removeTrailingSlash(url) {
727
737
  return url?.replace(/\/+$/, "");
728
738
  }
@@ -775,23 +785,6 @@ class SimpleEventEmitter {
775
785
  for (const listener of this.events["*"] || []) listener(event, payload);
776
786
  }
777
787
  }
778
- function isGzipSupported() {
779
- return "CompressionStream" in globalThis;
780
- }
781
- async function gzipCompress(input, isDebug = true) {
782
- try {
783
- const dataStream = new Blob([
784
- input
785
- ], {
786
- type: "text/plain"
787
- }).stream();
788
- const compressedStream = dataStream.pipeThrough(new CompressionStream("gzip"));
789
- return await new Response(compressedStream).blob();
790
- } catch (error) {
791
- if (isDebug) console.error("Failed to gzip compress data", error);
792
- return null;
793
- }
794
- }
795
788
  class PostHogFetchHttpError extends Error {
796
789
  constructor(response, reqByteLength) {
797
790
  super("HTTP error while fetching PostHog: status=" + response.status + ", reqByteLength=" + reqByteLength), this.response = response, this.reqByteLength = reqByteLength, this.name = "PostHogFetchHttpError";
@@ -837,9 +830,13 @@ class PostHogCoreStateless {
837
830
  this.promiseQueue = new PromiseQueue();
838
831
  this._events = new SimpleEventEmitter();
839
832
  this._isInitialized = false;
840
- assert(apiKey, "You must pass your PostHog project's api key.");
841
- this.apiKey = apiKey;
842
- 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");
843
840
  this.flushAt = options.flushAt ? Math.max(options.flushAt, 1) : 20;
844
841
  this.maxBatchSize = Math.max(this.flushAt, options.maxBatchSize ?? 100);
845
842
  this.maxQueueSize = Math.max(this.flushAt, options.maxQueueSize ?? 1e3);
@@ -856,11 +853,10 @@ class PostHogCoreStateless {
856
853
  this.featureFlagsRequestTimeoutMs = options.featureFlagsRequestTimeoutMs ?? 3e3;
857
854
  this.remoteConfigRequestTimeoutMs = options.remoteConfigRequestTimeoutMs ?? 3e3;
858
855
  this.disableGeoip = options.disableGeoip ?? true;
859
- this.disabled = options.disabled ?? false;
856
+ this.disabled = (options.disabled ?? false) || missingApiKey;
860
857
  this.historicalMigration = options?.historicalMigration ?? false;
861
858
  this._initPromise = Promise.resolve();
862
859
  this._isInitialized = true;
863
- this._logger = createLogger("[PostHog]", this.logMsgIfDebug.bind(this));
864
860
  this.evaluationContexts = options?.evaluationContexts ?? options?.evaluationEnvironments;
865
861
  if (options?.evaluationEnvironments && !options?.evaluationContexts) this._logger.warn("evaluationEnvironments is deprecated. Use evaluationContexts instead. This property will be removed in a future version.");
866
862
  this.disableCompression = !isGzipSupported() || (options?.disableCompression ?? false);
@@ -1025,7 +1021,7 @@ class PostHogCoreStateless {
1025
1021
  this._events.emit("error", error);
1026
1022
  });
1027
1023
  }
1028
- async getFlags(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}, fetchConfig = true) {
1024
+ async getFlags(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}, fetchConfig = false) {
1029
1025
  await this._initPromise;
1030
1026
  const configParam = fetchConfig ? "&config=true" : "";
1031
1027
  const url = `${this.host}/flags/?v=2${configParam}`;
@@ -1037,6 +1033,7 @@ class PostHogCoreStateless {
1037
1033
  group_properties: groupProperties,
1038
1034
  ...extraPayload
1039
1035
  };
1036
+ if (personProperties.$device_id) requestData.$device_id = personProperties.$device_id;
1040
1037
  if (this.evaluationContexts && this.evaluationContexts.length > 0) requestData.evaluation_contexts = this.evaluationContexts;
1041
1038
  const fetchOptions = {
1042
1039
  method: "POST",
@@ -1384,11 +1381,6 @@ class PostHogCoreStateless {
1384
1381
  this._events.emit("flush", sentMessages);
1385
1382
  }
1386
1383
  async fetchWithRetry(url, options, retryOptions, requestTimeout) {
1387
- AbortSignal.timeout ??= function(ms) {
1388
- const ctrl = new AbortController();
1389
- setTimeout(() => ctrl.abort(), ms);
1390
- return ctrl.signal;
1391
- };
1392
1384
  const body = options.body ? options.body : "";
1393
1385
  let reqByteLength = -1;
1394
1386
  try {
@@ -1401,14 +1393,19 @@ class PostHogCoreStateless {
1401
1393
  }
1402
1394
  }
1403
1395
  return await retriable(async () => {
1396
+ const ctrl = new AbortController();
1397
+ const timeoutMs = requestTimeout ?? this.requestTimeout;
1398
+ const timer = safeSetTimeout(() => ctrl.abort(), timeoutMs);
1404
1399
  let res = null;
1405
1400
  try {
1406
1401
  res = await this.fetch(url, {
1407
- signal: AbortSignal.timeout(requestTimeout ?? this.requestTimeout),
1402
+ signal: ctrl.signal,
1408
1403
  ...options
1409
1404
  });
1410
1405
  } catch (e) {
1411
1406
  throw new PostHogFetchNetworkError(e);
1407
+ } finally {
1408
+ clearTimeout(timer);
1412
1409
  }
1413
1410
  const isNoCors = "no-cors" === options.mode;
1414
1411
  if (!isNoCors && (res.status < 200 || res.status >= 400)) throw new PostHogFetchHttpError(res, reqByteLength);
@@ -1436,16 +1433,21 @@ class PostHogCoreStateless {
1436
1433
  await logFlushError(e);
1437
1434
  }
1438
1435
  };
1439
- return Promise.race([
1440
- new Promise((_, reject) => {
1441
- safeSetTimeout(() => {
1442
- this._logger.error("Timed out while shutting down PostHog");
1443
- hasTimedOut = true;
1444
- reject("Timeout while shutting down PostHog. Some events may not have been sent.");
1445
- }, shutdownTimeoutMs);
1446
- }),
1447
- doShutdown()
1448
- ]);
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
+ }
1449
1451
  }
1450
1452
  async shutdown(shutdownTimeoutMs = 3e4) {
1451
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");
@@ -2052,6 +2054,17 @@ function snipLine(line, colno) {
2052
2054
  if (end < lineLength) newLine += "...";
2053
2055
  return newLine;
2054
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
+ }
2055
2068
  function makeUncaughtExceptionHandler(captureFn, onFatalFn) {
2056
2069
  let calledFatalError = false;
2057
2070
  return Object.assign((error) => {
@@ -2103,12 +2116,11 @@ class ErrorTracking {
2103
2116
  const properties = {
2104
2117
  ...additionalProperties
2105
2118
  };
2106
- if (!distinctId) properties.$process_person_profile = false;
2107
2119
  const exceptionProperties = this.errorPropertiesBuilder.buildFromUnknown(error, hint);
2108
2120
  exceptionProperties.$exception_list = await this.errorPropertiesBuilder.modifyFrames(exceptionProperties.$exception_list);
2109
2121
  return {
2110
2122
  event: "$exception",
2111
- distinctId: distinctId || uuidv7(),
2123
+ distinctId,
2112
2124
  properties: {
2113
2125
  ...exceptionProperties,
2114
2126
  ...properties
@@ -2148,7 +2160,7 @@ class ErrorTracking {
2148
2160
  this._rateLimiter.stop();
2149
2161
  }
2150
2162
  }
2151
- const version = "5.26.0";
2163
+ const version = "5.30.1";
2152
2164
  const FeatureFlagError = {
2153
2165
  ERRORS_WHILE_COMPUTING: "errors_while_computing_flags",
2154
2166
  FLAG_MISSING: "flag_missing",
@@ -2477,6 +2489,9 @@ class FeatureFlagsPoller {
2477
2489
  isLocalEvaluationReady() {
2478
2490
  return (this.loadedSuccessfullyOnce ?? false) && (this.featureFlags?.length ?? 0) > 0;
2479
2491
  }
2492
+ getFlagDefinitionsLoadedAt() {
2493
+ return this.flagDefinitionsLoadedAt;
2494
+ }
2480
2495
  getPollingInterval() {
2481
2496
  if (!this.shouldBeginExponentialBackoff) return this.pollingInterval;
2482
2497
  return Math.min(SIXTY_SECONDS, this.pollingInterval * 2 ** this.backOffCount);
@@ -2544,6 +2559,7 @@ class FeatureFlagsPoller {
2544
2559
  cohorts: responseJson.cohorts || {}
2545
2560
  };
2546
2561
  this.updateFlagState(flagData);
2562
+ this.flagDefinitionsLoadedAt = Date.now();
2547
2563
  this.clearBackoff();
2548
2564
  if (this.cacheProvider && shouldFetch) try {
2549
2565
  await this.cacheProvider.onFlagDefinitionsReceived(flagData);
@@ -2574,7 +2590,7 @@ class FeatureFlagsPoller {
2574
2590
  };
2575
2591
  }
2576
2592
  _requestFeatureFlagDefinitions() {
2577
- 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`;
2578
2594
  const options = this.getPersonalApiKeyRequestOptions("GET", this.flagsEtag);
2579
2595
  let abortTimeout = null;
2580
2596
  if (this.timeout && "number" == typeof this.timeout) {
@@ -2671,6 +2687,45 @@ function matchProperty(property, propertyValues, warnFunction) {
2671
2687
  ].includes(operator)) return overrideDate < parsedDate;
2672
2688
  return overrideDate > parsedDate;
2673
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
+ }
2674
2729
  default:
2675
2730
  throw new InconclusiveMatchError(`Unknown operator: ${operator}`);
2676
2731
  }
@@ -2739,6 +2794,115 @@ function isValidRegex(regex) {
2739
2794
  return false;
2740
2795
  }
2741
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
+ }
2742
2906
  function convertToDateTime(value) {
2743
2907
  if (value instanceof Date) return value;
2744
2908
  if ("string" == typeof value || "number" == typeof value) {
@@ -2783,22 +2947,44 @@ class PostHogMemoryStorage {
2783
2947
  const MINIMUM_POLLING_INTERVAL = 100;
2784
2948
  const THIRTY_SECONDS = 3e4;
2785
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
+ }
2786
2964
  class PostHogBackendClient extends PostHogCoreStateless {
2787
2965
  constructor(apiKey, options = {}) {
2788
- super(apiKey, options), this._memoryStorage = new PostHogMemoryStorage();
2789
- 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;
2790
2974
  this.context = this.initializeContext();
2791
- this.options.featureFlagsPollingInterval = "number" == typeof options.featureFlagsPollingInterval ? Math.max(options.featureFlagsPollingInterval, MINIMUM_POLLING_INTERVAL) : THIRTY_SECONDS;
2792
- if (options.personalApiKey) {
2793
- 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.');
2794
- 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;
2795
2981
  if (shouldEnableLocalEvaluation) this.featureFlagsPoller = new FeatureFlagsPoller({
2796
2982
  pollingInterval: this.options.featureFlagsPollingInterval,
2797
- personalApiKey: options.personalApiKey,
2798
- projectApiKey: apiKey,
2799
- timeout: options.requestTimeout ?? 1e4,
2983
+ personalApiKey: normalizedOptions.personalApiKey,
2984
+ projectApiKey: normalizedApiKey,
2985
+ timeout: normalizedOptions.requestTimeout ?? 1e4,
2800
2986
  host: this.host,
2801
- fetch: options.fetch,
2987
+ fetch: normalizedOptions.fetch,
2802
2988
  onError: (err) => {
2803
2989
  this._events.emit("error", err);
2804
2990
  },
@@ -2806,13 +2992,74 @@ class PostHogBackendClient extends PostHogCoreStateless {
2806
2992
  this._events.emit("localEvaluationFlagsLoaded", count);
2807
2993
  },
2808
2994
  customHeaders: this.getCustomHeaders(),
2809
- cacheProvider: options.flagDefinitionCacheProvider,
2810
- strictLocalEvaluation: options.strictLocalEvaluation
2995
+ cacheProvider: normalizedOptions.flagDefinitionCacheProvider,
2996
+ strictLocalEvaluation: normalizedOptions.strictLocalEvaluation
2811
2997
  });
2812
2998
  }
2813
- this.errorTracking = new ErrorTracking(this, options, this._logger);
2999
+ this.errorTracking = new ErrorTracking(this, normalizedOptions, this._logger);
2814
3000
  this.distinctIdHasSentFlagCalls = {};
2815
- 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
+ }
2816
3063
  }
2817
3064
  getPersistedProperty(key) {
2818
3065
  return this._memoryStorage.getProperty(key);
@@ -3029,8 +3276,12 @@ class PostHogBackendClient extends PostHogCoreStateless {
3029
3276
  locally_evaluated: flagWasLocallyEvaluated,
3030
3277
  [`$feature/${key}`]: response,
3031
3278
  $feature_flag_request_id: requestId,
3032
- $feature_flag_evaluated_at: evaluatedAt
3279
+ $feature_flag_evaluated_at: flagWasLocallyEvaluated ? Date.now() : evaluatedAt
3033
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
+ }
3034
3285
  if (featureFlagError) properties.$feature_flag_error = featureFlagError;
3035
3286
  this.capture({
3036
3287
  distinctId,
@@ -3213,9 +3464,14 @@ class PostHogBackendClient extends PostHogCoreStateless {
3213
3464
  this.context?.enter(data, options);
3214
3465
  }
3215
3466
  async _shutdown(shutdownTimeoutMs) {
3216
- this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
3467
+ const resolve = this._consumeWaitUntilCycle();
3468
+ await this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
3217
3469
  this.errorTracking.shutdown();
3218
- return super._shutdown(shutdownTimeoutMs);
3470
+ try {
3471
+ return await super._shutdown(shutdownTimeoutMs);
3472
+ } finally {
3473
+ resolve?.();
3474
+ }
3219
3475
  }
3220
3476
  async _requestRemoteConfigPayload(flagKey) {
3221
3477
  if (!this.options.personalApiKey) return;
@@ -3332,7 +3588,7 @@ class PostHogBackendClient extends PostHogCoreStateless {
3332
3588
  async captureExceptionImmediate(error, distinctId, additionalProperties) {
3333
3589
  if (!ErrorTracking.isPreviouslyCapturedError(error)) {
3334
3590
  const syntheticException = new Error("PostHog syntheticException");
3335
- this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
3591
+ return this.addPendingPromise(ErrorTracking.buildEventMessage(error, {
3336
3592
  syntheticException
3337
3593
  }, distinctId, additionalProperties).then((msg) => this.captureImmediate(msg)));
3338
3594
  }
@@ -3485,7 +3741,8 @@ ErrorTracking.errorPropertiesBuilder = new ErrorPropertiesBuilder([
3485
3741
  new PrimitiveCoercer()
3486
3742
  ], createStackParser("node:javascript", nodeStackLineParser), [
3487
3743
  createModulerModifier(),
3488
- addSourceContext
3744
+ addSourceContext,
3745
+ createRelativePathModifier()
3489
3746
  ]);
3490
3747
  class PostHog extends PostHogBackendClient {
3491
3748
  getLibraryId() {
@@ -3816,30 +4073,30 @@ const shutdownSession = async (session2) => {
3816
4073
  };
3817
4074
  const toPosixPath = (input) => input.split(path.sep).join("/");
3818
4075
  const isSubpath = (candidate, root) => {
3819
- const relative = path.relative(root, candidate);
3820
- return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
4076
+ const relative2 = path.relative(root, candidate);
4077
+ return relative2 === "" || !relative2.startsWith("..") && !path.isAbsolute(relative2);
3821
4078
  };
3822
4079
  const classifyServerTarget = (absolutePath, projectRoot) => {
3823
4080
  if (!isSubpath(absolutePath, projectRoot)) {
3824
4081
  return "ssr";
3825
4082
  }
3826
- const relative = toPosixPath(path.relative(projectRoot, absolutePath));
3827
- 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/")) {
3828
4085
  return "api";
3829
4086
  }
3830
- if (relative.startsWith("src/worker/") || relative.includes("/src/worker/")) {
4087
+ if (relative2.startsWith("src/worker/") || relative2.includes("/src/worker/")) {
3831
4088
  return "worker";
3832
4089
  }
3833
- if (relative.startsWith("src/server/") || relative.includes("/src/server/")) {
4090
+ if (relative2.startsWith("src/server/") || relative2.includes("/src/server/")) {
3834
4091
  return "ssr";
3835
4092
  }
3836
- if (relative.startsWith("build/dist/api/") || relative.includes("/build/dist/api/")) {
4093
+ if (relative2.startsWith("build/dist/api/") || relative2.includes("/build/dist/api/")) {
3837
4094
  return "api";
3838
4095
  }
3839
- if (relative.startsWith("build/dist/worker/") || relative.includes("/build/dist/worker/")) {
4096
+ if (relative2.startsWith("build/dist/worker/") || relative2.includes("/build/dist/worker/")) {
3840
4097
  return "worker";
3841
4098
  }
3842
- if (relative.startsWith("build/dist/ssr/") || relative.includes("/build/dist/ssr/")) {
4099
+ if (relative2.startsWith("build/dist/ssr/") || relative2.includes("/build/dist/ssr/")) {
3843
4100
  return "ssr";
3844
4101
  }
3845
4102
  return "ssr";