posthog-node 3.6.3 → 4.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/lib/index.cjs.js +1087 -2227
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +47 -25
- package/lib/index.esm.js +1087 -2227
- package/lib/index.esm.js.map +1 -1
- package/lib/posthog-core/src/index.d.ts +44 -30
- package/lib/posthog-core/src/types.d.ts +19 -3
- package/lib/posthog-core/src/utils.d.ts +5 -4
- package/lib/posthog-node/src/posthog-node.d.ts +7 -8
- package/lib/posthog-node/src/types.d.ts +3 -1
- package/lib/posthog-node/test/test-utils.d.ts +8 -0
- package/package.json +1 -1
- package/src/posthog-node.ts +22 -14
- package/src/types.ts +3 -1
- package/test/feature-flags.spec.ts +63 -133
- package/test/posthog-node.spec.ts +1 -2
- package/test/test-utils.ts +64 -0
package/lib/index.cjs.js
CHANGED
|
@@ -4,161 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var rusha = require('rusha');
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
Copyright (c) Microsoft Corporation.
|
|
9
|
-
|
|
10
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
11
|
-
purpose with or without fee is hereby granted.
|
|
12
|
-
|
|
13
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
14
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
15
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
16
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
17
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
18
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
19
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
20
|
-
***************************************************************************** */
|
|
21
|
-
/* global Reflect, Promise */
|
|
22
|
-
var extendStatics = function (d, b) {
|
|
23
|
-
extendStatics = Object.setPrototypeOf ||
|
|
24
|
-
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
25
|
-
function (d, b) { for (var p in b)
|
|
26
|
-
if (Object.prototype.hasOwnProperty.call(b, p))
|
|
27
|
-
d[p] = b[p]; };
|
|
28
|
-
return extendStatics(d, b);
|
|
29
|
-
};
|
|
30
|
-
function __extends(d, b) {
|
|
31
|
-
if (typeof b !== "function" && b !== null)
|
|
32
|
-
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
33
|
-
extendStatics(d, b);
|
|
34
|
-
function __() { this.constructor = d; }
|
|
35
|
-
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
36
|
-
}
|
|
37
|
-
var __assign = function () {
|
|
38
|
-
__assign = Object.assign || function __assign(t) {
|
|
39
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
40
|
-
s = arguments[i];
|
|
41
|
-
for (var p in s)
|
|
42
|
-
if (Object.prototype.hasOwnProperty.call(s, p))
|
|
43
|
-
t[p] = s[p];
|
|
44
|
-
}
|
|
45
|
-
return t;
|
|
46
|
-
};
|
|
47
|
-
return __assign.apply(this, arguments);
|
|
48
|
-
};
|
|
49
|
-
function __rest(s, e) {
|
|
50
|
-
var t = {};
|
|
51
|
-
for (var p in s)
|
|
52
|
-
if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
53
|
-
t[p] = s[p];
|
|
54
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
55
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
56
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
57
|
-
t[p[i]] = s[p[i]];
|
|
58
|
-
}
|
|
59
|
-
return t;
|
|
60
|
-
}
|
|
61
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
62
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
63
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
64
|
-
function fulfilled(value) { try {
|
|
65
|
-
step(generator.next(value));
|
|
66
|
-
}
|
|
67
|
-
catch (e) {
|
|
68
|
-
reject(e);
|
|
69
|
-
} }
|
|
70
|
-
function rejected(value) { try {
|
|
71
|
-
step(generator["throw"](value));
|
|
72
|
-
}
|
|
73
|
-
catch (e) {
|
|
74
|
-
reject(e);
|
|
75
|
-
} }
|
|
76
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
77
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
function __generator(thisArg, body) {
|
|
81
|
-
var _ = { label: 0, sent: function () { if (t[0] & 1)
|
|
82
|
-
throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
83
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g;
|
|
84
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
85
|
-
function step(op) {
|
|
86
|
-
if (f)
|
|
87
|
-
throw new TypeError("Generator is already executing.");
|
|
88
|
-
while (_)
|
|
89
|
-
try {
|
|
90
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done)
|
|
91
|
-
return t;
|
|
92
|
-
if (y = 0, t)
|
|
93
|
-
op = [op[0] & 2, t.value];
|
|
94
|
-
switch (op[0]) {
|
|
95
|
-
case 0:
|
|
96
|
-
case 1:
|
|
97
|
-
t = op;
|
|
98
|
-
break;
|
|
99
|
-
case 4:
|
|
100
|
-
_.label++;
|
|
101
|
-
return { value: op[1], done: false };
|
|
102
|
-
case 5:
|
|
103
|
-
_.label++;
|
|
104
|
-
y = op[1];
|
|
105
|
-
op = [0];
|
|
106
|
-
continue;
|
|
107
|
-
case 7:
|
|
108
|
-
op = _.ops.pop();
|
|
109
|
-
_.trys.pop();
|
|
110
|
-
continue;
|
|
111
|
-
default:
|
|
112
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
113
|
-
_ = 0;
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
|
|
117
|
-
_.label = op[1];
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
if (op[0] === 6 && _.label < t[1]) {
|
|
121
|
-
_.label = t[1];
|
|
122
|
-
t = op;
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
125
|
-
if (t && _.label < t[2]) {
|
|
126
|
-
_.label = t[2];
|
|
127
|
-
_.ops.push(op);
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
if (t[2])
|
|
131
|
-
_.ops.pop();
|
|
132
|
-
_.trys.pop();
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
op = body.call(thisArg, _);
|
|
136
|
-
}
|
|
137
|
-
catch (e) {
|
|
138
|
-
op = [6, e];
|
|
139
|
-
y = 0;
|
|
140
|
-
}
|
|
141
|
-
finally {
|
|
142
|
-
f = t = 0;
|
|
143
|
-
}
|
|
144
|
-
if (op[0] & 5)
|
|
145
|
-
throw op[1];
|
|
146
|
-
return { value: op[0] ? op[1] : void 0, done: true };
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
function __spreadArray(to, from, pack) {
|
|
150
|
-
if (pack || arguments.length === 2)
|
|
151
|
-
for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
152
|
-
if (ar || !(i in from)) {
|
|
153
|
-
if (!ar)
|
|
154
|
-
ar = Array.prototype.slice.call(from, 0, i);
|
|
155
|
-
ar[i] = from[i];
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
var version = "3.6.3";
|
|
7
|
+
var version = "4.0.0-beta.1";
|
|
162
8
|
|
|
163
9
|
var PostHogPersistedProperty;
|
|
164
10
|
(function (PostHogPersistedProperty) {
|
|
@@ -184,48 +30,27 @@ function assert(truthyValue, message) {
|
|
|
184
30
|
}
|
|
185
31
|
}
|
|
186
32
|
function removeTrailingSlash(url) {
|
|
187
|
-
return url
|
|
33
|
+
return url?.replace(/\/+$/, '');
|
|
188
34
|
}
|
|
189
|
-
function retriable(fn, props) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
return [4 /*yield*/, new Promise(function (r) { return setTimeout(r, retryDelay); })];
|
|
205
|
-
case 2:
|
|
206
|
-
// don't wait when it's the last try
|
|
207
|
-
_d.sent();
|
|
208
|
-
_d.label = 3;
|
|
209
|
-
case 3:
|
|
210
|
-
_d.trys.push([3, 5, , 6]);
|
|
211
|
-
return [4 /*yield*/, fn()];
|
|
212
|
-
case 4:
|
|
213
|
-
res = _d.sent();
|
|
214
|
-
return [2 /*return*/, res];
|
|
215
|
-
case 5:
|
|
216
|
-
e_1 = _d.sent();
|
|
217
|
-
lastError = e_1;
|
|
218
|
-
if (!retryCheck(e_1)) {
|
|
219
|
-
throw e_1;
|
|
220
|
-
}
|
|
221
|
-
return [3 /*break*/, 6];
|
|
222
|
-
case 6:
|
|
223
|
-
i++;
|
|
224
|
-
return [3 /*break*/, 1];
|
|
225
|
-
case 7: throw lastError;
|
|
35
|
+
async function retriable(fn, props) {
|
|
36
|
+
let lastError = null;
|
|
37
|
+
for (let i = 0; i < props.retryCount + 1; i++) {
|
|
38
|
+
if (i > 0) {
|
|
39
|
+
// don't wait when it's the last try
|
|
40
|
+
await new Promise((r) => setTimeout(r, props.retryDelay));
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const res = await fn();
|
|
44
|
+
return res;
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
lastError = e;
|
|
48
|
+
if (!props.retryCheck(e)) {
|
|
49
|
+
throw e;
|
|
226
50
|
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
throw lastError;
|
|
229
54
|
}
|
|
230
55
|
function currentTimestamp() {
|
|
231
56
|
return new Date().getTime();
|
|
@@ -236,9 +61,9 @@ function currentISOTime() {
|
|
|
236
61
|
function safeSetTimeout(fn, timeout) {
|
|
237
62
|
// NOTE: we use this so rarely that it is totally fine to do `safeSetTimeout(fn, 0)``
|
|
238
63
|
// rather than setImmediate.
|
|
239
|
-
|
|
64
|
+
const t = setTimeout(fn, timeout);
|
|
240
65
|
// We unref if available to prevent Node.js hanging on exit
|
|
241
|
-
|
|
66
|
+
t?.unref && t?.unref();
|
|
242
67
|
return t;
|
|
243
68
|
}
|
|
244
69
|
|
|
@@ -252,24 +77,24 @@ function safeSetTimeout(fn, timeout) {
|
|
|
252
77
|
//
|
|
253
78
|
// LZ-based compression algorithm, version 1.4.4
|
|
254
79
|
// private property
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
80
|
+
const f = String.fromCharCode;
|
|
81
|
+
const keyStrBase64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
82
|
+
const baseReverseDic = {};
|
|
258
83
|
function getBaseValue(alphabet, character) {
|
|
259
84
|
if (!baseReverseDic[alphabet]) {
|
|
260
85
|
baseReverseDic[alphabet] = {};
|
|
261
|
-
for (
|
|
86
|
+
for (let i = 0; i < alphabet.length; i++) {
|
|
262
87
|
baseReverseDic[alphabet][alphabet.charAt(i)] = i;
|
|
263
88
|
}
|
|
264
89
|
}
|
|
265
90
|
return baseReverseDic[alphabet][character];
|
|
266
91
|
}
|
|
267
|
-
|
|
92
|
+
const LZString = {
|
|
268
93
|
compressToBase64: function (input) {
|
|
269
94
|
if (input == null) {
|
|
270
95
|
return '';
|
|
271
96
|
}
|
|
272
|
-
|
|
97
|
+
const res = LZString._compress(input, 6, function (a) {
|
|
273
98
|
return keyStrBase64.charAt(a);
|
|
274
99
|
});
|
|
275
100
|
switch (res.length % 4 // To produce valid Base64
|
|
@@ -305,8 +130,8 @@ var LZString = {
|
|
|
305
130
|
if (uncompressed == null) {
|
|
306
131
|
return '';
|
|
307
132
|
}
|
|
308
|
-
|
|
309
|
-
|
|
133
|
+
const context_dictionary = {}, context_dictionaryToCreate = {}, context_data = [];
|
|
134
|
+
let i, value, context_c = '', context_wc = '', context_w = '', context_enlargeIn = 2, // Compensate for the first entry which should not count
|
|
310
135
|
context_dictSize = 3, context_numBits = 2, context_data_val = 0, context_data_position = 0, ii;
|
|
311
136
|
for (ii = 0; ii < uncompressed.length; ii += 1) {
|
|
312
137
|
context_c = uncompressed.charAt(ii);
|
|
@@ -530,8 +355,8 @@ var LZString = {
|
|
|
530
355
|
});
|
|
531
356
|
},
|
|
532
357
|
_decompress: function (length, resetValue, getNextValue) {
|
|
533
|
-
|
|
534
|
-
|
|
358
|
+
const dictionary = [], result = [], data = { val: getNextValue(0), position: resetValue, index: 1 };
|
|
359
|
+
let enlargeIn = 4, dictSize = 4, numBits = 3, entry = '', i, w, bits, resb, maxpower, power, c;
|
|
535
360
|
for (i = 0; i < 3; i += 1) {
|
|
536
361
|
dictionary[i] = i;
|
|
537
362
|
}
|
|
@@ -673,33 +498,29 @@ var LZString = {
|
|
|
673
498
|
},
|
|
674
499
|
};
|
|
675
500
|
|
|
676
|
-
|
|
677
|
-
|
|
501
|
+
class SimpleEventEmitter {
|
|
502
|
+
constructor() {
|
|
678
503
|
this.events = {};
|
|
679
504
|
this.events = {};
|
|
680
505
|
}
|
|
681
|
-
|
|
682
|
-
var _this = this;
|
|
506
|
+
on(event, listener) {
|
|
683
507
|
if (!this.events[event]) {
|
|
684
508
|
this.events[event] = [];
|
|
685
509
|
}
|
|
686
510
|
this.events[event].push(listener);
|
|
687
|
-
return
|
|
688
|
-
|
|
511
|
+
return () => {
|
|
512
|
+
this.events[event] = this.events[event].filter((x) => x !== listener);
|
|
689
513
|
};
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
for (
|
|
693
|
-
var listener = _a[_i];
|
|
514
|
+
}
|
|
515
|
+
emit(event, payload) {
|
|
516
|
+
for (const listener of this.events[event] || []) {
|
|
694
517
|
listener(payload);
|
|
695
518
|
}
|
|
696
|
-
for (
|
|
697
|
-
var listener = _c[_b];
|
|
519
|
+
for (const listener of this.events['*'] || []) {
|
|
698
520
|
listener(event, payload);
|
|
699
521
|
}
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
}());
|
|
522
|
+
}
|
|
523
|
+
}
|
|
703
524
|
|
|
704
525
|
// vendor from: https://github.com/LiosK/uuidv7/blob/f30b7a7faff73afbce0b27a46c638310f96912ba/src/index.ts
|
|
705
526
|
// https://github.com/LiosK/uuidv7#license
|
|
@@ -710,11 +531,11 @@ var SimpleEventEmitter = /** @class */ (function () {
|
|
|
710
531
|
* @copyright 2021-2023 LiosK
|
|
711
532
|
* @packageDocumentation
|
|
712
533
|
*/
|
|
713
|
-
|
|
534
|
+
const DIGITS = "0123456789abcdef";
|
|
714
535
|
/** Represents a UUID as a 16-byte byte array. */
|
|
715
|
-
|
|
536
|
+
class UUID {
|
|
716
537
|
/** @param bytes - The 16-byte byte array representation. */
|
|
717
|
-
|
|
538
|
+
constructor(bytes) {
|
|
718
539
|
this.bytes = bytes;
|
|
719
540
|
}
|
|
720
541
|
/**
|
|
@@ -726,14 +547,14 @@ var UUID = /** @class */ (function () {
|
|
|
726
547
|
*
|
|
727
548
|
* @throws TypeError if the length of the argument is not 16.
|
|
728
549
|
*/
|
|
729
|
-
|
|
550
|
+
static ofInner(bytes) {
|
|
730
551
|
if (bytes.length !== 16) {
|
|
731
552
|
throw new TypeError("not 128-bit length");
|
|
732
553
|
}
|
|
733
554
|
else {
|
|
734
555
|
return new UUID(bytes);
|
|
735
556
|
}
|
|
736
|
-
}
|
|
557
|
+
}
|
|
737
558
|
/**
|
|
738
559
|
* Builds a byte array from UUIDv7 field values.
|
|
739
560
|
*
|
|
@@ -743,7 +564,7 @@ var UUID = /** @class */ (function () {
|
|
|
743
564
|
* @param randBLo - The lower 32 bits of 62-bit `rand_b` field value.
|
|
744
565
|
* @throws RangeError if any field value is out of the specified range.
|
|
745
566
|
*/
|
|
746
|
-
|
|
567
|
+
static fromFieldsV7(unixTsMs, randA, randBHi, randBLo) {
|
|
747
568
|
if (!Number.isInteger(unixTsMs) ||
|
|
748
569
|
!Number.isInteger(randA) ||
|
|
749
570
|
!Number.isInteger(randBHi) ||
|
|
@@ -758,12 +579,12 @@ var UUID = /** @class */ (function () {
|
|
|
758
579
|
randBLo > 4294967295) {
|
|
759
580
|
throw new RangeError("invalid field value");
|
|
760
581
|
}
|
|
761
|
-
|
|
762
|
-
bytes[0] = unixTsMs /
|
|
763
|
-
bytes[1] = unixTsMs /
|
|
764
|
-
bytes[2] = unixTsMs /
|
|
765
|
-
bytes[3] = unixTsMs /
|
|
766
|
-
bytes[4] = unixTsMs /
|
|
582
|
+
const bytes = new Uint8Array(16);
|
|
583
|
+
bytes[0] = unixTsMs / 2 ** 40;
|
|
584
|
+
bytes[1] = unixTsMs / 2 ** 32;
|
|
585
|
+
bytes[2] = unixTsMs / 2 ** 24;
|
|
586
|
+
bytes[3] = unixTsMs / 2 ** 16;
|
|
587
|
+
bytes[4] = unixTsMs / 2 ** 8;
|
|
767
588
|
bytes[5] = unixTsMs;
|
|
768
589
|
bytes[6] = 0x70 | (randA >>> 8);
|
|
769
590
|
bytes[7] = randA;
|
|
@@ -776,7 +597,7 @@ var UUID = /** @class */ (function () {
|
|
|
776
597
|
bytes[14] = randBLo >>> 8;
|
|
777
598
|
bytes[15] = randBLo;
|
|
778
599
|
return new UUID(bytes);
|
|
779
|
-
}
|
|
600
|
+
}
|
|
780
601
|
/**
|
|
781
602
|
* Builds a byte array from a string representation.
|
|
782
603
|
*
|
|
@@ -791,33 +612,38 @@ var UUID = /** @class */ (function () {
|
|
|
791
612
|
*
|
|
792
613
|
* @throws SyntaxError if the argument could not parse as a valid UUID string.
|
|
793
614
|
*/
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
var hex = undefined;
|
|
615
|
+
static parse(uuid) {
|
|
616
|
+
let hex = undefined;
|
|
797
617
|
switch (uuid.length) {
|
|
798
618
|
case 32:
|
|
799
|
-
hex =
|
|
619
|
+
hex = /^[0-9a-f]{32}$/i.exec(uuid)?.[0];
|
|
800
620
|
break;
|
|
801
621
|
case 36:
|
|
802
622
|
hex =
|
|
803
|
-
|
|
804
|
-
.exec(uuid)
|
|
623
|
+
/^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})$/i
|
|
624
|
+
.exec(uuid)
|
|
625
|
+
?.slice(1, 6)
|
|
626
|
+
.join("");
|
|
805
627
|
break;
|
|
806
628
|
case 38:
|
|
807
629
|
hex =
|
|
808
|
-
|
|
809
|
-
.exec(uuid)
|
|
630
|
+
/^\{([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})\}$/i
|
|
631
|
+
.exec(uuid)
|
|
632
|
+
?.slice(1, 6)
|
|
633
|
+
.join("");
|
|
810
634
|
break;
|
|
811
635
|
case 45:
|
|
812
636
|
hex =
|
|
813
|
-
|
|
814
|
-
.exec(uuid)
|
|
637
|
+
/^urn:uuid:([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})$/i
|
|
638
|
+
.exec(uuid)
|
|
639
|
+
?.slice(1, 6)
|
|
640
|
+
.join("");
|
|
815
641
|
break;
|
|
816
642
|
}
|
|
817
643
|
if (hex) {
|
|
818
|
-
|
|
819
|
-
for (
|
|
820
|
-
|
|
644
|
+
const inner = new Uint8Array(16);
|
|
645
|
+
for (let i = 0; i < 16; i += 4) {
|
|
646
|
+
const n = parseInt(hex.substring(2 * i, 2 * i + 8), 16);
|
|
821
647
|
inner[i + 0] = n >>> 24;
|
|
822
648
|
inner[i + 1] = n >>> 16;
|
|
823
649
|
inner[i + 2] = n >>> 8;
|
|
@@ -828,14 +654,14 @@ var UUID = /** @class */ (function () {
|
|
|
828
654
|
else {
|
|
829
655
|
throw new SyntaxError("could not parse UUID string");
|
|
830
656
|
}
|
|
831
|
-
}
|
|
657
|
+
}
|
|
832
658
|
/**
|
|
833
659
|
* @returns The 8-4-4-4-12 canonical hexadecimal string representation
|
|
834
660
|
* (`0189dcd5-5311-7d40-8db0-9496a2eef37b`).
|
|
835
661
|
*/
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
for (
|
|
662
|
+
toString() {
|
|
663
|
+
let text = "";
|
|
664
|
+
for (let i = 0; i < this.bytes.length; i++) {
|
|
839
665
|
text += DIGITS.charAt(this.bytes[i] >>> 4);
|
|
840
666
|
text += DIGITS.charAt(this.bytes[i] & 0xf);
|
|
841
667
|
if (i === 3 || i === 5 || i === 7 || i === 9) {
|
|
@@ -843,23 +669,23 @@ var UUID = /** @class */ (function () {
|
|
|
843
669
|
}
|
|
844
670
|
}
|
|
845
671
|
return text;
|
|
846
|
-
}
|
|
672
|
+
}
|
|
847
673
|
/**
|
|
848
674
|
* @returns The 32-digit hexadecimal representation without hyphens
|
|
849
675
|
* (`0189dcd553117d408db09496a2eef37b`).
|
|
850
676
|
*/
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
for (
|
|
677
|
+
toHex() {
|
|
678
|
+
let text = "";
|
|
679
|
+
for (let i = 0; i < this.bytes.length; i++) {
|
|
854
680
|
text += DIGITS.charAt(this.bytes[i] >>> 4);
|
|
855
681
|
text += DIGITS.charAt(this.bytes[i] & 0xf);
|
|
856
682
|
}
|
|
857
683
|
return text;
|
|
858
|
-
}
|
|
684
|
+
}
|
|
859
685
|
/** @returns The 8-4-4-4-12 canonical hexadecimal string representation. */
|
|
860
|
-
|
|
686
|
+
toJSON() {
|
|
861
687
|
return this.toString();
|
|
862
|
-
}
|
|
688
|
+
}
|
|
863
689
|
/**
|
|
864
690
|
* Reports the variant field value of the UUID or, if appropriate, "NIL" or
|
|
865
691
|
* "MAX".
|
|
@@ -868,57 +694,56 @@ var UUID = /** @class */ (function () {
|
|
|
868
694
|
* the Nil or Max UUID, although the Nil and Max UUIDs are technically
|
|
869
695
|
* subsumed under the variants `0b0` and `0b111`, respectively.
|
|
870
696
|
*/
|
|
871
|
-
|
|
872
|
-
|
|
697
|
+
getVariant() {
|
|
698
|
+
const n = this.bytes[8] >>> 4;
|
|
873
699
|
if (n < 0) {
|
|
874
700
|
throw new Error("unreachable");
|
|
875
701
|
}
|
|
876
|
-
else if (n <=
|
|
877
|
-
return this.bytes.every(
|
|
702
|
+
else if (n <= 0b0111) {
|
|
703
|
+
return this.bytes.every((e) => e === 0) ? "NIL" : "VAR_0";
|
|
878
704
|
}
|
|
879
|
-
else if (n <=
|
|
705
|
+
else if (n <= 0b1011) {
|
|
880
706
|
return "VAR_10";
|
|
881
707
|
}
|
|
882
|
-
else if (n <=
|
|
708
|
+
else if (n <= 0b1101) {
|
|
883
709
|
return "VAR_110";
|
|
884
710
|
}
|
|
885
|
-
else if (n <=
|
|
886
|
-
return this.bytes.every(
|
|
711
|
+
else if (n <= 0b1111) {
|
|
712
|
+
return this.bytes.every((e) => e === 0xff) ? "MAX" : "VAR_RESERVED";
|
|
887
713
|
}
|
|
888
714
|
else {
|
|
889
715
|
throw new Error("unreachable");
|
|
890
716
|
}
|
|
891
|
-
}
|
|
717
|
+
}
|
|
892
718
|
/**
|
|
893
719
|
* Returns the version field value of the UUID or `undefined` if the UUID does
|
|
894
720
|
* not have the variant field value of `0b10`.
|
|
895
721
|
*/
|
|
896
|
-
|
|
722
|
+
getVersion() {
|
|
897
723
|
return this.getVariant() === "VAR_10" ? this.bytes[6] >>> 4 : undefined;
|
|
898
|
-
}
|
|
724
|
+
}
|
|
899
725
|
/** Creates an object from `this`. */
|
|
900
|
-
|
|
726
|
+
clone() {
|
|
901
727
|
return new UUID(this.bytes.slice(0));
|
|
902
|
-
}
|
|
728
|
+
}
|
|
903
729
|
/** Returns true if `this` is equivalent to `other`. */
|
|
904
|
-
|
|
730
|
+
equals(other) {
|
|
905
731
|
return this.compareTo(other) === 0;
|
|
906
|
-
}
|
|
732
|
+
}
|
|
907
733
|
/**
|
|
908
734
|
* Returns a negative integer, zero, or positive integer if `this` is less
|
|
909
735
|
* than, equal to, or greater than `other`, respectively.
|
|
910
736
|
*/
|
|
911
|
-
|
|
912
|
-
for (
|
|
913
|
-
|
|
737
|
+
compareTo(other) {
|
|
738
|
+
for (let i = 0; i < 16; i++) {
|
|
739
|
+
const diff = this.bytes[i] - other.bytes[i];
|
|
914
740
|
if (diff !== 0) {
|
|
915
741
|
return Math.sign(diff);
|
|
916
742
|
}
|
|
917
743
|
}
|
|
918
744
|
return 0;
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
}());
|
|
745
|
+
}
|
|
746
|
+
}
|
|
922
747
|
/**
|
|
923
748
|
* Encapsulates the monotonic counter state.
|
|
924
749
|
*
|
|
@@ -928,16 +753,16 @@ var UUID = /** @class */ (function () {
|
|
|
928
753
|
* that is useful to absolutely guarantee the monotonically increasing order of
|
|
929
754
|
* generated UUIDs. See their respective documentation for details.
|
|
930
755
|
*/
|
|
931
|
-
|
|
756
|
+
class V7Generator {
|
|
932
757
|
/**
|
|
933
758
|
* Creates a generator object with the default random number generator, or
|
|
934
759
|
* with the specified one if passed as an argument. The specified random
|
|
935
760
|
* number generator should be cryptographically strong and securely seeded.
|
|
936
761
|
*/
|
|
937
|
-
|
|
762
|
+
constructor(randomNumberGenerator) {
|
|
938
763
|
this.timestamp = 0;
|
|
939
764
|
this.counter = 0;
|
|
940
|
-
this.random = randomNumberGenerator
|
|
765
|
+
this.random = randomNumberGenerator ?? getDefaultRandom();
|
|
941
766
|
}
|
|
942
767
|
/**
|
|
943
768
|
* Generates a new UUIDv7 object from the current timestamp, or resets the
|
|
@@ -953,9 +778,9 @@ var V7Generator = /** @class */ (function () {
|
|
|
953
778
|
* See {@link generateOrAbort} for the other mode of generation and
|
|
954
779
|
* {@link generateOrResetCore} for the low-level primitive.
|
|
955
780
|
*/
|
|
956
|
-
|
|
781
|
+
generate() {
|
|
957
782
|
return this.generateOrResetCore(Date.now(), 10000);
|
|
958
|
-
}
|
|
783
|
+
}
|
|
959
784
|
/**
|
|
960
785
|
* Generates a new UUIDv7 object from the current timestamp, or returns
|
|
961
786
|
* `undefined` upon significant timestamp rollback.
|
|
@@ -969,9 +794,9 @@ var V7Generator = /** @class */ (function () {
|
|
|
969
794
|
* See {@link generate} for the other mode of generation and
|
|
970
795
|
* {@link generateOrAbortCore} for the low-level primitive.
|
|
971
796
|
*/
|
|
972
|
-
|
|
797
|
+
generateOrAbort() {
|
|
973
798
|
return this.generateOrAbortCore(Date.now(), 10000);
|
|
974
|
-
}
|
|
799
|
+
}
|
|
975
800
|
/**
|
|
976
801
|
* Generates a new UUIDv7 object from the `unixTsMs` passed, or resets the
|
|
977
802
|
* generator upon significant timestamp rollback.
|
|
@@ -983,15 +808,15 @@ var V7Generator = /** @class */ (function () {
|
|
|
983
808
|
* considered significant. A suggested value is `10_000` (milliseconds).
|
|
984
809
|
* @throws RangeError if `unixTsMs` is not a 48-bit positive integer.
|
|
985
810
|
*/
|
|
986
|
-
|
|
987
|
-
|
|
811
|
+
generateOrResetCore(unixTsMs, rollbackAllowance) {
|
|
812
|
+
let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
|
|
988
813
|
if (value === undefined) {
|
|
989
814
|
// reset state and resume
|
|
990
815
|
this.timestamp = 0;
|
|
991
816
|
value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
|
|
992
817
|
}
|
|
993
818
|
return value;
|
|
994
|
-
}
|
|
819
|
+
}
|
|
995
820
|
/**
|
|
996
821
|
* Generates a new UUIDv7 object from the `unixTsMs` passed, or returns
|
|
997
822
|
* `undefined` upon significant timestamp rollback.
|
|
@@ -1003,8 +828,8 @@ var V7Generator = /** @class */ (function () {
|
|
|
1003
828
|
* considered significant. A suggested value is `10_000` (milliseconds).
|
|
1004
829
|
* @throws RangeError if `unixTsMs` is not a 48-bit positive integer.
|
|
1005
830
|
*/
|
|
1006
|
-
|
|
1007
|
-
|
|
831
|
+
generateOrAbortCore(unixTsMs, rollbackAllowance) {
|
|
832
|
+
const MAX_COUNTER = 4398046511103;
|
|
1008
833
|
if (!Number.isInteger(unixTsMs) ||
|
|
1009
834
|
unixTsMs < 1 ||
|
|
1010
835
|
unixTsMs > 281474976710655) {
|
|
@@ -1030,30 +855,29 @@ var V7Generator = /** @class */ (function () {
|
|
|
1030
855
|
// abort if clock went backwards to unbearable extent
|
|
1031
856
|
return undefined;
|
|
1032
857
|
}
|
|
1033
|
-
return UUID.fromFieldsV7(this.timestamp, Math.trunc(this.counter /
|
|
1034
|
-
}
|
|
858
|
+
return UUID.fromFieldsV7(this.timestamp, Math.trunc(this.counter / 2 ** 30), this.counter & (2 ** 30 - 1), this.random.nextUint32());
|
|
859
|
+
}
|
|
1035
860
|
/** Initializes the counter at a 42-bit random integer. */
|
|
1036
|
-
|
|
861
|
+
resetCounter() {
|
|
1037
862
|
this.counter =
|
|
1038
863
|
this.random.nextUint32() * 0x400 + (this.random.nextUint32() & 0x3ff);
|
|
1039
|
-
}
|
|
864
|
+
}
|
|
1040
865
|
/**
|
|
1041
866
|
* Generates a new UUIDv4 object utilizing the random number generator inside.
|
|
1042
867
|
*
|
|
1043
868
|
* @internal
|
|
1044
869
|
*/
|
|
1045
|
-
|
|
1046
|
-
|
|
870
|
+
generateV4() {
|
|
871
|
+
const bytes = new Uint8Array(Uint32Array.of(this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32(), this.random.nextUint32()).buffer);
|
|
1047
872
|
bytes[6] = 0x40 | (bytes[6] >>> 4);
|
|
1048
873
|
bytes[8] = 0x80 | (bytes[8] >>> 2);
|
|
1049
874
|
return UUID.ofInner(bytes);
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
}());
|
|
875
|
+
}
|
|
876
|
+
}
|
|
1053
877
|
/** A global flag to force use of cryptographically strong RNG. */
|
|
1054
878
|
// declare const UUIDV7_DENY_WEAK_RNG: boolean;
|
|
1055
879
|
/** Returns the default random number generator available in the environment. */
|
|
1056
|
-
|
|
880
|
+
const getDefaultRandom = () => {
|
|
1057
881
|
// fix: crypto isn't available in react-native, always use Math.random
|
|
1058
882
|
// // detect Web Crypto API
|
|
1059
883
|
// if (
|
|
@@ -1073,10 +897,8 @@ var getDefaultRandom = function () {
|
|
|
1073
897
|
// };
|
|
1074
898
|
// }
|
|
1075
899
|
return {
|
|
1076
|
-
nextUint32:
|
|
1077
|
-
|
|
1078
|
-
Math.trunc(Math.random() * 65536);
|
|
1079
|
-
},
|
|
900
|
+
nextUint32: () => Math.trunc(Math.random() * 65536) * 65536 +
|
|
901
|
+
Math.trunc(Math.random() * 65536),
|
|
1080
902
|
};
|
|
1081
903
|
};
|
|
1082
904
|
// /**
|
|
@@ -1095,927 +917,457 @@ var getDefaultRandom = function () {
|
|
|
1095
917
|
// return this.buffer[this.cursor++];
|
|
1096
918
|
// }
|
|
1097
919
|
// }
|
|
1098
|
-
|
|
920
|
+
let defaultGenerator;
|
|
1099
921
|
/**
|
|
1100
922
|
* Generates a UUIDv7 string.
|
|
1101
923
|
*
|
|
1102
924
|
* @returns The 8-4-4-4-12 canonical hexadecimal string representation
|
|
1103
925
|
* ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx").
|
|
1104
926
|
*/
|
|
1105
|
-
|
|
927
|
+
const uuidv7 = () => uuidv7obj().toString();
|
|
1106
928
|
/** Generates a UUIDv7 object. */
|
|
1107
|
-
|
|
1108
|
-
return (defaultGenerator || (defaultGenerator = new V7Generator())).generate();
|
|
1109
|
-
};
|
|
929
|
+
const uuidv7obj = () => (defaultGenerator || (defaultGenerator = new V7Generator())).generate();
|
|
1110
930
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
_this.name = 'PostHogFetchHttpError';
|
|
1117
|
-
return _this;
|
|
931
|
+
class PostHogFetchHttpError extends Error {
|
|
932
|
+
constructor(response) {
|
|
933
|
+
super('HTTP error while fetching PostHog: ' + response.status);
|
|
934
|
+
this.response = response;
|
|
935
|
+
this.name = 'PostHogFetchHttpError';
|
|
1118
936
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
__extends(PostHogFetchNetworkError, _super);
|
|
1123
|
-
function PostHogFetchNetworkError(error) {
|
|
1124
|
-
var _this =
|
|
937
|
+
}
|
|
938
|
+
class PostHogFetchNetworkError extends Error {
|
|
939
|
+
constructor(error) {
|
|
1125
940
|
// TRICKY: "cause" is a newer property but is just ignored otherwise. Cast to any to ignore the type issue.
|
|
941
|
+
// eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
|
|
1126
942
|
// @ts-ignore
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
return _this;
|
|
943
|
+
super('Network error while fetching PostHog', error instanceof Error ? { cause: error } : {});
|
|
944
|
+
this.error = error;
|
|
945
|
+
this.name = 'PostHogFetchNetworkError';
|
|
1131
946
|
}
|
|
1132
|
-
|
|
1133
|
-
}(Error));
|
|
947
|
+
}
|
|
1134
948
|
function isPostHogFetchError(err) {
|
|
1135
|
-
return typeof err === 'object' && (err
|
|
949
|
+
return typeof err === 'object' && (err instanceof PostHogFetchHttpError || err instanceof PostHogFetchNetworkError);
|
|
1136
950
|
}
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
var _a, _b, _c, _d, _e;
|
|
1140
|
-
this.debugMode = false;
|
|
951
|
+
class PostHogCoreStateless {
|
|
952
|
+
constructor(apiKey, options) {
|
|
1141
953
|
this.disableGeoip = true;
|
|
954
|
+
this.disabled = false;
|
|
955
|
+
this.defaultOptIn = true;
|
|
1142
956
|
this.pendingPromises = {};
|
|
1143
957
|
// internal
|
|
1144
958
|
this._events = new SimpleEventEmitter();
|
|
959
|
+
this._isInitialized = false;
|
|
1145
960
|
assert(apiKey, "You must pass your PostHog project's api key.");
|
|
1146
961
|
this.apiKey = apiKey;
|
|
1147
|
-
this.host = removeTrailingSlash(
|
|
1148
|
-
this.flushAt =
|
|
1149
|
-
this.flushInterval =
|
|
1150
|
-
this.captureMode =
|
|
962
|
+
this.host = removeTrailingSlash(options?.host || 'https://app.posthog.com');
|
|
963
|
+
this.flushAt = options?.flushAt ? Math.max(options?.flushAt, 1) : 20;
|
|
964
|
+
this.flushInterval = options?.flushInterval ?? 10000;
|
|
965
|
+
this.captureMode = options?.captureMode || 'form';
|
|
1151
966
|
// If enable is explicitly set to false we override the optout
|
|
1152
|
-
this.
|
|
967
|
+
this.defaultOptIn = options?.defaultOptIn ?? true;
|
|
1153
968
|
this._retryOptions = {
|
|
1154
|
-
retryCount:
|
|
1155
|
-
retryDelay:
|
|
969
|
+
retryCount: options?.fetchRetryCount ?? 3,
|
|
970
|
+
retryDelay: options?.fetchRetryDelay ?? 3000,
|
|
1156
971
|
retryCheck: isPostHogFetchError,
|
|
1157
972
|
};
|
|
1158
|
-
this.requestTimeout =
|
|
1159
|
-
this.
|
|
973
|
+
this.requestTimeout = options?.requestTimeout ?? 10000; // 10 seconds
|
|
974
|
+
this.featureFlagsRequestTimeoutMs = options?.featureFlagsRequestTimeoutMs ?? 3000; // 3 seconds
|
|
975
|
+
this.disableGeoip = options?.disableGeoip ?? true;
|
|
976
|
+
this.disabled = options?.disabled ?? false;
|
|
977
|
+
// Init promise allows the derived class to block calls until it is ready
|
|
978
|
+
this._initPromise = Promise.resolve();
|
|
979
|
+
this._isInitialized = true;
|
|
980
|
+
}
|
|
981
|
+
wrap(fn) {
|
|
982
|
+
if (this.disabled) {
|
|
983
|
+
if (this.isDebug) {
|
|
984
|
+
console.warn('[PostHog] The client is disabled');
|
|
985
|
+
}
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
if (this._isInitialized) {
|
|
989
|
+
// NOTE: We could also check for the "opt in" status here...
|
|
990
|
+
return fn();
|
|
991
|
+
}
|
|
992
|
+
this._initPromise.then(() => fn());
|
|
1160
993
|
}
|
|
1161
|
-
|
|
994
|
+
getCommonEventProperties() {
|
|
1162
995
|
return {
|
|
1163
996
|
$lib: this.getLibraryId(),
|
|
1164
997
|
$lib_version: this.getLibraryVersion(),
|
|
1165
998
|
};
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
this.
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
PostHogCoreStateless.prototype.on = function (event, cb) {
|
|
999
|
+
}
|
|
1000
|
+
get optedOut() {
|
|
1001
|
+
return this.getPersistedProperty(PostHogPersistedProperty.OptedOut) ?? !this.defaultOptIn;
|
|
1002
|
+
}
|
|
1003
|
+
async optIn() {
|
|
1004
|
+
this.wrap(() => {
|
|
1005
|
+
this.setPersistedProperty(PostHogPersistedProperty.OptedOut, false);
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
async optOut() {
|
|
1009
|
+
this.wrap(() => {
|
|
1010
|
+
this.setPersistedProperty(PostHogPersistedProperty.OptedOut, true);
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
on(event, cb) {
|
|
1182
1014
|
return this._events.on(event, cb);
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
if (enabled === void 0) { enabled = true; }
|
|
1187
|
-
(_a = this.removeDebugCallback) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
1188
|
-
this.debugMode = enabled;
|
|
1015
|
+
}
|
|
1016
|
+
debug(enabled = true) {
|
|
1017
|
+
this.removeDebugCallback?.();
|
|
1189
1018
|
if (enabled) {
|
|
1190
|
-
|
|
1019
|
+
const removeDebugCallback = this.on('*', (event, payload) => console.log('PostHog Debug', event, payload));
|
|
1020
|
+
this.removeDebugCallback = () => {
|
|
1021
|
+
removeDebugCallback();
|
|
1022
|
+
this.removeDebugCallback = undefined;
|
|
1023
|
+
};
|
|
1191
1024
|
}
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1025
|
+
}
|
|
1026
|
+
get isDebug() {
|
|
1027
|
+
return !!this.removeDebugCallback;
|
|
1028
|
+
}
|
|
1029
|
+
buildPayload(payload) {
|
|
1194
1030
|
return {
|
|
1195
1031
|
distinct_id: payload.distinct_id,
|
|
1196
1032
|
event: payload.event,
|
|
1197
|
-
properties:
|
|
1033
|
+
properties: {
|
|
1034
|
+
...(payload.properties || {}),
|
|
1035
|
+
...this.getCommonEventProperties(), // Common PH props
|
|
1036
|
+
},
|
|
1198
1037
|
};
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
var promiseUUID = uuidv7();
|
|
1038
|
+
}
|
|
1039
|
+
addPendingPromise(promise) {
|
|
1040
|
+
const promiseUUID = uuidv7();
|
|
1203
1041
|
this.pendingPromises[promiseUUID] = promise;
|
|
1204
|
-
promise.finally(
|
|
1205
|
-
delete
|
|
1042
|
+
promise.finally(() => {
|
|
1043
|
+
delete this.pendingPromises[promiseUUID];
|
|
1206
1044
|
});
|
|
1207
|
-
}
|
|
1045
|
+
}
|
|
1208
1046
|
/***
|
|
1209
1047
|
*** TRACKING
|
|
1210
1048
|
***/
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
var payload = this.buildPayload({ distinct_id: distinctId, event: event, properties: properties });
|
|
1224
|
-
this.enqueue('capture', payload, options);
|
|
1225
|
-
return this;
|
|
1226
|
-
};
|
|
1227
|
-
PostHogCoreStateless.prototype.aliasStateless = function (alias, distinctId, properties, options) {
|
|
1228
|
-
var payload = this.buildPayload({
|
|
1229
|
-
event: '$create_alias',
|
|
1230
|
-
distinct_id: distinctId,
|
|
1231
|
-
properties: __assign(__assign({}, (properties || {})), { distinct_id: distinctId, alias: alias }),
|
|
1049
|
+
identifyStateless(distinctId, properties, options) {
|
|
1050
|
+
this.wrap(() => {
|
|
1051
|
+
// The properties passed to identifyStateless are event properties.
|
|
1052
|
+
// To add person properties, pass in all person properties to the `$set` key.
|
|
1053
|
+
const payload = {
|
|
1054
|
+
...this.buildPayload({
|
|
1055
|
+
distinct_id: distinctId,
|
|
1056
|
+
event: '$identify',
|
|
1057
|
+
properties,
|
|
1058
|
+
}),
|
|
1059
|
+
};
|
|
1060
|
+
this.enqueue('identify', payload, options);
|
|
1232
1061
|
});
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1062
|
+
}
|
|
1063
|
+
captureStateless(distinctId, event, properties, options) {
|
|
1064
|
+
this.wrap(() => {
|
|
1065
|
+
const payload = this.buildPayload({ distinct_id: distinctId, event, properties });
|
|
1066
|
+
this.enqueue('capture', payload, options);
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
aliasStateless(alias, distinctId, properties, options) {
|
|
1070
|
+
this.wrap(() => {
|
|
1071
|
+
const payload = this.buildPayload({
|
|
1072
|
+
event: '$create_alias',
|
|
1073
|
+
distinct_id: distinctId,
|
|
1074
|
+
properties: {
|
|
1075
|
+
...(properties || {}),
|
|
1076
|
+
distinct_id: distinctId,
|
|
1077
|
+
alias,
|
|
1078
|
+
},
|
|
1079
|
+
});
|
|
1080
|
+
this.enqueue('alias', payload, options);
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1236
1083
|
/***
|
|
1237
1084
|
*** GROUPS
|
|
1238
1085
|
***/
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1086
|
+
groupIdentifyStateless(groupType, groupKey, groupProperties, options, distinctId, eventProperties) {
|
|
1087
|
+
this.wrap(() => {
|
|
1088
|
+
const payload = this.buildPayload({
|
|
1089
|
+
distinct_id: distinctId || `$${groupType}_${groupKey}`,
|
|
1090
|
+
event: '$groupidentify',
|
|
1091
|
+
properties: {
|
|
1092
|
+
$group_type: groupType,
|
|
1093
|
+
$group_key: groupKey,
|
|
1094
|
+
$group_set: groupProperties || {},
|
|
1095
|
+
...(eventProperties || {}),
|
|
1096
|
+
},
|
|
1097
|
+
});
|
|
1098
|
+
this.enqueue('capture', payload, options);
|
|
1244
1099
|
});
|
|
1245
|
-
|
|
1246
|
-
return this;
|
|
1247
|
-
};
|
|
1100
|
+
}
|
|
1248
1101
|
/***
|
|
1249
1102
|
*** FEATURE FLAGS
|
|
1250
1103
|
***/
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
});
|
|
1273
|
-
});
|
|
1274
|
-
};
|
|
1275
|
-
PostHogCoreStateless.prototype.getFeatureFlagStateless = function (key, distinctId, groups, personProperties, groupProperties, disableGeoip) {
|
|
1276
|
-
if (groups === void 0) { groups = {}; }
|
|
1277
|
-
if (personProperties === void 0) { personProperties = {}; }
|
|
1278
|
-
if (groupProperties === void 0) { groupProperties = {}; }
|
|
1279
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
1280
|
-
var featureFlags, response;
|
|
1281
|
-
return __generator(this, function (_a) {
|
|
1282
|
-
switch (_a.label) {
|
|
1283
|
-
case 0: return [4 /*yield*/, this.getFeatureFlagsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip)];
|
|
1284
|
-
case 1:
|
|
1285
|
-
featureFlags = _a.sent();
|
|
1286
|
-
if (!featureFlags) {
|
|
1287
|
-
// If we haven't loaded flags yet, or errored out, we respond with undefined
|
|
1288
|
-
return [2 /*return*/, undefined];
|
|
1289
|
-
}
|
|
1290
|
-
response = featureFlags[key];
|
|
1291
|
-
// `/decide` v3 returns all flags
|
|
1292
|
-
if (response === undefined) {
|
|
1293
|
-
// For cases where the flag is unknown, return false
|
|
1294
|
-
response = false;
|
|
1295
|
-
}
|
|
1296
|
-
// If we have flags we either return the value (true or string) or false
|
|
1297
|
-
return [2 /*return*/, response];
|
|
1298
|
-
}
|
|
1299
|
-
});
|
|
1300
|
-
});
|
|
1301
|
-
};
|
|
1302
|
-
PostHogCoreStateless.prototype.getFeatureFlagPayloadStateless = function (key, distinctId, groups, personProperties, groupProperties, disableGeoip) {
|
|
1303
|
-
if (groups === void 0) { groups = {}; }
|
|
1304
|
-
if (personProperties === void 0) { personProperties = {}; }
|
|
1305
|
-
if (groupProperties === void 0) { groupProperties = {}; }
|
|
1306
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
1307
|
-
var payloads, response;
|
|
1308
|
-
return __generator(this, function (_a) {
|
|
1309
|
-
switch (_a.label) {
|
|
1310
|
-
case 0: return [4 /*yield*/, this.getFeatureFlagPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip)];
|
|
1311
|
-
case 1:
|
|
1312
|
-
payloads = _a.sent();
|
|
1313
|
-
if (!payloads) {
|
|
1314
|
-
return [2 /*return*/, undefined];
|
|
1315
|
-
}
|
|
1316
|
-
response = payloads[key];
|
|
1317
|
-
// Undefined means a loading or missing data issue. Null means evaluation happened and there was no match
|
|
1318
|
-
if (response === undefined) {
|
|
1319
|
-
return [2 /*return*/, null];
|
|
1320
|
-
}
|
|
1321
|
-
return [2 /*return*/, this._parsePayload(response)];
|
|
1322
|
-
}
|
|
1323
|
-
});
|
|
1324
|
-
});
|
|
1325
|
-
};
|
|
1326
|
-
PostHogCoreStateless.prototype.getFeatureFlagPayloadsStateless = function (distinctId, groups, personProperties, groupProperties, disableGeoip) {
|
|
1327
|
-
if (groups === void 0) { groups = {}; }
|
|
1328
|
-
if (personProperties === void 0) { personProperties = {}; }
|
|
1329
|
-
if (groupProperties === void 0) { groupProperties = {}; }
|
|
1330
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
1331
|
-
var payloads;
|
|
1332
|
-
var _this = this;
|
|
1333
|
-
return __generator(this, function (_a) {
|
|
1334
|
-
switch (_a.label) {
|
|
1335
|
-
case 0: return [4 /*yield*/, this.getFeatureFlagsAndPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip)];
|
|
1336
|
-
case 1:
|
|
1337
|
-
payloads = (_a.sent()).payloads;
|
|
1338
|
-
if (payloads) {
|
|
1339
|
-
return [2 /*return*/, Object.fromEntries(Object.entries(payloads).map(function (_a) {
|
|
1340
|
-
var k = _a[0], v = _a[1];
|
|
1341
|
-
return [k, _this._parsePayload(v)];
|
|
1342
|
-
}))];
|
|
1343
|
-
}
|
|
1344
|
-
return [2 /*return*/, payloads];
|
|
1345
|
-
}
|
|
1346
|
-
});
|
|
1104
|
+
async getDecide(distinctId, groups = {}, personProperties = {}, groupProperties = {}, extraPayload = {}) {
|
|
1105
|
+
await this._initPromise;
|
|
1106
|
+
const url = `${this.host}/decide/?v=3`;
|
|
1107
|
+
const fetchOptions = {
|
|
1108
|
+
method: 'POST',
|
|
1109
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1110
|
+
body: JSON.stringify({
|
|
1111
|
+
token: this.apiKey,
|
|
1112
|
+
distinct_id: distinctId,
|
|
1113
|
+
groups,
|
|
1114
|
+
person_properties: personProperties,
|
|
1115
|
+
group_properties: groupProperties,
|
|
1116
|
+
...extraPayload,
|
|
1117
|
+
}),
|
|
1118
|
+
};
|
|
1119
|
+
// Don't retry /decide API calls
|
|
1120
|
+
return this.fetchWithRetry(url, fetchOptions, { retryCount: 0 }, this.featureFlagsRequestTimeoutMs)
|
|
1121
|
+
.then((response) => response.json())
|
|
1122
|
+
.catch((error) => {
|
|
1123
|
+
this._events.emit('error', error);
|
|
1124
|
+
return undefined;
|
|
1347
1125
|
});
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1126
|
+
}
|
|
1127
|
+
async getFeatureFlagStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
|
|
1128
|
+
await this._initPromise;
|
|
1129
|
+
const featureFlags = await this.getFeatureFlagsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip);
|
|
1130
|
+
if (!featureFlags) {
|
|
1131
|
+
// If we haven't loaded flags yet, or errored out, we respond with undefined
|
|
1132
|
+
return undefined;
|
|
1133
|
+
}
|
|
1134
|
+
let response = featureFlags[key];
|
|
1135
|
+
// `/decide` v3 returns all flags
|
|
1136
|
+
if (response === undefined) {
|
|
1137
|
+
// For cases where the flag is unknown, return false
|
|
1138
|
+
response = false;
|
|
1139
|
+
}
|
|
1140
|
+
// If we have flags we either return the value (true or string) or false
|
|
1141
|
+
return response;
|
|
1142
|
+
}
|
|
1143
|
+
async getFeatureFlagPayloadStateless(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
|
|
1144
|
+
await this._initPromise;
|
|
1145
|
+
const payloads = await this.getFeatureFlagPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip);
|
|
1146
|
+
if (!payloads) {
|
|
1147
|
+
return undefined;
|
|
1148
|
+
}
|
|
1149
|
+
const response = payloads[key];
|
|
1150
|
+
// Undefined means a loading or missing data issue. Null means evaluation happened and there was no match
|
|
1151
|
+
if (response === undefined) {
|
|
1152
|
+
return null;
|
|
1153
|
+
}
|
|
1154
|
+
return this._parsePayload(response);
|
|
1155
|
+
}
|
|
1156
|
+
async getFeatureFlagPayloadsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
|
|
1157
|
+
await this._initPromise;
|
|
1158
|
+
const payloads = (await this.getFeatureFlagsAndPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip)).payloads;
|
|
1159
|
+
if (payloads) {
|
|
1160
|
+
return Object.fromEntries(Object.entries(payloads).map(([k, v]) => [k, this._parsePayload(v)]));
|
|
1161
|
+
}
|
|
1162
|
+
return payloads;
|
|
1163
|
+
}
|
|
1164
|
+
_parsePayload(response) {
|
|
1350
1165
|
try {
|
|
1351
1166
|
return JSON.parse(response);
|
|
1352
1167
|
}
|
|
1353
|
-
catch
|
|
1168
|
+
catch {
|
|
1354
1169
|
return response;
|
|
1355
1170
|
}
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
var extraPayload, decideResponse, flags, payloads;
|
|
1376
|
-
return __generator(this, function (_a) {
|
|
1377
|
-
switch (_a.label) {
|
|
1378
|
-
case 0:
|
|
1379
|
-
extraPayload = {};
|
|
1380
|
-
if (disableGeoip !== null && disableGeoip !== void 0 ? disableGeoip : this.disableGeoip) {
|
|
1381
|
-
extraPayload['geoip_disable'] = true;
|
|
1382
|
-
}
|
|
1383
|
-
return [4 /*yield*/, this.getDecide(distinctId, groups, personProperties, groupProperties, extraPayload)];
|
|
1384
|
-
case 1:
|
|
1385
|
-
decideResponse = _a.sent();
|
|
1386
|
-
flags = decideResponse === null || decideResponse === void 0 ? void 0 : decideResponse.featureFlags;
|
|
1387
|
-
payloads = decideResponse === null || decideResponse === void 0 ? void 0 : decideResponse.featureFlagPayloads;
|
|
1388
|
-
return [2 /*return*/, {
|
|
1389
|
-
flags: flags,
|
|
1390
|
-
payloads: payloads,
|
|
1391
|
-
}];
|
|
1392
|
-
}
|
|
1393
|
-
});
|
|
1394
|
-
});
|
|
1395
|
-
};
|
|
1171
|
+
}
|
|
1172
|
+
async getFeatureFlagsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
|
|
1173
|
+
await this._initPromise;
|
|
1174
|
+
return (await this.getFeatureFlagsAndPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip)).flags;
|
|
1175
|
+
}
|
|
1176
|
+
async getFeatureFlagsAndPayloadsStateless(distinctId, groups = {}, personProperties = {}, groupProperties = {}, disableGeoip) {
|
|
1177
|
+
await this._initPromise;
|
|
1178
|
+
const extraPayload = {};
|
|
1179
|
+
if (disableGeoip ?? this.disableGeoip) {
|
|
1180
|
+
extraPayload['geoip_disable'] = true;
|
|
1181
|
+
}
|
|
1182
|
+
const decideResponse = await this.getDecide(distinctId, groups, personProperties, groupProperties, extraPayload);
|
|
1183
|
+
const flags = decideResponse?.featureFlags;
|
|
1184
|
+
const payloads = decideResponse?.featureFlagPayloads;
|
|
1185
|
+
return {
|
|
1186
|
+
flags,
|
|
1187
|
+
payloads,
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1396
1190
|
/***
|
|
1397
1191
|
*** QUEUEING AND FLUSHING
|
|
1398
1192
|
***/
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
return;
|
|
1405
|
-
}
|
|
1406
|
-
var message = __assign(__assign({}, _message), { type: type, library: this.getLibraryId(), library_version: this.getLibraryVersion(), timestamp: (options === null || options === void 0 ? void 0 : options.timestamp) ? options === null || options === void 0 ? void 0 : options.timestamp : currentISOTime(), uuid: (options === null || options === void 0 ? void 0 : options.uuid) ? options.uuid : uuidv7() });
|
|
1407
|
-
var addGeoipDisableProperty = (_a = options === null || options === void 0 ? void 0 : options.disableGeoip) !== null && _a !== void 0 ? _a : this.disableGeoip;
|
|
1408
|
-
if (addGeoipDisableProperty) {
|
|
1409
|
-
if (!message.properties) {
|
|
1410
|
-
message.properties = {};
|
|
1193
|
+
enqueue(type, _message, options) {
|
|
1194
|
+
this.wrap(() => {
|
|
1195
|
+
if (this.optedOut) {
|
|
1196
|
+
this._events.emit(type, `Library is disabled. Not sending event. To re-enable, call posthog.optIn()`);
|
|
1197
|
+
return;
|
|
1411
1198
|
}
|
|
1412
|
-
message
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1199
|
+
const message = {
|
|
1200
|
+
..._message,
|
|
1201
|
+
type: type,
|
|
1202
|
+
library: this.getLibraryId(),
|
|
1203
|
+
library_version: this.getLibraryVersion(),
|
|
1204
|
+
timestamp: options?.timestamp ? options?.timestamp : currentISOTime(),
|
|
1205
|
+
uuid: options?.uuid ? options.uuid : uuidv7(),
|
|
1206
|
+
};
|
|
1207
|
+
const addGeoipDisableProperty = options?.disableGeoip ?? this.disableGeoip;
|
|
1208
|
+
if (addGeoipDisableProperty) {
|
|
1209
|
+
if (!message.properties) {
|
|
1210
|
+
message.properties = {};
|
|
1211
|
+
}
|
|
1212
|
+
message['properties']['$geoip_disable'] = true;
|
|
1213
|
+
}
|
|
1214
|
+
if (message.distinctId) {
|
|
1215
|
+
message.distinct_id = message.distinctId;
|
|
1216
|
+
delete message.distinctId;
|
|
1217
|
+
}
|
|
1218
|
+
const queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
|
|
1219
|
+
queue.push({ message });
|
|
1220
|
+
this.setPersistedProperty(PostHogPersistedProperty.Queue, queue);
|
|
1221
|
+
this._events.emit(type, message);
|
|
1222
|
+
// Flush queued events if we meet the flushAt length
|
|
1223
|
+
if (queue.length >= this.flushAt) {
|
|
1224
|
+
this.flush();
|
|
1225
|
+
}
|
|
1226
|
+
if (this.flushInterval && !this._flushTimer) {
|
|
1227
|
+
this._flushTimer = safeSetTimeout(() => this.flush(), this.flushInterval);
|
|
1228
|
+
}
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
async flushAsync() {
|
|
1232
|
+
await this._initPromise;
|
|
1233
|
+
return new Promise((resolve, reject) => {
|
|
1234
|
+
this.flush((err, data) => {
|
|
1434
1235
|
return err ? reject(err) : resolve(data);
|
|
1435
1236
|
});
|
|
1436
1237
|
});
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
}
|
|
1444
|
-
var queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
|
|
1445
|
-
if (!queue.length) {
|
|
1446
|
-
return callback === null || callback === void 0 ? void 0 : callback();
|
|
1447
|
-
}
|
|
1448
|
-
var items = queue.splice(0, this.flushAt);
|
|
1449
|
-
this.setPersistedProperty(PostHogPersistedProperty.Queue, queue);
|
|
1450
|
-
var messages = items.map(function (item) { return item.message; });
|
|
1451
|
-
var data = {
|
|
1452
|
-
api_key: this.apiKey,
|
|
1453
|
-
batch: messages,
|
|
1454
|
-
sent_at: currentISOTime(),
|
|
1455
|
-
};
|
|
1456
|
-
var done = function (err) {
|
|
1457
|
-
if (err) {
|
|
1458
|
-
_this._events.emit('error', err);
|
|
1238
|
+
}
|
|
1239
|
+
flush(callback) {
|
|
1240
|
+
this.wrap(() => {
|
|
1241
|
+
if (this._flushTimer) {
|
|
1242
|
+
clearTimeout(this._flushTimer);
|
|
1243
|
+
this._flushTimer = null;
|
|
1459
1244
|
}
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
// Don't set the user agent if we're not on a browser. The latest spec allows
|
|
1464
|
-
// the User-Agent header (see https://fetch.spec.whatwg.org/#terminology-headers
|
|
1465
|
-
// and https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader),
|
|
1466
|
-
// but browsers such as Chrome and Safari have not caught up.
|
|
1467
|
-
this.getCustomUserAgent();
|
|
1468
|
-
var payload = JSON.stringify(data);
|
|
1469
|
-
var url = this.captureMode === 'form'
|
|
1470
|
-
? "".concat(this.host, "/e/?ip=1&_=").concat(currentTimestamp(), "&v=").concat(this.getLibraryVersion())
|
|
1471
|
-
: "".concat(this.host, "/batch/");
|
|
1472
|
-
var fetchOptions = this.captureMode === 'form'
|
|
1473
|
-
? {
|
|
1474
|
-
method: 'POST',
|
|
1475
|
-
mode: 'no-cors',
|
|
1476
|
-
credentials: 'omit',
|
|
1477
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
1478
|
-
body: "data=".concat(encodeURIComponent(LZString.compressToBase64(payload)), "&compression=lz64"),
|
|
1245
|
+
const queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
|
|
1246
|
+
if (!queue.length) {
|
|
1247
|
+
return callback?.();
|
|
1479
1248
|
}
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1249
|
+
const items = queue.splice(0, this.flushAt);
|
|
1250
|
+
this.setPersistedProperty(PostHogPersistedProperty.Queue, queue);
|
|
1251
|
+
const messages = items.map((item) => item.message);
|
|
1252
|
+
const data = {
|
|
1253
|
+
api_key: this.apiKey,
|
|
1254
|
+
batch: messages,
|
|
1255
|
+
sent_at: currentISOTime(),
|
|
1484
1256
|
};
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
.catch(function (err) {
|
|
1489
|
-
done(err);
|
|
1490
|
-
}));
|
|
1491
|
-
};
|
|
1492
|
-
PostHogCoreStateless.prototype.fetchWithRetry = function (url, options, retryOptions) {
|
|
1493
|
-
var _a;
|
|
1494
|
-
var _b;
|
|
1495
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
1496
|
-
var _this = this;
|
|
1497
|
-
return __generator(this, function (_c) {
|
|
1498
|
-
switch (_c.label) {
|
|
1499
|
-
case 0:
|
|
1500
|
-
(_a = (_b = AbortSignal).timeout) !== null && _a !== void 0 ? _a : (_b.timeout = function timeout(ms) {
|
|
1501
|
-
var ctrl = new AbortController();
|
|
1502
|
-
setTimeout(function () { return ctrl.abort(); }, ms);
|
|
1503
|
-
return ctrl.signal;
|
|
1504
|
-
});
|
|
1505
|
-
return [4 /*yield*/, retriable(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1506
|
-
var res, e_1, isNoCors;
|
|
1507
|
-
return __generator(this, function (_a) {
|
|
1508
|
-
switch (_a.label) {
|
|
1509
|
-
case 0:
|
|
1510
|
-
res = null;
|
|
1511
|
-
_a.label = 1;
|
|
1512
|
-
case 1:
|
|
1513
|
-
_a.trys.push([1, 3, , 4]);
|
|
1514
|
-
return [4 /*yield*/, this.fetch(url, __assign({ signal: AbortSignal.timeout(this.requestTimeout) }, options))];
|
|
1515
|
-
case 2:
|
|
1516
|
-
res = _a.sent();
|
|
1517
|
-
return [3 /*break*/, 4];
|
|
1518
|
-
case 3:
|
|
1519
|
-
e_1 = _a.sent();
|
|
1520
|
-
// fetch will only throw on network errors or on timeouts
|
|
1521
|
-
throw new PostHogFetchNetworkError(e_1);
|
|
1522
|
-
case 4:
|
|
1523
|
-
isNoCors = options.mode === 'no-cors';
|
|
1524
|
-
if (!isNoCors && (res.status < 200 || res.status >= 400)) {
|
|
1525
|
-
throw new PostHogFetchHttpError(res);
|
|
1526
|
-
}
|
|
1527
|
-
return [2 /*return*/, res];
|
|
1528
|
-
}
|
|
1529
|
-
});
|
|
1530
|
-
}); }, __assign(__assign({}, this._retryOptions), retryOptions))];
|
|
1531
|
-
case 1: return [2 /*return*/, _c.sent()];
|
|
1257
|
+
const done = (err) => {
|
|
1258
|
+
if (err) {
|
|
1259
|
+
this._events.emit('error', err);
|
|
1532
1260
|
}
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
});
|
|
1553
|
-
}))
|
|
1554
|
-
// flush again to make sure we send all events, some of which might've been added
|
|
1555
|
-
// while we were waiting for the pending promises to resolve
|
|
1556
|
-
// For example, see sendFeatureFlags in posthog-node/src/posthog-node.ts::capture
|
|
1557
|
-
];
|
|
1558
|
-
case 3:
|
|
1559
|
-
_a.sent();
|
|
1560
|
-
// flush again to make sure we send all events, some of which might've been added
|
|
1561
|
-
// while we were waiting for the pending promises to resolve
|
|
1562
|
-
// For example, see sendFeatureFlags in posthog-node/src/posthog-node.ts::capture
|
|
1563
|
-
return [4 /*yield*/, this.flushAsync()];
|
|
1564
|
-
case 4:
|
|
1565
|
-
// flush again to make sure we send all events, some of which might've been added
|
|
1566
|
-
// while we were waiting for the pending promises to resolve
|
|
1567
|
-
// For example, see sendFeatureFlags in posthog-node/src/posthog-node.ts::capture
|
|
1568
|
-
_a.sent();
|
|
1569
|
-
return [3 /*break*/, 6];
|
|
1570
|
-
case 5:
|
|
1571
|
-
e_2 = _a.sent();
|
|
1572
|
-
if (!isPostHogFetchError(e_2)) {
|
|
1573
|
-
throw e_2;
|
|
1574
|
-
}
|
|
1575
|
-
console.error('Error while shutting down PostHog', e_2);
|
|
1576
|
-
return [3 /*break*/, 6];
|
|
1577
|
-
case 6: return [2 /*return*/];
|
|
1261
|
+
callback?.(err, messages);
|
|
1262
|
+
this._events.emit('flush', messages);
|
|
1263
|
+
};
|
|
1264
|
+
// Don't set the user agent if we're not on a browser. The latest spec allows
|
|
1265
|
+
// the User-Agent header (see https://fetch.spec.whatwg.org/#terminology-headers
|
|
1266
|
+
// and https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader),
|
|
1267
|
+
// but browsers such as Chrome and Safari have not caught up.
|
|
1268
|
+
this.getCustomUserAgent();
|
|
1269
|
+
const payload = JSON.stringify(data);
|
|
1270
|
+
const url = this.captureMode === 'form'
|
|
1271
|
+
? `${this.host}/e/?ip=1&_=${currentTimestamp()}&v=${this.getLibraryVersion()}`
|
|
1272
|
+
: `${this.host}/batch/`;
|
|
1273
|
+
const fetchOptions = this.captureMode === 'form'
|
|
1274
|
+
? {
|
|
1275
|
+
method: 'POST',
|
|
1276
|
+
mode: 'no-cors',
|
|
1277
|
+
credentials: 'omit',
|
|
1278
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
1279
|
+
body: `data=${encodeURIComponent(LZString.compressToBase64(payload))}&compression=lz64`,
|
|
1578
1280
|
}
|
|
1579
|
-
|
|
1281
|
+
: {
|
|
1282
|
+
method: 'POST',
|
|
1283
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1284
|
+
body: payload,
|
|
1285
|
+
};
|
|
1286
|
+
const requestPromise = this.fetchWithRetry(url, fetchOptions);
|
|
1287
|
+
this.addPendingPromise(requestPromise
|
|
1288
|
+
.then(() => done())
|
|
1289
|
+
.catch((err) => {
|
|
1290
|
+
done(err);
|
|
1291
|
+
}));
|
|
1580
1292
|
});
|
|
1581
|
-
};
|
|
1582
|
-
PostHogCoreStateless.prototype.shutdown = function () {
|
|
1583
|
-
void this.shutdownAsync();
|
|
1584
|
-
};
|
|
1585
|
-
return PostHogCoreStateless;
|
|
1586
|
-
}());
|
|
1587
|
-
/** @class */ ((function (_super) {
|
|
1588
|
-
__extends(PostHogCore, _super);
|
|
1589
|
-
function PostHogCore(apiKey, options) {
|
|
1590
|
-
var _this = this;
|
|
1591
|
-
var _a, _b, _c;
|
|
1592
|
-
// Default for stateful mode is to not disable geoip. Only override if explicitly set
|
|
1593
|
-
var disableGeoipOption = (_a = options === null || options === void 0 ? void 0 : options.disableGeoip) !== null && _a !== void 0 ? _a : false;
|
|
1594
|
-
_this = _super.call(this, apiKey, __assign(__assign({}, options), { disableGeoip: disableGeoipOption })) || this;
|
|
1595
|
-
_this.flagCallReported = {};
|
|
1596
|
-
_this.sessionProps = {};
|
|
1597
|
-
_this.sendFeatureFlagEvent = (_b = options === null || options === void 0 ? void 0 : options.sendFeatureFlagEvent) !== null && _b !== void 0 ? _b : true;
|
|
1598
|
-
_this._sessionExpirationTimeSeconds = (_c = options === null || options === void 0 ? void 0 : options.sessionExpirationTimeSeconds) !== null && _c !== void 0 ? _c : 1800; // 30 minutes
|
|
1599
|
-
return _this;
|
|
1600
1293
|
}
|
|
1601
|
-
|
|
1602
|
-
var _a
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1294
|
+
async fetchWithRetry(url, options, retryOptions, requestTimeout) {
|
|
1295
|
+
var _a;
|
|
1296
|
+
(_a = AbortSignal).timeout ?? (_a.timeout = function timeout(ms) {
|
|
1297
|
+
const ctrl = new AbortController();
|
|
1298
|
+
setTimeout(() => ctrl.abort(), ms);
|
|
1299
|
+
return ctrl.signal;
|
|
1300
|
+
});
|
|
1301
|
+
return await retriable(async () => {
|
|
1302
|
+
let res = null;
|
|
1303
|
+
try {
|
|
1304
|
+
res = await this.fetch(url, {
|
|
1305
|
+
signal: AbortSignal.timeout(requestTimeout ?? this.requestTimeout),
|
|
1306
|
+
...options,
|
|
1307
|
+
});
|
|
1606
1308
|
}
|
|
1607
|
-
|
|
1608
|
-
|
|
1309
|
+
catch (e) {
|
|
1310
|
+
// fetch will only throw on network errors or on timeouts
|
|
1311
|
+
throw new PostHogFetchNetworkError(e);
|
|
1609
1312
|
}
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
return ((res[key] = ((_b = (_a = options.bootstrap) === null || _a === void 0 ? void 0 : _a.featureFlags) === null || _b === void 0 ? void 0 : _b[key]) || false), res);
|
|
1617
|
-
}, {});
|
|
1618
|
-
this.setKnownFeatureFlags(activeFlags);
|
|
1619
|
-
(options === null || options === void 0 ? void 0 : options.bootstrap.featureFlagPayloads) && this.setKnownFeatureFlagPayloads(options === null || options === void 0 ? void 0 : options.bootstrap.featureFlagPayloads);
|
|
1620
|
-
}
|
|
1621
|
-
};
|
|
1622
|
-
Object.defineProperty(PostHogCore.prototype, "props", {
|
|
1623
|
-
// NOTE: Props are lazy loaded from localstorage hence the complex getter setter logic
|
|
1624
|
-
get: function () {
|
|
1625
|
-
if (!this._props) {
|
|
1626
|
-
this._props = this.getPersistedProperty(PostHogPersistedProperty.Props);
|
|
1313
|
+
// If we're in no-cors mode, we can't access the response status
|
|
1314
|
+
// We only throw on HTTP errors if we're not in no-cors mode
|
|
1315
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Request/mode#no-cors
|
|
1316
|
+
const isNoCors = options.mode === 'no-cors';
|
|
1317
|
+
if (!isNoCors && (res.status < 200 || res.status >= 400)) {
|
|
1318
|
+
throw new PostHogFetchHttpError(res);
|
|
1627
1319
|
}
|
|
1628
|
-
return
|
|
1629
|
-
},
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1320
|
+
return res;
|
|
1321
|
+
}, { ...this._retryOptions, ...retryOptions });
|
|
1322
|
+
}
|
|
1323
|
+
async shutdownAsync(shutdownTimeoutMs) {
|
|
1324
|
+
await this._initPromise;
|
|
1325
|
+
clearTimeout(this._flushTimer);
|
|
1326
|
+
try {
|
|
1327
|
+
await Promise.all(Object.values(this.pendingPromises).map((x) => x.catch(() => {
|
|
1328
|
+
// ignore errors as we are shutting down and can't deal with them anyways.
|
|
1329
|
+
})));
|
|
1330
|
+
const timeout = shutdownTimeoutMs ?? 30000;
|
|
1331
|
+
const startTimeWithDelay = Date.now() + timeout;
|
|
1332
|
+
while (true) {
|
|
1333
|
+
const queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
|
|
1334
|
+
if (queue.length === 0) {
|
|
1335
|
+
break;
|
|
1336
|
+
}
|
|
1337
|
+
// flush again to make sure we send all events, some of which might've been added
|
|
1338
|
+
// while we were waiting for the pending promises to resolve
|
|
1339
|
+
// For example, see sendFeatureFlags in posthog-node/src/posthog-node.ts::capture
|
|
1340
|
+
await this.flushAsync();
|
|
1341
|
+
// If we've been waiting for more than the shutdownTimeoutMs, stop it
|
|
1342
|
+
const now = Date.now();
|
|
1343
|
+
if (startTimeWithDelay < now) {
|
|
1344
|
+
break;
|
|
1345
|
+
}
|
|
1651
1346
|
}
|
|
1652
1347
|
}
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
var featureVariantProperties = {};
|
|
1657
|
-
if (featureFlags) {
|
|
1658
|
-
for (var _i = 0, _a = Object.entries(featureFlags); _i < _a.length; _i++) {
|
|
1659
|
-
var _b = _a[_i], feature = _b[0], variant = _b[1];
|
|
1660
|
-
featureVariantProperties["$feature/".concat(feature)] = variant;
|
|
1348
|
+
catch (e) {
|
|
1349
|
+
if (!isPostHogFetchError(e)) {
|
|
1350
|
+
throw e;
|
|
1661
1351
|
}
|
|
1352
|
+
console.error('Error while shutting down PostHog', e);
|
|
1662
1353
|
}
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
PostHogCore.prototype.getSessionId = function () {
|
|
1669
|
-
var sessionId = this.getPersistedProperty(PostHogPersistedProperty.SessionId);
|
|
1670
|
-
var sessionTimestamp = this.getPersistedProperty(PostHogPersistedProperty.SessionLastTimestamp) || 0;
|
|
1671
|
-
if (!sessionId || Date.now() - sessionTimestamp > this._sessionExpirationTimeSeconds * 1000) {
|
|
1672
|
-
sessionId = uuidv7();
|
|
1673
|
-
this.setPersistedProperty(PostHogPersistedProperty.SessionId, sessionId);
|
|
1674
|
-
}
|
|
1675
|
-
this.setPersistedProperty(PostHogPersistedProperty.SessionLastTimestamp, Date.now());
|
|
1676
|
-
return sessionId;
|
|
1677
|
-
};
|
|
1678
|
-
PostHogCore.prototype.resetSessionId = function () {
|
|
1679
|
-
this.setPersistedProperty(PostHogPersistedProperty.SessionId, null);
|
|
1680
|
-
};
|
|
1681
|
-
PostHogCore.prototype.getAnonymousId = function () {
|
|
1682
|
-
var anonId = this.getPersistedProperty(PostHogPersistedProperty.AnonymousId);
|
|
1683
|
-
if (!anonId) {
|
|
1684
|
-
anonId = uuidv7();
|
|
1685
|
-
this.setPersistedProperty(PostHogPersistedProperty.AnonymousId, anonId);
|
|
1686
|
-
}
|
|
1687
|
-
return anonId;
|
|
1688
|
-
};
|
|
1689
|
-
PostHogCore.prototype.getDistinctId = function () {
|
|
1690
|
-
return this.getPersistedProperty(PostHogPersistedProperty.DistinctId) || this.getAnonymousId();
|
|
1691
|
-
};
|
|
1692
|
-
PostHogCore.prototype.unregister = function (property) {
|
|
1693
|
-
delete this.props[property];
|
|
1694
|
-
this.setPersistedProperty(PostHogPersistedProperty.Props, this.props);
|
|
1695
|
-
};
|
|
1696
|
-
PostHogCore.prototype.register = function (properties) {
|
|
1697
|
-
this.props = __assign(__assign({}, this.props), properties);
|
|
1698
|
-
this.setPersistedProperty(PostHogPersistedProperty.Props, this.props);
|
|
1699
|
-
};
|
|
1700
|
-
PostHogCore.prototype.registerForSession = function (properties) {
|
|
1701
|
-
this.sessionProps = __assign(__assign({}, this.sessionProps), properties);
|
|
1702
|
-
};
|
|
1703
|
-
PostHogCore.prototype.unregisterForSession = function (property) {
|
|
1704
|
-
delete this.sessionProps[property];
|
|
1705
|
-
};
|
|
1706
|
-
/***
|
|
1707
|
-
*** TRACKING
|
|
1708
|
-
***/
|
|
1709
|
-
PostHogCore.prototype.identify = function (distinctId, properties, options) {
|
|
1710
|
-
var previousDistinctId = this.getDistinctId();
|
|
1711
|
-
distinctId = distinctId || previousDistinctId;
|
|
1712
|
-
if (properties === null || properties === void 0 ? void 0 : properties.$groups) {
|
|
1713
|
-
this.groups(properties.$groups);
|
|
1714
|
-
}
|
|
1715
|
-
var allProperties = this.enrichProperties(__assign(__assign({}, properties), { $anon_distinct_id: this.getAnonymousId(), $set: properties }));
|
|
1716
|
-
if (distinctId !== previousDistinctId) {
|
|
1717
|
-
// We keep the AnonymousId to be used by decide calls and identify to link the previousId
|
|
1718
|
-
this.setPersistedProperty(PostHogPersistedProperty.AnonymousId, previousDistinctId);
|
|
1719
|
-
this.setPersistedProperty(PostHogPersistedProperty.DistinctId, distinctId);
|
|
1720
|
-
this.reloadFeatureFlags();
|
|
1721
|
-
}
|
|
1722
|
-
_super.prototype.identifyStateless.call(this, distinctId, allProperties, options);
|
|
1723
|
-
return this;
|
|
1724
|
-
};
|
|
1725
|
-
PostHogCore.prototype.capture = function (event, properties, options) {
|
|
1726
|
-
var distinctId = this.getDistinctId();
|
|
1727
|
-
if (properties === null || properties === void 0 ? void 0 : properties.$groups) {
|
|
1728
|
-
this.groups(properties.$groups);
|
|
1729
|
-
}
|
|
1730
|
-
var allProperties = this.enrichProperties(properties);
|
|
1731
|
-
_super.prototype.captureStateless.call(this, distinctId, event, allProperties, options);
|
|
1732
|
-
return this;
|
|
1733
|
-
};
|
|
1734
|
-
PostHogCore.prototype.alias = function (alias) {
|
|
1735
|
-
var distinctId = this.getDistinctId();
|
|
1736
|
-
var allProperties = this.enrichProperties({});
|
|
1737
|
-
_super.prototype.aliasStateless.call(this, alias, distinctId, allProperties);
|
|
1738
|
-
return this;
|
|
1739
|
-
};
|
|
1740
|
-
PostHogCore.prototype.autocapture = function (eventType, elements, properties, options) {
|
|
1741
|
-
if (properties === void 0) { properties = {}; }
|
|
1742
|
-
var distinctId = this.getDistinctId();
|
|
1743
|
-
var payload = {
|
|
1744
|
-
distinct_id: distinctId,
|
|
1745
|
-
event: '$autocapture',
|
|
1746
|
-
properties: __assign(__assign({}, this.enrichProperties(properties)), { $event_type: eventType, $elements: elements }),
|
|
1747
|
-
};
|
|
1748
|
-
this.enqueue('autocapture', payload, options);
|
|
1749
|
-
return this;
|
|
1750
|
-
};
|
|
1751
|
-
/***
|
|
1752
|
-
*** GROUPS
|
|
1753
|
-
***/
|
|
1754
|
-
PostHogCore.prototype.groups = function (groups) {
|
|
1755
|
-
// Get persisted groups
|
|
1756
|
-
var existingGroups = this.props.$groups || {};
|
|
1757
|
-
this.register({
|
|
1758
|
-
$groups: __assign(__assign({}, existingGroups), groups),
|
|
1759
|
-
});
|
|
1760
|
-
if (Object.keys(groups).find(function (type) { return existingGroups[type] !== groups[type]; })) {
|
|
1761
|
-
this.reloadFeatureFlags();
|
|
1762
|
-
}
|
|
1763
|
-
return this;
|
|
1764
|
-
};
|
|
1765
|
-
PostHogCore.prototype.group = function (groupType, groupKey, groupProperties, options) {
|
|
1766
|
-
var _a;
|
|
1767
|
-
this.groups((_a = {},
|
|
1768
|
-
_a[groupType] = groupKey,
|
|
1769
|
-
_a));
|
|
1770
|
-
if (groupProperties) {
|
|
1771
|
-
this.groupIdentify(groupType, groupKey, groupProperties, options);
|
|
1772
|
-
}
|
|
1773
|
-
return this;
|
|
1774
|
-
};
|
|
1775
|
-
PostHogCore.prototype.groupIdentify = function (groupType, groupKey, groupProperties, options) {
|
|
1776
|
-
var distinctId = this.getDistinctId();
|
|
1777
|
-
var eventProperties = this.enrichProperties({});
|
|
1778
|
-
_super.prototype.groupIdentifyStateless.call(this, groupType, groupKey, groupProperties, options, distinctId, eventProperties);
|
|
1779
|
-
return this;
|
|
1780
|
-
};
|
|
1781
|
-
/***
|
|
1782
|
-
* PROPERTIES
|
|
1783
|
-
***/
|
|
1784
|
-
PostHogCore.prototype.setPersonPropertiesForFlags = function (properties) {
|
|
1785
|
-
// Get persisted person properties
|
|
1786
|
-
var existingProperties = this.getPersistedProperty(PostHogPersistedProperty.PersonProperties) || {};
|
|
1787
|
-
this.setPersistedProperty(PostHogPersistedProperty.PersonProperties, __assign(__assign({}, existingProperties), properties));
|
|
1788
|
-
return this;
|
|
1789
|
-
};
|
|
1790
|
-
PostHogCore.prototype.resetPersonPropertiesForFlags = function () {
|
|
1791
|
-
this.setPersistedProperty(PostHogPersistedProperty.PersonProperties, {});
|
|
1792
|
-
};
|
|
1793
|
-
/** @deprecated - Renamed to setPersonPropertiesForFlags */
|
|
1794
|
-
PostHogCore.prototype.personProperties = function (properties) {
|
|
1795
|
-
return this.setPersonPropertiesForFlags(properties);
|
|
1796
|
-
};
|
|
1797
|
-
PostHogCore.prototype.setGroupPropertiesForFlags = function (properties) {
|
|
1798
|
-
// Get persisted group properties
|
|
1799
|
-
var existingProperties = this.getPersistedProperty(PostHogPersistedProperty.GroupProperties) || {};
|
|
1800
|
-
if (Object.keys(existingProperties).length !== 0) {
|
|
1801
|
-
Object.keys(existingProperties).forEach(function (groupType) {
|
|
1802
|
-
existingProperties[groupType] = __assign(__assign({}, existingProperties[groupType]), properties[groupType]);
|
|
1803
|
-
delete properties[groupType];
|
|
1804
|
-
});
|
|
1805
|
-
}
|
|
1806
|
-
this.setPersistedProperty(PostHogPersistedProperty.GroupProperties, __assign(__assign({}, existingProperties), properties));
|
|
1807
|
-
return this;
|
|
1808
|
-
};
|
|
1809
|
-
PostHogCore.prototype.resetGroupPropertiesForFlags = function () {
|
|
1810
|
-
this.setPersistedProperty(PostHogPersistedProperty.GroupProperties, {});
|
|
1811
|
-
};
|
|
1812
|
-
/** @deprecated - Renamed to setGroupPropertiesForFlags */
|
|
1813
|
-
PostHogCore.prototype.groupProperties = function (properties) {
|
|
1814
|
-
return this.setGroupPropertiesForFlags(properties);
|
|
1815
|
-
};
|
|
1816
|
-
/***
|
|
1817
|
-
*** FEATURE FLAGS
|
|
1818
|
-
***/
|
|
1819
|
-
PostHogCore.prototype.decideAsync = function (sendAnonDistinctId) {
|
|
1820
|
-
if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
|
|
1821
|
-
if (this._decideResponsePromise) {
|
|
1822
|
-
return this._decideResponsePromise;
|
|
1823
|
-
}
|
|
1824
|
-
return this._decideAsync(sendAnonDistinctId);
|
|
1825
|
-
};
|
|
1826
|
-
PostHogCore.prototype._decideAsync = function (sendAnonDistinctId) {
|
|
1827
|
-
if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
|
|
1828
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
1829
|
-
var distinctId, groups, personProperties, groupProperties, extraProperties;
|
|
1830
|
-
var _this = this;
|
|
1831
|
-
return __generator(this, function (_a) {
|
|
1832
|
-
distinctId = this.getDistinctId();
|
|
1833
|
-
groups = this.props.$groups || {};
|
|
1834
|
-
personProperties = this.getPersistedProperty(PostHogPersistedProperty.PersonProperties) || {};
|
|
1835
|
-
groupProperties = this.getPersistedProperty(PostHogPersistedProperty.GroupProperties) || {};
|
|
1836
|
-
extraProperties = {
|
|
1837
|
-
$anon_distinct_id: sendAnonDistinctId ? this.getAnonymousId() : undefined,
|
|
1838
|
-
};
|
|
1839
|
-
this._decideResponsePromise = _super.prototype.getDecide.call(this, distinctId, groups, personProperties, groupProperties, extraProperties)
|
|
1840
|
-
.then(function (res) {
|
|
1841
|
-
if (res === null || res === void 0 ? void 0 : res.featureFlags) {
|
|
1842
|
-
var newFeatureFlags = res.featureFlags;
|
|
1843
|
-
var newFeatureFlagPayloads = res.featureFlagPayloads;
|
|
1844
|
-
if (res.errorsWhileComputingFlags) {
|
|
1845
|
-
// if not all flags were computed, we upsert flags instead of replacing them
|
|
1846
|
-
var currentFlags = _this.getPersistedProperty(PostHogPersistedProperty.FeatureFlags);
|
|
1847
|
-
var currentFlagPayloads = _this.getPersistedProperty(PostHogPersistedProperty.FeatureFlagPayloads);
|
|
1848
|
-
newFeatureFlags = __assign(__assign({}, currentFlags), res.featureFlags);
|
|
1849
|
-
newFeatureFlagPayloads = __assign(__assign({}, currentFlagPayloads), res.featureFlagPayloads);
|
|
1850
|
-
}
|
|
1851
|
-
_this.setKnownFeatureFlags(newFeatureFlags);
|
|
1852
|
-
_this.setKnownFeatureFlagPayloads(newFeatureFlagPayloads);
|
|
1853
|
-
}
|
|
1854
|
-
return res;
|
|
1855
|
-
})
|
|
1856
|
-
.finally(function () {
|
|
1857
|
-
_this._decideResponsePromise = undefined;
|
|
1858
|
-
});
|
|
1859
|
-
return [2 /*return*/, this._decideResponsePromise];
|
|
1860
|
-
});
|
|
1861
|
-
});
|
|
1862
|
-
};
|
|
1863
|
-
PostHogCore.prototype.setKnownFeatureFlags = function (featureFlags) {
|
|
1864
|
-
this.setPersistedProperty(PostHogPersistedProperty.FeatureFlags, featureFlags);
|
|
1865
|
-
this._events.emit('featureflags', featureFlags);
|
|
1866
|
-
};
|
|
1867
|
-
PostHogCore.prototype.setKnownFeatureFlagPayloads = function (featureFlagPayloads) {
|
|
1868
|
-
this.setPersistedProperty(PostHogPersistedProperty.FeatureFlagPayloads, featureFlagPayloads);
|
|
1869
|
-
};
|
|
1870
|
-
PostHogCore.prototype.getFeatureFlag = function (key) {
|
|
1871
|
-
var featureFlags = this.getFeatureFlags();
|
|
1872
|
-
if (!featureFlags) {
|
|
1873
|
-
// If we haven't loaded flags yet, or errored out, we respond with undefined
|
|
1874
|
-
return undefined;
|
|
1875
|
-
}
|
|
1876
|
-
var response = featureFlags[key];
|
|
1877
|
-
// `/decide` v3 returns all flags
|
|
1878
|
-
if (response === undefined) {
|
|
1879
|
-
// For cases where the flag is unknown, return false
|
|
1880
|
-
response = false;
|
|
1881
|
-
}
|
|
1882
|
-
if (this.sendFeatureFlagEvent && !this.flagCallReported[key]) {
|
|
1883
|
-
this.flagCallReported[key] = true;
|
|
1884
|
-
this.capture('$feature_flag_called', {
|
|
1885
|
-
$feature_flag: key,
|
|
1886
|
-
$feature_flag_response: response,
|
|
1887
|
-
});
|
|
1888
|
-
}
|
|
1889
|
-
// If we have flags we either return the value (true or string) or false
|
|
1890
|
-
return response;
|
|
1891
|
-
};
|
|
1892
|
-
PostHogCore.prototype.getFeatureFlagPayload = function (key) {
|
|
1893
|
-
var payloads = this.getFeatureFlagPayloads();
|
|
1894
|
-
if (!payloads) {
|
|
1895
|
-
return undefined;
|
|
1896
|
-
}
|
|
1897
|
-
var response = payloads[key];
|
|
1898
|
-
// Undefined means a loading or missing data issue. Null means evaluation happened and there was no match
|
|
1899
|
-
if (response === undefined) {
|
|
1900
|
-
return null;
|
|
1901
|
-
}
|
|
1902
|
-
return this._parsePayload(response);
|
|
1903
|
-
};
|
|
1904
|
-
PostHogCore.prototype.getFeatureFlagPayloads = function () {
|
|
1905
|
-
var _this = this;
|
|
1906
|
-
var payloads = this.getPersistedProperty(PostHogPersistedProperty.FeatureFlagPayloads);
|
|
1907
|
-
if (payloads) {
|
|
1908
|
-
return Object.fromEntries(Object.entries(payloads).map(function (_a) {
|
|
1909
|
-
var k = _a[0], v = _a[1];
|
|
1910
|
-
return [k, _this._parsePayload(v)];
|
|
1911
|
-
}));
|
|
1912
|
-
}
|
|
1913
|
-
return payloads;
|
|
1914
|
-
};
|
|
1915
|
-
PostHogCore.prototype.getFeatureFlags = function () {
|
|
1916
|
-
var flags = this.getPersistedProperty(PostHogPersistedProperty.FeatureFlags);
|
|
1917
|
-
var overriddenFlags = this.getPersistedProperty(PostHogPersistedProperty.OverrideFeatureFlags);
|
|
1918
|
-
if (!overriddenFlags) {
|
|
1919
|
-
return flags;
|
|
1920
|
-
}
|
|
1921
|
-
flags = flags || {};
|
|
1922
|
-
for (var key in overriddenFlags) {
|
|
1923
|
-
if (!overriddenFlags[key]) {
|
|
1924
|
-
delete flags[key];
|
|
1925
|
-
}
|
|
1926
|
-
else {
|
|
1927
|
-
flags[key] = overriddenFlags[key];
|
|
1928
|
-
}
|
|
1929
|
-
}
|
|
1930
|
-
return flags;
|
|
1931
|
-
};
|
|
1932
|
-
PostHogCore.prototype.getFeatureFlagsAndPayloads = function () {
|
|
1933
|
-
var flags = this.getFeatureFlags();
|
|
1934
|
-
var payloads = this.getFeatureFlagPayloads();
|
|
1935
|
-
return {
|
|
1936
|
-
flags: flags,
|
|
1937
|
-
payloads: payloads,
|
|
1938
|
-
};
|
|
1939
|
-
};
|
|
1940
|
-
PostHogCore.prototype.isFeatureEnabled = function (key) {
|
|
1941
|
-
var response = this.getFeatureFlag(key);
|
|
1942
|
-
if (response === undefined) {
|
|
1943
|
-
return undefined;
|
|
1944
|
-
}
|
|
1945
|
-
return !!response;
|
|
1946
|
-
};
|
|
1947
|
-
// Used when we want to trigger the reload but we don't care about the result
|
|
1948
|
-
PostHogCore.prototype.reloadFeatureFlags = function (cb) {
|
|
1949
|
-
this.decideAsync()
|
|
1950
|
-
.then(function (res) {
|
|
1951
|
-
cb === null || cb === void 0 ? void 0 : cb(undefined, res === null || res === void 0 ? void 0 : res.featureFlags);
|
|
1952
|
-
})
|
|
1953
|
-
.catch(function (e) {
|
|
1954
|
-
cb === null || cb === void 0 ? void 0 : cb(e, undefined);
|
|
1955
|
-
if (!cb) {
|
|
1956
|
-
console.log('[PostHog] Error reloading feature flags', e);
|
|
1957
|
-
}
|
|
1958
|
-
});
|
|
1959
|
-
};
|
|
1960
|
-
PostHogCore.prototype.reloadFeatureFlagsAsync = function (sendAnonDistinctId) {
|
|
1961
|
-
var _a;
|
|
1962
|
-
if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
|
|
1963
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
1964
|
-
return __generator(this, function (_b) {
|
|
1965
|
-
switch (_b.label) {
|
|
1966
|
-
case 0: return [4 /*yield*/, this.decideAsync(sendAnonDistinctId)];
|
|
1967
|
-
case 1: return [2 /*return*/, (_a = (_b.sent())) === null || _a === void 0 ? void 0 : _a.featureFlags];
|
|
1968
|
-
}
|
|
1969
|
-
});
|
|
1970
|
-
});
|
|
1971
|
-
};
|
|
1972
|
-
PostHogCore.prototype.onFeatureFlags = function (cb) {
|
|
1973
|
-
var _this = this;
|
|
1974
|
-
return this.on('featureflags', function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1975
|
-
var flags;
|
|
1976
|
-
return __generator(this, function (_a) {
|
|
1977
|
-
flags = this.getFeatureFlags();
|
|
1978
|
-
if (flags) {
|
|
1979
|
-
cb(flags);
|
|
1980
|
-
}
|
|
1981
|
-
return [2 /*return*/];
|
|
1982
|
-
});
|
|
1983
|
-
}); });
|
|
1984
|
-
};
|
|
1985
|
-
PostHogCore.prototype.onFeatureFlag = function (key, cb) {
|
|
1986
|
-
var _this = this;
|
|
1987
|
-
return this.on('featureflags', function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1988
|
-
var flagResponse;
|
|
1989
|
-
return __generator(this, function (_a) {
|
|
1990
|
-
flagResponse = this.getFeatureFlag(key);
|
|
1991
|
-
if (flagResponse !== undefined) {
|
|
1992
|
-
cb(flagResponse);
|
|
1993
|
-
}
|
|
1994
|
-
return [2 /*return*/];
|
|
1995
|
-
});
|
|
1996
|
-
}); });
|
|
1997
|
-
};
|
|
1998
|
-
PostHogCore.prototype.overrideFeatureFlag = function (flags) {
|
|
1999
|
-
if (flags === null) {
|
|
2000
|
-
return this.setPersistedProperty(PostHogPersistedProperty.OverrideFeatureFlags, null);
|
|
2001
|
-
}
|
|
2002
|
-
return this.setPersistedProperty(PostHogPersistedProperty.OverrideFeatureFlags, flags);
|
|
2003
|
-
};
|
|
2004
|
-
return PostHogCore;
|
|
2005
|
-
})(PostHogCoreStateless));
|
|
1354
|
+
}
|
|
1355
|
+
shutdown(shutdownTimeoutMs) {
|
|
1356
|
+
void this.shutdownAsync(shutdownTimeoutMs);
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
2006
1359
|
|
|
2007
|
-
|
|
2008
|
-
|
|
1360
|
+
class PostHogMemoryStorage {
|
|
1361
|
+
constructor() {
|
|
2009
1362
|
this._memoryStorage = {};
|
|
2010
1363
|
}
|
|
2011
|
-
|
|
1364
|
+
getProperty(key) {
|
|
2012
1365
|
return this._memoryStorage[key];
|
|
2013
|
-
}
|
|
2014
|
-
|
|
1366
|
+
}
|
|
1367
|
+
setProperty(key, value) {
|
|
2015
1368
|
this._memoryStorage[key] = value !== null ? value : undefined;
|
|
2016
|
-
}
|
|
2017
|
-
|
|
2018
|
-
}());
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
2019
1371
|
|
|
2020
1372
|
/**
|
|
2021
1373
|
* Fetch wrapper
|
|
@@ -2025,120 +1377,70 @@ var PostHogMemoryStorage = /** @class */ (function () {
|
|
|
2025
1377
|
* This is currently solved by using the global fetch if available instead.
|
|
2026
1378
|
* See https://github.com/PostHog/posthog-js-lite/issues/127 for more info
|
|
2027
1379
|
*/
|
|
2028
|
-
|
|
2029
|
-
var _fetch = // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
|
|
1380
|
+
let _fetch = // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
|
|
2030
1381
|
// @ts-ignore
|
|
2031
1382
|
typeof fetch !== 'undefined' ? fetch : typeof global.fetch !== 'undefined' ? global.fetch : undefined;
|
|
2032
1383
|
|
|
2033
1384
|
if (!_fetch) {
|
|
2034
1385
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
_fetch =
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
url: url,
|
|
2047
|
-
headers: options.headers,
|
|
2048
|
-
method: options.method.toLowerCase(),
|
|
2049
|
-
data: options.body,
|
|
2050
|
-
signal: options.signal,
|
|
2051
|
-
// fetch only throws on network errors, not on HTTP errors
|
|
2052
|
-
validateStatus: function () {
|
|
2053
|
-
return true;
|
|
2054
|
-
}
|
|
2055
|
-
})];
|
|
2056
|
-
|
|
2057
|
-
case 1:
|
|
2058
|
-
res = _a.sent();
|
|
2059
|
-
return [2
|
|
2060
|
-
/*return*/
|
|
2061
|
-
, {
|
|
2062
|
-
status: res.status,
|
|
2063
|
-
text: function () {
|
|
2064
|
-
return __awaiter(void 0, void 0, void 0, function () {
|
|
2065
|
-
return __generator(this, function (_a) {
|
|
2066
|
-
return [2
|
|
2067
|
-
/*return*/
|
|
2068
|
-
, res.data];
|
|
2069
|
-
});
|
|
2070
|
-
});
|
|
2071
|
-
},
|
|
2072
|
-
json: function () {
|
|
2073
|
-
return __awaiter(void 0, void 0, void 0, function () {
|
|
2074
|
-
return __generator(this, function (_a) {
|
|
2075
|
-
return [2
|
|
2076
|
-
/*return*/
|
|
2077
|
-
, res.data];
|
|
2078
|
-
});
|
|
2079
|
-
});
|
|
2080
|
-
}
|
|
2081
|
-
}];
|
|
2082
|
-
}
|
|
2083
|
-
});
|
|
1386
|
+
const axios = require('axios');
|
|
1387
|
+
|
|
1388
|
+
_fetch = async (url, options) => {
|
|
1389
|
+
const res = await axios.request({
|
|
1390
|
+
url,
|
|
1391
|
+
headers: options.headers,
|
|
1392
|
+
method: options.method.toLowerCase(),
|
|
1393
|
+
data: options.body,
|
|
1394
|
+
signal: options.signal,
|
|
1395
|
+
// fetch only throws on network errors, not on HTTP errors
|
|
1396
|
+
validateStatus: () => true
|
|
2084
1397
|
});
|
|
1398
|
+
return {
|
|
1399
|
+
status: res.status,
|
|
1400
|
+
text: async () => res.data,
|
|
1401
|
+
json: async () => res.data
|
|
1402
|
+
};
|
|
2085
1403
|
};
|
|
2086
1404
|
} // NOTE: We have to export this as default, even though we prefer named exports as we are relying on detecting "fetch" in the global scope
|
|
2087
1405
|
|
|
2088
1406
|
|
|
2089
1407
|
var fetch$1 = _fetch;
|
|
2090
1408
|
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
var ClientError =
|
|
2094
|
-
/** @class */
|
|
2095
|
-
function (_super) {
|
|
2096
|
-
__extends(ClientError, _super);
|
|
2097
|
-
|
|
2098
|
-
function ClientError(message) {
|
|
2099
|
-
var _this = _super.call(this) || this;
|
|
1409
|
+
const LONG_SCALE = 0xfffffffffffffff;
|
|
2100
1410
|
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
1411
|
+
class ClientError extends Error {
|
|
1412
|
+
constructor(message) {
|
|
1413
|
+
super();
|
|
1414
|
+
Error.captureStackTrace(this, this.constructor);
|
|
1415
|
+
this.name = 'ClientError';
|
|
1416
|
+
this.message = message;
|
|
1417
|
+
Object.setPrototypeOf(this, ClientError.prototype);
|
|
2106
1418
|
}
|
|
2107
1419
|
|
|
2108
|
-
|
|
2109
|
-
}(Error);
|
|
2110
|
-
|
|
2111
|
-
var InconclusiveMatchError =
|
|
2112
|
-
/** @class */
|
|
2113
|
-
function (_super) {
|
|
2114
|
-
__extends(InconclusiveMatchError, _super);
|
|
2115
|
-
|
|
2116
|
-
function InconclusiveMatchError(message) {
|
|
2117
|
-
var _this = _super.call(this, message) || this;
|
|
1420
|
+
}
|
|
2118
1421
|
|
|
2119
|
-
|
|
2120
|
-
|
|
1422
|
+
class InconclusiveMatchError extends Error {
|
|
1423
|
+
constructor(message) {
|
|
1424
|
+
super(message);
|
|
1425
|
+
this.name = this.constructor.name;
|
|
1426
|
+
Error.captureStackTrace(this, this.constructor); // instanceof doesn't work in ES3 or ES5
|
|
2121
1427
|
// https://www.dannyguo.com/blog/how-to-fix-instanceof-not-working-for-custom-errors-in-typescript/
|
|
2122
1428
|
// this is the workaround
|
|
2123
1429
|
|
|
2124
|
-
Object.setPrototypeOf(
|
|
2125
|
-
return _this;
|
|
1430
|
+
Object.setPrototypeOf(this, InconclusiveMatchError.prototype);
|
|
2126
1431
|
}
|
|
2127
1432
|
|
|
2128
|
-
|
|
2129
|
-
}(Error);
|
|
2130
|
-
|
|
2131
|
-
var FeatureFlagsPoller =
|
|
2132
|
-
/** @class */
|
|
2133
|
-
function () {
|
|
2134
|
-
function FeatureFlagsPoller(_a) {
|
|
2135
|
-
var pollingInterval = _a.pollingInterval,
|
|
2136
|
-
personalApiKey = _a.personalApiKey,
|
|
2137
|
-
projectApiKey = _a.projectApiKey,
|
|
2138
|
-
timeout = _a.timeout,
|
|
2139
|
-
host = _a.host,
|
|
2140
|
-
options = __rest(_a, ["pollingInterval", "personalApiKey", "projectApiKey", "timeout", "host"]);
|
|
1433
|
+
}
|
|
2141
1434
|
|
|
1435
|
+
class FeatureFlagsPoller {
|
|
1436
|
+
constructor({
|
|
1437
|
+
pollingInterval,
|
|
1438
|
+
personalApiKey,
|
|
1439
|
+
projectApiKey,
|
|
1440
|
+
timeout,
|
|
1441
|
+
host,
|
|
1442
|
+
...options
|
|
1443
|
+
}) {
|
|
2142
1444
|
this.debugMode = false;
|
|
2143
1445
|
this.pollingInterval = pollingInterval;
|
|
2144
1446
|
this.personalApiKey = personalApiKey;
|
|
@@ -2157,234 +1459,99 @@ function () {
|
|
|
2157
1459
|
void this.loadFeatureFlags();
|
|
2158
1460
|
}
|
|
2159
1461
|
|
|
2160
|
-
|
|
2161
|
-
if (enabled === void 0) {
|
|
2162
|
-
enabled = true;
|
|
2163
|
-
}
|
|
2164
|
-
|
|
1462
|
+
debug(enabled = true) {
|
|
2165
1463
|
this.debugMode = enabled;
|
|
2166
|
-
}
|
|
1464
|
+
}
|
|
2167
1465
|
|
|
2168
|
-
|
|
2169
|
-
|
|
1466
|
+
async getFeatureFlag(key, distinctId, groups = {}, personProperties = {}, groupProperties = {}) {
|
|
1467
|
+
await this.loadFeatureFlags();
|
|
1468
|
+
let response = undefined;
|
|
1469
|
+
let featureFlag = undefined;
|
|
2170
1470
|
|
|
2171
|
-
if (
|
|
2172
|
-
|
|
1471
|
+
if (!this.loadedSuccessfullyOnce) {
|
|
1472
|
+
return response;
|
|
2173
1473
|
}
|
|
2174
1474
|
|
|
2175
|
-
|
|
2176
|
-
|
|
1475
|
+
for (const flag of this.featureFlags) {
|
|
1476
|
+
if (key === flag.key) {
|
|
1477
|
+
featureFlag = flag;
|
|
1478
|
+
break;
|
|
1479
|
+
}
|
|
2177
1480
|
}
|
|
2178
1481
|
|
|
2179
|
-
if (
|
|
2180
|
-
|
|
2181
|
-
|
|
1482
|
+
if (featureFlag !== undefined) {
|
|
1483
|
+
try {
|
|
1484
|
+
response = this.computeFlagLocally(featureFlag, distinctId, groups, personProperties, groupProperties);
|
|
2182
1485
|
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
return __generator(this, function (_c) {
|
|
2187
|
-
switch (_c.label) {
|
|
2188
|
-
case 0:
|
|
2189
|
-
return [4
|
|
2190
|
-
/*yield*/
|
|
2191
|
-
, this.loadFeatureFlags()];
|
|
2192
|
-
|
|
2193
|
-
case 1:
|
|
2194
|
-
_c.sent();
|
|
2195
|
-
|
|
2196
|
-
response = undefined;
|
|
2197
|
-
featureFlag = undefined;
|
|
2198
|
-
|
|
2199
|
-
if (!this.loadedSuccessfullyOnce) {
|
|
2200
|
-
return [2
|
|
2201
|
-
/*return*/
|
|
2202
|
-
, response];
|
|
2203
|
-
}
|
|
2204
|
-
|
|
2205
|
-
for (_i = 0, _b = this.featureFlags; _i < _b.length; _i++) {
|
|
2206
|
-
flag = _b[_i];
|
|
2207
|
-
|
|
2208
|
-
if (key === flag.key) {
|
|
2209
|
-
featureFlag = flag;
|
|
2210
|
-
break;
|
|
2211
|
-
}
|
|
2212
|
-
}
|
|
2213
|
-
|
|
2214
|
-
if (featureFlag !== undefined) {
|
|
2215
|
-
try {
|
|
2216
|
-
response = this.computeFlagLocally(featureFlag, distinctId, groups, personProperties, groupProperties);
|
|
2217
|
-
|
|
2218
|
-
if (this.debugMode) {
|
|
2219
|
-
console.debug("Successfully computed flag locally: ".concat(key, " -> ").concat(response));
|
|
2220
|
-
}
|
|
2221
|
-
} catch (e) {
|
|
2222
|
-
if (e instanceof InconclusiveMatchError) {
|
|
2223
|
-
if (this.debugMode) {
|
|
2224
|
-
console.debug("InconclusiveMatchError when computing flag locally: ".concat(key, ": ").concat(e));
|
|
2225
|
-
}
|
|
2226
|
-
} else if (e instanceof Error) {
|
|
2227
|
-
(_a = this.onError) === null || _a === void 0 ? void 0 : _a.call(this, new Error("Error computing flag locally: ".concat(key, ": ").concat(e)));
|
|
2228
|
-
}
|
|
2229
|
-
}
|
|
2230
|
-
}
|
|
2231
|
-
|
|
2232
|
-
return [2
|
|
2233
|
-
/*return*/
|
|
2234
|
-
, response];
|
|
1486
|
+
if (this.debugMode) {
|
|
1487
|
+
console.debug(`Successfully computed flag locally: ${key} -> ${response}`);
|
|
2235
1488
|
}
|
|
2236
|
-
})
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
2244
|
-
var response;
|
|
2245
|
-
return __generator(this, function (_j) {
|
|
2246
|
-
switch (_j.label) {
|
|
2247
|
-
case 0:
|
|
2248
|
-
return [4
|
|
2249
|
-
/*yield*/
|
|
2250
|
-
, this.loadFeatureFlags()];
|
|
2251
|
-
|
|
2252
|
-
case 1:
|
|
2253
|
-
_j.sent();
|
|
2254
|
-
|
|
2255
|
-
response = undefined;
|
|
2256
|
-
|
|
2257
|
-
if (!this.loadedSuccessfullyOnce) {
|
|
2258
|
-
return [2
|
|
2259
|
-
/*return*/
|
|
2260
|
-
, undefined];
|
|
2261
|
-
}
|
|
2262
|
-
|
|
2263
|
-
if (typeof matchValue == 'boolean') {
|
|
2264
|
-
response = (_d = (_c = (_b = (_a = this.featureFlagsByKey) === null || _a === void 0 ? void 0 : _a[key]) === null || _b === void 0 ? void 0 : _b.filters) === null || _c === void 0 ? void 0 : _c.payloads) === null || _d === void 0 ? void 0 : _d[matchValue.toString()];
|
|
2265
|
-
} else if (typeof matchValue == 'string') {
|
|
2266
|
-
response = (_h = (_g = (_f = (_e = this.featureFlagsByKey) === null || _e === void 0 ? void 0 : _e[key]) === null || _f === void 0 ? void 0 : _f.filters) === null || _g === void 0 ? void 0 : _g.payloads) === null || _h === void 0 ? void 0 : _h[matchValue];
|
|
2267
|
-
} // Undefined means a loading or missing data issue. Null means evaluation happened and there was no match
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
if (response === undefined) {
|
|
2271
|
-
return [2
|
|
2272
|
-
/*return*/
|
|
2273
|
-
, null];
|
|
2274
|
-
}
|
|
2275
|
-
|
|
2276
|
-
return [2
|
|
2277
|
-
/*return*/
|
|
2278
|
-
, response];
|
|
1489
|
+
} catch (e) {
|
|
1490
|
+
if (e instanceof InconclusiveMatchError) {
|
|
1491
|
+
if (this.debugMode) {
|
|
1492
|
+
console.debug(`InconclusiveMatchError when computing flag locally: ${key}: ${e}`);
|
|
1493
|
+
}
|
|
1494
|
+
} else if (e instanceof Error) {
|
|
1495
|
+
this.onError?.(new Error(`Error computing flag locally: ${key}: ${e}`));
|
|
2279
1496
|
}
|
|
2280
|
-
}
|
|
2281
|
-
});
|
|
2282
|
-
};
|
|
2283
|
-
|
|
2284
|
-
FeatureFlagsPoller.prototype.getAllFlagsAndPayloads = function (distinctId, groups, personProperties, groupProperties) {
|
|
2285
|
-
if (groups === void 0) {
|
|
2286
|
-
groups = {};
|
|
1497
|
+
}
|
|
2287
1498
|
}
|
|
2288
1499
|
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
}
|
|
1500
|
+
return response;
|
|
1501
|
+
}
|
|
2292
1502
|
|
|
2293
|
-
|
|
2294
|
-
|
|
1503
|
+
async computeFeatureFlagPayloadLocally(key, matchValue) {
|
|
1504
|
+
await this.loadFeatureFlags();
|
|
1505
|
+
let response = undefined;
|
|
1506
|
+
|
|
1507
|
+
if (!this.loadedSuccessfullyOnce) {
|
|
1508
|
+
return undefined;
|
|
2295
1509
|
}
|
|
2296
1510
|
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
return __generator(this, function (_a) {
|
|
2303
|
-
switch (_a.label) {
|
|
2304
|
-
case 0:
|
|
2305
|
-
return [4
|
|
2306
|
-
/*yield*/
|
|
2307
|
-
, this.loadFeatureFlags()];
|
|
2308
|
-
|
|
2309
|
-
case 1:
|
|
2310
|
-
_a.sent();
|
|
2311
|
-
|
|
2312
|
-
response = {};
|
|
2313
|
-
payloads = {};
|
|
2314
|
-
fallbackToDecide = this.featureFlags.length == 0;
|
|
2315
|
-
this.featureFlags.map(function (flag) {
|
|
2316
|
-
return __awaiter(_this, void 0, void 0, function () {
|
|
2317
|
-
var matchValue, matchPayload, e_1;
|
|
2318
|
-
|
|
2319
|
-
var _a;
|
|
2320
|
-
|
|
2321
|
-
return __generator(this, function (_b) {
|
|
2322
|
-
switch (_b.label) {
|
|
2323
|
-
case 0:
|
|
2324
|
-
_b.trys.push([0, 2,, 3]);
|
|
2325
|
-
|
|
2326
|
-
matchValue = this.computeFlagLocally(flag, distinctId, groups, personProperties, groupProperties);
|
|
2327
|
-
response[flag.key] = matchValue;
|
|
2328
|
-
return [4
|
|
2329
|
-
/*yield*/
|
|
2330
|
-
, this.computeFeatureFlagPayloadLocally(flag.key, matchValue)];
|
|
2331
|
-
|
|
2332
|
-
case 1:
|
|
2333
|
-
matchPayload = _b.sent();
|
|
2334
|
-
|
|
2335
|
-
if (matchPayload) {
|
|
2336
|
-
payloads[flag.key] = matchPayload;
|
|
2337
|
-
}
|
|
2338
|
-
|
|
2339
|
-
return [3
|
|
2340
|
-
/*break*/
|
|
2341
|
-
, 3];
|
|
2342
|
-
|
|
2343
|
-
case 2:
|
|
2344
|
-
e_1 = _b.sent();
|
|
2345
|
-
|
|
2346
|
-
if (e_1 instanceof InconclusiveMatchError) ; else if (e_1 instanceof Error) {
|
|
2347
|
-
(_a = this.onError) === null || _a === void 0 ? void 0 : _a.call(this, new Error("Error computing flag locally: ".concat(flag.key, ": ").concat(e_1)));
|
|
2348
|
-
}
|
|
2349
|
-
|
|
2350
|
-
fallbackToDecide = true;
|
|
2351
|
-
return [3
|
|
2352
|
-
/*break*/
|
|
2353
|
-
, 3];
|
|
2354
|
-
|
|
2355
|
-
case 3:
|
|
2356
|
-
return [2
|
|
2357
|
-
/*return*/
|
|
2358
|
-
];
|
|
2359
|
-
}
|
|
2360
|
-
});
|
|
2361
|
-
});
|
|
2362
|
-
});
|
|
2363
|
-
return [2
|
|
2364
|
-
/*return*/
|
|
2365
|
-
, {
|
|
2366
|
-
response: response,
|
|
2367
|
-
payloads: payloads,
|
|
2368
|
-
fallbackToDecide: fallbackToDecide
|
|
2369
|
-
}];
|
|
2370
|
-
}
|
|
2371
|
-
});
|
|
2372
|
-
});
|
|
2373
|
-
};
|
|
1511
|
+
if (typeof matchValue == 'boolean') {
|
|
1512
|
+
response = this.featureFlagsByKey?.[key]?.filters?.payloads?.[matchValue.toString()];
|
|
1513
|
+
} else if (typeof matchValue == 'string') {
|
|
1514
|
+
response = this.featureFlagsByKey?.[key]?.filters?.payloads?.[matchValue];
|
|
1515
|
+
} // Undefined means a loading or missing data issue. Null means evaluation happened and there was no match
|
|
2374
1516
|
|
|
2375
|
-
FeatureFlagsPoller.prototype.computeFlagLocally = function (flag, distinctId, groups, personProperties, groupProperties) {
|
|
2376
|
-
if (groups === void 0) {
|
|
2377
|
-
groups = {};
|
|
2378
|
-
}
|
|
2379
1517
|
|
|
2380
|
-
if (
|
|
2381
|
-
|
|
1518
|
+
if (response === undefined) {
|
|
1519
|
+
return null;
|
|
2382
1520
|
}
|
|
2383
1521
|
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
1522
|
+
return response;
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
async getAllFlagsAndPayloads(distinctId, groups = {}, personProperties = {}, groupProperties = {}) {
|
|
1526
|
+
await this.loadFeatureFlags();
|
|
1527
|
+
const response = {};
|
|
1528
|
+
const payloads = {};
|
|
1529
|
+
let fallbackToDecide = this.featureFlags.length == 0;
|
|
1530
|
+
this.featureFlags.map(async flag => {
|
|
1531
|
+
try {
|
|
1532
|
+
const matchValue = this.computeFlagLocally(flag, distinctId, groups, personProperties, groupProperties);
|
|
1533
|
+
response[flag.key] = matchValue;
|
|
1534
|
+
const matchPayload = await this.computeFeatureFlagPayloadLocally(flag.key, matchValue);
|
|
2387
1535
|
|
|
1536
|
+
if (matchPayload) {
|
|
1537
|
+
payloads[flag.key] = matchPayload;
|
|
1538
|
+
}
|
|
1539
|
+
} catch (e) {
|
|
1540
|
+
if (e instanceof InconclusiveMatchError) ; else if (e instanceof Error) {
|
|
1541
|
+
this.onError?.(new Error(`Error computing flag locally: ${flag.key}: ${e}`));
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
fallbackToDecide = true;
|
|
1545
|
+
}
|
|
1546
|
+
});
|
|
1547
|
+
return {
|
|
1548
|
+
response,
|
|
1549
|
+
payloads,
|
|
1550
|
+
fallbackToDecide
|
|
1551
|
+
};
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
computeFlagLocally(flag, distinctId, groups = {}, personProperties = {}, groupProperties = {}) {
|
|
2388
1555
|
if (flag.ensure_experience_continuity) {
|
|
2389
1556
|
throw new InconclusiveMatchError('Flag has experience continuity enabled');
|
|
2390
1557
|
}
|
|
@@ -2393,15 +1560,15 @@ function () {
|
|
|
2393
1560
|
return false;
|
|
2394
1561
|
}
|
|
2395
1562
|
|
|
2396
|
-
|
|
2397
|
-
|
|
1563
|
+
const flagFilters = flag.filters || {};
|
|
1564
|
+
const aggregation_group_type_index = flagFilters.aggregation_group_type_index;
|
|
2398
1565
|
|
|
2399
1566
|
if (aggregation_group_type_index != undefined) {
|
|
2400
|
-
|
|
1567
|
+
const groupName = this.groupTypeMapping[String(aggregation_group_type_index)];
|
|
2401
1568
|
|
|
2402
1569
|
if (!groupName) {
|
|
2403
1570
|
if (this.debugMode) {
|
|
2404
|
-
console.warn(
|
|
1571
|
+
console.warn(`[FEATURE FLAGS] Unknown group type index ${aggregation_group_type_index} for feature flag ${flag.key}`);
|
|
2405
1572
|
}
|
|
2406
1573
|
|
|
2407
1574
|
throw new InconclusiveMatchError('Flag has unknown group type index');
|
|
@@ -2409,31 +1576,29 @@ function () {
|
|
|
2409
1576
|
|
|
2410
1577
|
if (!(groupName in groups)) {
|
|
2411
1578
|
if (this.debugMode) {
|
|
2412
|
-
console.warn(
|
|
1579
|
+
console.warn(`[FEATURE FLAGS] Can't compute group feature flag: ${flag.key} without group names passed in`);
|
|
2413
1580
|
}
|
|
2414
1581
|
|
|
2415
1582
|
return false;
|
|
2416
1583
|
}
|
|
2417
1584
|
|
|
2418
|
-
|
|
1585
|
+
const focusedGroupProperties = groupProperties[groupName];
|
|
2419
1586
|
return this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties);
|
|
2420
1587
|
} else {
|
|
2421
1588
|
return this.matchFeatureFlagProperties(flag, distinctId, personProperties);
|
|
2422
1589
|
}
|
|
2423
|
-
}
|
|
2424
|
-
|
|
2425
|
-
FeatureFlagsPoller.prototype.matchFeatureFlagProperties = function (flag, distinctId, properties) {
|
|
2426
|
-
var _a;
|
|
1590
|
+
}
|
|
2427
1591
|
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
1592
|
+
matchFeatureFlagProperties(flag, distinctId, properties) {
|
|
1593
|
+
const flagFilters = flag.filters || {};
|
|
1594
|
+
const flagConditions = flagFilters.groups || [];
|
|
1595
|
+
let isInconclusive = false;
|
|
1596
|
+
let result = undefined; // # Stable sort conditions with variant overrides to the top. This ensures that if overrides are present, they are
|
|
2432
1597
|
// # evaluated first, and the variant override is applied to the first matching condition.
|
|
2433
1598
|
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
1599
|
+
const sortedFlagConditions = [...flagConditions].sort((conditionA, conditionB) => {
|
|
1600
|
+
const AHasVariantOverride = !!conditionA.variant;
|
|
1601
|
+
const BHasVariantOverride = !!conditionB.variant;
|
|
2437
1602
|
|
|
2438
1603
|
if (AHasVariantOverride && BHasVariantOverride) {
|
|
2439
1604
|
return 0;
|
|
@@ -2446,21 +1611,19 @@ function () {
|
|
|
2446
1611
|
}
|
|
2447
1612
|
});
|
|
2448
1613
|
|
|
2449
|
-
|
|
1614
|
+
for (const condition of sortedFlagConditions) {
|
|
2450
1615
|
try {
|
|
2451
|
-
if (
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
if (
|
|
2456
|
-
|
|
2457
|
-
})) {
|
|
2458
|
-
result = variantOverride_1;
|
|
1616
|
+
if (this.isConditionMatch(flag, distinctId, condition, properties)) {
|
|
1617
|
+
const variantOverride = condition.variant;
|
|
1618
|
+
const flagVariants = flagFilters.multivariate?.variants || [];
|
|
1619
|
+
|
|
1620
|
+
if (variantOverride && flagVariants.some(variant => variant.key === variantOverride)) {
|
|
1621
|
+
result = variantOverride;
|
|
2459
1622
|
} else {
|
|
2460
|
-
result =
|
|
1623
|
+
result = this.getMatchingVariant(flag, distinctId) || true;
|
|
2461
1624
|
}
|
|
2462
1625
|
|
|
2463
|
-
|
|
1626
|
+
break;
|
|
2464
1627
|
}
|
|
2465
1628
|
} catch (e) {
|
|
2466
1629
|
if (e instanceof InconclusiveMatchError) {
|
|
@@ -2469,16 +1632,6 @@ function () {
|
|
|
2469
1632
|
throw e;
|
|
2470
1633
|
}
|
|
2471
1634
|
}
|
|
2472
|
-
};
|
|
2473
|
-
|
|
2474
|
-
var this_1 = this;
|
|
2475
|
-
|
|
2476
|
-
for (var _i = 0, sortedFlagConditions_1 = sortedFlagConditions; _i < sortedFlagConditions_1.length; _i++) {
|
|
2477
|
-
var condition = sortedFlagConditions_1[_i];
|
|
2478
|
-
|
|
2479
|
-
var state_1 = _loop_1(condition);
|
|
2480
|
-
|
|
2481
|
-
if (state_1 === "break") break;
|
|
2482
1635
|
}
|
|
2483
1636
|
|
|
2484
1637
|
if (result !== undefined) {
|
|
@@ -2489,16 +1642,15 @@ function () {
|
|
|
2489
1642
|
|
|
2490
1643
|
|
|
2491
1644
|
return false;
|
|
2492
|
-
}
|
|
1645
|
+
}
|
|
2493
1646
|
|
|
2494
|
-
|
|
2495
|
-
|
|
1647
|
+
isConditionMatch(flag, distinctId, condition, properties) {
|
|
1648
|
+
const rolloutPercentage = condition.rollout_percentage;
|
|
2496
1649
|
|
|
2497
1650
|
if ((condition.properties || []).length > 0) {
|
|
2498
|
-
for (
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
var matches = false;
|
|
1651
|
+
for (const prop of condition.properties) {
|
|
1652
|
+
const propertyType = prop.type;
|
|
1653
|
+
let matches = false;
|
|
2502
1654
|
|
|
2503
1655
|
if (propertyType === 'cohort') {
|
|
2504
1656
|
matches = matchCohort(prop, properties, this.cohorts);
|
|
@@ -2521,12 +1673,12 @@ function () {
|
|
|
2521
1673
|
}
|
|
2522
1674
|
|
|
2523
1675
|
return true;
|
|
2524
|
-
}
|
|
1676
|
+
}
|
|
2525
1677
|
|
|
2526
|
-
|
|
2527
|
-
|
|
1678
|
+
getMatchingVariant(flag, distinctId) {
|
|
1679
|
+
const hashValue = _hash(flag.key, distinctId, 'variant');
|
|
2528
1680
|
|
|
2529
|
-
|
|
1681
|
+
const matchingVariant = this.variantLookupTable(flag).find(variant => {
|
|
2530
1682
|
return hashValue >= variant.valueMin && hashValue < variant.valueMax;
|
|
2531
1683
|
});
|
|
2532
1684
|
|
|
@@ -2535,238 +1687,133 @@ function () {
|
|
|
2535
1687
|
}
|
|
2536
1688
|
|
|
2537
1689
|
return undefined;
|
|
2538
|
-
}
|
|
2539
|
-
|
|
2540
|
-
FeatureFlagsPoller.prototype.variantLookupTable = function (flag) {
|
|
2541
|
-
var _a;
|
|
1690
|
+
}
|
|
2542
1691
|
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
multivariates.
|
|
1692
|
+
variantLookupTable(flag) {
|
|
1693
|
+
const lookupTable = [];
|
|
1694
|
+
let valueMin = 0;
|
|
1695
|
+
let valueMax = 0;
|
|
1696
|
+
const flagFilters = flag.filters || {};
|
|
1697
|
+
const multivariates = flagFilters.multivariate?.variants || [];
|
|
1698
|
+
multivariates.forEach(variant => {
|
|
2549
1699
|
valueMax = valueMin + variant.rollout_percentage / 100.0;
|
|
2550
1700
|
lookupTable.push({
|
|
2551
|
-
valueMin
|
|
2552
|
-
valueMax
|
|
1701
|
+
valueMin,
|
|
1702
|
+
valueMax,
|
|
2553
1703
|
key: variant.key
|
|
2554
1704
|
});
|
|
2555
1705
|
valueMin = valueMax;
|
|
2556
1706
|
});
|
|
2557
1707
|
return lookupTable;
|
|
2558
|
-
}
|
|
1708
|
+
}
|
|
2559
1709
|
|
|
2560
|
-
|
|
2561
|
-
if (
|
|
2562
|
-
|
|
1710
|
+
async loadFeatureFlags(forceReload = false) {
|
|
1711
|
+
if (!this.loadedSuccessfullyOnce || forceReload) {
|
|
1712
|
+
await this._loadFeatureFlags();
|
|
2563
1713
|
}
|
|
1714
|
+
}
|
|
2564
1715
|
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
/*break*/
|
|
2571
|
-
, 2];
|
|
2572
|
-
return [4
|
|
2573
|
-
/*yield*/
|
|
2574
|
-
, this._loadFeatureFlags()];
|
|
2575
|
-
|
|
2576
|
-
case 1:
|
|
2577
|
-
_a.sent();
|
|
2578
|
-
|
|
2579
|
-
_a.label = 2;
|
|
2580
|
-
|
|
2581
|
-
case 2:
|
|
2582
|
-
return [2
|
|
2583
|
-
/*return*/
|
|
2584
|
-
];
|
|
2585
|
-
}
|
|
2586
|
-
});
|
|
2587
|
-
});
|
|
2588
|
-
};
|
|
1716
|
+
async _loadFeatureFlags() {
|
|
1717
|
+
if (this.poller) {
|
|
1718
|
+
clearTimeout(this.poller);
|
|
1719
|
+
this.poller = undefined;
|
|
1720
|
+
}
|
|
2589
1721
|
|
|
2590
|
-
|
|
2591
|
-
var _a, _b;
|
|
2592
|
-
|
|
2593
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
2594
|
-
var res, responseJson, err_1;
|
|
2595
|
-
|
|
2596
|
-
var _this = this;
|
|
2597
|
-
|
|
2598
|
-
return __generator(this, function (_c) {
|
|
2599
|
-
switch (_c.label) {
|
|
2600
|
-
case 0:
|
|
2601
|
-
if (this.poller) {
|
|
2602
|
-
clearTimeout(this.poller);
|
|
2603
|
-
this.poller = undefined;
|
|
2604
|
-
}
|
|
2605
|
-
|
|
2606
|
-
this.poller = setTimeout(function () {
|
|
2607
|
-
return _this._loadFeatureFlags();
|
|
2608
|
-
}, this.pollingInterval);
|
|
2609
|
-
_c.label = 1;
|
|
2610
|
-
|
|
2611
|
-
case 1:
|
|
2612
|
-
_c.trys.push([1, 4,, 5]);
|
|
2613
|
-
|
|
2614
|
-
return [4
|
|
2615
|
-
/*yield*/
|
|
2616
|
-
, this._requestFeatureFlagDefinitions()];
|
|
2617
|
-
|
|
2618
|
-
case 2:
|
|
2619
|
-
res = _c.sent();
|
|
2620
|
-
|
|
2621
|
-
if (res && res.status === 401) {
|
|
2622
|
-
throw new ClientError("Your personalApiKey is invalid. Are you sure you're not using your Project API key? More information: https://posthog.com/docs/api/overview");
|
|
2623
|
-
}
|
|
2624
|
-
|
|
2625
|
-
if (res && res.status !== 200) {
|
|
2626
|
-
// something else went wrong, or the server is down.
|
|
2627
|
-
// In this case, don't override existing flags
|
|
2628
|
-
return [2
|
|
2629
|
-
/*return*/
|
|
2630
|
-
];
|
|
2631
|
-
}
|
|
2632
|
-
|
|
2633
|
-
return [4
|
|
2634
|
-
/*yield*/
|
|
2635
|
-
, res.json()];
|
|
2636
|
-
|
|
2637
|
-
case 3:
|
|
2638
|
-
responseJson = _c.sent();
|
|
2639
|
-
|
|
2640
|
-
if (!('flags' in responseJson)) {
|
|
2641
|
-
(_a = this.onError) === null || _a === void 0 ? void 0 : _a.call(this, new Error("Invalid response when getting feature flags: ".concat(JSON.stringify(responseJson))));
|
|
2642
|
-
}
|
|
2643
|
-
|
|
2644
|
-
this.featureFlags = responseJson.flags || [];
|
|
2645
|
-
this.featureFlagsByKey = this.featureFlags.reduce(function (acc, curr) {
|
|
2646
|
-
return acc[curr.key] = curr, acc;
|
|
2647
|
-
}, {});
|
|
2648
|
-
this.groupTypeMapping = responseJson.group_type_mapping || {};
|
|
2649
|
-
this.cohorts = responseJson.cohorts || [];
|
|
2650
|
-
this.loadedSuccessfullyOnce = true;
|
|
2651
|
-
return [3
|
|
2652
|
-
/*break*/
|
|
2653
|
-
, 5];
|
|
2654
|
-
|
|
2655
|
-
case 4:
|
|
2656
|
-
err_1 = _c.sent(); // if an error that is not an instance of ClientError is thrown
|
|
2657
|
-
// we silently ignore the error when reloading feature flags
|
|
2658
|
-
|
|
2659
|
-
if (err_1 instanceof ClientError) {
|
|
2660
|
-
(_b = this.onError) === null || _b === void 0 ? void 0 : _b.call(this, err_1);
|
|
2661
|
-
}
|
|
2662
|
-
|
|
2663
|
-
return [3
|
|
2664
|
-
/*break*/
|
|
2665
|
-
, 5];
|
|
2666
|
-
|
|
2667
|
-
case 5:
|
|
2668
|
-
return [2
|
|
2669
|
-
/*return*/
|
|
2670
|
-
];
|
|
2671
|
-
}
|
|
2672
|
-
});
|
|
2673
|
-
});
|
|
2674
|
-
};
|
|
1722
|
+
this.poller = setTimeout(() => this._loadFeatureFlags(), this.pollingInterval);
|
|
2675
1723
|
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
var url, options, abortTimeout, controller_1;
|
|
2679
|
-
return __generator(this, function (_a) {
|
|
2680
|
-
switch (_a.label) {
|
|
2681
|
-
case 0:
|
|
2682
|
-
url = "".concat(this.host, "/api/feature_flag/local_evaluation?token=").concat(this.projectApiKey, "&send_cohorts");
|
|
2683
|
-
options = {
|
|
2684
|
-
method: 'GET',
|
|
2685
|
-
headers: {
|
|
2686
|
-
'Content-Type': 'application/json',
|
|
2687
|
-
Authorization: "Bearer ".concat(this.personalApiKey),
|
|
2688
|
-
'user-agent': "posthog-node/".concat(version)
|
|
2689
|
-
}
|
|
2690
|
-
};
|
|
2691
|
-
abortTimeout = null;
|
|
2692
|
-
|
|
2693
|
-
if (this.timeout && typeof this.timeout === 'number') {
|
|
2694
|
-
controller_1 = new AbortController();
|
|
2695
|
-
abortTimeout = safeSetTimeout(function () {
|
|
2696
|
-
controller_1.abort();
|
|
2697
|
-
}, this.timeout);
|
|
2698
|
-
options.signal = controller_1.signal;
|
|
2699
|
-
}
|
|
2700
|
-
|
|
2701
|
-
_a.label = 1;
|
|
2702
|
-
|
|
2703
|
-
case 1:
|
|
2704
|
-
_a.trys.push([1,, 3, 4]);
|
|
2705
|
-
|
|
2706
|
-
return [4
|
|
2707
|
-
/*yield*/
|
|
2708
|
-
, this.fetch(url, options)];
|
|
2709
|
-
|
|
2710
|
-
case 2:
|
|
2711
|
-
return [2
|
|
2712
|
-
/*return*/
|
|
2713
|
-
, _a.sent()];
|
|
2714
|
-
|
|
2715
|
-
case 3:
|
|
2716
|
-
clearTimeout(abortTimeout);
|
|
2717
|
-
return [7
|
|
2718
|
-
/*endfinally*/
|
|
2719
|
-
];
|
|
2720
|
-
|
|
2721
|
-
case 4:
|
|
2722
|
-
return [2
|
|
2723
|
-
/*return*/
|
|
2724
|
-
];
|
|
2725
|
-
}
|
|
2726
|
-
});
|
|
2727
|
-
});
|
|
2728
|
-
};
|
|
1724
|
+
try {
|
|
1725
|
+
const res = await this._requestFeatureFlagDefinitions();
|
|
2729
1726
|
|
|
2730
|
-
|
|
1727
|
+
if (res && res.status === 401) {
|
|
1728
|
+
throw new ClientError(`Your personalApiKey is invalid. Are you sure you're not using your Project API key? More information: https://posthog.com/docs/api/overview`);
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
if (res && res.status !== 200) {
|
|
1732
|
+
// something else went wrong, or the server is down.
|
|
1733
|
+
// In this case, don't override existing flags
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
const responseJson = await res.json();
|
|
1738
|
+
|
|
1739
|
+
if (!('flags' in responseJson)) {
|
|
1740
|
+
this.onError?.(new Error(`Invalid response when getting feature flags: ${JSON.stringify(responseJson)}`));
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
this.featureFlags = responseJson.flags || [];
|
|
1744
|
+
this.featureFlagsByKey = this.featureFlags.reduce((acc, curr) => (acc[curr.key] = curr, acc), {});
|
|
1745
|
+
this.groupTypeMapping = responseJson.group_type_mapping || {};
|
|
1746
|
+
this.cohorts = responseJson.cohorts || [];
|
|
1747
|
+
this.loadedSuccessfullyOnce = true;
|
|
1748
|
+
} catch (err) {
|
|
1749
|
+
// if an error that is not an instance of ClientError is thrown
|
|
1750
|
+
// we silently ignore the error when reloading feature flags
|
|
1751
|
+
if (err instanceof ClientError) {
|
|
1752
|
+
this.onError?.(err);
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
async _requestFeatureFlagDefinitions() {
|
|
1758
|
+
const url = `${this.host}/api/feature_flag/local_evaluation?token=${this.projectApiKey}&send_cohorts`;
|
|
1759
|
+
const options = {
|
|
1760
|
+
method: 'GET',
|
|
1761
|
+
headers: {
|
|
1762
|
+
'Content-Type': 'application/json',
|
|
1763
|
+
Authorization: `Bearer ${this.personalApiKey}`,
|
|
1764
|
+
'user-agent': `posthog-node/${version}`
|
|
1765
|
+
}
|
|
1766
|
+
};
|
|
1767
|
+
let abortTimeout = null;
|
|
1768
|
+
|
|
1769
|
+
if (this.timeout && typeof this.timeout === 'number') {
|
|
1770
|
+
const controller = new AbortController();
|
|
1771
|
+
abortTimeout = safeSetTimeout(() => {
|
|
1772
|
+
controller.abort();
|
|
1773
|
+
}, this.timeout);
|
|
1774
|
+
options.signal = controller.signal;
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
try {
|
|
1778
|
+
return await this.fetch(url, options);
|
|
1779
|
+
} finally {
|
|
1780
|
+
clearTimeout(abortTimeout);
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
stopPoller() {
|
|
2731
1785
|
clearTimeout(this.poller);
|
|
2732
|
-
}
|
|
1786
|
+
}
|
|
2733
1787
|
|
|
2734
|
-
|
|
2735
|
-
}(); // # This function takes a distinct_id and a feature flag key and returns a float between 0 and 1.
|
|
1788
|
+
} // # This function takes a distinct_id and a feature flag key and returns a float between 0 and 1.
|
|
2736
1789
|
// # Given the same distinct_id and key, it'll always return the same float. These floats are
|
|
2737
1790
|
// # uniformly distributed between 0 and 1, so if we want to show this feature to 20% of traffic
|
|
2738
1791
|
// # we can do _hash(key, distinct_id) < 0.2
|
|
2739
1792
|
|
|
2740
1793
|
|
|
2741
|
-
function _hash(key, distinctId, salt) {
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
}
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
var sha1Hash = rusha.createHash();
|
|
2748
|
-
sha1Hash.update("".concat(key, ".").concat(distinctId).concat(salt));
|
|
1794
|
+
function _hash(key, distinctId, salt = '') {
|
|
1795
|
+
// rusha is a fast sha1 implementation in pure javascript
|
|
1796
|
+
const sha1Hash = rusha.createHash();
|
|
1797
|
+
sha1Hash.update(`${key}.${distinctId}${salt}`);
|
|
2749
1798
|
return parseInt(sha1Hash.digest('hex').slice(0, 15), 16) / LONG_SCALE;
|
|
2750
1799
|
}
|
|
2751
1800
|
|
|
2752
1801
|
function matchProperty(property, propertyValues) {
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
1802
|
+
const key = property.key;
|
|
1803
|
+
const value = property.value;
|
|
1804
|
+
const operator = property.operator || 'exact';
|
|
2756
1805
|
|
|
2757
1806
|
if (!(key in propertyValues)) {
|
|
2758
|
-
throw new InconclusiveMatchError(
|
|
1807
|
+
throw new InconclusiveMatchError(`Property ${key} not found in propertyValues`);
|
|
2759
1808
|
} else if (operator === 'is_not_set') {
|
|
2760
|
-
throw new InconclusiveMatchError(
|
|
1809
|
+
throw new InconclusiveMatchError(`Operator is_not_set is not supported`);
|
|
2761
1810
|
}
|
|
2762
1811
|
|
|
2763
|
-
|
|
1812
|
+
const overrideValue = propertyValues[key];
|
|
2764
1813
|
|
|
2765
1814
|
function computeExactMatch(value, overrideValue) {
|
|
2766
1815
|
if (Array.isArray(value)) {
|
|
2767
|
-
return value.map(
|
|
2768
|
-
return String(val).toLowerCase();
|
|
2769
|
-
}).includes(String(overrideValue).toLowerCase());
|
|
1816
|
+
return value.map(val => String(val).toLowerCase()).includes(String(overrideValue).toLowerCase());
|
|
2770
1817
|
}
|
|
2771
1818
|
|
|
2772
1819
|
return String(value).toLowerCase() === String(overrideValue).toLowerCase();
|
|
@@ -2782,7 +1829,7 @@ function matchProperty(property, propertyValues) {
|
|
|
2782
1829
|
} else if (operator === 'lte') {
|
|
2783
1830
|
return lhs <= rhs;
|
|
2784
1831
|
} else {
|
|
2785
|
-
throw new Error(
|
|
1832
|
+
throw new Error(`Invalid operator: ${operator}`);
|
|
2786
1833
|
}
|
|
2787
1834
|
}
|
|
2788
1835
|
|
|
@@ -2815,7 +1862,7 @@ function matchProperty(property, propertyValues) {
|
|
|
2815
1862
|
{
|
|
2816
1863
|
// :TRICKY: We adjust comparison based on the override value passed in,
|
|
2817
1864
|
// to make sure we handle both numeric and string comparisons appropriately.
|
|
2818
|
-
|
|
1865
|
+
let parsedValue = typeof value === 'number' ? value : null;
|
|
2819
1866
|
|
|
2820
1867
|
if (typeof value === 'string') {
|
|
2821
1868
|
try {
|
|
@@ -2839,17 +1886,17 @@ function matchProperty(property, propertyValues) {
|
|
|
2839
1886
|
case 'is_date_after':
|
|
2840
1887
|
case 'is_date_before':
|
|
2841
1888
|
{
|
|
2842
|
-
|
|
1889
|
+
let parsedDate = relativeDateParseForFeatureFlagMatching(String(value));
|
|
2843
1890
|
|
|
2844
1891
|
if (parsedDate == null) {
|
|
2845
1892
|
parsedDate = convertToDateTime(value);
|
|
2846
1893
|
}
|
|
2847
1894
|
|
|
2848
1895
|
if (parsedDate == null) {
|
|
2849
|
-
throw new InconclusiveMatchError(
|
|
1896
|
+
throw new InconclusiveMatchError(`Invalid date: ${value}`);
|
|
2850
1897
|
}
|
|
2851
1898
|
|
|
2852
|
-
|
|
1899
|
+
const overrideDate = convertToDateTime(overrideValue);
|
|
2853
1900
|
|
|
2854
1901
|
if (['is_date_before'].includes(operator)) {
|
|
2855
1902
|
return overrideDate < parsedDate;
|
|
@@ -2859,18 +1906,18 @@ function matchProperty(property, propertyValues) {
|
|
|
2859
1906
|
}
|
|
2860
1907
|
|
|
2861
1908
|
default:
|
|
2862
|
-
throw new InconclusiveMatchError(
|
|
1909
|
+
throw new InconclusiveMatchError(`Unknown operator: ${operator}`);
|
|
2863
1910
|
}
|
|
2864
1911
|
}
|
|
2865
1912
|
|
|
2866
1913
|
function matchCohort(property, propertyValues, cohortProperties) {
|
|
2867
|
-
|
|
1914
|
+
const cohortId = String(property.value);
|
|
2868
1915
|
|
|
2869
1916
|
if (!(cohortId in cohortProperties)) {
|
|
2870
1917
|
throw new InconclusiveMatchError("can't match cohort without a given cohort property value");
|
|
2871
1918
|
}
|
|
2872
1919
|
|
|
2873
|
-
|
|
1920
|
+
const propertyGroup = cohortProperties[cohortId];
|
|
2874
1921
|
return matchPropertyGroup(propertyGroup, propertyValues, cohortProperties);
|
|
2875
1922
|
}
|
|
2876
1923
|
|
|
@@ -2879,23 +1926,21 @@ function matchPropertyGroup(propertyGroup, propertyValues, cohortProperties) {
|
|
|
2879
1926
|
return true;
|
|
2880
1927
|
}
|
|
2881
1928
|
|
|
2882
|
-
|
|
2883
|
-
|
|
1929
|
+
const propertyGroupType = propertyGroup.type;
|
|
1930
|
+
const properties = propertyGroup.values;
|
|
2884
1931
|
|
|
2885
1932
|
if (!properties || properties.length === 0) {
|
|
2886
1933
|
// empty groups are no-ops, always match
|
|
2887
1934
|
return true;
|
|
2888
1935
|
}
|
|
2889
1936
|
|
|
2890
|
-
|
|
1937
|
+
let errorMatchingLocally = false;
|
|
2891
1938
|
|
|
2892
1939
|
if ('values' in properties[0]) {
|
|
2893
1940
|
// a nested property group
|
|
2894
|
-
for (
|
|
2895
|
-
var prop = _a[_i];
|
|
2896
|
-
|
|
1941
|
+
for (const prop of properties) {
|
|
2897
1942
|
try {
|
|
2898
|
-
|
|
1943
|
+
const matches = matchPropertyGroup(prop, propertyValues, cohortProperties);
|
|
2899
1944
|
|
|
2900
1945
|
if (propertyGroupType === 'AND') {
|
|
2901
1946
|
if (!matches) {
|
|
@@ -2909,7 +1954,7 @@ function matchPropertyGroup(propertyGroup, propertyValues, cohortProperties) {
|
|
|
2909
1954
|
}
|
|
2910
1955
|
} catch (err) {
|
|
2911
1956
|
if (err instanceof InconclusiveMatchError) {
|
|
2912
|
-
console.debug(
|
|
1957
|
+
console.debug(`Failed to compute property ${prop} locally: ${err}`);
|
|
2913
1958
|
errorMatchingLocally = true;
|
|
2914
1959
|
} else {
|
|
2915
1960
|
throw err;
|
|
@@ -2924,11 +1969,9 @@ function matchPropertyGroup(propertyGroup, propertyValues, cohortProperties) {
|
|
|
2924
1969
|
|
|
2925
1970
|
return propertyGroupType === 'AND';
|
|
2926
1971
|
} else {
|
|
2927
|
-
for (
|
|
2928
|
-
var prop = _c[_b];
|
|
2929
|
-
|
|
1972
|
+
for (const prop of properties) {
|
|
2930
1973
|
try {
|
|
2931
|
-
|
|
1974
|
+
let matches;
|
|
2932
1975
|
|
|
2933
1976
|
if (prop.type === 'cohort') {
|
|
2934
1977
|
matches = matchCohort(prop, propertyValues, cohortProperties);
|
|
@@ -2936,7 +1979,7 @@ function matchPropertyGroup(propertyGroup, propertyValues, cohortProperties) {
|
|
|
2936
1979
|
matches = matchProperty(prop, propertyValues);
|
|
2937
1980
|
}
|
|
2938
1981
|
|
|
2939
|
-
|
|
1982
|
+
const negation = prop.negation || false;
|
|
2940
1983
|
|
|
2941
1984
|
if (propertyGroupType === 'AND') {
|
|
2942
1985
|
// if negated property, do the inverse
|
|
@@ -2959,7 +2002,7 @@ function matchPropertyGroup(propertyGroup, propertyValues, cohortProperties) {
|
|
|
2959
2002
|
}
|
|
2960
2003
|
} catch (err) {
|
|
2961
2004
|
if (err instanceof InconclusiveMatchError) {
|
|
2962
|
-
console.debug(
|
|
2005
|
+
console.debug(`Failed to compute property ${prop} locally: ${err}`);
|
|
2963
2006
|
errorMatchingLocally = true;
|
|
2964
2007
|
} else {
|
|
2965
2008
|
throw err;
|
|
@@ -2989,36 +2032,36 @@ function convertToDateTime(value) {
|
|
|
2989
2032
|
if (value instanceof Date) {
|
|
2990
2033
|
return value;
|
|
2991
2034
|
} else if (typeof value === 'string' || typeof value === 'number') {
|
|
2992
|
-
|
|
2035
|
+
const date = new Date(value);
|
|
2993
2036
|
|
|
2994
2037
|
if (!isNaN(date.valueOf())) {
|
|
2995
2038
|
return date;
|
|
2996
2039
|
}
|
|
2997
2040
|
|
|
2998
|
-
throw new InconclusiveMatchError(
|
|
2041
|
+
throw new InconclusiveMatchError(`${value} is in an invalid date format`);
|
|
2999
2042
|
} else {
|
|
3000
|
-
throw new InconclusiveMatchError(
|
|
2043
|
+
throw new InconclusiveMatchError(`The date provided ${value} must be a string, number, or date object`);
|
|
3001
2044
|
}
|
|
3002
2045
|
}
|
|
3003
2046
|
|
|
3004
2047
|
function relativeDateParseForFeatureFlagMatching(value) {
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
2048
|
+
const regex = /^-?(?<number>[0-9]+)(?<interval>[a-z])$/;
|
|
2049
|
+
const match = value.match(regex);
|
|
2050
|
+
const parsedDt = new Date(new Date().toISOString());
|
|
3008
2051
|
|
|
3009
2052
|
if (match) {
|
|
3010
2053
|
if (!match.groups) {
|
|
3011
2054
|
return null;
|
|
3012
2055
|
}
|
|
3013
2056
|
|
|
3014
|
-
|
|
2057
|
+
const number = parseInt(match.groups['number']);
|
|
3015
2058
|
|
|
3016
2059
|
if (number >= 10000) {
|
|
3017
2060
|
// Guard against overflow, disallow numbers greater than 10_000
|
|
3018
2061
|
return null;
|
|
3019
2062
|
}
|
|
3020
2063
|
|
|
3021
|
-
|
|
2064
|
+
const interval = match.groups['interval'];
|
|
3022
2065
|
|
|
3023
2066
|
if (interval == 'h') {
|
|
3024
2067
|
parsedDt.setUTCHours(parsedDt.getUTCHours() - number);
|
|
@@ -3040,561 +2083,388 @@ function relativeDateParseForFeatureFlagMatching(value) {
|
|
|
3040
2083
|
}
|
|
3041
2084
|
}
|
|
3042
2085
|
|
|
3043
|
-
|
|
3044
|
-
|
|
2086
|
+
const THIRTY_SECONDS = 30 * 1000;
|
|
2087
|
+
const MAX_CACHE_SIZE = 50 * 1000; // The actual exported Nodejs API.
|
|
3045
2088
|
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
if (options === void 0) {
|
|
3053
|
-
options = {};
|
|
3054
|
-
}
|
|
3055
|
-
|
|
3056
|
-
var _this = this;
|
|
3057
|
-
|
|
3058
|
-
var _a;
|
|
3059
|
-
|
|
3060
|
-
options.captureMode = (options === null || options === void 0 ? void 0 : options.captureMode) || 'json';
|
|
3061
|
-
_this = _super.call(this, apiKey, options) || this;
|
|
3062
|
-
_this._memoryStorage = new PostHogMemoryStorage();
|
|
3063
|
-
_this.options = options;
|
|
2089
|
+
class PostHog extends PostHogCoreStateless {
|
|
2090
|
+
constructor(apiKey, options = {}) {
|
|
2091
|
+
options.captureMode = options?.captureMode || 'json';
|
|
2092
|
+
super(apiKey, options);
|
|
2093
|
+
this._memoryStorage = new PostHogMemoryStorage();
|
|
2094
|
+
this.options = options;
|
|
3064
2095
|
|
|
3065
2096
|
if (options.personalApiKey) {
|
|
3066
|
-
|
|
2097
|
+
this.featureFlagsPoller = new FeatureFlagsPoller({
|
|
3067
2098
|
pollingInterval: typeof options.featureFlagsPollingInterval === 'number' ? options.featureFlagsPollingInterval : THIRTY_SECONDS,
|
|
3068
2099
|
personalApiKey: options.personalApiKey,
|
|
3069
2100
|
projectApiKey: apiKey,
|
|
3070
|
-
timeout:
|
|
3071
|
-
host:
|
|
2101
|
+
timeout: options.requestTimeout ?? 10000,
|
|
2102
|
+
host: this.host,
|
|
3072
2103
|
fetch: options.fetch,
|
|
3073
|
-
onError:
|
|
3074
|
-
|
|
2104
|
+
onError: err => {
|
|
2105
|
+
this._events.emit('error', err);
|
|
3075
2106
|
}
|
|
3076
2107
|
});
|
|
3077
2108
|
}
|
|
3078
2109
|
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
return _this;
|
|
2110
|
+
this.distinctIdHasSentFlagCalls = {};
|
|
2111
|
+
this.maxCacheSize = options.maxCacheSize || MAX_CACHE_SIZE;
|
|
3082
2112
|
}
|
|
3083
2113
|
|
|
3084
|
-
|
|
2114
|
+
getPersistedProperty(key) {
|
|
3085
2115
|
return this._memoryStorage.getProperty(key);
|
|
3086
|
-
}
|
|
2116
|
+
}
|
|
3087
2117
|
|
|
3088
|
-
|
|
2118
|
+
setPersistedProperty(key, value) {
|
|
3089
2119
|
return this._memoryStorage.setProperty(key, value);
|
|
3090
|
-
}
|
|
2120
|
+
}
|
|
3091
2121
|
|
|
3092
|
-
|
|
2122
|
+
fetch(url, options) {
|
|
3093
2123
|
return this.options.fetch ? this.options.fetch(url, options) : fetch$1(url, options);
|
|
3094
|
-
}
|
|
2124
|
+
}
|
|
3095
2125
|
|
|
3096
|
-
|
|
2126
|
+
getLibraryId() {
|
|
3097
2127
|
return 'posthog-node';
|
|
3098
|
-
}
|
|
2128
|
+
}
|
|
3099
2129
|
|
|
3100
|
-
|
|
2130
|
+
getLibraryVersion() {
|
|
3101
2131
|
return version;
|
|
3102
|
-
}
|
|
2132
|
+
}
|
|
3103
2133
|
|
|
3104
|
-
|
|
3105
|
-
return
|
|
3106
|
-
}
|
|
2134
|
+
getCustomUserAgent() {
|
|
2135
|
+
return `posthog-node/${version}`;
|
|
2136
|
+
}
|
|
3107
2137
|
|
|
3108
|
-
|
|
3109
|
-
return
|
|
3110
|
-
}
|
|
2138
|
+
enable() {
|
|
2139
|
+
return super.optIn();
|
|
2140
|
+
}
|
|
3111
2141
|
|
|
3112
|
-
|
|
3113
|
-
return
|
|
3114
|
-
}
|
|
2142
|
+
disable() {
|
|
2143
|
+
return super.optOut();
|
|
2144
|
+
}
|
|
3115
2145
|
|
|
3116
|
-
|
|
3117
|
-
|
|
2146
|
+
debug(enabled = true) {
|
|
2147
|
+
super.debug(enabled);
|
|
2148
|
+
this.featureFlagsPoller?.debug(enabled);
|
|
2149
|
+
}
|
|
3118
2150
|
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
2151
|
+
capture({
|
|
2152
|
+
distinctId,
|
|
2153
|
+
event,
|
|
2154
|
+
properties,
|
|
2155
|
+
groups,
|
|
2156
|
+
sendFeatureFlags,
|
|
2157
|
+
timestamp,
|
|
2158
|
+
disableGeoip,
|
|
2159
|
+
uuid
|
|
2160
|
+
}) {
|
|
2161
|
+
const _capture = props => {
|
|
2162
|
+
super.captureStateless(distinctId, event, props, {
|
|
2163
|
+
timestamp,
|
|
2164
|
+
disableGeoip,
|
|
2165
|
+
uuid
|
|
2166
|
+
});
|
|
2167
|
+
};
|
|
3122
2168
|
|
|
3123
|
-
|
|
2169
|
+
const _getFlags = (distinctId, groups, disableGeoip) => {
|
|
2170
|
+
return super.getFeatureFlagsStateless(distinctId, groups, undefined, undefined, disableGeoip);
|
|
2171
|
+
}; // :TRICKY: If we flush, or need to shut down, to not lose events we want this promise to resolve before we flush
|
|
3124
2172
|
|
|
3125
|
-
(_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.debug(enabled);
|
|
3126
|
-
};
|
|
3127
2173
|
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
groups = _a.groups,
|
|
3135
|
-
sendFeatureFlags = _a.sendFeatureFlags,
|
|
3136
|
-
timestamp = _a.timestamp,
|
|
3137
|
-
disableGeoip = _a.disableGeoip,
|
|
3138
|
-
uuid = _a.uuid;
|
|
3139
|
-
|
|
3140
|
-
var _capture = function (props) {
|
|
3141
|
-
_super.prototype.captureStateless.call(_this, distinctId, event, props, {
|
|
3142
|
-
timestamp: timestamp,
|
|
3143
|
-
disableGeoip: disableGeoip,
|
|
3144
|
-
uuid: uuid
|
|
3145
|
-
});
|
|
3146
|
-
}; // :TRICKY: If we flush, or need to shut down, to not lose events we want this promise to resolve before we flush
|
|
2174
|
+
const capturePromise = Promise.resolve().then(async () => {
|
|
2175
|
+
if (sendFeatureFlags) {
|
|
2176
|
+
// If we are sending feature flags, we need to make sure we have the latest flags
|
|
2177
|
+
// return await super.getFeatureFlagsStateless(distinctId, groups, undefined, undefined, disableGeoip)
|
|
2178
|
+
return await _getFlags(distinctId, groups, disableGeoip);
|
|
2179
|
+
}
|
|
3147
2180
|
|
|
2181
|
+
if ((this.featureFlagsPoller?.featureFlags?.length || 0) > 0) {
|
|
2182
|
+
// Otherwise we may as well check for the flags locally and include them if there
|
|
2183
|
+
const groupsWithStringValues = {};
|
|
3148
2184
|
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
case 0:
|
|
3158
|
-
if (!sendFeatureFlags) return [3
|
|
3159
|
-
/*break*/
|
|
3160
|
-
, 2];
|
|
3161
|
-
return [4
|
|
3162
|
-
/*yield*/
|
|
3163
|
-
, _super.prototype.getFeatureFlagsStateless.call(this, distinctId, groups, undefined, undefined, disableGeoip)];
|
|
3164
|
-
|
|
3165
|
-
case 1:
|
|
3166
|
-
// If we are sending feature flags, we need to make sure we have the latest flags
|
|
3167
|
-
return [2
|
|
3168
|
-
/*return*/
|
|
3169
|
-
, _e.sent()];
|
|
3170
|
-
|
|
3171
|
-
case 2:
|
|
3172
|
-
if (!((((_d = (_c = this.featureFlagsPoller) === null || _c === void 0 ? void 0 : _c.featureFlags) === null || _d === void 0 ? void 0 : _d.length) || 0) > 0)) return [3
|
|
3173
|
-
/*break*/
|
|
3174
|
-
, 4];
|
|
3175
|
-
groupsWithStringValues = {};
|
|
3176
|
-
|
|
3177
|
-
for (_i = 0, _a = Object.entries(groups || {}); _i < _a.length; _i++) {
|
|
3178
|
-
_b = _a[_i], key = _b[0], value = _b[1];
|
|
3179
|
-
groupsWithStringValues[key] = String(value);
|
|
3180
|
-
}
|
|
3181
|
-
|
|
3182
|
-
return [4
|
|
3183
|
-
/*yield*/
|
|
3184
|
-
, this.getAllFlags(distinctId, {
|
|
3185
|
-
groups: groupsWithStringValues,
|
|
3186
|
-
disableGeoip: disableGeoip,
|
|
3187
|
-
onlyEvaluateLocally: true
|
|
3188
|
-
})];
|
|
3189
|
-
|
|
3190
|
-
case 3:
|
|
3191
|
-
return [2
|
|
3192
|
-
/*return*/
|
|
3193
|
-
, _e.sent()];
|
|
3194
|
-
|
|
3195
|
-
case 4:
|
|
3196
|
-
return [2
|
|
3197
|
-
/*return*/
|
|
3198
|
-
, {}];
|
|
3199
|
-
}
|
|
2185
|
+
for (const [key, value] of Object.entries(groups || {})) {
|
|
2186
|
+
groupsWithStringValues[key] = String(value);
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
return await this.getAllFlags(distinctId, {
|
|
2190
|
+
groups: groupsWithStringValues,
|
|
2191
|
+
disableGeoip,
|
|
2192
|
+
onlyEvaluateLocally: true
|
|
3200
2193
|
});
|
|
3201
|
-
}
|
|
3202
|
-
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
return {};
|
|
2197
|
+
}).then(flags => {
|
|
3203
2198
|
// Derive the relevant flag properties to add
|
|
3204
|
-
|
|
2199
|
+
const additionalProperties = {};
|
|
3205
2200
|
|
|
3206
2201
|
if (flags) {
|
|
3207
|
-
for (
|
|
3208
|
-
|
|
3209
|
-
feature = _b[0],
|
|
3210
|
-
variant = _b[1];
|
|
3211
|
-
additionalProperties["$feature/".concat(feature)] = variant;
|
|
2202
|
+
for (const [feature, variant] of Object.entries(flags)) {
|
|
2203
|
+
additionalProperties[`$feature/${feature}`] = variant;
|
|
3212
2204
|
}
|
|
3213
2205
|
}
|
|
3214
2206
|
|
|
3215
|
-
|
|
3216
|
-
return (flags === null || flags === void 0 ? void 0 : flags[flag]) !== false;
|
|
3217
|
-
});
|
|
2207
|
+
const activeFlags = Object.keys(flags || {}).filter(flag => flags?.[flag] !== false);
|
|
3218
2208
|
|
|
3219
2209
|
if (activeFlags.length > 0) {
|
|
3220
2210
|
additionalProperties['$active_feature_flags'] = activeFlags;
|
|
3221
2211
|
}
|
|
3222
2212
|
|
|
3223
2213
|
return additionalProperties;
|
|
3224
|
-
}).catch(
|
|
2214
|
+
}).catch(() => {
|
|
3225
2215
|
// Something went wrong getting the flag info - we should capture the event anyways
|
|
3226
2216
|
return {};
|
|
3227
|
-
}).then(
|
|
2217
|
+
}).then(additionalProperties => {
|
|
3228
2218
|
// No matter what - capture the event
|
|
3229
|
-
_capture(
|
|
2219
|
+
_capture({ ...additionalProperties,
|
|
2220
|
+
...properties,
|
|
3230
2221
|
$groups: groups
|
|
3231
|
-
})
|
|
2222
|
+
});
|
|
3232
2223
|
});
|
|
3233
2224
|
this.addPendingPromise(capturePromise);
|
|
3234
|
-
}
|
|
3235
|
-
|
|
3236
|
-
PostHog.prototype.identify = function (_a) {
|
|
3237
|
-
var distinctId = _a.distinctId,
|
|
3238
|
-
properties = _a.properties,
|
|
3239
|
-
disableGeoip = _a.disableGeoip; // Catch properties passed as $set and move them to the top level
|
|
3240
|
-
|
|
3241
|
-
var personProperties = (properties === null || properties === void 0 ? void 0 : properties.$set) || properties;
|
|
2225
|
+
}
|
|
3242
2226
|
|
|
3243
|
-
|
|
2227
|
+
identify({
|
|
2228
|
+
distinctId,
|
|
2229
|
+
properties,
|
|
2230
|
+
disableGeoip
|
|
2231
|
+
}) {
|
|
2232
|
+
// Catch properties passed as $set and move them to the top level
|
|
2233
|
+
const personProperties = properties?.$set || properties;
|
|
2234
|
+
super.identifyStateless(distinctId, {
|
|
3244
2235
|
$set: personProperties
|
|
3245
2236
|
}, {
|
|
3246
|
-
disableGeoip
|
|
2237
|
+
disableGeoip
|
|
3247
2238
|
});
|
|
3248
|
-
}
|
|
2239
|
+
}
|
|
3249
2240
|
|
|
3250
|
-
|
|
3251
|
-
|
|
2241
|
+
alias(data) {
|
|
2242
|
+
super.aliasStateless(data.alias, data.distinctId, undefined, {
|
|
3252
2243
|
disableGeoip: data.disableGeoip
|
|
3253
2244
|
});
|
|
3254
|
-
}
|
|
2245
|
+
}
|
|
3255
2246
|
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
onlyEvaluateLocally = false;
|
|
3275
|
-
}
|
|
3276
|
-
|
|
3277
|
-
if (sendFeatureFlagEvents == undefined) {
|
|
3278
|
-
sendFeatureFlagEvents = true;
|
|
3279
|
-
}
|
|
3280
|
-
|
|
3281
|
-
return [4
|
|
3282
|
-
/*yield*/
|
|
3283
|
-
, (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.getFeatureFlag(key, distinctId, groups, personProperties, groupProperties)];
|
|
3284
|
-
|
|
3285
|
-
case 1:
|
|
3286
|
-
response = _e.sent();
|
|
3287
|
-
flagWasLocallyEvaluated = response !== undefined;
|
|
3288
|
-
if (!(!flagWasLocallyEvaluated && !onlyEvaluateLocally)) return [3
|
|
3289
|
-
/*break*/
|
|
3290
|
-
, 3];
|
|
3291
|
-
return [4
|
|
3292
|
-
/*yield*/
|
|
3293
|
-
, _super.prototype.getFeatureFlagStateless.call(this, key, distinctId, groups, personProperties, groupProperties, disableGeoip)];
|
|
3294
|
-
|
|
3295
|
-
case 2:
|
|
3296
|
-
response = _e.sent();
|
|
3297
|
-
_e.label = 3;
|
|
3298
|
-
|
|
3299
|
-
case 3:
|
|
3300
|
-
featureFlagReportedKey = "".concat(key, "_").concat(response);
|
|
3301
|
-
|
|
3302
|
-
if (sendFeatureFlagEvents && (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey))) {
|
|
3303
|
-
if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) {
|
|
3304
|
-
this.distinctIdHasSentFlagCalls = {};
|
|
3305
|
-
}
|
|
3306
|
-
|
|
3307
|
-
if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) {
|
|
3308
|
-
this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
|
|
3309
|
-
} else {
|
|
3310
|
-
this.distinctIdHasSentFlagCalls[distinctId] = [featureFlagReportedKey];
|
|
3311
|
-
}
|
|
3312
|
-
|
|
3313
|
-
this.capture({
|
|
3314
|
-
distinctId: distinctId,
|
|
3315
|
-
event: '$feature_flag_called',
|
|
3316
|
-
properties: (_d = {
|
|
3317
|
-
$feature_flag: key,
|
|
3318
|
-
$feature_flag_response: response,
|
|
3319
|
-
locally_evaluated: flagWasLocallyEvaluated
|
|
3320
|
-
}, _d["$feature/".concat(key)] = response, _d),
|
|
3321
|
-
groups: groups,
|
|
3322
|
-
disableGeoip: disableGeoip
|
|
3323
|
-
});
|
|
3324
|
-
}
|
|
3325
|
-
|
|
3326
|
-
return [2
|
|
3327
|
-
/*return*/
|
|
3328
|
-
, response];
|
|
3329
|
-
}
|
|
3330
|
-
});
|
|
3331
|
-
});
|
|
3332
|
-
};
|
|
2247
|
+
async getFeatureFlag(key, distinctId, options) {
|
|
2248
|
+
const {
|
|
2249
|
+
groups,
|
|
2250
|
+
disableGeoip
|
|
2251
|
+
} = options || {};
|
|
2252
|
+
let {
|
|
2253
|
+
onlyEvaluateLocally,
|
|
2254
|
+
sendFeatureFlagEvents,
|
|
2255
|
+
personProperties,
|
|
2256
|
+
groupProperties
|
|
2257
|
+
} = options || {};
|
|
2258
|
+
const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
|
|
2259
|
+
personProperties = adjustedProperties.allPersonProperties;
|
|
2260
|
+
groupProperties = adjustedProperties.allGroupProperties; // set defaults
|
|
2261
|
+
|
|
2262
|
+
if (onlyEvaluateLocally == undefined) {
|
|
2263
|
+
onlyEvaluateLocally = false;
|
|
2264
|
+
}
|
|
3333
2265
|
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
3338
|
-
var _b, groups, disableGeoip, _c, onlyEvaluateLocally, personProperties, groupProperties, adjustedProperties, response, payloadWasLocallyEvaluated;
|
|
3339
|
-
|
|
3340
|
-
return __generator(this, function (_d) {
|
|
3341
|
-
switch (_d.label) {
|
|
3342
|
-
case 0:
|
|
3343
|
-
_b = options || {}, groups = _b.groups, disableGeoip = _b.disableGeoip;
|
|
3344
|
-
_c = options || {}, onlyEvaluateLocally = _c.onlyEvaluateLocally, _c.sendFeatureFlagEvents, personProperties = _c.personProperties, groupProperties = _c.groupProperties;
|
|
3345
|
-
adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
|
|
3346
|
-
personProperties = adjustedProperties.allPersonProperties;
|
|
3347
|
-
groupProperties = adjustedProperties.allGroupProperties;
|
|
3348
|
-
response = undefined;
|
|
3349
|
-
if (!!matchValue) return [3
|
|
3350
|
-
/*break*/
|
|
3351
|
-
, 2];
|
|
3352
|
-
return [4
|
|
3353
|
-
/*yield*/
|
|
3354
|
-
, this.getFeatureFlag(key, distinctId, __assign(__assign({}, options), {
|
|
3355
|
-
onlyEvaluateLocally: true
|
|
3356
|
-
}))];
|
|
3357
|
-
|
|
3358
|
-
case 1:
|
|
3359
|
-
matchValue = _d.sent();
|
|
3360
|
-
_d.label = 2;
|
|
3361
|
-
|
|
3362
|
-
case 2:
|
|
3363
|
-
if (!matchValue) return [3
|
|
3364
|
-
/*break*/
|
|
3365
|
-
, 4];
|
|
3366
|
-
return [4
|
|
3367
|
-
/*yield*/
|
|
3368
|
-
, (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.computeFeatureFlagPayloadLocally(key, matchValue)];
|
|
3369
|
-
|
|
3370
|
-
case 3:
|
|
3371
|
-
response = _d.sent();
|
|
3372
|
-
_d.label = 4;
|
|
3373
|
-
|
|
3374
|
-
case 4:
|
|
3375
|
-
// set defaults
|
|
3376
|
-
if (onlyEvaluateLocally == undefined) {
|
|
3377
|
-
onlyEvaluateLocally = false;
|
|
3378
|
-
}
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
if (onlyEvaluateLocally == undefined) {
|
|
3382
|
-
onlyEvaluateLocally = false;
|
|
3383
|
-
}
|
|
3384
|
-
|
|
3385
|
-
payloadWasLocallyEvaluated = response !== undefined;
|
|
3386
|
-
if (!(!payloadWasLocallyEvaluated && !onlyEvaluateLocally)) return [3
|
|
3387
|
-
/*break*/
|
|
3388
|
-
, 6];
|
|
3389
|
-
return [4
|
|
3390
|
-
/*yield*/
|
|
3391
|
-
, _super.prototype.getFeatureFlagPayloadStateless.call(this, key, distinctId, groups, personProperties, groupProperties, disableGeoip)];
|
|
3392
|
-
|
|
3393
|
-
case 5:
|
|
3394
|
-
response = _d.sent();
|
|
3395
|
-
_d.label = 6;
|
|
3396
|
-
|
|
3397
|
-
case 6:
|
|
3398
|
-
try {
|
|
3399
|
-
return [2
|
|
3400
|
-
/*return*/
|
|
3401
|
-
, JSON.parse(response)];
|
|
3402
|
-
} catch (_e) {
|
|
3403
|
-
return [2
|
|
3404
|
-
/*return*/
|
|
3405
|
-
, response];
|
|
3406
|
-
}
|
|
3407
|
-
|
|
3408
|
-
return [2
|
|
3409
|
-
/*return*/
|
|
3410
|
-
];
|
|
3411
|
-
}
|
|
3412
|
-
});
|
|
3413
|
-
});
|
|
3414
|
-
};
|
|
2266
|
+
if (sendFeatureFlagEvents == undefined) {
|
|
2267
|
+
sendFeatureFlagEvents = true;
|
|
2268
|
+
}
|
|
3415
2269
|
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
var feat;
|
|
3419
|
-
return __generator(this, function (_a) {
|
|
3420
|
-
switch (_a.label) {
|
|
3421
|
-
case 0:
|
|
3422
|
-
return [4
|
|
3423
|
-
/*yield*/
|
|
3424
|
-
, this.getFeatureFlag(key, distinctId, options)];
|
|
3425
|
-
|
|
3426
|
-
case 1:
|
|
3427
|
-
feat = _a.sent();
|
|
3428
|
-
|
|
3429
|
-
if (feat === undefined) {
|
|
3430
|
-
return [2
|
|
3431
|
-
/*return*/
|
|
3432
|
-
, undefined];
|
|
3433
|
-
}
|
|
3434
|
-
|
|
3435
|
-
return [2
|
|
3436
|
-
/*return*/
|
|
3437
|
-
, !!feat || false];
|
|
3438
|
-
}
|
|
3439
|
-
});
|
|
3440
|
-
});
|
|
3441
|
-
};
|
|
2270
|
+
let response = await this.featureFlagsPoller?.getFeatureFlag(key, distinctId, groups, personProperties, groupProperties);
|
|
2271
|
+
const flagWasLocallyEvaluated = response !== undefined;
|
|
3442
2272
|
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
2273
|
+
if (!flagWasLocallyEvaluated && !onlyEvaluateLocally) {
|
|
2274
|
+
response = await super.getFeatureFlagStateless(key, distinctId, groups, personProperties, groupProperties, disableGeoip);
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
const featureFlagReportedKey = `${key}_${response}`;
|
|
2278
|
+
|
|
2279
|
+
if (sendFeatureFlagEvents && (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey))) {
|
|
2280
|
+
if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) {
|
|
2281
|
+
this.distinctIdHasSentFlagCalls = {};
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) {
|
|
2285
|
+
this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
|
|
2286
|
+
} else {
|
|
2287
|
+
this.distinctIdHasSentFlagCalls[distinctId] = [featureFlagReportedKey];
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
this.capture({
|
|
2291
|
+
distinctId,
|
|
2292
|
+
event: '$feature_flag_called',
|
|
2293
|
+
properties: {
|
|
2294
|
+
$feature_flag: key,
|
|
2295
|
+
$feature_flag_response: response,
|
|
2296
|
+
locally_evaluated: flagWasLocallyEvaluated,
|
|
2297
|
+
[`$feature/${key}`]: response
|
|
2298
|
+
},
|
|
2299
|
+
groups,
|
|
2300
|
+
disableGeoip
|
|
3459
2301
|
});
|
|
3460
|
-
}
|
|
3461
|
-
};
|
|
2302
|
+
}
|
|
3462
2303
|
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
case 1:
|
|
3487
|
-
localEvaluationResult = _d.sent();
|
|
3488
|
-
featureFlags = {};
|
|
3489
|
-
featureFlagPayloads = {};
|
|
3490
|
-
fallbackToDecide = true;
|
|
3491
|
-
|
|
3492
|
-
if (localEvaluationResult) {
|
|
3493
|
-
featureFlags = localEvaluationResult.response;
|
|
3494
|
-
featureFlagPayloads = localEvaluationResult.payloads;
|
|
3495
|
-
fallbackToDecide = localEvaluationResult.fallbackToDecide;
|
|
3496
|
-
}
|
|
3497
|
-
|
|
3498
|
-
if (!(fallbackToDecide && !onlyEvaluateLocally)) return [3
|
|
3499
|
-
/*break*/
|
|
3500
|
-
, 3];
|
|
3501
|
-
return [4
|
|
3502
|
-
/*yield*/
|
|
3503
|
-
, _super.prototype.getFeatureFlagsAndPayloadsStateless.call(this, distinctId, groups, personProperties, groupProperties, disableGeoip)];
|
|
3504
|
-
|
|
3505
|
-
case 2:
|
|
3506
|
-
remoteEvaluationResult = _d.sent();
|
|
3507
|
-
featureFlags = __assign(__assign({}, featureFlags), remoteEvaluationResult.flags || {});
|
|
3508
|
-
featureFlagPayloads = __assign(__assign({}, featureFlagPayloads), remoteEvaluationResult.payloads || {});
|
|
3509
|
-
_d.label = 3;
|
|
3510
|
-
|
|
3511
|
-
case 3:
|
|
3512
|
-
return [2
|
|
3513
|
-
/*return*/
|
|
3514
|
-
, {
|
|
3515
|
-
featureFlags: featureFlags,
|
|
3516
|
-
featureFlagPayloads: featureFlagPayloads
|
|
3517
|
-
}];
|
|
3518
|
-
}
|
|
2304
|
+
return response;
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
async getFeatureFlagPayload(key, distinctId, matchValue, options) {
|
|
2308
|
+
const {
|
|
2309
|
+
groups,
|
|
2310
|
+
disableGeoip
|
|
2311
|
+
} = options || {};
|
|
2312
|
+
let {
|
|
2313
|
+
onlyEvaluateLocally,
|
|
2314
|
+
sendFeatureFlagEvents,
|
|
2315
|
+
personProperties,
|
|
2316
|
+
groupProperties
|
|
2317
|
+
} = options || {};
|
|
2318
|
+
const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
|
|
2319
|
+
personProperties = adjustedProperties.allPersonProperties;
|
|
2320
|
+
groupProperties = adjustedProperties.allGroupProperties;
|
|
2321
|
+
let response = undefined; // Try to get match value locally if not provided
|
|
2322
|
+
|
|
2323
|
+
if (!matchValue) {
|
|
2324
|
+
matchValue = await this.getFeatureFlag(key, distinctId, { ...options,
|
|
2325
|
+
onlyEvaluateLocally: true
|
|
3519
2326
|
});
|
|
3520
|
-
}
|
|
3521
|
-
};
|
|
2327
|
+
}
|
|
3522
2328
|
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
properties = _a.properties,
|
|
3527
|
-
distinctId = _a.distinctId,
|
|
3528
|
-
disableGeoip = _a.disableGeoip;
|
|
2329
|
+
if (matchValue) {
|
|
2330
|
+
response = await this.featureFlagsPoller?.computeFeatureFlagPayloadLocally(key, matchValue);
|
|
2331
|
+
} // set defaults
|
|
3529
2332
|
|
|
3530
|
-
_super.prototype.groupIdentifyStateless.call(this, groupType, groupKey, properties, {
|
|
3531
|
-
disableGeoip: disableGeoip
|
|
3532
|
-
}, distinctId);
|
|
3533
|
-
};
|
|
3534
2333
|
|
|
3535
|
-
|
|
3536
|
-
|
|
2334
|
+
if (onlyEvaluateLocally == undefined) {
|
|
2335
|
+
onlyEvaluateLocally = false;
|
|
2336
|
+
}
|
|
3537
2337
|
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
case 0:
|
|
3542
|
-
return [4
|
|
3543
|
-
/*yield*/
|
|
3544
|
-
, (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.loadFeatureFlags(true)];
|
|
2338
|
+
if (sendFeatureFlagEvents == undefined) {
|
|
2339
|
+
sendFeatureFlagEvents = true;
|
|
2340
|
+
} // set defaults
|
|
3545
2341
|
|
|
3546
|
-
case 1:
|
|
3547
|
-
_b.sent();
|
|
3548
2342
|
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
}
|
|
3553
|
-
});
|
|
3554
|
-
});
|
|
3555
|
-
};
|
|
2343
|
+
if (onlyEvaluateLocally == undefined) {
|
|
2344
|
+
onlyEvaluateLocally = false;
|
|
2345
|
+
}
|
|
3556
2346
|
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
2347
|
+
const payloadWasLocallyEvaluated = response !== undefined;
|
|
2348
|
+
|
|
2349
|
+
if (!payloadWasLocallyEvaluated && !onlyEvaluateLocally) {
|
|
2350
|
+
response = await super.getFeatureFlagPayloadStateless(key, distinctId, groups, personProperties, groupProperties, disableGeoip);
|
|
2351
|
+
}
|
|
3560
2352
|
|
|
3561
|
-
|
|
3562
|
-
|
|
2353
|
+
try {
|
|
2354
|
+
return JSON.parse(response);
|
|
2355
|
+
} catch {
|
|
2356
|
+
return response;
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
3563
2359
|
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
}
|
|
2360
|
+
async isFeatureEnabled(key, distinctId, options) {
|
|
2361
|
+
const feat = await this.getFeatureFlag(key, distinctId, options);
|
|
2362
|
+
|
|
2363
|
+
if (feat === undefined) {
|
|
2364
|
+
return undefined;
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
return !!feat || false;
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
async getAllFlags(distinctId, options) {
|
|
2371
|
+
const response = await this.getAllFlagsAndPayloads(distinctId, options);
|
|
2372
|
+
return response.featureFlags;
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
async getAllFlagsAndPayloads(distinctId, options) {
|
|
2376
|
+
const {
|
|
2377
|
+
groups,
|
|
2378
|
+
disableGeoip
|
|
2379
|
+
} = options || {};
|
|
2380
|
+
let {
|
|
2381
|
+
onlyEvaluateLocally,
|
|
2382
|
+
personProperties,
|
|
2383
|
+
groupProperties
|
|
2384
|
+
} = options || {};
|
|
2385
|
+
const adjustedProperties = this.addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties);
|
|
2386
|
+
personProperties = adjustedProperties.allPersonProperties;
|
|
2387
|
+
groupProperties = adjustedProperties.allGroupProperties; // set defaults
|
|
2388
|
+
|
|
2389
|
+
if (onlyEvaluateLocally == undefined) {
|
|
2390
|
+
onlyEvaluateLocally = false;
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
const localEvaluationResult = await this.featureFlagsPoller?.getAllFlagsAndPayloads(distinctId, groups, personProperties, groupProperties);
|
|
2394
|
+
let featureFlags = {};
|
|
2395
|
+
let featureFlagPayloads = {};
|
|
2396
|
+
let fallbackToDecide = true;
|
|
2397
|
+
|
|
2398
|
+
if (localEvaluationResult) {
|
|
2399
|
+
featureFlags = localEvaluationResult.response;
|
|
2400
|
+
featureFlagPayloads = localEvaluationResult.payloads;
|
|
2401
|
+
fallbackToDecide = localEvaluationResult.fallbackToDecide;
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
if (fallbackToDecide && !onlyEvaluateLocally) {
|
|
2405
|
+
const remoteEvaluationResult = await super.getFeatureFlagsAndPayloadsStateless(distinctId, groups, personProperties, groupProperties, disableGeoip);
|
|
2406
|
+
featureFlags = { ...featureFlags,
|
|
2407
|
+
...(remoteEvaluationResult.flags || {})
|
|
2408
|
+
};
|
|
2409
|
+
featureFlagPayloads = { ...featureFlagPayloads,
|
|
2410
|
+
...(remoteEvaluationResult.payloads || {})
|
|
2411
|
+
};
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
return {
|
|
2415
|
+
featureFlags,
|
|
2416
|
+
featureFlagPayloads
|
|
2417
|
+
};
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
groupIdentify({
|
|
2421
|
+
groupType,
|
|
2422
|
+
groupKey,
|
|
2423
|
+
properties,
|
|
2424
|
+
distinctId,
|
|
2425
|
+
disableGeoip
|
|
2426
|
+
}) {
|
|
2427
|
+
super.groupIdentifyStateless(groupType, groupKey, properties, {
|
|
2428
|
+
disableGeoip
|
|
2429
|
+
}, distinctId);
|
|
2430
|
+
}
|
|
3573
2431
|
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
2432
|
+
async reloadFeatureFlags() {
|
|
2433
|
+
await this.featureFlagsPoller?.loadFeatureFlags(true);
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
shutdown(shutdownTimeoutMs) {
|
|
2437
|
+
void this.shutdownAsync(shutdownTimeoutMs);
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
async shutdownAsync(shutdownTimeoutMs) {
|
|
2441
|
+
this.featureFlagsPoller?.stopPoller();
|
|
2442
|
+
return super.shutdownAsync(shutdownTimeoutMs);
|
|
2443
|
+
}
|
|
3578
2444
|
|
|
3579
|
-
|
|
2445
|
+
addLocalPersonAndGroupProperties(distinctId, groups, personProperties, groupProperties) {
|
|
2446
|
+
const allPersonProperties = {
|
|
2447
|
+
distinct_id: distinctId,
|
|
2448
|
+
...(personProperties || {})
|
|
2449
|
+
};
|
|
2450
|
+
const allGroupProperties = {};
|
|
3580
2451
|
|
|
3581
2452
|
if (groups) {
|
|
3582
|
-
for (
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
}
|
|
2453
|
+
for (const groupName of Object.keys(groups)) {
|
|
2454
|
+
allGroupProperties[groupName] = {
|
|
2455
|
+
$group_key: groups[groupName],
|
|
2456
|
+
...(groupProperties?.[groupName] || {})
|
|
2457
|
+
};
|
|
3587
2458
|
}
|
|
3588
2459
|
}
|
|
3589
2460
|
|
|
3590
2461
|
return {
|
|
3591
|
-
allPersonProperties
|
|
3592
|
-
allGroupProperties
|
|
2462
|
+
allPersonProperties,
|
|
2463
|
+
allGroupProperties
|
|
3593
2464
|
};
|
|
3594
|
-
}
|
|
2465
|
+
}
|
|
3595
2466
|
|
|
3596
|
-
|
|
3597
|
-
}(PostHogCoreStateless);
|
|
2467
|
+
}
|
|
3598
2468
|
|
|
3599
2469
|
/**
|
|
3600
2470
|
* Integrate Sentry with PostHog. This will add a direct link to the person in Sentry, and an $exception event in PostHog.
|
|
@@ -3615,27 +2485,19 @@ function (_super) {
|
|
|
3615
2485
|
* @param {Number} [projectId] Optional: The Sentry project id, used to send a direct link from PostHog to Sentry
|
|
3616
2486
|
* @param {string} [prefix] Optional: Url of a self-hosted sentry instance (default: https://sentry.io/organizations/)
|
|
3617
2487
|
*/
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
function () {
|
|
3621
|
-
function PostHogSentryIntegration(posthog, posthogHost, organization, prefix) {
|
|
3622
|
-
var _a;
|
|
3623
|
-
|
|
2488
|
+
class PostHogSentryIntegration {
|
|
2489
|
+
constructor(posthog, posthogHost, organization, prefix) {
|
|
3624
2490
|
this.posthog = posthog;
|
|
3625
2491
|
this.posthogHost = posthogHost;
|
|
3626
2492
|
this.organization = organization;
|
|
3627
2493
|
this.prefix = prefix;
|
|
3628
2494
|
this.name = 'posthog-node';
|
|
3629
|
-
this.posthogHost =
|
|
2495
|
+
this.posthogHost = posthog.options.host ?? 'https://app.posthog.com';
|
|
3630
2496
|
}
|
|
3631
2497
|
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
addGlobalEventProcessor(function (event) {
|
|
3636
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
3637
|
-
|
|
3638
|
-
if (((_a = event.exception) === null || _a === void 0 ? void 0 : _a.values) === undefined || event.exception.values.length === 0) {
|
|
2498
|
+
setupOnce(addGlobalEventProcessor, getCurrentHub) {
|
|
2499
|
+
addGlobalEventProcessor(event => {
|
|
2500
|
+
if (event.exception?.values === undefined || event.exception.values.length === 0) {
|
|
3639
2501
|
return event;
|
|
3640
2502
|
}
|
|
3641
2503
|
|
|
@@ -3643,47 +2505,45 @@ function () {
|
|
|
3643
2505
|
event.tags = {};
|
|
3644
2506
|
}
|
|
3645
2507
|
|
|
3646
|
-
|
|
2508
|
+
const sentry = getCurrentHub(); // Get the PostHog user ID from a specific tag, which users can set on their Sentry scope as they need.
|
|
3647
2509
|
|
|
3648
|
-
|
|
2510
|
+
const userId = event.tags[PostHogSentryIntegration.POSTHOG_ID_TAG];
|
|
3649
2511
|
|
|
3650
2512
|
if (userId === undefined) {
|
|
3651
2513
|
// If we can't find a user ID, don't bother linking the event. We won't be able to send anything meaningful to PostHog without it.
|
|
3652
2514
|
return event;
|
|
3653
2515
|
}
|
|
3654
2516
|
|
|
3655
|
-
event.tags['PostHog Person URL'] = new URL(
|
|
3656
|
-
|
|
2517
|
+
event.tags['PostHog Person URL'] = new URL(`/person/${userId}`, this.posthogHost).toString();
|
|
2518
|
+
const properties = {
|
|
3657
2519
|
// PostHog Exception Properties
|
|
3658
|
-
$exception_message:
|
|
3659
|
-
$exception_type:
|
|
2520
|
+
$exception_message: event.exception.values[0]?.value,
|
|
2521
|
+
$exception_type: event.exception.values[0]?.type,
|
|
3660
2522
|
$exception_personURL: event.tags['PostHog Person URL'],
|
|
3661
2523
|
// Sentry Exception Properties
|
|
3662
2524
|
$sentry_event_id: event.event_id,
|
|
3663
2525
|
$sentry_exception: event.exception,
|
|
3664
|
-
$sentry_exception_message:
|
|
3665
|
-
$sentry_exception_type:
|
|
2526
|
+
$sentry_exception_message: event.exception.values[0]?.value,
|
|
2527
|
+
$sentry_exception_type: event.exception.values[0]?.type,
|
|
3666
2528
|
$sentry_tags: event.tags
|
|
3667
2529
|
};
|
|
3668
|
-
|
|
2530
|
+
const projectId = sentry.getClient()?.getDsn()?.projectId;
|
|
3669
2531
|
|
|
3670
|
-
if (
|
|
3671
|
-
properties.$sentry_url =
|
|
2532
|
+
if (this.organization !== undefined && projectId !== undefined && event.event_id !== undefined) {
|
|
2533
|
+
properties.$sentry_url = `${this.prefix ?? 'https://sentry.io/organizations'}/${this.organization}/issues/?project=${projectId}&query=${event.event_id}`;
|
|
3672
2534
|
}
|
|
3673
2535
|
|
|
3674
|
-
|
|
2536
|
+
this.posthog.capture({
|
|
3675
2537
|
event: '$exception',
|
|
3676
2538
|
distinctId: userId,
|
|
3677
|
-
properties
|
|
2539
|
+
properties
|
|
3678
2540
|
});
|
|
3679
|
-
|
|
3680
2541
|
return event;
|
|
3681
2542
|
});
|
|
3682
|
-
}
|
|
2543
|
+
}
|
|
3683
2544
|
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
}();
|
|
2545
|
+
}
|
|
2546
|
+
PostHogSentryIntegration.POSTHOG_ID_TAG = 'posthog_distinct_id';
|
|
3687
2547
|
|
|
3688
2548
|
exports.PostHog = PostHog;
|
|
3689
2549
|
exports.PostHogSentryIntegration = PostHogSentryIntegration;
|