posthog-js-lite 3.6.0 → 4.0.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/lib/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- var version = "3.6.0";
1
+ var version = "4.0.0";
2
2
 
3
3
  var PostHogPersistedProperty;
4
4
  (function (PostHogPersistedProperty) {
@@ -28,6 +28,12 @@ var PostHogPersistedProperty;
28
28
  PostHogPersistedProperty["Surveys"] = "surveys";
29
29
  PostHogPersistedProperty["RemoteConfig"] = "remote_config";
30
30
  })(PostHogPersistedProperty || (PostHogPersistedProperty = {}));
31
+ // Any key prefixed with `attr__` can be added
32
+ var Compression;
33
+ (function (Compression) {
34
+ Compression["GZipJS"] = "gzip-js";
35
+ Compression["Base64"] = "base64";
36
+ })(Compression || (Compression = {}));
31
37
  var SurveyPosition;
32
38
  (function (SurveyPosition) {
33
39
  SurveyPosition["Left"] = "left";
@@ -373,436 +379,33 @@ function allSettled(promises) {
373
379
  return Promise.all(promises.map((p) => (p ?? Promise.resolve()).then((value) => ({ status: 'fulfilled', value }), (reason) => ({ status: 'rejected', reason }))));
374
380
  }
375
381
 
376
- // Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
377
- // This work is free. You can redistribute it and/or modify it
378
- // under the terms of the WTFPL, Version 2
379
- // For more information see LICENSE.txt or http://www.wtfpl.net/
380
- //
381
- // For more information, the home page:
382
- // http://pieroxy.net/blog/pages/lz-string/testing.html
383
- //
384
- // LZ-based compression algorithm, version 1.4.4
385
- // private property
386
- const f = String.fromCharCode;
387
- const keyStrBase64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
388
- const baseReverseDic = {};
389
- function getBaseValue(alphabet, character) {
390
- if (!baseReverseDic[alphabet]) {
391
- baseReverseDic[alphabet] = {};
392
- for (let i = 0; i < alphabet.length; i++) {
393
- baseReverseDic[alphabet][alphabet.charAt(i)] = i;
394
- }
395
- }
396
- return baseReverseDic[alphabet][character];
382
+ /**
383
+ * Older browsers and some runtimes don't support this yet
384
+ * This API (as of 2025-05-07) is not available on React Native.
385
+ */
386
+ function isGzipSupported() {
387
+ return 'CompressionStream' in globalThis;
397
388
  }
398
- const LZString = {
399
- compressToBase64: function (input) {
400
- if (input == null) {
401
- return '';
402
- }
403
- const res = LZString._compress(input, 6, function (a) {
404
- return keyStrBase64.charAt(a);
405
- });
406
- switch (res.length % 4 // To produce valid Base64
407
- ) {
408
- default: // When could this happen ?
409
- case 0:
410
- return res;
411
- case 1:
412
- return res + '===';
413
- case 2:
414
- return res + '==';
415
- case 3:
416
- return res + '=';
417
- }
418
- },
419
- decompressFromBase64: function (input) {
420
- if (input == null) {
421
- return '';
422
- }
423
- if (input == '') {
424
- return null;
425
- }
426
- return LZString._decompress(input.length, 32, function (index) {
427
- return getBaseValue(keyStrBase64, input.charAt(index));
428
- });
429
- },
430
- compress: function (uncompressed) {
431
- return LZString._compress(uncompressed, 16, function (a) {
432
- return f(a);
433
- });
434
- },
435
- _compress: function (uncompressed, bitsPerChar, getCharFromInt) {
436
- if (uncompressed == null) {
437
- return '';
438
- }
439
- const context_dictionary = {}, context_dictionaryToCreate = {}, context_data = [];
440
- let i, value, context_c = '', context_wc = '', context_w = '', context_enlargeIn = 2, // Compensate for the first entry which should not count
441
- context_dictSize = 3, context_numBits = 2, context_data_val = 0, context_data_position = 0, ii;
442
- for (ii = 0; ii < uncompressed.length; ii += 1) {
443
- context_c = uncompressed.charAt(ii);
444
- if (!Object.prototype.hasOwnProperty.call(context_dictionary, context_c)) {
445
- context_dictionary[context_c] = context_dictSize++;
446
- context_dictionaryToCreate[context_c] = true;
447
- }
448
- context_wc = context_w + context_c;
449
- if (Object.prototype.hasOwnProperty.call(context_dictionary, context_wc)) {
450
- context_w = context_wc;
451
- }
452
- else {
453
- if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
454
- if (context_w.charCodeAt(0) < 256) {
455
- for (i = 0; i < context_numBits; i++) {
456
- context_data_val = context_data_val << 1;
457
- if (context_data_position == bitsPerChar - 1) {
458
- context_data_position = 0;
459
- context_data.push(getCharFromInt(context_data_val));
460
- context_data_val = 0;
461
- }
462
- else {
463
- context_data_position++;
464
- }
465
- }
466
- value = context_w.charCodeAt(0);
467
- for (i = 0; i < 8; i++) {
468
- context_data_val = (context_data_val << 1) | (value & 1);
469
- if (context_data_position == bitsPerChar - 1) {
470
- context_data_position = 0;
471
- context_data.push(getCharFromInt(context_data_val));
472
- context_data_val = 0;
473
- }
474
- else {
475
- context_data_position++;
476
- }
477
- value = value >> 1;
478
- }
479
- }
480
- else {
481
- value = 1;
482
- for (i = 0; i < context_numBits; i++) {
483
- context_data_val = (context_data_val << 1) | value;
484
- if (context_data_position == bitsPerChar - 1) {
485
- context_data_position = 0;
486
- context_data.push(getCharFromInt(context_data_val));
487
- context_data_val = 0;
488
- }
489
- else {
490
- context_data_position++;
491
- }
492
- value = 0;
493
- }
494
- value = context_w.charCodeAt(0);
495
- for (i = 0; i < 16; i++) {
496
- context_data_val = (context_data_val << 1) | (value & 1);
497
- if (context_data_position == bitsPerChar - 1) {
498
- context_data_position = 0;
499
- context_data.push(getCharFromInt(context_data_val));
500
- context_data_val = 0;
501
- }
502
- else {
503
- context_data_position++;
504
- }
505
- value = value >> 1;
506
- }
507
- }
508
- context_enlargeIn--;
509
- if (context_enlargeIn == 0) {
510
- context_enlargeIn = Math.pow(2, context_numBits);
511
- context_numBits++;
512
- }
513
- delete context_dictionaryToCreate[context_w];
514
- }
515
- else {
516
- value = context_dictionary[context_w];
517
- for (i = 0; i < context_numBits; i++) {
518
- context_data_val = (context_data_val << 1) | (value & 1);
519
- if (context_data_position == bitsPerChar - 1) {
520
- context_data_position = 0;
521
- context_data.push(getCharFromInt(context_data_val));
522
- context_data_val = 0;
523
- }
524
- else {
525
- context_data_position++;
526
- }
527
- value = value >> 1;
528
- }
529
- }
530
- context_enlargeIn--;
531
- if (context_enlargeIn == 0) {
532
- context_enlargeIn = Math.pow(2, context_numBits);
533
- context_numBits++;
534
- }
535
- // Add wc to the dictionary.
536
- context_dictionary[context_wc] = context_dictSize++;
537
- context_w = String(context_c);
538
- }
539
- }
540
- // Output the code for w.
541
- if (context_w !== '') {
542
- if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
543
- if (context_w.charCodeAt(0) < 256) {
544
- for (i = 0; i < context_numBits; i++) {
545
- context_data_val = context_data_val << 1;
546
- if (context_data_position == bitsPerChar - 1) {
547
- context_data_position = 0;
548
- context_data.push(getCharFromInt(context_data_val));
549
- context_data_val = 0;
550
- }
551
- else {
552
- context_data_position++;
553
- }
554
- }
555
- value = context_w.charCodeAt(0);
556
- for (i = 0; i < 8; i++) {
557
- context_data_val = (context_data_val << 1) | (value & 1);
558
- if (context_data_position == bitsPerChar - 1) {
559
- context_data_position = 0;
560
- context_data.push(getCharFromInt(context_data_val));
561
- context_data_val = 0;
562
- }
563
- else {
564
- context_data_position++;
565
- }
566
- value = value >> 1;
567
- }
568
- }
569
- else {
570
- value = 1;
571
- for (i = 0; i < context_numBits; i++) {
572
- context_data_val = (context_data_val << 1) | value;
573
- if (context_data_position == bitsPerChar - 1) {
574
- context_data_position = 0;
575
- context_data.push(getCharFromInt(context_data_val));
576
- context_data_val = 0;
577
- }
578
- else {
579
- context_data_position++;
580
- }
581
- value = 0;
582
- }
583
- value = context_w.charCodeAt(0);
584
- for (i = 0; i < 16; i++) {
585
- context_data_val = (context_data_val << 1) | (value & 1);
586
- if (context_data_position == bitsPerChar - 1) {
587
- context_data_position = 0;
588
- context_data.push(getCharFromInt(context_data_val));
589
- context_data_val = 0;
590
- }
591
- else {
592
- context_data_position++;
593
- }
594
- value = value >> 1;
595
- }
596
- }
597
- context_enlargeIn--;
598
- if (context_enlargeIn == 0) {
599
- context_enlargeIn = Math.pow(2, context_numBits);
600
- context_numBits++;
601
- }
602
- delete context_dictionaryToCreate[context_w];
603
- }
604
- else {
605
- value = context_dictionary[context_w];
606
- for (i = 0; i < context_numBits; i++) {
607
- context_data_val = (context_data_val << 1) | (value & 1);
608
- if (context_data_position == bitsPerChar - 1) {
609
- context_data_position = 0;
610
- context_data.push(getCharFromInt(context_data_val));
611
- context_data_val = 0;
612
- }
613
- else {
614
- context_data_position++;
615
- }
616
- value = value >> 1;
617
- }
618
- }
619
- context_enlargeIn--;
620
- if (context_enlargeIn == 0) {
621
- context_enlargeIn = Math.pow(2, context_numBits);
622
- context_numBits++;
623
- }
624
- }
625
- // Mark the end of the stream
626
- value = 2;
627
- for (i = 0; i < context_numBits; i++) {
628
- context_data_val = (context_data_val << 1) | (value & 1);
629
- if (context_data_position == bitsPerChar - 1) {
630
- context_data_position = 0;
631
- context_data.push(getCharFromInt(context_data_val));
632
- context_data_val = 0;
633
- }
634
- else {
635
- context_data_position++;
636
- }
637
- value = value >> 1;
638
- }
639
- // Flush the last char
640
- while (true) {
641
- context_data_val = context_data_val << 1;
642
- if (context_data_position == bitsPerChar - 1) {
643
- context_data.push(getCharFromInt(context_data_val));
644
- break;
645
- }
646
- else {
647
- context_data_position++;
648
- }
649
- }
650
- return context_data.join('');
651
- },
652
- decompress: function (compressed) {
653
- if (compressed == null) {
654
- return '';
655
- }
656
- if (compressed == '') {
657
- return null;
658
- }
659
- return LZString._decompress(compressed.length, 32768, function (index) {
660
- return compressed.charCodeAt(index);
661
- });
662
- },
663
- _decompress: function (length, resetValue, getNextValue) {
664
- const dictionary = [], result = [], data = { val: getNextValue(0), position: resetValue, index: 1 };
665
- let enlargeIn = 4, dictSize = 4, numBits = 3, entry = '', i, w, bits, resb, maxpower, power, c;
666
- for (i = 0; i < 3; i += 1) {
667
- dictionary[i] = i;
668
- }
669
- bits = 0;
670
- maxpower = Math.pow(2, 2);
671
- power = 1;
672
- while (power != maxpower) {
673
- resb = data.val & data.position;
674
- data.position >>= 1;
675
- if (data.position == 0) {
676
- data.position = resetValue;
677
- data.val = getNextValue(data.index++);
678
- }
679
- bits |= (resb > 0 ? 1 : 0) * power;
680
- power <<= 1;
681
- }
682
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
683
- switch ((bits)) {
684
- case 0:
685
- bits = 0;
686
- maxpower = Math.pow(2, 8);
687
- power = 1;
688
- while (power != maxpower) {
689
- resb = data.val & data.position;
690
- data.position >>= 1;
691
- if (data.position == 0) {
692
- data.position = resetValue;
693
- data.val = getNextValue(data.index++);
694
- }
695
- bits |= (resb > 0 ? 1 : 0) * power;
696
- power <<= 1;
697
- }
698
- c = f(bits);
699
- break;
700
- case 1:
701
- bits = 0;
702
- maxpower = Math.pow(2, 16);
703
- power = 1;
704
- while (power != maxpower) {
705
- resb = data.val & data.position;
706
- data.position >>= 1;
707
- if (data.position == 0) {
708
- data.position = resetValue;
709
- data.val = getNextValue(data.index++);
710
- }
711
- bits |= (resb > 0 ? 1 : 0) * power;
712
- power <<= 1;
713
- }
714
- c = f(bits);
715
- break;
716
- case 2:
717
- return '';
718
- }
719
- dictionary[3] = c;
720
- w = c;
721
- result.push(c);
722
- while (true) {
723
- if (data.index > length) {
724
- return '';
725
- }
726
- bits = 0;
727
- maxpower = Math.pow(2, numBits);
728
- power = 1;
729
- while (power != maxpower) {
730
- resb = data.val & data.position;
731
- data.position >>= 1;
732
- if (data.position == 0) {
733
- data.position = resetValue;
734
- data.val = getNextValue(data.index++);
735
- }
736
- bits |= (resb > 0 ? 1 : 0) * power;
737
- power <<= 1;
738
- }
739
- switch ((c = bits)) {
740
- case 0:
741
- bits = 0;
742
- maxpower = Math.pow(2, 8);
743
- power = 1;
744
- while (power != maxpower) {
745
- resb = data.val & data.position;
746
- data.position >>= 1;
747
- if (data.position == 0) {
748
- data.position = resetValue;
749
- data.val = getNextValue(data.index++);
750
- }
751
- bits |= (resb > 0 ? 1 : 0) * power;
752
- power <<= 1;
753
- }
754
- dictionary[dictSize++] = f(bits);
755
- c = dictSize - 1;
756
- enlargeIn--;
757
- break;
758
- case 1:
759
- bits = 0;
760
- maxpower = Math.pow(2, 16);
761
- power = 1;
762
- while (power != maxpower) {
763
- resb = data.val & data.position;
764
- data.position >>= 1;
765
- if (data.position == 0) {
766
- data.position = resetValue;
767
- data.val = getNextValue(data.index++);
768
- }
769
- bits |= (resb > 0 ? 1 : 0) * power;
770
- power <<= 1;
771
- }
772
- dictionary[dictSize++] = f(bits);
773
- c = dictSize - 1;
774
- enlargeIn--;
775
- break;
776
- case 2:
777
- return result.join('');
778
- }
779
- if (enlargeIn == 0) {
780
- enlargeIn = Math.pow(2, numBits);
781
- numBits++;
782
- }
783
- if (dictionary[c]) {
784
- entry = dictionary[c];
785
- }
786
- else {
787
- if (c === dictSize) {
788
- entry = w + w.charAt(0);
789
- }
790
- else {
791
- return null;
792
- }
793
- }
794
- result.push(entry);
795
- // Add w+entry[0] to the dictionary.
796
- dictionary[dictSize++] = w + entry.charAt(0);
797
- enlargeIn--;
798
- w = entry;
799
- if (enlargeIn == 0) {
800
- enlargeIn = Math.pow(2, numBits);
801
- numBits++;
802
- }
389
+ /**
390
+ * Gzip a string using Compression Streams API if it's available
391
+ */
392
+ async function gzipCompress(input, isDebug = true) {
393
+ try {
394
+ // Turn the string into a stream using a Blob, and then compress it
395
+ const dataStream = new Blob([input], {
396
+ type: 'text/plain',
397
+ }).stream();
398
+ const compressedStream = dataStream.pipeThrough(new CompressionStream('gzip'));
399
+ // Using a Response to easily extract the readablestream value. Decoding into a string for fetch
400
+ return await new Response(compressedStream).blob();
401
+ }
402
+ catch (error) {
403
+ if (isDebug) {
404
+ console.error('Failed to gzip compress data', error);
803
405
  }
804
- },
805
- };
406
+ return null;
407
+ }
408
+ }
806
409
 
807
410
  class SimpleEventEmitter {
808
411
  constructor() {
@@ -1302,7 +905,6 @@ class PostHogCoreStateless {
1302
905
  this.maxBatchSize = Math.max(this.flushAt, options?.maxBatchSize ?? 100);
1303
906
  this.maxQueueSize = Math.max(this.flushAt, options?.maxQueueSize ?? 1000);
1304
907
  this.flushInterval = options?.flushInterval ?? 10000;
1305
- this.captureMode = options?.captureMode || 'json';
1306
908
  this.preloadFeatureFlags = options?.preloadFeatureFlags ?? true;
1307
909
  // If enable is explicitly set to false we override the optout
1308
910
  this.defaultOptIn = options?.defaultOptIn ?? true;
@@ -1321,6 +923,7 @@ class PostHogCoreStateless {
1321
923
  // Init promise allows the derived class to block calls until it is ready
1322
924
  this._initPromise = Promise.resolve();
1323
925
  this._isInitialized = true;
926
+ this.disableCompression = !isGzipSupported() || (options?.disableCompression ?? false);
1324
927
  }
1325
928
  logMsgIfDebug(fn) {
1326
929
  if (this.isDebug) {
@@ -1742,22 +1345,17 @@ class PostHogCoreStateless {
1742
1345
  data.historical_migration = true;
1743
1346
  }
1744
1347
  const payload = JSON.stringify(data);
1745
- const url = this.captureMode === 'form'
1746
- ? `${this.host}/e/?ip=1&_=${currentTimestamp()}&v=${this.getLibraryVersion()}`
1747
- : `${this.host}/batch/`;
1748
- const fetchOptions = this.captureMode === 'form'
1749
- ? {
1750
- method: 'POST',
1751
- mode: 'no-cors',
1752
- credentials: 'omit',
1753
- headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/x-www-form-urlencoded' },
1754
- body: `data=${encodeURIComponent(LZString.compressToBase64(payload))}&compression=lz64`,
1755
- }
1756
- : {
1757
- method: 'POST',
1758
- headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/json' },
1759
- body: payload,
1760
- };
1348
+ const url = `${this.host}/batch/`;
1349
+ const gzippedPayload = !this.disableCompression ? await gzipCompress(payload, this.isDebug) : null;
1350
+ const fetchOptions = {
1351
+ method: 'POST',
1352
+ headers: {
1353
+ ...this.getCustomHeaders(),
1354
+ 'Content-Type': 'application/json',
1355
+ ...(gzippedPayload !== null && { 'Content-Encoding': 'gzip' }),
1356
+ },
1357
+ body: gzippedPayload || payload,
1358
+ };
1761
1359
  try {
1762
1360
  await this.fetchWithRetry(url, fetchOptions);
1763
1361
  }
@@ -1881,22 +1479,17 @@ class PostHogCoreStateless {
1881
1479
  data.historical_migration = true;
1882
1480
  }
1883
1481
  const payload = JSON.stringify(data);
1884
- const url = this.captureMode === 'form'
1885
- ? `${this.host}/e/?ip=1&_=${currentTimestamp()}&v=${this.getLibraryVersion()}`
1886
- : `${this.host}/batch/`;
1887
- const fetchOptions = this.captureMode === 'form'
1888
- ? {
1889
- method: 'POST',
1890
- mode: 'no-cors',
1891
- credentials: 'omit',
1892
- headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/x-www-form-urlencoded' },
1893
- body: `data=${encodeURIComponent(LZString.compressToBase64(payload))}&compression=lz64`,
1894
- }
1895
- : {
1896
- method: 'POST',
1897
- headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/json' },
1898
- body: payload,
1899
- };
1482
+ const url = `${this.host}/batch/`;
1483
+ const gzippedPayload = !this.disableCompression ? await gzipCompress(payload, this.isDebug) : null;
1484
+ const fetchOptions = {
1485
+ method: 'POST',
1486
+ headers: {
1487
+ ...this.getCustomHeaders(),
1488
+ 'Content-Type': 'application/json',
1489
+ ...(gzippedPayload !== null && { 'Content-Encoding': 'gzip' }),
1490
+ },
1491
+ body: gzippedPayload || payload,
1492
+ };
1900
1493
  const retryOptions = {
1901
1494
  retryCheck: (err) => {
1902
1495
  // don't automatically retry on 413 errors, we want to reduce the batch size first
@@ -1941,11 +1534,21 @@ class PostHogCoreStateless {
1941
1534
  const body = options.body ? options.body : '';
1942
1535
  let reqByteLength = -1;
1943
1536
  try {
1944
- reqByteLength = Buffer.byteLength(body, STRING_FORMAT);
1537
+ if (body instanceof Blob) {
1538
+ reqByteLength = body.size;
1539
+ }
1540
+ else {
1541
+ reqByteLength = Buffer.byteLength(body, STRING_FORMAT);
1542
+ }
1945
1543
  }
1946
1544
  catch {
1947
- const encoded = new TextEncoder().encode(body);
1948
- reqByteLength = encoded.length;
1545
+ if (body instanceof Blob) {
1546
+ reqByteLength = body.size;
1547
+ }
1548
+ else {
1549
+ const encoded = new TextEncoder().encode(body);
1550
+ reqByteLength = encoded.length;
1551
+ }
1949
1552
  }
1950
1553
  return await retriable(async () => {
1951
1554
  let res = null;
@@ -2299,10 +1902,6 @@ class PostHogCore extends PostHogCoreStateless {
2299
1902
  this.setPersistedProperty(PostHogPersistedProperty.PersonProperties, null);
2300
1903
  });
2301
1904
  }
2302
- /** @deprecated - Renamed to setPersonPropertiesForFlags */
2303
- personProperties(properties) {
2304
- return this.setPersonPropertiesForFlags(properties);
2305
- }
2306
1905
  setGroupPropertiesForFlags(properties) {
2307
1906
  this.wrap(() => {
2308
1907
  // Get persisted group properties
@@ -2328,12 +1927,6 @@ class PostHogCore extends PostHogCoreStateless {
2328
1927
  this.setPersistedProperty(PostHogPersistedProperty.GroupProperties, null);
2329
1928
  });
2330
1929
  }
2331
- /** @deprecated - Renamed to setGroupPropertiesForFlags */
2332
- groupProperties(properties) {
2333
- this.wrap(() => {
2334
- this.setGroupPropertiesForFlags(properties);
2335
- });
2336
- }
2337
1930
  async remoteConfigAsync() {
2338
1931
  await this._initPromise;
2339
1932
  if (this._remoteConfigResponsePromise) {
@@ -2407,6 +2000,9 @@ class PostHogCore extends PostHogCoreStateless {
2407
2000
  else if (this.preloadFeatureFlags !== false) {
2408
2001
  this.reloadFeatureFlags();
2409
2002
  }
2003
+ if (!response.supportedCompression?.includes(Compression.GZipJS)) {
2004
+ this.disableCompression = true;
2005
+ }
2410
2006
  remoteConfig = response;
2411
2007
  }
2412
2008
  return remoteConfig;