posthog-node 2.0.0-alpha9 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +0 -2
- package/index.ts +0 -3
- package/lib/index.cjs.js +950 -91
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +87 -11
- package/lib/index.esm.js +949 -89
- package/lib/index.esm.js.map +1 -1
- package/lib/posthog-core/src/index.d.ts +19 -6
- package/lib/posthog-core/src/types.d.ts +6 -2
- package/lib/posthog-node/index.d.ts +0 -2
- package/lib/posthog-node/src/feature-flags.d.ts +50 -0
- package/lib/posthog-node/src/fetch.d.ts +2 -0
- package/lib/posthog-node/src/posthog-node.d.ts +32 -5
- package/lib/posthog-node/src/types.d.ts +69 -6
- package/package.json +4 -7
- package/src/feature-flags.ts +412 -0
- package/src/fetch.ts +20 -0
- package/src/posthog-node.ts +190 -32
- package/src/types.ts +72 -8
- package/test/feature-flags.spec.ts +3190 -0
- package/test/posthog-node.spec.ts +317 -40
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
import axios from 'axios';
|
|
2
3
|
|
|
3
4
|
/******************************************************************************
|
|
4
5
|
Copyright (c) Microsoft Corporation.
|
|
@@ -42,6 +43,18 @@ var __assign = function () {
|
|
|
42
43
|
};
|
|
43
44
|
return __assign.apply(this, arguments);
|
|
44
45
|
};
|
|
46
|
+
function __rest(s, e) {
|
|
47
|
+
var t = {};
|
|
48
|
+
for (var p in s)
|
|
49
|
+
if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
50
|
+
t[p] = s[p];
|
|
51
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
52
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
53
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
54
|
+
t[p[i]] = s[p[i]];
|
|
55
|
+
}
|
|
56
|
+
return t;
|
|
57
|
+
}
|
|
45
58
|
function __awaiter(thisArg, _arguments, P, generator) {
|
|
46
59
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
47
60
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -129,9 +142,20 @@ function __generator(thisArg, body) {
|
|
|
129
142
|
throw op[1];
|
|
130
143
|
return { value: op[0] ? op[1] : void 0, done: true };
|
|
131
144
|
}
|
|
145
|
+
}
|
|
146
|
+
function __spreadArray(to, from, pack) {
|
|
147
|
+
if (pack || arguments.length === 2)
|
|
148
|
+
for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
149
|
+
if (ar || !(i in from)) {
|
|
150
|
+
if (!ar)
|
|
151
|
+
ar = Array.prototype.slice.call(from, 0, i);
|
|
152
|
+
ar[i] = from[i];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
132
156
|
}
|
|
133
157
|
|
|
134
|
-
var version = "2.
|
|
158
|
+
var version = "2.1.0";
|
|
135
159
|
|
|
136
160
|
var PostHogPersistedProperty;
|
|
137
161
|
(function (PostHogPersistedProperty) {
|
|
@@ -144,6 +168,8 @@ var PostHogPersistedProperty;
|
|
|
144
168
|
PostHogPersistedProperty["OptedOut"] = "opted_out";
|
|
145
169
|
PostHogPersistedProperty["SessionId"] = "session_id";
|
|
146
170
|
PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
|
|
171
|
+
PostHogPersistedProperty["PersonProperties"] = "person_properties";
|
|
172
|
+
PostHogPersistedProperty["GroupProperties"] = "group_properties";
|
|
147
173
|
})(PostHogPersistedProperty || (PostHogPersistedProperty = {}));
|
|
148
174
|
|
|
149
175
|
function assert(truthyValue, message) {
|
|
@@ -717,12 +743,14 @@ var PostHogCore = /** @class */ (function () {
|
|
|
717
743
|
}
|
|
718
744
|
PostHogCore.prototype.getCommonEventProperties = function () {
|
|
719
745
|
var featureFlags = this.getFeatureFlags();
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
746
|
+
var featureVariantProperties = {};
|
|
747
|
+
if (featureFlags) {
|
|
748
|
+
for (var _i = 0, _a = Object.entries(featureFlags); _i < _a.length; _i++) {
|
|
749
|
+
var _b = _a[_i], feature = _b[0], variant = _b[1];
|
|
750
|
+
featureVariantProperties["$feature/".concat(feature)] = variant;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
return __assign({ $lib: this.getLibraryId(), $lib_version: this.getLibraryVersion(), $active_feature_flags: featureFlags ? Object.keys(featureFlags) : undefined }, featureVariantProperties);
|
|
726
754
|
};
|
|
727
755
|
Object.defineProperty(PostHogCore.prototype, "props", {
|
|
728
756
|
// NOTE: Props are lazy loaded from localstorage hence the complex getter setter logic
|
|
@@ -738,6 +766,9 @@ var PostHogCore = /** @class */ (function () {
|
|
|
738
766
|
enumerable: false,
|
|
739
767
|
configurable: true
|
|
740
768
|
});
|
|
769
|
+
PostHogCore.prototype.clearProps = function () {
|
|
770
|
+
this.props = undefined;
|
|
771
|
+
};
|
|
741
772
|
Object.defineProperty(PostHogCore.prototype, "optedOut", {
|
|
742
773
|
get: function () {
|
|
743
774
|
var _a, _b;
|
|
@@ -755,9 +786,15 @@ var PostHogCore = /** @class */ (function () {
|
|
|
755
786
|
PostHogCore.prototype.on = function (event, cb) {
|
|
756
787
|
return this._events.on(event, cb);
|
|
757
788
|
};
|
|
758
|
-
PostHogCore.prototype.reset = function () {
|
|
759
|
-
|
|
760
|
-
|
|
789
|
+
PostHogCore.prototype.reset = function (propertiesToKeep) {
|
|
790
|
+
var allPropertiesToKeep = __spreadArray([PostHogPersistedProperty.Queue], (propertiesToKeep || []), true);
|
|
791
|
+
// clean up props
|
|
792
|
+
this.clearProps();
|
|
793
|
+
for (var _i = 0, _a = Object.keys(PostHogPersistedProperty); _i < _a.length; _i++) {
|
|
794
|
+
var key = _a[_i];
|
|
795
|
+
if (!allPropertiesToKeep.includes(PostHogPersistedProperty[key])) {
|
|
796
|
+
this.setPersistedProperty(PostHogPersistedProperty[key], null);
|
|
797
|
+
}
|
|
761
798
|
}
|
|
762
799
|
};
|
|
763
800
|
PostHogCore.prototype.debug = function (enabled) {
|
|
@@ -832,12 +869,18 @@ var PostHogCore = /** @class */ (function () {
|
|
|
832
869
|
this.enqueue('identify', payload);
|
|
833
870
|
return this;
|
|
834
871
|
};
|
|
835
|
-
PostHogCore.prototype.capture = function (event, properties) {
|
|
872
|
+
PostHogCore.prototype.capture = function (event, properties, forceSendFeatureFlags) {
|
|
873
|
+
if (forceSendFeatureFlags === void 0) { forceSendFeatureFlags = false; }
|
|
836
874
|
if (properties === null || properties === void 0 ? void 0 : properties.$groups) {
|
|
837
875
|
this.groups(properties.$groups);
|
|
838
876
|
}
|
|
839
|
-
|
|
840
|
-
|
|
877
|
+
if (forceSendFeatureFlags) {
|
|
878
|
+
this._sendFeatureFlags(event, properties);
|
|
879
|
+
}
|
|
880
|
+
else {
|
|
881
|
+
var payload = this.buildPayload({ event: event, properties: properties });
|
|
882
|
+
this.enqueue('capture', payload);
|
|
883
|
+
}
|
|
841
884
|
return this;
|
|
842
885
|
};
|
|
843
886
|
PostHogCore.prototype.alias = function (alias) {
|
|
@@ -867,7 +910,6 @@ var PostHogCore = /** @class */ (function () {
|
|
|
867
910
|
PostHogCore.prototype.groups = function (groups) {
|
|
868
911
|
// Get persisted groups
|
|
869
912
|
var existingGroups = this.props.$groups || {};
|
|
870
|
-
// NOTE: Should we do the same for groups listed in identify / capture?
|
|
871
913
|
this.register({
|
|
872
914
|
$groups: __assign(__assign({}, existingGroups), groups),
|
|
873
915
|
});
|
|
@@ -895,31 +937,58 @@ var PostHogCore = /** @class */ (function () {
|
|
|
895
937
|
this.enqueue('capture', payload);
|
|
896
938
|
return this;
|
|
897
939
|
};
|
|
940
|
+
/***
|
|
941
|
+
* PROPERTIES
|
|
942
|
+
***/
|
|
943
|
+
PostHogCore.prototype.personProperties = function (properties) {
|
|
944
|
+
// Get persisted person properties
|
|
945
|
+
var existingProperties = this.getPersistedProperty(PostHogPersistedProperty.PersonProperties) || {};
|
|
946
|
+
this.setPersistedProperty(PostHogPersistedProperty.PersonProperties, __assign(__assign({}, existingProperties), properties));
|
|
947
|
+
return this;
|
|
948
|
+
};
|
|
949
|
+
PostHogCore.prototype.groupProperties = function (properties) {
|
|
950
|
+
// Get persisted group properties
|
|
951
|
+
var existingProperties = this.getPersistedProperty(PostHogPersistedProperty.GroupProperties) || {};
|
|
952
|
+
if (Object.keys(existingProperties).length !== 0) {
|
|
953
|
+
Object.keys(existingProperties).forEach(function (groupType) {
|
|
954
|
+
existingProperties[groupType] = __assign(__assign({}, existingProperties[groupType]), properties[groupType]);
|
|
955
|
+
delete properties[groupType];
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
this.setPersistedProperty(PostHogPersistedProperty.GroupProperties, __assign(__assign({}, existingProperties), properties));
|
|
959
|
+
return this;
|
|
960
|
+
};
|
|
898
961
|
/***
|
|
899
962
|
*** FEATURE FLAGS
|
|
900
963
|
***/
|
|
901
|
-
PostHogCore.prototype.decideAsync = function () {
|
|
964
|
+
PostHogCore.prototype.decideAsync = function (sendAnonDistinctId) {
|
|
965
|
+
if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
|
|
902
966
|
if (this._decideResponsePromise) {
|
|
903
967
|
return this._decideResponsePromise;
|
|
904
968
|
}
|
|
905
|
-
return this._decideAsync();
|
|
969
|
+
return this._decideAsync(sendAnonDistinctId);
|
|
906
970
|
};
|
|
907
|
-
PostHogCore.prototype._decideAsync = function () {
|
|
971
|
+
PostHogCore.prototype._decideAsync = function (sendAnonDistinctId) {
|
|
972
|
+
if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
|
|
908
973
|
return __awaiter(this, void 0, void 0, function () {
|
|
909
|
-
var url, distinctId, groups, fetchOptions;
|
|
974
|
+
var url, distinctId, groups, personProperties, groupProperties, fetchOptions;
|
|
910
975
|
var _this = this;
|
|
911
976
|
return __generator(this, function (_a) {
|
|
912
977
|
url = "".concat(this.host, "/decide/?v=2");
|
|
913
978
|
distinctId = this.getDistinctId();
|
|
914
979
|
groups = this.props.$groups || {};
|
|
980
|
+
personProperties = this.getPersistedProperty(PostHogPersistedProperty.PersonProperties) || {};
|
|
981
|
+
groupProperties = this.getPersistedProperty(PostHogPersistedProperty.GroupProperties) || {};
|
|
915
982
|
fetchOptions = {
|
|
916
983
|
method: 'POST',
|
|
917
984
|
headers: { 'Content-Type': 'application/json' },
|
|
918
985
|
body: JSON.stringify({
|
|
919
986
|
token: this.apiKey,
|
|
920
987
|
distinct_id: distinctId,
|
|
921
|
-
$anon_distinct_id: this.getAnonymousId(),
|
|
988
|
+
$anon_distinct_id: sendAnonDistinctId ? this.getAnonymousId() : undefined,
|
|
922
989
|
groups: groups,
|
|
990
|
+
person_properties: personProperties,
|
|
991
|
+
group_properties: groupProperties,
|
|
923
992
|
}),
|
|
924
993
|
};
|
|
925
994
|
this._decideResponsePromise = this.fetchWithRetry(url, fetchOptions)
|
|
@@ -938,23 +1007,26 @@ var PostHogCore = /** @class */ (function () {
|
|
|
938
1007
|
});
|
|
939
1008
|
});
|
|
940
1009
|
};
|
|
941
|
-
PostHogCore.prototype.getFeatureFlag = function (key
|
|
942
|
-
var _a;
|
|
943
|
-
if (defaultResult === void 0) { defaultResult = false; }
|
|
1010
|
+
PostHogCore.prototype.getFeatureFlag = function (key) {
|
|
944
1011
|
var featureFlags = this.getFeatureFlags();
|
|
945
1012
|
if (!featureFlags) {
|
|
946
|
-
// If we haven't loaded flags yet we respond undefined
|
|
1013
|
+
// If we haven't loaded flags yet, or errored out, we respond with undefined
|
|
947
1014
|
return undefined;
|
|
948
1015
|
}
|
|
1016
|
+
var response = featureFlags[key];
|
|
1017
|
+
if (response === undefined) {
|
|
1018
|
+
// `/decide` returns nothing for flags which are false.
|
|
1019
|
+
response = false;
|
|
1020
|
+
}
|
|
949
1021
|
if (this.sendFeatureFlagEvent && !this.flagCallReported[key]) {
|
|
950
1022
|
this.flagCallReported[key] = true;
|
|
951
1023
|
this.capture('$feature_flag_called', {
|
|
952
1024
|
$feature_flag: key,
|
|
953
|
-
$feature_flag_response:
|
|
1025
|
+
$feature_flag_response: response,
|
|
954
1026
|
});
|
|
955
1027
|
}
|
|
956
|
-
// If we have flags we either return the value (true or string) or
|
|
957
|
-
return
|
|
1028
|
+
// If we have flags we either return the value (true or string) or false
|
|
1029
|
+
return response;
|
|
958
1030
|
};
|
|
959
1031
|
PostHogCore.prototype.getFeatureFlags = function () {
|
|
960
1032
|
var flags = this.getPersistedProperty(PostHogPersistedProperty.FeatureFlags);
|
|
@@ -973,17 +1045,19 @@ var PostHogCore = /** @class */ (function () {
|
|
|
973
1045
|
}
|
|
974
1046
|
return flags;
|
|
975
1047
|
};
|
|
976
|
-
PostHogCore.prototype.isFeatureEnabled = function (key
|
|
977
|
-
var
|
|
978
|
-
if (
|
|
979
|
-
|
|
980
|
-
|
|
1048
|
+
PostHogCore.prototype.isFeatureEnabled = function (key) {
|
|
1049
|
+
var response = this.getFeatureFlag(key);
|
|
1050
|
+
if (response === undefined) {
|
|
1051
|
+
return undefined;
|
|
1052
|
+
}
|
|
1053
|
+
return !!response;
|
|
981
1054
|
};
|
|
982
|
-
PostHogCore.prototype.reloadFeatureFlagsAsync = function () {
|
|
1055
|
+
PostHogCore.prototype.reloadFeatureFlagsAsync = function (sendAnonDistinctId) {
|
|
1056
|
+
if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
|
|
983
1057
|
return __awaiter(this, void 0, void 0, function () {
|
|
984
1058
|
return __generator(this, function (_a) {
|
|
985
1059
|
switch (_a.label) {
|
|
986
|
-
case 0: return [4 /*yield*/, this.decideAsync()];
|
|
1060
|
+
case 0: return [4 /*yield*/, this.decideAsync(sendAnonDistinctId)];
|
|
987
1061
|
case 1: return [2 /*return*/, (_a.sent()).featureFlags];
|
|
988
1062
|
}
|
|
989
1063
|
});
|
|
@@ -1021,6 +1095,14 @@ var PostHogCore = /** @class */ (function () {
|
|
|
1021
1095
|
}
|
|
1022
1096
|
return this.setPersistedProperty(PostHogPersistedProperty.OverrideFeatureFlags, flags);
|
|
1023
1097
|
};
|
|
1098
|
+
PostHogCore.prototype._sendFeatureFlags = function (event, properties) {
|
|
1099
|
+
var _this = this;
|
|
1100
|
+
this.reloadFeatureFlagsAsync(false).finally(function () {
|
|
1101
|
+
// Try to enqueue message irrespective of errors during feature flag fetching
|
|
1102
|
+
var payload = _this.buildPayload({ event: event, properties: properties });
|
|
1103
|
+
_this.enqueue('capture', payload);
|
|
1104
|
+
});
|
|
1105
|
+
};
|
|
1024
1106
|
/***
|
|
1025
1107
|
*** QUEUEING AND FLUSHING
|
|
1026
1108
|
***/
|
|
@@ -1049,13 +1131,15 @@ var PostHogCore = /** @class */ (function () {
|
|
|
1049
1131
|
PostHogCore.prototype.flushAsync = function () {
|
|
1050
1132
|
var _this = this;
|
|
1051
1133
|
return new Promise(function (resolve, reject) {
|
|
1052
|
-
_this.flush(function (err, data) {
|
|
1134
|
+
_this.flush(function (err, data) {
|
|
1135
|
+
return err ? reject(err) : resolve(data);
|
|
1136
|
+
});
|
|
1053
1137
|
});
|
|
1054
1138
|
};
|
|
1055
1139
|
PostHogCore.prototype.flush = function (callback) {
|
|
1056
1140
|
var _this = this;
|
|
1057
1141
|
if (this.optedOut) {
|
|
1058
|
-
return callback
|
|
1142
|
+
return callback === null || callback === void 0 ? void 0 : callback();
|
|
1059
1143
|
}
|
|
1060
1144
|
if (this._flushTimer) {
|
|
1061
1145
|
clearTimeout(this._flushTimer);
|
|
@@ -1063,7 +1147,7 @@ var PostHogCore = /** @class */ (function () {
|
|
|
1063
1147
|
}
|
|
1064
1148
|
var queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
|
|
1065
1149
|
if (!queue.length) {
|
|
1066
|
-
return callback
|
|
1150
|
+
return callback === null || callback === void 0 ? void 0 : callback();
|
|
1067
1151
|
}
|
|
1068
1152
|
var items = queue.splice(0, this.flushAt);
|
|
1069
1153
|
this.setPersistedProperty(PostHogPersistedProperty.Queue, queue);
|
|
@@ -1150,12 +1234,608 @@ var PostHogMemoryStorage = /** @class */ (function () {
|
|
|
1150
1234
|
return PostHogMemoryStorage;
|
|
1151
1235
|
}());
|
|
1152
1236
|
|
|
1153
|
-
|
|
1237
|
+
// So that alternative implementations can be used if desired
|
|
1238
|
+
|
|
1239
|
+
var fetch = function (url, options) {
|
|
1240
|
+
return __awaiter(void 0, void 0, void 0, function () {
|
|
1241
|
+
var res;
|
|
1242
|
+
return __generator(this, function (_a) {
|
|
1243
|
+
switch (_a.label) {
|
|
1244
|
+
case 0:
|
|
1245
|
+
return [4
|
|
1246
|
+
/*yield*/
|
|
1247
|
+
, axios.request({
|
|
1248
|
+
url: url,
|
|
1249
|
+
headers: options.headers,
|
|
1250
|
+
method: options.method.toLowerCase(),
|
|
1251
|
+
data: options.body,
|
|
1252
|
+
signal: options.signal
|
|
1253
|
+
})];
|
|
1254
|
+
|
|
1255
|
+
case 1:
|
|
1256
|
+
res = _a.sent();
|
|
1257
|
+
return [2
|
|
1258
|
+
/*return*/
|
|
1259
|
+
, {
|
|
1260
|
+
status: res.status,
|
|
1261
|
+
text: function () {
|
|
1262
|
+
return res.data;
|
|
1263
|
+
},
|
|
1264
|
+
json: function () {
|
|
1265
|
+
return res.data;
|
|
1266
|
+
}
|
|
1267
|
+
}];
|
|
1268
|
+
}
|
|
1269
|
+
});
|
|
1270
|
+
});
|
|
1271
|
+
};
|
|
1272
|
+
|
|
1273
|
+
var LONG_SCALE = 0xfffffffffffffff;
|
|
1274
|
+
|
|
1275
|
+
var ClientError =
|
|
1154
1276
|
/** @class */
|
|
1155
1277
|
function (_super) {
|
|
1156
|
-
__extends(
|
|
1278
|
+
__extends(ClientError, _super);
|
|
1157
1279
|
|
|
1158
|
-
function
|
|
1280
|
+
function ClientError(message) {
|
|
1281
|
+
var _this = _super.call(this) || this;
|
|
1282
|
+
|
|
1283
|
+
Error.captureStackTrace(_this, _this.constructor);
|
|
1284
|
+
_this.name = 'ClientError';
|
|
1285
|
+
_this.message = message;
|
|
1286
|
+
Object.setPrototypeOf(_this, ClientError.prototype);
|
|
1287
|
+
return _this;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
return ClientError;
|
|
1291
|
+
}(Error);
|
|
1292
|
+
|
|
1293
|
+
var InconclusiveMatchError =
|
|
1294
|
+
/** @class */
|
|
1295
|
+
function (_super) {
|
|
1296
|
+
__extends(InconclusiveMatchError, _super);
|
|
1297
|
+
|
|
1298
|
+
function InconclusiveMatchError(message) {
|
|
1299
|
+
var _this = _super.call(this, message) || this;
|
|
1300
|
+
|
|
1301
|
+
_this.name = _this.constructor.name;
|
|
1302
|
+
Error.captureStackTrace(_this, _this.constructor); // instanceof doesn't work in ES3 or ES5
|
|
1303
|
+
// https://www.dannyguo.com/blog/how-to-fix-instanceof-not-working-for-custom-errors-in-typescript/
|
|
1304
|
+
// this is the workaround
|
|
1305
|
+
|
|
1306
|
+
Object.setPrototypeOf(_this, InconclusiveMatchError.prototype);
|
|
1307
|
+
return _this;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
return InconclusiveMatchError;
|
|
1311
|
+
}(Error);
|
|
1312
|
+
|
|
1313
|
+
var FeatureFlagsPoller =
|
|
1314
|
+
/** @class */
|
|
1315
|
+
function () {
|
|
1316
|
+
function FeatureFlagsPoller(_a) {
|
|
1317
|
+
var pollingInterval = _a.pollingInterval,
|
|
1318
|
+
personalApiKey = _a.personalApiKey,
|
|
1319
|
+
projectApiKey = _a.projectApiKey,
|
|
1320
|
+
timeout = _a.timeout,
|
|
1321
|
+
host = _a.host,
|
|
1322
|
+
options = __rest(_a, ["pollingInterval", "personalApiKey", "projectApiKey", "timeout", "host"]);
|
|
1323
|
+
|
|
1324
|
+
this.pollingInterval = pollingInterval;
|
|
1325
|
+
this.personalApiKey = personalApiKey;
|
|
1326
|
+
this.featureFlags = [];
|
|
1327
|
+
this.groupTypeMapping = {};
|
|
1328
|
+
this.loadedSuccessfullyOnce = false;
|
|
1329
|
+
this.timeout = timeout;
|
|
1330
|
+
this.projectApiKey = projectApiKey;
|
|
1331
|
+
this.host = host;
|
|
1332
|
+
this.poller = undefined; // NOTE: as any is required here as the AbortSignal typing is slightly misaligned but works just fine
|
|
1333
|
+
|
|
1334
|
+
this.fetch = options.fetch || fetch;
|
|
1335
|
+
void this.loadFeatureFlags();
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
FeatureFlagsPoller.prototype.getFeatureFlag = function (key, distinctId, groups, personProperties, groupProperties) {
|
|
1339
|
+
if (groups === void 0) {
|
|
1340
|
+
groups = {};
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
if (personProperties === void 0) {
|
|
1344
|
+
personProperties = {};
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
if (groupProperties === void 0) {
|
|
1348
|
+
groupProperties = {};
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1352
|
+
var response, featureFlag, _i, _a, flag;
|
|
1353
|
+
|
|
1354
|
+
return __generator(this, function (_b) {
|
|
1355
|
+
switch (_b.label) {
|
|
1356
|
+
case 0:
|
|
1357
|
+
return [4
|
|
1358
|
+
/*yield*/
|
|
1359
|
+
, this.loadFeatureFlags()];
|
|
1360
|
+
|
|
1361
|
+
case 1:
|
|
1362
|
+
_b.sent();
|
|
1363
|
+
|
|
1364
|
+
response = undefined;
|
|
1365
|
+
featureFlag = undefined;
|
|
1366
|
+
|
|
1367
|
+
if (!this.loadedSuccessfullyOnce) {
|
|
1368
|
+
return [2
|
|
1369
|
+
/*return*/
|
|
1370
|
+
, response];
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
for (_i = 0, _a = this.featureFlags; _i < _a.length; _i++) {
|
|
1374
|
+
flag = _a[_i];
|
|
1375
|
+
|
|
1376
|
+
if (key === flag.key) {
|
|
1377
|
+
featureFlag = flag;
|
|
1378
|
+
break;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
if (featureFlag !== undefined) {
|
|
1383
|
+
try {
|
|
1384
|
+
response = this.computeFlagLocally(featureFlag, distinctId, groups, personProperties, groupProperties);
|
|
1385
|
+
console.debug("Successfully computed flag locally: ".concat(key, " -> ").concat(response));
|
|
1386
|
+
} catch (e) {
|
|
1387
|
+
if (e instanceof InconclusiveMatchError) {
|
|
1388
|
+
console.debug("Can't compute flag locally: ".concat(key, ": ").concat(e));
|
|
1389
|
+
} else if (e instanceof Error) {
|
|
1390
|
+
console.error("Error computing flag locally: ".concat(key, ": ").concat(e));
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
return [2
|
|
1396
|
+
/*return*/
|
|
1397
|
+
, response];
|
|
1398
|
+
}
|
|
1399
|
+
});
|
|
1400
|
+
});
|
|
1401
|
+
};
|
|
1402
|
+
|
|
1403
|
+
FeatureFlagsPoller.prototype.getAllFlags = function (distinctId, groups, personProperties, groupProperties) {
|
|
1404
|
+
if (groups === void 0) {
|
|
1405
|
+
groups = {};
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
if (personProperties === void 0) {
|
|
1409
|
+
personProperties = {};
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
if (groupProperties === void 0) {
|
|
1413
|
+
groupProperties = {};
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1417
|
+
var response, fallbackToDecide;
|
|
1418
|
+
|
|
1419
|
+
var _this = this;
|
|
1420
|
+
|
|
1421
|
+
return __generator(this, function (_a) {
|
|
1422
|
+
switch (_a.label) {
|
|
1423
|
+
case 0:
|
|
1424
|
+
return [4
|
|
1425
|
+
/*yield*/
|
|
1426
|
+
, this.loadFeatureFlags()];
|
|
1427
|
+
|
|
1428
|
+
case 1:
|
|
1429
|
+
_a.sent();
|
|
1430
|
+
|
|
1431
|
+
response = {};
|
|
1432
|
+
fallbackToDecide = this.featureFlags.length == 0;
|
|
1433
|
+
this.featureFlags.map(function (flag) {
|
|
1434
|
+
try {
|
|
1435
|
+
response[flag.key] = _this.computeFlagLocally(flag, distinctId, groups, personProperties, groupProperties);
|
|
1436
|
+
} catch (e) {
|
|
1437
|
+
if (e instanceof InconclusiveMatchError) ; else if (e instanceof Error) {
|
|
1438
|
+
console.error("Error computing flag locally: ".concat(flag.key, ": ").concat(e));
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
fallbackToDecide = true;
|
|
1442
|
+
}
|
|
1443
|
+
});
|
|
1444
|
+
return [2
|
|
1445
|
+
/*return*/
|
|
1446
|
+
, {
|
|
1447
|
+
response: response,
|
|
1448
|
+
fallbackToDecide: fallbackToDecide
|
|
1449
|
+
}];
|
|
1450
|
+
}
|
|
1451
|
+
});
|
|
1452
|
+
});
|
|
1453
|
+
};
|
|
1454
|
+
|
|
1455
|
+
FeatureFlagsPoller.prototype.computeFlagLocally = function (flag, distinctId, groups, personProperties, groupProperties) {
|
|
1456
|
+
if (groups === void 0) {
|
|
1457
|
+
groups = {};
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
if (personProperties === void 0) {
|
|
1461
|
+
personProperties = {};
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
if (groupProperties === void 0) {
|
|
1465
|
+
groupProperties = {};
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
if (flag.ensure_experience_continuity) {
|
|
1469
|
+
throw new InconclusiveMatchError('Flag has experience continuity enabled');
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
if (!flag.active) {
|
|
1473
|
+
return false;
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
var flagFilters = flag.filters || {};
|
|
1477
|
+
var aggregation_group_type_index = flagFilters.aggregation_group_type_index;
|
|
1478
|
+
|
|
1479
|
+
if (aggregation_group_type_index != undefined) {
|
|
1480
|
+
var groupName = this.groupTypeMapping[String(aggregation_group_type_index)];
|
|
1481
|
+
|
|
1482
|
+
if (!groupName) {
|
|
1483
|
+
console.warn("[FEATURE FLAGS] Unknown group type index ".concat(aggregation_group_type_index, " for feature flag ").concat(flag.key));
|
|
1484
|
+
throw new InconclusiveMatchError('Flag has unknown group type index');
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
if (!(groupName in groups)) {
|
|
1488
|
+
console.warn("[FEATURE FLAGS] Can't compute group feature flag: ".concat(flag.key, " without group names passed in"));
|
|
1489
|
+
return false;
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
var focusedGroupProperties = groupProperties[groupName];
|
|
1493
|
+
return this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties);
|
|
1494
|
+
} else {
|
|
1495
|
+
return this.matchFeatureFlagProperties(flag, distinctId, personProperties);
|
|
1496
|
+
}
|
|
1497
|
+
};
|
|
1498
|
+
|
|
1499
|
+
FeatureFlagsPoller.prototype.matchFeatureFlagProperties = function (flag, distinctId, properties) {
|
|
1500
|
+
var _this = this;
|
|
1501
|
+
|
|
1502
|
+
var flagFilters = flag.filters || {};
|
|
1503
|
+
var flagConditions = flagFilters.groups || [];
|
|
1504
|
+
var isInconclusive = false;
|
|
1505
|
+
var result = undefined;
|
|
1506
|
+
flagConditions.forEach(function (condition) {
|
|
1507
|
+
try {
|
|
1508
|
+
if (_this.isConditionMatch(flag, distinctId, condition, properties)) {
|
|
1509
|
+
result = _this.getMatchingVariant(flag, distinctId) || true;
|
|
1510
|
+
}
|
|
1511
|
+
} catch (e) {
|
|
1512
|
+
if (e instanceof InconclusiveMatchError) {
|
|
1513
|
+
isInconclusive = true;
|
|
1514
|
+
} else {
|
|
1515
|
+
throw e;
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
});
|
|
1519
|
+
|
|
1520
|
+
if (result !== undefined) {
|
|
1521
|
+
return result;
|
|
1522
|
+
} else if (isInconclusive) {
|
|
1523
|
+
throw new InconclusiveMatchError("Can't determine if feature flag is enabled or not with given properties");
|
|
1524
|
+
} // We can only return False when all conditions are False
|
|
1525
|
+
|
|
1526
|
+
|
|
1527
|
+
return false;
|
|
1528
|
+
};
|
|
1529
|
+
|
|
1530
|
+
FeatureFlagsPoller.prototype.isConditionMatch = function (flag, distinctId, condition, properties) {
|
|
1531
|
+
var rolloutPercentage = condition.rollout_percentage;
|
|
1532
|
+
|
|
1533
|
+
if ((condition.properties || []).length > 0) {
|
|
1534
|
+
var matchAll = condition.properties.every(function (property) {
|
|
1535
|
+
return matchProperty(property, properties);
|
|
1536
|
+
});
|
|
1537
|
+
|
|
1538
|
+
if (!matchAll) {
|
|
1539
|
+
return false;
|
|
1540
|
+
} else if (rolloutPercentage == undefined) {
|
|
1541
|
+
// == to include `null` as a match, not just `undefined`
|
|
1542
|
+
return true;
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
if (rolloutPercentage != undefined && _hash(flag.key, distinctId) > rolloutPercentage / 100.0) {
|
|
1547
|
+
return false;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
return true;
|
|
1551
|
+
};
|
|
1552
|
+
|
|
1553
|
+
FeatureFlagsPoller.prototype.getMatchingVariant = function (flag, distinctId) {
|
|
1554
|
+
var hashValue = _hash(flag.key, distinctId, 'variant');
|
|
1555
|
+
|
|
1556
|
+
var matchingVariant = this.variantLookupTable(flag).find(function (variant) {
|
|
1557
|
+
return hashValue >= variant.valueMin && hashValue < variant.valueMax;
|
|
1558
|
+
});
|
|
1559
|
+
|
|
1560
|
+
if (matchingVariant) {
|
|
1561
|
+
return matchingVariant.key;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
return undefined;
|
|
1565
|
+
};
|
|
1566
|
+
|
|
1567
|
+
FeatureFlagsPoller.prototype.variantLookupTable = function (flag) {
|
|
1568
|
+
var _a;
|
|
1569
|
+
|
|
1570
|
+
var lookupTable = [];
|
|
1571
|
+
var valueMin = 0;
|
|
1572
|
+
var valueMax = 0;
|
|
1573
|
+
var flagFilters = flag.filters || {};
|
|
1574
|
+
var multivariates = ((_a = flagFilters.multivariate) === null || _a === void 0 ? void 0 : _a.variants) || [];
|
|
1575
|
+
multivariates.forEach(function (variant) {
|
|
1576
|
+
valueMax = valueMin + variant.rollout_percentage / 100.0;
|
|
1577
|
+
lookupTable.push({
|
|
1578
|
+
valueMin: valueMin,
|
|
1579
|
+
valueMax: valueMax,
|
|
1580
|
+
key: variant.key
|
|
1581
|
+
});
|
|
1582
|
+
valueMin = valueMax;
|
|
1583
|
+
});
|
|
1584
|
+
return lookupTable;
|
|
1585
|
+
};
|
|
1586
|
+
|
|
1587
|
+
FeatureFlagsPoller.prototype.loadFeatureFlags = function (forceReload) {
|
|
1588
|
+
if (forceReload === void 0) {
|
|
1589
|
+
forceReload = false;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1593
|
+
return __generator(this, function (_a) {
|
|
1594
|
+
switch (_a.label) {
|
|
1595
|
+
case 0:
|
|
1596
|
+
if (!(!this.loadedSuccessfullyOnce || forceReload)) return [3
|
|
1597
|
+
/*break*/
|
|
1598
|
+
, 2];
|
|
1599
|
+
return [4
|
|
1600
|
+
/*yield*/
|
|
1601
|
+
, this._loadFeatureFlags()];
|
|
1602
|
+
|
|
1603
|
+
case 1:
|
|
1604
|
+
_a.sent();
|
|
1605
|
+
|
|
1606
|
+
_a.label = 2;
|
|
1607
|
+
|
|
1608
|
+
case 2:
|
|
1609
|
+
return [2
|
|
1610
|
+
/*return*/
|
|
1611
|
+
];
|
|
1612
|
+
}
|
|
1613
|
+
});
|
|
1614
|
+
});
|
|
1615
|
+
};
|
|
1616
|
+
|
|
1617
|
+
FeatureFlagsPoller.prototype._loadFeatureFlags = function () {
|
|
1618
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1619
|
+
var res, responseJson, err_1;
|
|
1620
|
+
|
|
1621
|
+
var _this = this;
|
|
1622
|
+
|
|
1623
|
+
return __generator(this, function (_a) {
|
|
1624
|
+
switch (_a.label) {
|
|
1625
|
+
case 0:
|
|
1626
|
+
if (this.poller) {
|
|
1627
|
+
clearTimeout(this.poller);
|
|
1628
|
+
this.poller = undefined;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
this.poller = setTimeout(function () {
|
|
1632
|
+
return _this._loadFeatureFlags();
|
|
1633
|
+
}, this.pollingInterval);
|
|
1634
|
+
_a.label = 1;
|
|
1635
|
+
|
|
1636
|
+
case 1:
|
|
1637
|
+
_a.trys.push([1, 4,, 5]);
|
|
1638
|
+
|
|
1639
|
+
return [4
|
|
1640
|
+
/*yield*/
|
|
1641
|
+
, this._requestFeatureFlagDefinitions()];
|
|
1642
|
+
|
|
1643
|
+
case 2:
|
|
1644
|
+
res = _a.sent();
|
|
1645
|
+
|
|
1646
|
+
if (res && res.status === 401) {
|
|
1647
|
+
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");
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
return [4
|
|
1651
|
+
/*yield*/
|
|
1652
|
+
, res.json()];
|
|
1653
|
+
|
|
1654
|
+
case 3:
|
|
1655
|
+
responseJson = _a.sent();
|
|
1656
|
+
|
|
1657
|
+
if (!('flags' in responseJson)) {
|
|
1658
|
+
console.error("Invalid response when getting feature flags: ".concat(JSON.stringify(responseJson)));
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
this.featureFlags = responseJson.flags || [];
|
|
1662
|
+
this.groupTypeMapping = responseJson.group_type_mapping || {};
|
|
1663
|
+
this.loadedSuccessfullyOnce = true;
|
|
1664
|
+
return [3
|
|
1665
|
+
/*break*/
|
|
1666
|
+
, 5];
|
|
1667
|
+
|
|
1668
|
+
case 4:
|
|
1669
|
+
err_1 = _a.sent(); // if an error that is not an instance of ClientError is thrown
|
|
1670
|
+
// we silently ignore the error when reloading feature flags
|
|
1671
|
+
|
|
1672
|
+
if (err_1 instanceof ClientError) {
|
|
1673
|
+
throw err_1;
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
return [3
|
|
1677
|
+
/*break*/
|
|
1678
|
+
, 5];
|
|
1679
|
+
|
|
1680
|
+
case 5:
|
|
1681
|
+
return [2
|
|
1682
|
+
/*return*/
|
|
1683
|
+
];
|
|
1684
|
+
}
|
|
1685
|
+
});
|
|
1686
|
+
});
|
|
1687
|
+
};
|
|
1688
|
+
|
|
1689
|
+
FeatureFlagsPoller.prototype._requestFeatureFlagDefinitions = function () {
|
|
1690
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1691
|
+
var url, options, abortTimeout, controller_1, err_2;
|
|
1692
|
+
return __generator(this, function (_a) {
|
|
1693
|
+
switch (_a.label) {
|
|
1694
|
+
case 0:
|
|
1695
|
+
url = "".concat(this.host, "/api/feature_flag/local_evaluation?token=").concat(this.projectApiKey);
|
|
1696
|
+
options = {
|
|
1697
|
+
method: 'GET',
|
|
1698
|
+
headers: {
|
|
1699
|
+
'Content-Type': 'application/json',
|
|
1700
|
+
Authorization: "Bearer ".concat(this.personalApiKey),
|
|
1701
|
+
'user-agent': "posthog-node/".concat(version)
|
|
1702
|
+
}
|
|
1703
|
+
};
|
|
1704
|
+
abortTimeout = null;
|
|
1705
|
+
|
|
1706
|
+
if (this.timeout && typeof this.timeout === 'number') {
|
|
1707
|
+
controller_1 = new AbortController();
|
|
1708
|
+
abortTimeout = safeSetTimeout(function () {
|
|
1709
|
+
controller_1.abort();
|
|
1710
|
+
}, this.timeout);
|
|
1711
|
+
options.signal = controller_1.signal;
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
_a.label = 1;
|
|
1715
|
+
|
|
1716
|
+
case 1:
|
|
1717
|
+
_a.trys.push([1, 3, 4, 5]);
|
|
1718
|
+
|
|
1719
|
+
return [4
|
|
1720
|
+
/*yield*/
|
|
1721
|
+
, this.fetch(url, options)];
|
|
1722
|
+
|
|
1723
|
+
case 2:
|
|
1724
|
+
return [2
|
|
1725
|
+
/*return*/
|
|
1726
|
+
, _a.sent()];
|
|
1727
|
+
|
|
1728
|
+
case 3:
|
|
1729
|
+
err_2 = _a.sent();
|
|
1730
|
+
throw new Error("Request failed with error: ".concat(err_2));
|
|
1731
|
+
|
|
1732
|
+
case 4:
|
|
1733
|
+
clearTimeout(abortTimeout);
|
|
1734
|
+
return [7
|
|
1735
|
+
/*endfinally*/
|
|
1736
|
+
];
|
|
1737
|
+
|
|
1738
|
+
case 5:
|
|
1739
|
+
return [2
|
|
1740
|
+
/*return*/
|
|
1741
|
+
];
|
|
1742
|
+
}
|
|
1743
|
+
});
|
|
1744
|
+
});
|
|
1745
|
+
};
|
|
1746
|
+
|
|
1747
|
+
FeatureFlagsPoller.prototype.stopPoller = function () {
|
|
1748
|
+
clearTimeout(this.poller);
|
|
1749
|
+
};
|
|
1750
|
+
|
|
1751
|
+
return FeatureFlagsPoller;
|
|
1752
|
+
}(); // # This function takes a distinct_id and a feature flag key and returns a float between 0 and 1.
|
|
1753
|
+
// # Given the same distinct_id and key, it'll always return the same float. These floats are
|
|
1754
|
+
// # uniformly distributed between 0 and 1, so if we want to show this feature to 20% of traffic
|
|
1755
|
+
// # we can do _hash(key, distinct_id) < 0.2
|
|
1756
|
+
|
|
1757
|
+
|
|
1758
|
+
function _hash(key, distinctId, salt) {
|
|
1759
|
+
if (salt === void 0) {
|
|
1760
|
+
salt = '';
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
var sha1Hash = createHash('sha1');
|
|
1764
|
+
sha1Hash.update("".concat(key, ".").concat(distinctId).concat(salt));
|
|
1765
|
+
return parseInt(sha1Hash.digest('hex').slice(0, 15), 16) / LONG_SCALE;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
function matchProperty(property, propertyValues) {
|
|
1769
|
+
var key = property.key;
|
|
1770
|
+
var value = property.value;
|
|
1771
|
+
var operator = property.operator || 'exact';
|
|
1772
|
+
|
|
1773
|
+
if (!(key in propertyValues)) {
|
|
1774
|
+
throw new InconclusiveMatchError("Property ".concat(key, " not found in propertyValues"));
|
|
1775
|
+
} else if (operator === 'is_not_set') {
|
|
1776
|
+
throw new InconclusiveMatchError("Operator is_not_set is not supported");
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
var overrideValue = propertyValues[key];
|
|
1780
|
+
|
|
1781
|
+
switch (operator) {
|
|
1782
|
+
case 'exact':
|
|
1783
|
+
return Array.isArray(value) ? value.indexOf(overrideValue) !== -1 : value === overrideValue;
|
|
1784
|
+
|
|
1785
|
+
case 'is_not':
|
|
1786
|
+
return Array.isArray(value) ? value.indexOf(overrideValue) === -1 : value !== overrideValue;
|
|
1787
|
+
|
|
1788
|
+
case 'is_set':
|
|
1789
|
+
return key in propertyValues;
|
|
1790
|
+
|
|
1791
|
+
case 'icontains':
|
|
1792
|
+
return String(overrideValue).toLowerCase().includes(String(value).toLowerCase());
|
|
1793
|
+
|
|
1794
|
+
case 'not_icontains':
|
|
1795
|
+
return !String(overrideValue).toLowerCase().includes(String(value).toLowerCase());
|
|
1796
|
+
|
|
1797
|
+
case 'regex':
|
|
1798
|
+
return isValidRegex(String(value)) && String(overrideValue).match(String(value)) !== null;
|
|
1799
|
+
|
|
1800
|
+
case 'not_regex':
|
|
1801
|
+
return isValidRegex(String(value)) && String(overrideValue).match(String(value)) === null;
|
|
1802
|
+
|
|
1803
|
+
case 'gt':
|
|
1804
|
+
return typeof overrideValue == typeof value && overrideValue > value;
|
|
1805
|
+
|
|
1806
|
+
case 'gte':
|
|
1807
|
+
return typeof overrideValue == typeof value && overrideValue >= value;
|
|
1808
|
+
|
|
1809
|
+
case 'lt':
|
|
1810
|
+
return typeof overrideValue == typeof value && overrideValue < value;
|
|
1811
|
+
|
|
1812
|
+
case 'lte':
|
|
1813
|
+
return typeof overrideValue == typeof value && overrideValue <= value;
|
|
1814
|
+
|
|
1815
|
+
default:
|
|
1816
|
+
console.error("Unknown operator: ".concat(operator));
|
|
1817
|
+
return false;
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
function isValidRegex(regex) {
|
|
1822
|
+
try {
|
|
1823
|
+
new RegExp(regex);
|
|
1824
|
+
return true;
|
|
1825
|
+
} catch (err) {
|
|
1826
|
+
return false;
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
var THIRTY_SECONDS = 30 * 1000;
|
|
1831
|
+
var MAX_CACHE_SIZE = 50 * 1000;
|
|
1832
|
+
|
|
1833
|
+
var PostHogClient =
|
|
1834
|
+
/** @class */
|
|
1835
|
+
function (_super) {
|
|
1836
|
+
__extends(PostHogClient, _super);
|
|
1837
|
+
|
|
1838
|
+
function PostHogClient(apiKey, options) {
|
|
1159
1839
|
if (options === void 0) {
|
|
1160
1840
|
options = {};
|
|
1161
1841
|
}
|
|
@@ -1165,91 +1845,103 @@ function (_super) {
|
|
|
1165
1845
|
options.captureMode = (options === null || options === void 0 ? void 0 : options.captureMode) || 'json';
|
|
1166
1846
|
options.preloadFeatureFlags = false; // Don't preload as this makes no sense without a distinctId
|
|
1167
1847
|
|
|
1848
|
+
options.sendFeatureFlagEvent = false; // Let `posthog-node` handle this on its own, since we're dealing with multiple distinctIDs
|
|
1849
|
+
|
|
1168
1850
|
_this = _super.call(this, apiKey, options) || this;
|
|
1851
|
+
_this.options = options;
|
|
1169
1852
|
_this._memoryStorage = new PostHogMemoryStorage();
|
|
1170
1853
|
return _this;
|
|
1171
1854
|
}
|
|
1172
1855
|
|
|
1173
|
-
|
|
1856
|
+
PostHogClient.prototype.getPersistedProperty = function (key) {
|
|
1174
1857
|
return this._memoryStorage.getProperty(key);
|
|
1175
1858
|
};
|
|
1176
1859
|
|
|
1177
|
-
|
|
1860
|
+
PostHogClient.prototype.setPersistedProperty = function (key, value) {
|
|
1178
1861
|
return this._memoryStorage.setProperty(key, value);
|
|
1179
1862
|
};
|
|
1180
1863
|
|
|
1181
|
-
|
|
1864
|
+
PostHogClient.prototype.getSessionId = function () {
|
|
1182
1865
|
// Sessions don't make sense for Node
|
|
1183
1866
|
return undefined;
|
|
1184
1867
|
};
|
|
1185
1868
|
|
|
1186
|
-
|
|
1187
|
-
return
|
|
1869
|
+
PostHogClient.prototype.fetch = function (url, options) {
|
|
1870
|
+
return this.options.fetch ? this.options.fetch(url, options) : fetch(url, options);
|
|
1188
1871
|
};
|
|
1189
1872
|
|
|
1190
|
-
|
|
1873
|
+
PostHogClient.prototype.getLibraryId = function () {
|
|
1191
1874
|
return 'posthog-node';
|
|
1192
1875
|
};
|
|
1193
1876
|
|
|
1194
|
-
|
|
1877
|
+
PostHogClient.prototype.getLibraryVersion = function () {
|
|
1195
1878
|
return version;
|
|
1196
1879
|
};
|
|
1197
1880
|
|
|
1198
|
-
|
|
1881
|
+
PostHogClient.prototype.getCustomUserAgent = function () {
|
|
1199
1882
|
return "posthog-node/".concat(version);
|
|
1200
1883
|
};
|
|
1201
1884
|
|
|
1202
|
-
return
|
|
1885
|
+
return PostHogClient;
|
|
1203
1886
|
}(PostHogCore); // The actual exported Nodejs API.
|
|
1204
1887
|
|
|
1205
1888
|
|
|
1206
|
-
var
|
|
1889
|
+
var PostHog =
|
|
1207
1890
|
/** @class */
|
|
1208
1891
|
function () {
|
|
1209
|
-
function
|
|
1892
|
+
function PostHog(apiKey, options) {
|
|
1210
1893
|
if (options === void 0) {
|
|
1211
1894
|
options = {};
|
|
1212
1895
|
}
|
|
1213
1896
|
|
|
1214
|
-
this._sharedClient = new
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
PostHogGlobal.prototype.reInit = function (distinctId) {
|
|
1218
|
-
// Certain properties we want to persist
|
|
1219
|
-
var propertiesToKeep = [PostHogPersistedProperty.Queue, PostHogPersistedProperty.OptedOut];
|
|
1897
|
+
this._sharedClient = new PostHogClient(apiKey, options);
|
|
1220
1898
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1899
|
+
if (options.personalApiKey) {
|
|
1900
|
+
this.featureFlagsPoller = new FeatureFlagsPoller({
|
|
1901
|
+
pollingInterval: typeof options.featureFlagsPollingInterval === 'number' ? options.featureFlagsPollingInterval : THIRTY_SECONDS,
|
|
1902
|
+
personalApiKey: options.personalApiKey,
|
|
1903
|
+
projectApiKey: apiKey,
|
|
1904
|
+
timeout: options.requestTimeout,
|
|
1905
|
+
host: this._sharedClient.host,
|
|
1906
|
+
fetch: options.fetch
|
|
1907
|
+
});
|
|
1225
1908
|
}
|
|
1226
1909
|
|
|
1910
|
+
this.distinctIdHasSentFlagCalls = {};
|
|
1911
|
+
this.maxCacheSize = options.maxCacheSize || MAX_CACHE_SIZE;
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
PostHog.prototype.reInit = function (distinctId) {
|
|
1915
|
+
// Certain properties we want to persist. Queue is persisted always by default.
|
|
1916
|
+
this._sharedClient.reset([PostHogPersistedProperty.OptedOut]);
|
|
1917
|
+
|
|
1227
1918
|
this._sharedClient.setPersistedProperty(PostHogPersistedProperty.DistinctId, distinctId);
|
|
1228
1919
|
};
|
|
1229
1920
|
|
|
1230
|
-
|
|
1921
|
+
PostHog.prototype.enable = function () {
|
|
1231
1922
|
return this._sharedClient.optIn();
|
|
1232
1923
|
};
|
|
1233
1924
|
|
|
1234
|
-
|
|
1925
|
+
PostHog.prototype.disable = function () {
|
|
1235
1926
|
return this._sharedClient.optOut();
|
|
1236
1927
|
};
|
|
1237
1928
|
|
|
1238
|
-
|
|
1929
|
+
PostHog.prototype.capture = function (_a) {
|
|
1239
1930
|
var distinctId = _a.distinctId,
|
|
1240
1931
|
event = _a.event,
|
|
1241
1932
|
properties = _a.properties,
|
|
1242
|
-
groups = _a.groups
|
|
1933
|
+
groups = _a.groups,
|
|
1934
|
+
sendFeatureFlags = _a.sendFeatureFlags;
|
|
1243
1935
|
this.reInit(distinctId);
|
|
1244
1936
|
|
|
1245
1937
|
if (groups) {
|
|
1246
1938
|
this._sharedClient.groups(groups);
|
|
1247
1939
|
}
|
|
1248
1940
|
|
|
1249
|
-
this._sharedClient.capture(event, properties);
|
|
1941
|
+
this._sharedClient.capture(event, properties, sendFeatureFlags || false);
|
|
1250
1942
|
};
|
|
1251
1943
|
|
|
1252
|
-
|
|
1944
|
+
PostHog.prototype.identify = function (_a) {
|
|
1253
1945
|
var distinctId = _a.distinctId,
|
|
1254
1946
|
properties = _a.properties;
|
|
1255
1947
|
this.reInit(distinctId);
|
|
@@ -1257,39 +1949,101 @@ function () {
|
|
|
1257
1949
|
this._sharedClient.identify(distinctId, properties);
|
|
1258
1950
|
};
|
|
1259
1951
|
|
|
1260
|
-
|
|
1952
|
+
PostHog.prototype.alias = function (data) {
|
|
1261
1953
|
this.reInit(data.distinctId);
|
|
1262
1954
|
|
|
1263
1955
|
this._sharedClient.alias(data.alias);
|
|
1264
1956
|
};
|
|
1265
1957
|
|
|
1266
|
-
|
|
1958
|
+
PostHog.prototype.getFeatureFlag = function (key, distinctId, options) {
|
|
1959
|
+
var _a;
|
|
1960
|
+
|
|
1267
1961
|
return __awaiter(this, void 0, void 0, function () {
|
|
1268
|
-
|
|
1269
|
-
|
|
1962
|
+
var _b, groups, personProperties, groupProperties, _c, onlyEvaluateLocally, sendFeatureFlagEvents, response, flagWasLocallyEvaluated, featureFlagReportedKey;
|
|
1963
|
+
|
|
1964
|
+
return __generator(this, function (_d) {
|
|
1965
|
+
switch (_d.label) {
|
|
1270
1966
|
case 0:
|
|
1967
|
+
_b = options || {}, groups = _b.groups, personProperties = _b.personProperties, groupProperties = _b.groupProperties;
|
|
1968
|
+
_c = options || {}, onlyEvaluateLocally = _c.onlyEvaluateLocally, sendFeatureFlagEvents = _c.sendFeatureFlagEvents; // set defaults
|
|
1969
|
+
|
|
1970
|
+
if (onlyEvaluateLocally == undefined) {
|
|
1971
|
+
onlyEvaluateLocally = false;
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
if (sendFeatureFlagEvents == undefined) {
|
|
1975
|
+
sendFeatureFlagEvents = true;
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
return [4
|
|
1979
|
+
/*yield*/
|
|
1980
|
+
, (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.getFeatureFlag(key, distinctId, groups, personProperties, groupProperties)];
|
|
1981
|
+
|
|
1982
|
+
case 1:
|
|
1983
|
+
response = _d.sent();
|
|
1984
|
+
flagWasLocallyEvaluated = response !== undefined;
|
|
1985
|
+
if (!(!flagWasLocallyEvaluated && !onlyEvaluateLocally)) return [3
|
|
1986
|
+
/*break*/
|
|
1987
|
+
, 3];
|
|
1271
1988
|
this.reInit(distinctId);
|
|
1272
1989
|
|
|
1273
|
-
if (groups) {
|
|
1990
|
+
if (groups != undefined) {
|
|
1274
1991
|
this._sharedClient.groups(groups);
|
|
1275
1992
|
}
|
|
1276
1993
|
|
|
1994
|
+
if (personProperties) {
|
|
1995
|
+
this._sharedClient.personProperties(personProperties);
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
if (groupProperties) {
|
|
1999
|
+
this._sharedClient.groupProperties(groupProperties);
|
|
2000
|
+
}
|
|
2001
|
+
|
|
1277
2002
|
return [4
|
|
1278
2003
|
/*yield*/
|
|
1279
|
-
, this._sharedClient.reloadFeatureFlagsAsync()];
|
|
2004
|
+
, this._sharedClient.reloadFeatureFlagsAsync(false)];
|
|
1280
2005
|
|
|
1281
|
-
case
|
|
1282
|
-
|
|
2006
|
+
case 2:
|
|
2007
|
+
_d.sent();
|
|
2008
|
+
|
|
2009
|
+
response = this._sharedClient.getFeatureFlag(key);
|
|
2010
|
+
_d.label = 3;
|
|
2011
|
+
|
|
2012
|
+
case 3:
|
|
2013
|
+
featureFlagReportedKey = "".concat(key, "_").concat(response);
|
|
2014
|
+
|
|
2015
|
+
if (sendFeatureFlagEvents && (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey))) {
|
|
2016
|
+
if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) {
|
|
2017
|
+
this.distinctIdHasSentFlagCalls = {};
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) {
|
|
2021
|
+
this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
|
|
2022
|
+
} else {
|
|
2023
|
+
this.distinctIdHasSentFlagCalls[distinctId] = [featureFlagReportedKey];
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
this.capture({
|
|
2027
|
+
distinctId: distinctId,
|
|
2028
|
+
event: '$feature_flag_called',
|
|
2029
|
+
properties: {
|
|
2030
|
+
$feature_flag: key,
|
|
2031
|
+
$feature_flag_response: response,
|
|
2032
|
+
locally_evaluated: flagWasLocallyEvaluated
|
|
2033
|
+
},
|
|
2034
|
+
groups: groups
|
|
2035
|
+
});
|
|
2036
|
+
}
|
|
1283
2037
|
|
|
1284
2038
|
return [2
|
|
1285
2039
|
/*return*/
|
|
1286
|
-
,
|
|
2040
|
+
, response];
|
|
1287
2041
|
}
|
|
1288
2042
|
});
|
|
1289
2043
|
});
|
|
1290
2044
|
};
|
|
1291
2045
|
|
|
1292
|
-
|
|
2046
|
+
PostHog.prototype.isFeatureEnabled = function (key, distinctId, options) {
|
|
1293
2047
|
return __awaiter(this, void 0, void 0, function () {
|
|
1294
2048
|
var feat;
|
|
1295
2049
|
return __generator(this, function (_a) {
|
|
@@ -1297,19 +2051,94 @@ function () {
|
|
|
1297
2051
|
case 0:
|
|
1298
2052
|
return [4
|
|
1299
2053
|
/*yield*/
|
|
1300
|
-
, this.getFeatureFlag(key, distinctId,
|
|
2054
|
+
, this.getFeatureFlag(key, distinctId, options)];
|
|
1301
2055
|
|
|
1302
2056
|
case 1:
|
|
1303
2057
|
feat = _a.sent();
|
|
2058
|
+
|
|
2059
|
+
if (feat === undefined) {
|
|
2060
|
+
return [2
|
|
2061
|
+
/*return*/
|
|
2062
|
+
, undefined];
|
|
2063
|
+
}
|
|
2064
|
+
|
|
1304
2065
|
return [2
|
|
1305
2066
|
/*return*/
|
|
1306
|
-
, !!feat ||
|
|
2067
|
+
, !!feat || false];
|
|
1307
2068
|
}
|
|
1308
2069
|
});
|
|
1309
2070
|
});
|
|
1310
2071
|
};
|
|
1311
2072
|
|
|
1312
|
-
|
|
2073
|
+
PostHog.prototype.getAllFlags = function (distinctId, options) {
|
|
2074
|
+
var _a;
|
|
2075
|
+
|
|
2076
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
2077
|
+
var _b, groups, personProperties, groupProperties, onlyEvaluateLocally, localEvaluationResult, response, fallbackToDecide, remoteEvaluationResult;
|
|
2078
|
+
|
|
2079
|
+
return __generator(this, function (_c) {
|
|
2080
|
+
switch (_c.label) {
|
|
2081
|
+
case 0:
|
|
2082
|
+
_b = options || {}, groups = _b.groups, personProperties = _b.personProperties, groupProperties = _b.groupProperties;
|
|
2083
|
+
onlyEvaluateLocally = (options || {}).onlyEvaluateLocally; // set defaults
|
|
2084
|
+
|
|
2085
|
+
if (onlyEvaluateLocally == undefined) {
|
|
2086
|
+
onlyEvaluateLocally = false;
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
return [4
|
|
2090
|
+
/*yield*/
|
|
2091
|
+
, (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.getAllFlags(distinctId, groups, personProperties, groupProperties)];
|
|
2092
|
+
|
|
2093
|
+
case 1:
|
|
2094
|
+
localEvaluationResult = _c.sent();
|
|
2095
|
+
response = {};
|
|
2096
|
+
fallbackToDecide = true;
|
|
2097
|
+
|
|
2098
|
+
if (localEvaluationResult) {
|
|
2099
|
+
response = localEvaluationResult.response;
|
|
2100
|
+
fallbackToDecide = localEvaluationResult.fallbackToDecide;
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
if (!(fallbackToDecide && !onlyEvaluateLocally)) return [3
|
|
2104
|
+
/*break*/
|
|
2105
|
+
, 3];
|
|
2106
|
+
this.reInit(distinctId);
|
|
2107
|
+
|
|
2108
|
+
if (groups) {
|
|
2109
|
+
this._sharedClient.groups(groups);
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2112
|
+
if (personProperties) {
|
|
2113
|
+
this._sharedClient.personProperties(personProperties);
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
if (groupProperties) {
|
|
2117
|
+
this._sharedClient.groupProperties(groupProperties);
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
return [4
|
|
2121
|
+
/*yield*/
|
|
2122
|
+
, this._sharedClient.reloadFeatureFlagsAsync(false)];
|
|
2123
|
+
|
|
2124
|
+
case 2:
|
|
2125
|
+
_c.sent();
|
|
2126
|
+
|
|
2127
|
+
remoteEvaluationResult = this._sharedClient.getFeatureFlags();
|
|
2128
|
+
return [2
|
|
2129
|
+
/*return*/
|
|
2130
|
+
, __assign(__assign({}, response), remoteEvaluationResult)];
|
|
2131
|
+
|
|
2132
|
+
case 3:
|
|
2133
|
+
return [2
|
|
2134
|
+
/*return*/
|
|
2135
|
+
, response];
|
|
2136
|
+
}
|
|
2137
|
+
});
|
|
2138
|
+
});
|
|
2139
|
+
};
|
|
2140
|
+
|
|
2141
|
+
PostHog.prototype.groupIdentify = function (_a) {
|
|
1313
2142
|
var groupType = _a.groupType,
|
|
1314
2143
|
groupKey = _a.groupKey,
|
|
1315
2144
|
properties = _a.properties;
|
|
@@ -1317,24 +2146,55 @@ function () {
|
|
|
1317
2146
|
this._sharedClient.groupIdentify(groupType, groupKey, properties);
|
|
1318
2147
|
};
|
|
1319
2148
|
|
|
1320
|
-
|
|
1321
|
-
|
|
2149
|
+
PostHog.prototype.reloadFeatureFlags = function () {
|
|
2150
|
+
var _a;
|
|
2151
|
+
|
|
2152
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
2153
|
+
return __generator(this, function (_b) {
|
|
2154
|
+
switch (_b.label) {
|
|
2155
|
+
case 0:
|
|
2156
|
+
return [4
|
|
2157
|
+
/*yield*/
|
|
2158
|
+
, (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.loadFeatureFlags(true)];
|
|
2159
|
+
|
|
2160
|
+
case 1:
|
|
2161
|
+
_b.sent();
|
|
2162
|
+
|
|
2163
|
+
return [2
|
|
2164
|
+
/*return*/
|
|
2165
|
+
];
|
|
2166
|
+
}
|
|
2167
|
+
});
|
|
2168
|
+
});
|
|
1322
2169
|
};
|
|
1323
2170
|
|
|
1324
|
-
|
|
1325
|
-
|
|
2171
|
+
PostHog.prototype.flush = function () {
|
|
2172
|
+
this._sharedClient.flush();
|
|
1326
2173
|
};
|
|
1327
2174
|
|
|
1328
|
-
|
|
1329
|
-
|
|
2175
|
+
PostHog.prototype.shutdown = function () {
|
|
2176
|
+
void this.shutdownAsync();
|
|
1330
2177
|
};
|
|
1331
2178
|
|
|
1332
|
-
|
|
2179
|
+
PostHog.prototype.shutdownAsync = function () {
|
|
2180
|
+
var _a;
|
|
2181
|
+
|
|
2182
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
2183
|
+
return __generator(this, function (_b) {
|
|
2184
|
+
(_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.stopPoller();
|
|
2185
|
+
return [2
|
|
2186
|
+
/*return*/
|
|
2187
|
+
, this._sharedClient.shutdownAsync()];
|
|
2188
|
+
});
|
|
2189
|
+
});
|
|
2190
|
+
};
|
|
2191
|
+
|
|
2192
|
+
PostHog.prototype.debug = function (enabled) {
|
|
1333
2193
|
return this._sharedClient.debug(enabled);
|
|
1334
2194
|
};
|
|
1335
2195
|
|
|
1336
|
-
return
|
|
2196
|
+
return PostHog;
|
|
1337
2197
|
}();
|
|
1338
2198
|
|
|
1339
|
-
export {
|
|
2199
|
+
export { PostHog };
|
|
1340
2200
|
//# sourceMappingURL=index.esm.js.map
|