posthog-js-lite 3.6.0 → 4.1.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/CHANGELOG.md +11 -0
- package/lib/index.cjs +129 -645
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.ts +39 -39
- package/lib/index.mjs +129 -645
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/posthog-web.spec.ts +1 -1
package/lib/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var version = "
|
|
1
|
+
var version = "4.1.0";
|
|
2
2
|
|
|
3
3
|
var PostHogPersistedProperty;
|
|
4
4
|
(function (PostHogPersistedProperty) {
|
|
@@ -22,12 +22,18 @@ var PostHogPersistedProperty;
|
|
|
22
22
|
PostHogPersistedProperty["InstalledAppBuild"] = "installed_app_build";
|
|
23
23
|
PostHogPersistedProperty["InstalledAppVersion"] = "installed_app_version";
|
|
24
24
|
PostHogPersistedProperty["SessionReplay"] = "session_replay";
|
|
25
|
-
PostHogPersistedProperty["DecideEndpointWasHit"] = "decide_endpoint_was_hit";
|
|
26
25
|
PostHogPersistedProperty["SurveyLastSeenDate"] = "survey_last_seen_date";
|
|
27
26
|
PostHogPersistedProperty["SurveysSeen"] = "surveys_seen";
|
|
28
27
|
PostHogPersistedProperty["Surveys"] = "surveys";
|
|
29
28
|
PostHogPersistedProperty["RemoteConfig"] = "remote_config";
|
|
29
|
+
PostHogPersistedProperty["FlagsEndpointWasHit"] = "flags_endpoint_was_hit";
|
|
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";
|
|
@@ -88,27 +94,27 @@ var ActionStepStringMatching;
|
|
|
88
94
|
ActionStepStringMatching["Regex"] = "regex";
|
|
89
95
|
})(ActionStepStringMatching || (ActionStepStringMatching = {}));
|
|
90
96
|
|
|
91
|
-
const
|
|
92
|
-
if ('flags' in
|
|
93
|
-
// Convert
|
|
94
|
-
const featureFlags = getFlagValuesFromFlags(
|
|
95
|
-
const featureFlagPayloads = getPayloadsFromFlags(
|
|
97
|
+
const normalizeFlagsResponse = (flagsResponse) => {
|
|
98
|
+
if ('flags' in flagsResponse) {
|
|
99
|
+
// Convert v2 format to v1 format
|
|
100
|
+
const featureFlags = getFlagValuesFromFlags(flagsResponse.flags);
|
|
101
|
+
const featureFlagPayloads = getPayloadsFromFlags(flagsResponse.flags);
|
|
96
102
|
return {
|
|
97
|
-
...
|
|
103
|
+
...flagsResponse,
|
|
98
104
|
featureFlags,
|
|
99
105
|
featureFlagPayloads,
|
|
100
106
|
};
|
|
101
107
|
}
|
|
102
108
|
else {
|
|
103
|
-
// Convert
|
|
104
|
-
const featureFlags =
|
|
105
|
-
const featureFlagPayloads = Object.fromEntries(Object.entries(
|
|
109
|
+
// Convert v1 format to v2 format
|
|
110
|
+
const featureFlags = flagsResponse.featureFlags ?? {};
|
|
111
|
+
const featureFlagPayloads = Object.fromEntries(Object.entries(flagsResponse.featureFlagPayloads || {}).map(([k, v]) => [k, parsePayload(v)]));
|
|
106
112
|
const flags = Object.fromEntries(Object.entries(featureFlags).map(([key, value]) => [
|
|
107
113
|
key,
|
|
108
114
|
getFlagDetailFromFlagAndPayload(key, value, featureFlagPayloads[key]),
|
|
109
115
|
]));
|
|
110
116
|
return {
|
|
111
|
-
...
|
|
117
|
+
...flagsResponse,
|
|
112
118
|
featureFlags,
|
|
113
119
|
featureFlagPayloads,
|
|
114
120
|
flags,
|
|
@@ -180,7 +186,7 @@ const parsePayload = (response) => {
|
|
|
180
186
|
* @param featureFlagPayloads - The feature flag payloads
|
|
181
187
|
* @returns The normalized flag details
|
|
182
188
|
*/
|
|
183
|
-
const
|
|
189
|
+
const createFlagsResponseFromFlagsAndPayloads = (featureFlags, featureFlagPayloads) => {
|
|
184
190
|
// If a feature flag payload key is not in the feature flags, we treat it as true feature flag.
|
|
185
191
|
const allKeys = [...new Set([...Object.keys(featureFlags ?? {}), ...Object.keys(featureFlagPayloads ?? {})])];
|
|
186
192
|
const enabledFlags = allKeys
|
|
@@ -190,7 +196,7 @@ const createDecideResponseFromFlagsAndPayloads = (featureFlags, featureFlagPaylo
|
|
|
190
196
|
featureFlags: enabledFlags,
|
|
191
197
|
featureFlagPayloads: featureFlagPayloads ?? {},
|
|
192
198
|
};
|
|
193
|
-
return
|
|
199
|
+
return normalizeFlagsResponse(flagDetails);
|
|
194
200
|
};
|
|
195
201
|
const updateFlagValue = (flag, value) => {
|
|
196
202
|
return {
|
|
@@ -206,90 +212,6 @@ function getVariantFromValue(value) {
|
|
|
206
212
|
return typeof value === 'string' ? value : undefined;
|
|
207
213
|
}
|
|
208
214
|
|
|
209
|
-
// Rollout constants
|
|
210
|
-
const NEW_FLAGS_ROLLOUT_PERCENTAGE = 1;
|
|
211
|
-
// The fnv1a hashes of the tokens that are explicitly excluded from the rollout
|
|
212
|
-
// see https://github.com/PostHog/posthog-js-lite/blob/main/posthog-core/src/utils.ts#L84
|
|
213
|
-
// are hashed API tokens from our top 10 for each category supported by this SDK.
|
|
214
|
-
const NEW_FLAGS_EXCLUDED_HASHES = new Set([
|
|
215
|
-
// Node
|
|
216
|
-
'61be3dd8',
|
|
217
|
-
'96f6df5f',
|
|
218
|
-
'8cfdba9b',
|
|
219
|
-
'bf027177',
|
|
220
|
-
'e59430a8',
|
|
221
|
-
'7fa5500b',
|
|
222
|
-
'569798e9',
|
|
223
|
-
'04809ff7',
|
|
224
|
-
'0ebc61a5',
|
|
225
|
-
'32de7f98',
|
|
226
|
-
'3beeb69a',
|
|
227
|
-
'12d34ad9',
|
|
228
|
-
'733853ec',
|
|
229
|
-
'0645bb64',
|
|
230
|
-
'5dcbee21',
|
|
231
|
-
'b1f95fa3',
|
|
232
|
-
'2189e408',
|
|
233
|
-
'82b460c2',
|
|
234
|
-
'3a8cc979',
|
|
235
|
-
'29ef8843',
|
|
236
|
-
'2cdbf767',
|
|
237
|
-
'38084b54',
|
|
238
|
-
// React Native
|
|
239
|
-
'50f9f8de',
|
|
240
|
-
'41d0df91',
|
|
241
|
-
'5c236689',
|
|
242
|
-
'c11aedd3',
|
|
243
|
-
'ada46672',
|
|
244
|
-
'f4331ee1',
|
|
245
|
-
'42fed62a',
|
|
246
|
-
'c957462c',
|
|
247
|
-
'd62f705a',
|
|
248
|
-
// Web (lots of teams per org, hence lots of API tokens)
|
|
249
|
-
'e0162666',
|
|
250
|
-
'01b3e5cf',
|
|
251
|
-
'441cef7f',
|
|
252
|
-
'bb9cafee',
|
|
253
|
-
'8f348eb0',
|
|
254
|
-
'b2553f3a',
|
|
255
|
-
'97469d7d',
|
|
256
|
-
'39f21a76',
|
|
257
|
-
'03706dcc',
|
|
258
|
-
'27d50569',
|
|
259
|
-
'307584a7',
|
|
260
|
-
'6433e92e',
|
|
261
|
-
'150c7fbb',
|
|
262
|
-
'49f57f22',
|
|
263
|
-
'3772f65b',
|
|
264
|
-
'01eb8256',
|
|
265
|
-
'3c9e9234',
|
|
266
|
-
'f853c7f7',
|
|
267
|
-
'c0ac4b67',
|
|
268
|
-
'cd609d40',
|
|
269
|
-
'10ca9b1a',
|
|
270
|
-
'8a87f11b',
|
|
271
|
-
'8e8e5216',
|
|
272
|
-
'1f6b63b3',
|
|
273
|
-
'db7943dd',
|
|
274
|
-
'79b7164c',
|
|
275
|
-
'07f78e33',
|
|
276
|
-
'2d21b6fd',
|
|
277
|
-
'952db5ee',
|
|
278
|
-
'a7d3b43f',
|
|
279
|
-
'1924dd9c',
|
|
280
|
-
'84e1b8f6',
|
|
281
|
-
'dff631b6',
|
|
282
|
-
'c5aa8a79',
|
|
283
|
-
'fa133a95',
|
|
284
|
-
'498a4508',
|
|
285
|
-
'24748755',
|
|
286
|
-
'98f3d658',
|
|
287
|
-
'21bbda67',
|
|
288
|
-
'7dbfed69',
|
|
289
|
-
'be3ec24c',
|
|
290
|
-
'fc80b8e2',
|
|
291
|
-
'75cc0998',
|
|
292
|
-
]);
|
|
293
215
|
const STRING_FORMAT = 'utf8';
|
|
294
216
|
function assert(truthyValue, message) {
|
|
295
217
|
if (!truthyValue || typeof truthyValue !== 'string' || isEmpty(truthyValue)) {
|
|
@@ -345,464 +267,37 @@ const isError = (x) => {
|
|
|
345
267
|
function getFetch() {
|
|
346
268
|
return typeof fetch !== 'undefined' ? fetch : typeof globalThis.fetch !== 'undefined' ? globalThis.fetch : undefined;
|
|
347
269
|
}
|
|
348
|
-
// FNV-1a hash function
|
|
349
|
-
// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
|
350
|
-
// I know, I know, I'm rolling my own hash function, but I didn't want to take on
|
|
351
|
-
// a crypto dependency and this is just temporary anyway
|
|
352
|
-
function fnv1a(str) {
|
|
353
|
-
let hash = 0x811c9dc5; // FNV offset basis
|
|
354
|
-
for (let i = 0; i < str.length; i++) {
|
|
355
|
-
hash ^= str.charCodeAt(i);
|
|
356
|
-
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
|
|
357
|
-
}
|
|
358
|
-
// Convert to hex string, padding to 8 chars
|
|
359
|
-
return (hash >>> 0).toString(16).padStart(8, '0');
|
|
360
|
-
}
|
|
361
|
-
function isTokenInRollout(token, percentage = 0, excludedHashes) {
|
|
362
|
-
const tokenHash = fnv1a(token);
|
|
363
|
-
// Check excluded hashes (we're explicitly including these tokens from the rollout)
|
|
364
|
-
if (excludedHashes?.has(tokenHash)) {
|
|
365
|
-
return false;
|
|
366
|
-
}
|
|
367
|
-
// Convert hash to int and divide by max value to get number between 0-1
|
|
368
|
-
const hashInt = parseInt(tokenHash, 16);
|
|
369
|
-
const hashFloat = hashInt / 0xffffffff;
|
|
370
|
-
return hashFloat < percentage;
|
|
371
|
-
}
|
|
372
270
|
function allSettled(promises) {
|
|
373
271
|
return Promise.all(promises.map((p) => (p ?? Promise.resolve()).then((value) => ({ status: 'fulfilled', value }), (reason) => ({ status: 'rejected', reason }))));
|
|
374
272
|
}
|
|
375
273
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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];
|
|
274
|
+
/**
|
|
275
|
+
* Older browsers and some runtimes don't support this yet
|
|
276
|
+
* This API (as of 2025-05-07) is not available on React Native.
|
|
277
|
+
*/
|
|
278
|
+
function isGzipSupported() {
|
|
279
|
+
return 'CompressionStream' in globalThis;
|
|
397
280
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
)
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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
|
-
}
|
|
281
|
+
/**
|
|
282
|
+
* Gzip a string using Compression Streams API if it's available
|
|
283
|
+
*/
|
|
284
|
+
async function gzipCompress(input, isDebug = true) {
|
|
285
|
+
try {
|
|
286
|
+
// Turn the string into a stream using a Blob, and then compress it
|
|
287
|
+
const dataStream = new Blob([input], {
|
|
288
|
+
type: 'text/plain',
|
|
289
|
+
}).stream();
|
|
290
|
+
const compressedStream = dataStream.pipeThrough(new CompressionStream('gzip'));
|
|
291
|
+
// Using a Response to easily extract the readablestream value. Decoding into a string for fetch
|
|
292
|
+
return await new Response(compressedStream).blob();
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
if (isDebug) {
|
|
296
|
+
console.error('Failed to gzip compress data', error);
|
|
803
297
|
}
|
|
804
|
-
|
|
805
|
-
}
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
806
301
|
|
|
807
302
|
class SimpleEventEmitter {
|
|
808
303
|
constructor() {
|
|
@@ -1302,7 +797,6 @@ class PostHogCoreStateless {
|
|
|
1302
797
|
this.maxBatchSize = Math.max(this.flushAt, options?.maxBatchSize ?? 100);
|
|
1303
798
|
this.maxQueueSize = Math.max(this.flushAt, options?.maxQueueSize ?? 1000);
|
|
1304
799
|
this.flushInterval = options?.flushInterval ?? 10000;
|
|
1305
|
-
this.captureMode = options?.captureMode || 'json';
|
|
1306
800
|
this.preloadFeatureFlags = options?.preloadFeatureFlags ?? true;
|
|
1307
801
|
// If enable is explicitly set to false we override the optout
|
|
1308
802
|
this.defaultOptIn = options?.defaultOptIn ?? true;
|
|
@@ -1321,6 +815,7 @@ class PostHogCoreStateless {
|
|
|
1321
815
|
// Init promise allows the derived class to block calls until it is ready
|
|
1322
816
|
this._initPromise = Promise.resolve();
|
|
1323
817
|
this._isInitialized = true;
|
|
818
|
+
this.disableCompression = !isGzipSupported() || (options?.disableCompression ?? false);
|
|
1324
819
|
}
|
|
1325
820
|
logMsgIfDebug(fn) {
|
|
1326
821
|
if (this.isDebug) {
|
|
@@ -1503,13 +998,9 @@ class PostHogCoreStateless {
|
|
|
1503
998
|
/***
|
|
1504
999
|
*** FEATURE FLAGS
|
|
1505
1000
|
***/
|
|
1506
|
-
async
|
|
1001
|
+
async getFlags(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}) {
|
|
1507
1002
|
await this._initPromise;
|
|
1508
|
-
|
|
1509
|
-
// This is a temporary measure to ensure that we can still use the old flags API
|
|
1510
|
-
// while we migrate to the new flags API
|
|
1511
|
-
const useFlags = isTokenInRollout(this.apiKey, NEW_FLAGS_ROLLOUT_PERCENTAGE, NEW_FLAGS_EXCLUDED_HASHES);
|
|
1512
|
-
const url = useFlags ? `${this.host}/flags/?v=2` : `${this.host}/decide/?v=4`;
|
|
1003
|
+
const url = `${this.host}/flags/?v=2&config=true`;
|
|
1513
1004
|
const fetchOptions = {
|
|
1514
1005
|
method: 'POST',
|
|
1515
1006
|
headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/json' },
|
|
@@ -1522,11 +1013,11 @@ class PostHogCoreStateless {
|
|
|
1522
1013
|
...extraPayload,
|
|
1523
1014
|
}),
|
|
1524
1015
|
};
|
|
1525
|
-
this.logMsgIfDebug(() => console.log('PostHog Debug', '
|
|
1526
|
-
// Don't retry /
|
|
1016
|
+
this.logMsgIfDebug(() => console.log('PostHog Debug', 'Flags URL', url));
|
|
1017
|
+
// Don't retry /flags API calls
|
|
1527
1018
|
return this.fetchWithRetry(url, fetchOptions, { retryCount: 0 }, this.featureFlagsRequestTimeoutMs)
|
|
1528
1019
|
.then((response) => response.json())
|
|
1529
|
-
.then((response) =>
|
|
1020
|
+
.then((response) => normalizeFlagsResponse(response))
|
|
1530
1021
|
.catch((error) => {
|
|
1531
1022
|
this._events.emit('error', error);
|
|
1532
1023
|
return undefined;
|
|
@@ -1555,15 +1046,15 @@ class PostHogCoreStateless {
|
|
|
1555
1046
|
}
|
|
1556
1047
|
async getFeatureFlagDetailStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
|
|
1557
1048
|
await this._initPromise;
|
|
1558
|
-
const
|
|
1559
|
-
if (
|
|
1049
|
+
const flagsResponse = await this.getFeatureFlagDetailsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip, [key]);
|
|
1050
|
+
if (flagsResponse === undefined) {
|
|
1560
1051
|
return undefined;
|
|
1561
1052
|
}
|
|
1562
|
-
const featureFlags =
|
|
1053
|
+
const featureFlags = flagsResponse.flags;
|
|
1563
1054
|
const flagDetail = featureFlags[key];
|
|
1564
1055
|
return {
|
|
1565
1056
|
response: flagDetail,
|
|
1566
|
-
requestId:
|
|
1057
|
+
requestId: flagsResponse.requestId,
|
|
1567
1058
|
};
|
|
1568
1059
|
}
|
|
1569
1060
|
async getFeatureFlagPayloadStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
|
|
@@ -1613,26 +1104,26 @@ class PostHogCoreStateless {
|
|
|
1613
1104
|
if (flagKeysToEvaluate) {
|
|
1614
1105
|
extraPayload['flag_keys_to_evaluate'] = flagKeysToEvaluate;
|
|
1615
1106
|
}
|
|
1616
|
-
const
|
|
1617
|
-
if (
|
|
1107
|
+
const flagsResponse = await this.getFlags(distinctId, groups, personProperties, groupProperties, extraPayload);
|
|
1108
|
+
if (flagsResponse === undefined) {
|
|
1618
1109
|
// We probably errored out, so return undefined
|
|
1619
1110
|
return undefined;
|
|
1620
1111
|
}
|
|
1621
|
-
// if there's an error on the
|
|
1622
|
-
if (
|
|
1112
|
+
// if there's an error on the flagsResponse, log a console error, but don't throw an error
|
|
1113
|
+
if (flagsResponse.errorsWhileComputingFlags) {
|
|
1623
1114
|
console.error('[FEATURE FLAGS] Error while computing feature flags, some flags may be missing or incorrect. Learn more at https://posthog.com/docs/feature-flags/best-practices');
|
|
1624
1115
|
}
|
|
1625
1116
|
// Add check for quota limitation on feature flags
|
|
1626
|
-
if (
|
|
1117
|
+
if (flagsResponse.quotaLimited?.includes(QuotaLimitedFeature.FeatureFlags)) {
|
|
1627
1118
|
console.warn('[FEATURE FLAGS] Feature flags quota limit exceeded - feature flags unavailable. Learn more about billing limits at https://posthog.com/docs/billing/limits-alerts');
|
|
1628
1119
|
return {
|
|
1629
1120
|
flags: {},
|
|
1630
1121
|
featureFlags: {},
|
|
1631
1122
|
featureFlagPayloads: {},
|
|
1632
|
-
requestId:
|
|
1123
|
+
requestId: flagsResponse?.requestId,
|
|
1633
1124
|
};
|
|
1634
1125
|
}
|
|
1635
|
-
return
|
|
1126
|
+
return flagsResponse;
|
|
1636
1127
|
}
|
|
1637
1128
|
/***
|
|
1638
1129
|
*** SURVEYS
|
|
@@ -1742,22 +1233,17 @@ class PostHogCoreStateless {
|
|
|
1742
1233
|
data.historical_migration = true;
|
|
1743
1234
|
}
|
|
1744
1235
|
const payload = JSON.stringify(data);
|
|
1745
|
-
const url = this.
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
: {
|
|
1757
|
-
method: 'POST',
|
|
1758
|
-
headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/json' },
|
|
1759
|
-
body: payload,
|
|
1760
|
-
};
|
|
1236
|
+
const url = `${this.host}/batch/`;
|
|
1237
|
+
const gzippedPayload = !this.disableCompression ? await gzipCompress(payload, this.isDebug) : null;
|
|
1238
|
+
const fetchOptions = {
|
|
1239
|
+
method: 'POST',
|
|
1240
|
+
headers: {
|
|
1241
|
+
...this.getCustomHeaders(),
|
|
1242
|
+
'Content-Type': 'application/json',
|
|
1243
|
+
...(gzippedPayload !== null && { 'Content-Encoding': 'gzip' }),
|
|
1244
|
+
},
|
|
1245
|
+
body: gzippedPayload || payload,
|
|
1246
|
+
};
|
|
1761
1247
|
try {
|
|
1762
1248
|
await this.fetchWithRetry(url, fetchOptions);
|
|
1763
1249
|
}
|
|
@@ -1881,22 +1367,17 @@ class PostHogCoreStateless {
|
|
|
1881
1367
|
data.historical_migration = true;
|
|
1882
1368
|
}
|
|
1883
1369
|
const payload = JSON.stringify(data);
|
|
1884
|
-
const url = this.
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
: {
|
|
1896
|
-
method: 'POST',
|
|
1897
|
-
headers: { ...this.getCustomHeaders(), 'Content-Type': 'application/json' },
|
|
1898
|
-
body: payload,
|
|
1899
|
-
};
|
|
1370
|
+
const url = `${this.host}/batch/`;
|
|
1371
|
+
const gzippedPayload = !this.disableCompression ? await gzipCompress(payload, this.isDebug) : null;
|
|
1372
|
+
const fetchOptions = {
|
|
1373
|
+
method: 'POST',
|
|
1374
|
+
headers: {
|
|
1375
|
+
...this.getCustomHeaders(),
|
|
1376
|
+
'Content-Type': 'application/json',
|
|
1377
|
+
...(gzippedPayload !== null && { 'Content-Encoding': 'gzip' }),
|
|
1378
|
+
},
|
|
1379
|
+
body: gzippedPayload || payload,
|
|
1380
|
+
};
|
|
1900
1381
|
const retryOptions = {
|
|
1901
1382
|
retryCheck: (err) => {
|
|
1902
1383
|
// don't automatically retry on 413 errors, we want to reduce the batch size first
|
|
@@ -1941,11 +1422,21 @@ class PostHogCoreStateless {
|
|
|
1941
1422
|
const body = options.body ? options.body : '';
|
|
1942
1423
|
let reqByteLength = -1;
|
|
1943
1424
|
try {
|
|
1944
|
-
|
|
1425
|
+
if (body instanceof Blob) {
|
|
1426
|
+
reqByteLength = body.size;
|
|
1427
|
+
}
|
|
1428
|
+
else {
|
|
1429
|
+
reqByteLength = Buffer.byteLength(body, STRING_FORMAT);
|
|
1430
|
+
}
|
|
1945
1431
|
}
|
|
1946
1432
|
catch {
|
|
1947
|
-
|
|
1948
|
-
|
|
1433
|
+
if (body instanceof Blob) {
|
|
1434
|
+
reqByteLength = body.size;
|
|
1435
|
+
}
|
|
1436
|
+
else {
|
|
1437
|
+
const encoded = new TextEncoder().encode(body);
|
|
1438
|
+
reqByteLength = encoded.length;
|
|
1439
|
+
}
|
|
1949
1440
|
}
|
|
1950
1441
|
return await retriable(async () => {
|
|
1951
1442
|
let res = null;
|
|
@@ -2064,7 +1555,7 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2064
1555
|
const bootstrapFeatureFlags = bootstrap.featureFlags;
|
|
2065
1556
|
const bootstrapFeatureFlagPayloads = bootstrap.featureFlagPayloads ?? {};
|
|
2066
1557
|
if (bootstrapFeatureFlags && Object.keys(bootstrapFeatureFlags).length) {
|
|
2067
|
-
const normalizedBootstrapFeatureFlagDetails =
|
|
1558
|
+
const normalizedBootstrapFeatureFlagDetails = createFlagsResponseFromFlagsAndPayloads(bootstrapFeatureFlags, bootstrapFeatureFlagPayloads);
|
|
2068
1559
|
if (Object.keys(normalizedBootstrapFeatureFlagDetails.flags).length > 0) {
|
|
2069
1560
|
this.setBootstrappedFeatureFlagDetails(normalizedBootstrapFeatureFlagDetails);
|
|
2070
1561
|
const currentFeatureFlagDetails = this.getKnownFeatureFlagDetails() || { flags: {}, requestId: undefined };
|
|
@@ -2206,7 +1697,7 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2206
1697
|
...maybeAdd('$set_once', userPropsOnce),
|
|
2207
1698
|
});
|
|
2208
1699
|
if (distinctId !== previousDistinctId) {
|
|
2209
|
-
// We keep the AnonymousId to be used by
|
|
1700
|
+
// We keep the AnonymousId to be used by flags calls and identify to link the previousId
|
|
2210
1701
|
this.setPersistedProperty(PostHogPersistedProperty.AnonymousId, previousDistinctId);
|
|
2211
1702
|
this.setPersistedProperty(PostHogPersistedProperty.DistinctId, distinctId);
|
|
2212
1703
|
this.reloadFeatureFlags();
|
|
@@ -2299,10 +1790,6 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2299
1790
|
this.setPersistedProperty(PostHogPersistedProperty.PersonProperties, null);
|
|
2300
1791
|
});
|
|
2301
1792
|
}
|
|
2302
|
-
/** @deprecated - Renamed to setPersonPropertiesForFlags */
|
|
2303
|
-
personProperties(properties) {
|
|
2304
|
-
return this.setPersonPropertiesForFlags(properties);
|
|
2305
|
-
}
|
|
2306
1793
|
setGroupPropertiesForFlags(properties) {
|
|
2307
1794
|
this.wrap(() => {
|
|
2308
1795
|
// Get persisted group properties
|
|
@@ -2328,12 +1815,6 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2328
1815
|
this.setPersistedProperty(PostHogPersistedProperty.GroupProperties, null);
|
|
2329
1816
|
});
|
|
2330
1817
|
}
|
|
2331
|
-
/** @deprecated - Renamed to setGroupPropertiesForFlags */
|
|
2332
|
-
groupProperties(properties) {
|
|
2333
|
-
this.wrap(() => {
|
|
2334
|
-
this.setGroupPropertiesForFlags(properties);
|
|
2335
|
-
});
|
|
2336
|
-
}
|
|
2337
1818
|
async remoteConfigAsync() {
|
|
2338
1819
|
await this._initPromise;
|
|
2339
1820
|
if (this._remoteConfigResponsePromise) {
|
|
@@ -2344,12 +1825,12 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2344
1825
|
/***
|
|
2345
1826
|
*** FEATURE FLAGS
|
|
2346
1827
|
***/
|
|
2347
|
-
async
|
|
1828
|
+
async flagsAsync(sendAnonDistinctId = true) {
|
|
2348
1829
|
await this._initPromise;
|
|
2349
|
-
if (this.
|
|
2350
|
-
return this.
|
|
1830
|
+
if (this._flagsResponsePromise) {
|
|
1831
|
+
return this._flagsResponsePromise;
|
|
2351
1832
|
}
|
|
2352
|
-
return this.
|
|
1833
|
+
return this._flagsAsync(sendAnonDistinctId);
|
|
2353
1834
|
}
|
|
2354
1835
|
cacheSessionReplay(source, response) {
|
|
2355
1836
|
const sessionReplay = response?.sessionRecording;
|
|
@@ -2407,6 +1888,9 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2407
1888
|
else if (this.preloadFeatureFlags !== false) {
|
|
2408
1889
|
this.reloadFeatureFlags();
|
|
2409
1890
|
}
|
|
1891
|
+
if (!response.supportedCompression?.includes(Compression.GZipJS)) {
|
|
1892
|
+
this.disableCompression = true;
|
|
1893
|
+
}
|
|
2410
1894
|
remoteConfig = response;
|
|
2411
1895
|
}
|
|
2412
1896
|
return remoteConfig;
|
|
@@ -2417,8 +1901,8 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2417
1901
|
});
|
|
2418
1902
|
return this._remoteConfigResponsePromise;
|
|
2419
1903
|
}
|
|
2420
|
-
async
|
|
2421
|
-
this.
|
|
1904
|
+
async _flagsAsync(sendAnonDistinctId = true) {
|
|
1905
|
+
this._flagsResponsePromise = this._initPromise
|
|
2422
1906
|
.then(async () => {
|
|
2423
1907
|
const distinctId = this.getDistinctId();
|
|
2424
1908
|
const groups = this.props.$groups || {};
|
|
@@ -2428,7 +1912,7 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2428
1912
|
const extraProperties = {
|
|
2429
1913
|
$anon_distinct_id: sendAnonDistinctId ? this.getAnonymousId() : undefined,
|
|
2430
1914
|
};
|
|
2431
|
-
const res = await super.
|
|
1915
|
+
const res = await super.getFlags(distinctId, groups, personProperties, groupProperties, extraProperties);
|
|
2432
1916
|
// Add check for quota limitation on feature flags
|
|
2433
1917
|
if (res?.quotaLimited?.includes(QuotaLimitedFeature.FeatureFlags)) {
|
|
2434
1918
|
// Unset all feature flags by setting to null
|
|
@@ -2452,22 +1936,22 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2452
1936
|
};
|
|
2453
1937
|
}
|
|
2454
1938
|
this.setKnownFeatureFlagDetails(newFeatureFlagDetails);
|
|
2455
|
-
// Mark that we hit the /
|
|
2456
|
-
this.setPersistedProperty(PostHogPersistedProperty.
|
|
2457
|
-
this.cacheSessionReplay('
|
|
1939
|
+
// Mark that we hit the /flags endpoint so we can capture this in the $feature_flag_called event
|
|
1940
|
+
this.setPersistedProperty(PostHogPersistedProperty.FlagsEndpointWasHit, true);
|
|
1941
|
+
this.cacheSessionReplay('flags', res);
|
|
2458
1942
|
}
|
|
2459
1943
|
return res;
|
|
2460
1944
|
})
|
|
2461
1945
|
.finally(() => {
|
|
2462
|
-
this.
|
|
1946
|
+
this._flagsResponsePromise = undefined;
|
|
2463
1947
|
});
|
|
2464
|
-
return this.
|
|
1948
|
+
return this._flagsResponsePromise;
|
|
2465
1949
|
}
|
|
2466
1950
|
// We only store the flags and request id in the feature flag details storage key
|
|
2467
|
-
setKnownFeatureFlagDetails(
|
|
1951
|
+
setKnownFeatureFlagDetails(flagsResponse) {
|
|
2468
1952
|
this.wrap(() => {
|
|
2469
|
-
this.setPersistedProperty(PostHogPersistedProperty.FeatureFlagDetails,
|
|
2470
|
-
this._events.emit('featureflags', getFlagValuesFromFlags(
|
|
1953
|
+
this.setPersistedProperty(PostHogPersistedProperty.FeatureFlagDetails, flagsResponse);
|
|
1954
|
+
this._events.emit('featureflags', getFlagValuesFromFlags(flagsResponse?.flags ?? {}));
|
|
2471
1955
|
});
|
|
2472
1956
|
}
|
|
2473
1957
|
getKnownFeatureFlagDetails() {
|
|
@@ -2479,9 +1963,9 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2479
1963
|
if (featureFlags === undefined && featureFlagPayloads === undefined) {
|
|
2480
1964
|
return undefined;
|
|
2481
1965
|
}
|
|
2482
|
-
return
|
|
1966
|
+
return createFlagsResponseFromFlagsAndPayloads(featureFlags ?? {}, featureFlagPayloads ?? {});
|
|
2483
1967
|
}
|
|
2484
|
-
return
|
|
1968
|
+
return normalizeFlagsResponse(storedDetails);
|
|
2485
1969
|
}
|
|
2486
1970
|
getKnownFeatureFlags() {
|
|
2487
1971
|
const featureFlagDetails = this.getKnownFeatureFlagDetails();
|
|
@@ -2545,8 +2029,8 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2545
2029
|
...maybeAdd('$feature_flag_reason', featureFlag?.reason?.description ?? featureFlag?.reason?.code),
|
|
2546
2030
|
...maybeAdd('$feature_flag_bootstrapped_response', bootstrappedResponse),
|
|
2547
2031
|
...maybeAdd('$feature_flag_bootstrapped_payload', bootstrappedPayload),
|
|
2548
|
-
// If we haven't yet received a response from the /
|
|
2549
|
-
$used_bootstrap_value: !this.getPersistedProperty(PostHogPersistedProperty.
|
|
2032
|
+
// If we haven't yet received a response from the /flags endpoint, we must have used the bootstrapped value
|
|
2033
|
+
$used_bootstrap_value: !this.getPersistedProperty(PostHogPersistedProperty.FlagsEndpointWasHit),
|
|
2550
2034
|
...maybeAdd('$feature_flag_request_id', details.requestId),
|
|
2551
2035
|
});
|
|
2552
2036
|
}
|
|
@@ -2595,7 +2079,7 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2595
2079
|
...details,
|
|
2596
2080
|
flags,
|
|
2597
2081
|
};
|
|
2598
|
-
return
|
|
2082
|
+
return normalizeFlagsResponse(result);
|
|
2599
2083
|
}
|
|
2600
2084
|
getFeatureFlagsAndPayloads() {
|
|
2601
2085
|
const flags = this.getFeatureFlags();
|
|
@@ -2613,14 +2097,14 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2613
2097
|
return !!response;
|
|
2614
2098
|
}
|
|
2615
2099
|
// Used when we want to trigger the reload but we don't care about the result
|
|
2616
|
-
reloadFeatureFlags(
|
|
2617
|
-
this.
|
|
2100
|
+
reloadFeatureFlags(options) {
|
|
2101
|
+
this.flagsAsync(true)
|
|
2618
2102
|
.then((res) => {
|
|
2619
|
-
cb?.(undefined, res?.featureFlags);
|
|
2103
|
+
options?.cb?.(undefined, res?.featureFlags);
|
|
2620
2104
|
})
|
|
2621
2105
|
.catch((e) => {
|
|
2622
|
-
cb?.(e, undefined);
|
|
2623
|
-
if (!cb) {
|
|
2106
|
+
options?.cb?.(e, undefined);
|
|
2107
|
+
if (!options?.cb) {
|
|
2624
2108
|
this.logMsgIfDebug(() => console.log('PostHog Debug', 'Error reloading feature flags', e));
|
|
2625
2109
|
}
|
|
2626
2110
|
});
|
|
@@ -2628,8 +2112,8 @@ class PostHogCore extends PostHogCoreStateless {
|
|
|
2628
2112
|
async reloadRemoteConfigAsync() {
|
|
2629
2113
|
return await this.remoteConfigAsync();
|
|
2630
2114
|
}
|
|
2631
|
-
async reloadFeatureFlagsAsync(sendAnonDistinctId
|
|
2632
|
-
return (await this.
|
|
2115
|
+
async reloadFeatureFlagsAsync(sendAnonDistinctId) {
|
|
2116
|
+
return (await this.flagsAsync(sendAnonDistinctId ?? true))?.featureFlags;
|
|
2633
2117
|
}
|
|
2634
2118
|
onFeatureFlags(cb) {
|
|
2635
2119
|
return this.on('featureflags', async () => {
|