posthog-node 2.0.0-alpha7 → 2.0.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 +12 -0
- package/README.md +0 -2
- package/lib/index.cjs.js +907 -96
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.d.ts +69 -10
- package/lib/index.esm.js +908 -97
- package/lib/index.esm.js.map +1 -1
- package/lib/posthog-core/src/index.d.ts +21 -8
- package/lib/posthog-core/src/types.d.ts +5 -2
- package/lib/posthog-core/src/utils.d.ts +0 -1
- package/lib/posthog-node/src/feature-flags.d.ts +48 -0
- package/lib/posthog-node/src/posthog-node.d.ts +30 -3
- package/lib/posthog-node/src/types.d.ts +69 -6
- package/package.json +1 -1
- package/src/feature-flags.ts +396 -0
- package/src/posthog-node.ts +184 -26
- package/src/types.ts +72 -8
- package/test/feature-flags.spec.ts +3192 -0
- package/test/posthog-node.spec.ts +300 -24
package/lib/index.cjs.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var undici = require('undici');
|
|
6
|
+
var crypto = require('crypto');
|
|
6
7
|
|
|
7
8
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
9
|
|
|
@@ -137,12 +138,24 @@ function __generator(thisArg, body) {
|
|
|
137
138
|
throw op[1];
|
|
138
139
|
return { value: op[0] ? op[1] : void 0, done: true };
|
|
139
140
|
}
|
|
141
|
+
}
|
|
142
|
+
function __spreadArray(to, from, pack) {
|
|
143
|
+
if (pack || arguments.length === 2)
|
|
144
|
+
for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
145
|
+
if (ar || !(i in from)) {
|
|
146
|
+
if (!ar)
|
|
147
|
+
ar = Array.prototype.slice.call(from, 0, i);
|
|
148
|
+
ar[i] = from[i];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
140
152
|
}
|
|
141
153
|
|
|
142
|
-
var version = "2.0.
|
|
154
|
+
var version = "2.0.1";
|
|
143
155
|
|
|
144
156
|
var PostHogPersistedProperty;
|
|
145
157
|
(function (PostHogPersistedProperty) {
|
|
158
|
+
PostHogPersistedProperty["AnonymousId"] = "anonymous_id";
|
|
146
159
|
PostHogPersistedProperty["DistinctId"] = "distinct_id";
|
|
147
160
|
PostHogPersistedProperty["Props"] = "props";
|
|
148
161
|
PostHogPersistedProperty["FeatureFlags"] = "feature_flags";
|
|
@@ -151,6 +164,8 @@ var PostHogPersistedProperty;
|
|
|
151
164
|
PostHogPersistedProperty["OptedOut"] = "opted_out";
|
|
152
165
|
PostHogPersistedProperty["SessionId"] = "session_id";
|
|
153
166
|
PostHogPersistedProperty["SessionLastTimestamp"] = "session_timestamp";
|
|
167
|
+
PostHogPersistedProperty["PersonProperties"] = "person_properties";
|
|
168
|
+
PostHogPersistedProperty["GroupProperties"] = "group_properties";
|
|
154
169
|
})(PostHogPersistedProperty || (PostHogPersistedProperty = {}));
|
|
155
170
|
|
|
156
171
|
function assert(truthyValue, message) {
|
|
@@ -697,7 +712,7 @@ var SimpleEventEmitter = /** @class */ (function () {
|
|
|
697
712
|
var PostHogCore = /** @class */ (function () {
|
|
698
713
|
function PostHogCore(apiKey, options) {
|
|
699
714
|
var _this = this;
|
|
700
|
-
var _a, _b, _c, _d, _e
|
|
715
|
+
var _a, _b, _c, _d, _e;
|
|
701
716
|
this.flagCallReported = {};
|
|
702
717
|
// internal
|
|
703
718
|
this._events = new SimpleEventEmitter();
|
|
@@ -708,14 +723,13 @@ var PostHogCore = /** @class */ (function () {
|
|
|
708
723
|
this.flushInterval = (_a = options === null || options === void 0 ? void 0 : options.flushInterval) !== null && _a !== void 0 ? _a : 10000;
|
|
709
724
|
this.captureMode = (options === null || options === void 0 ? void 0 : options.captureMode) || 'form';
|
|
710
725
|
this.sendFeatureFlagEvent = (_b = options === null || options === void 0 ? void 0 : options.sendFeatureFlagEvent) !== null && _b !== void 0 ? _b : true;
|
|
711
|
-
this._decidePollInterval = Math.max(0, (_c = options === null || options === void 0 ? void 0 : options.decidePollInterval) !== null && _c !== void 0 ? _c : 30000);
|
|
712
726
|
// If enable is explicitly set to false we override the optout
|
|
713
727
|
this._optoutOverride = (options === null || options === void 0 ? void 0 : options.enable) === false;
|
|
714
728
|
this._retryOptions = {
|
|
715
|
-
retryCount: (
|
|
716
|
-
retryDelay: (
|
|
729
|
+
retryCount: (_c = options === null || options === void 0 ? void 0 : options.fetchRetryCount) !== null && _c !== void 0 ? _c : 3,
|
|
730
|
+
retryDelay: (_d = options === null || options === void 0 ? void 0 : options.fetchRetryDelay) !== null && _d !== void 0 ? _d : 3000,
|
|
717
731
|
};
|
|
718
|
-
this._sessionExpirationTimeSeconds = (
|
|
732
|
+
this._sessionExpirationTimeSeconds = (_e = options === null || options === void 0 ? void 0 : options.sessionExpirationTimeSeconds) !== null && _e !== void 0 ? _e : 1800; // 30 minutes
|
|
719
733
|
// NOTE: It is important we don't initiate anything in the constructor as some async IO may still be underway on the parent
|
|
720
734
|
if ((options === null || options === void 0 ? void 0 : options.preloadFeatureFlags) !== false) {
|
|
721
735
|
safeSetTimeout(function () {
|
|
@@ -725,12 +739,14 @@ var PostHogCore = /** @class */ (function () {
|
|
|
725
739
|
}
|
|
726
740
|
PostHogCore.prototype.getCommonEventProperties = function () {
|
|
727
741
|
var featureFlags = this.getFeatureFlags();
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
742
|
+
var featureVariantProperties = {};
|
|
743
|
+
if (featureFlags) {
|
|
744
|
+
for (var _i = 0, _a = Object.entries(featureFlags); _i < _a.length; _i++) {
|
|
745
|
+
var _b = _a[_i], feature = _b[0], variant = _b[1];
|
|
746
|
+
featureVariantProperties["$feature/".concat(feature)] = variant;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return __assign({ $lib: this.getLibraryId(), $lib_version: this.getLibraryVersion(), $active_feature_flags: featureFlags ? Object.keys(featureFlags) : undefined }, featureVariantProperties);
|
|
734
750
|
};
|
|
735
751
|
Object.defineProperty(PostHogCore.prototype, "props", {
|
|
736
752
|
// NOTE: Props are lazy loaded from localstorage hence the complex getter setter logic
|
|
@@ -746,6 +762,9 @@ var PostHogCore = /** @class */ (function () {
|
|
|
746
762
|
enumerable: false,
|
|
747
763
|
configurable: true
|
|
748
764
|
});
|
|
765
|
+
PostHogCore.prototype.clearProps = function () {
|
|
766
|
+
this.props = undefined;
|
|
767
|
+
};
|
|
749
768
|
Object.defineProperty(PostHogCore.prototype, "optedOut", {
|
|
750
769
|
get: function () {
|
|
751
770
|
var _a, _b;
|
|
@@ -763,11 +782,16 @@ var PostHogCore = /** @class */ (function () {
|
|
|
763
782
|
PostHogCore.prototype.on = function (event, cb) {
|
|
764
783
|
return this._events.on(event, cb);
|
|
765
784
|
};
|
|
766
|
-
PostHogCore.prototype.reset = function () {
|
|
767
|
-
|
|
768
|
-
|
|
785
|
+
PostHogCore.prototype.reset = function (propertiesToKeep) {
|
|
786
|
+
var allPropertiesToKeep = __spreadArray([PostHogPersistedProperty.Queue], (propertiesToKeep || []), true);
|
|
787
|
+
// clean up props
|
|
788
|
+
this.clearProps();
|
|
789
|
+
for (var _i = 0, _a = Object.keys(PostHogPersistedProperty); _i < _a.length; _i++) {
|
|
790
|
+
var key = _a[_i];
|
|
791
|
+
if (!allPropertiesToKeep.includes(PostHogPersistedProperty[key])) {
|
|
792
|
+
this.setPersistedProperty(PostHogPersistedProperty[key], null);
|
|
793
|
+
}
|
|
769
794
|
}
|
|
770
|
-
this.setPersistedProperty(PostHogPersistedProperty.DistinctId, generateUUID(globalThis));
|
|
771
795
|
};
|
|
772
796
|
PostHogCore.prototype.debug = function (enabled) {
|
|
773
797
|
var _a;
|
|
@@ -797,13 +821,16 @@ var PostHogCore = /** @class */ (function () {
|
|
|
797
821
|
PostHogCore.prototype.resetSessionId = function () {
|
|
798
822
|
this.setPersistedProperty(PostHogPersistedProperty.SessionId, null);
|
|
799
823
|
};
|
|
800
|
-
PostHogCore.prototype.
|
|
801
|
-
var
|
|
802
|
-
if (!
|
|
803
|
-
|
|
804
|
-
this.setPersistedProperty(PostHogPersistedProperty.
|
|
824
|
+
PostHogCore.prototype.getAnonymousId = function () {
|
|
825
|
+
var anonId = this.getPersistedProperty(PostHogPersistedProperty.AnonymousId);
|
|
826
|
+
if (!anonId) {
|
|
827
|
+
anonId = generateUUID(globalThis);
|
|
828
|
+
this.setPersistedProperty(PostHogPersistedProperty.AnonymousId, anonId);
|
|
805
829
|
}
|
|
806
|
-
return
|
|
830
|
+
return anonId;
|
|
831
|
+
};
|
|
832
|
+
PostHogCore.prototype.getDistinctId = function () {
|
|
833
|
+
return this.getPersistedProperty(PostHogPersistedProperty.DistinctId) || this.getAnonymousId();
|
|
807
834
|
};
|
|
808
835
|
PostHogCore.prototype.register = function (properties) {
|
|
809
836
|
this.props = __assign(__assign({}, this.props), properties);
|
|
@@ -817,32 +844,39 @@ var PostHogCore = /** @class */ (function () {
|
|
|
817
844
|
*** TRACKING
|
|
818
845
|
***/
|
|
819
846
|
PostHogCore.prototype.identify = function (distinctId, properties) {
|
|
820
|
-
|
|
847
|
+
var previousDistinctId = this.getDistinctId();
|
|
848
|
+
distinctId = distinctId || previousDistinctId;
|
|
821
849
|
if (properties === null || properties === void 0 ? void 0 : properties.$groups) {
|
|
822
850
|
this.groups(properties.$groups);
|
|
823
851
|
}
|
|
824
852
|
var payload = __assign(__assign({}, this.buildPayload({
|
|
825
853
|
distinct_id: distinctId,
|
|
826
854
|
event: '$identify',
|
|
827
|
-
properties: __assign(__assign({}, (properties || {})), { $anon_distinct_id: this.
|
|
855
|
+
properties: __assign(__assign({}, (properties || {})), { $anon_distinct_id: this.getAnonymousId() }),
|
|
828
856
|
})), { $set: properties });
|
|
829
|
-
if (distinctId !==
|
|
857
|
+
if (distinctId !== previousDistinctId) {
|
|
858
|
+
// We keep the AnonymousId to be used by decide calls and identify to link the previousId
|
|
859
|
+
this.setPersistedProperty(PostHogPersistedProperty.AnonymousId, previousDistinctId);
|
|
830
860
|
this.setPersistedProperty(PostHogPersistedProperty.DistinctId, distinctId);
|
|
861
|
+
if (this.getFeatureFlags()) {
|
|
862
|
+
void this.reloadFeatureFlagsAsync();
|
|
863
|
+
}
|
|
831
864
|
}
|
|
832
865
|
this.enqueue('identify', payload);
|
|
833
866
|
return this;
|
|
834
867
|
};
|
|
835
|
-
PostHogCore.prototype.capture = function (event, properties) {
|
|
836
|
-
|
|
837
|
-
if (properties && properties['groups']) {
|
|
838
|
-
properties.$groups = properties.groups;
|
|
839
|
-
delete properties.groups;
|
|
840
|
-
}
|
|
868
|
+
PostHogCore.prototype.capture = function (event, properties, forceSendFeatureFlags) {
|
|
869
|
+
if (forceSendFeatureFlags === void 0) { forceSendFeatureFlags = false; }
|
|
841
870
|
if (properties === null || properties === void 0 ? void 0 : properties.$groups) {
|
|
842
871
|
this.groups(properties.$groups);
|
|
843
872
|
}
|
|
844
|
-
|
|
845
|
-
|
|
873
|
+
if (forceSendFeatureFlags) {
|
|
874
|
+
this._sendFeatureFlags(event, properties);
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
var payload = this.buildPayload({ event: event, properties: properties });
|
|
878
|
+
this.enqueue('capture', payload);
|
|
879
|
+
}
|
|
846
880
|
return this;
|
|
847
881
|
};
|
|
848
882
|
PostHogCore.prototype.alias = function (alias) {
|
|
@@ -872,11 +906,10 @@ var PostHogCore = /** @class */ (function () {
|
|
|
872
906
|
PostHogCore.prototype.groups = function (groups) {
|
|
873
907
|
// Get persisted groups
|
|
874
908
|
var existingGroups = this.props.$groups || {};
|
|
875
|
-
// NOTE: Should we do the same for groups listed in identify / capture?
|
|
876
909
|
this.register({
|
|
877
910
|
$groups: __assign(__assign({}, existingGroups), groups),
|
|
878
911
|
});
|
|
879
|
-
if (Object.keys(groups).find(function (type) { return existingGroups[type] !== groups[type]; }) && this.
|
|
912
|
+
if (Object.keys(groups).find(function (type) { return existingGroups[type] !== groups[type]; }) && this.getFeatureFlags()) {
|
|
880
913
|
void this.reloadFeatureFlagsAsync();
|
|
881
914
|
}
|
|
882
915
|
return this;
|
|
@@ -900,58 +933,96 @@ var PostHogCore = /** @class */ (function () {
|
|
|
900
933
|
this.enqueue('capture', payload);
|
|
901
934
|
return this;
|
|
902
935
|
};
|
|
936
|
+
/***
|
|
937
|
+
* PROPERTIES
|
|
938
|
+
***/
|
|
939
|
+
PostHogCore.prototype.personProperties = function (properties) {
|
|
940
|
+
// Get persisted person properties
|
|
941
|
+
var existingProperties = this.getPersistedProperty(PostHogPersistedProperty.PersonProperties) || {};
|
|
942
|
+
this.setPersistedProperty(PostHogPersistedProperty.PersonProperties, __assign(__assign({}, existingProperties), properties));
|
|
943
|
+
return this;
|
|
944
|
+
};
|
|
945
|
+
PostHogCore.prototype.groupProperties = function (properties) {
|
|
946
|
+
// Get persisted group properties
|
|
947
|
+
var existingProperties = this.getPersistedProperty(PostHogPersistedProperty.GroupProperties) || {};
|
|
948
|
+
if (Object.keys(existingProperties).length !== 0) {
|
|
949
|
+
Object.keys(existingProperties).forEach(function (groupType) {
|
|
950
|
+
existingProperties[groupType] = __assign(__assign({}, existingProperties[groupType]), properties[groupType]);
|
|
951
|
+
delete properties[groupType];
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
this.setPersistedProperty(PostHogPersistedProperty.GroupProperties, __assign(__assign({}, existingProperties), properties));
|
|
955
|
+
return this;
|
|
956
|
+
};
|
|
903
957
|
/***
|
|
904
958
|
*** FEATURE FLAGS
|
|
905
959
|
***/
|
|
906
|
-
PostHogCore.prototype.decideAsync = function () {
|
|
960
|
+
PostHogCore.prototype.decideAsync = function (sendAnonDistinctId) {
|
|
961
|
+
if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
|
|
907
962
|
if (this._decideResponsePromise) {
|
|
908
963
|
return this._decideResponsePromise;
|
|
909
964
|
}
|
|
910
|
-
return this._decideAsync();
|
|
965
|
+
return this._decideAsync(sendAnonDistinctId);
|
|
911
966
|
};
|
|
912
|
-
PostHogCore.prototype._decideAsync = function () {
|
|
967
|
+
PostHogCore.prototype._decideAsync = function (sendAnonDistinctId) {
|
|
968
|
+
if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
|
|
913
969
|
return __awaiter(this, void 0, void 0, function () {
|
|
914
|
-
var url, distinctId, groups, fetchOptions;
|
|
970
|
+
var url, distinctId, groups, personProperties, groupProperties, fetchOptions;
|
|
915
971
|
var _this = this;
|
|
916
972
|
return __generator(this, function (_a) {
|
|
917
973
|
url = "".concat(this.host, "/decide/?v=2");
|
|
918
974
|
distinctId = this.getDistinctId();
|
|
919
975
|
groups = this.props.$groups || {};
|
|
976
|
+
personProperties = this.getPersistedProperty(PostHogPersistedProperty.PersonProperties) || {};
|
|
977
|
+
groupProperties = this.getPersistedProperty(PostHogPersistedProperty.GroupProperties) || {};
|
|
920
978
|
fetchOptions = {
|
|
921
979
|
method: 'POST',
|
|
922
980
|
headers: { 'Content-Type': 'application/json' },
|
|
923
|
-
body: JSON.stringify({
|
|
981
|
+
body: JSON.stringify({
|
|
982
|
+
token: this.apiKey,
|
|
983
|
+
distinct_id: distinctId,
|
|
984
|
+
$anon_distinct_id: sendAnonDistinctId ? this.getAnonymousId() : undefined,
|
|
985
|
+
groups: groups,
|
|
986
|
+
person_properties: personProperties,
|
|
987
|
+
group_properties: groupProperties,
|
|
988
|
+
}),
|
|
924
989
|
};
|
|
925
990
|
this._decideResponsePromise = this.fetchWithRetry(url, fetchOptions)
|
|
926
991
|
.then(function (r) { return r.json(); })
|
|
927
992
|
.then(function (res) {
|
|
928
993
|
if (res.featureFlags) {
|
|
929
994
|
_this.setPersistedProperty(PostHogPersistedProperty.FeatureFlags, res.featureFlags);
|
|
995
|
+
_this._events.emit('featureflags', res.featureFlags);
|
|
930
996
|
}
|
|
931
|
-
_this._events.emit('featureflags', res.featureFlags);
|
|
932
997
|
return res;
|
|
998
|
+
})
|
|
999
|
+
.finally(function () {
|
|
1000
|
+
_this._decideResponsePromise = undefined;
|
|
933
1001
|
});
|
|
934
1002
|
return [2 /*return*/, this._decideResponsePromise];
|
|
935
1003
|
});
|
|
936
1004
|
});
|
|
937
1005
|
};
|
|
938
|
-
PostHogCore.prototype.getFeatureFlag = function (key
|
|
939
|
-
var _a;
|
|
940
|
-
if (defaultResult === void 0) { defaultResult = false; }
|
|
1006
|
+
PostHogCore.prototype.getFeatureFlag = function (key) {
|
|
941
1007
|
var featureFlags = this.getFeatureFlags();
|
|
942
1008
|
if (!featureFlags) {
|
|
943
|
-
// If we haven't loaded flags yet we respond undefined
|
|
1009
|
+
// If we haven't loaded flags yet, or errored out, we respond with undefined
|
|
944
1010
|
return undefined;
|
|
945
1011
|
}
|
|
1012
|
+
var response = featureFlags[key];
|
|
1013
|
+
if (response === undefined) {
|
|
1014
|
+
// `/decide` returns nothing for flags which are false.
|
|
1015
|
+
response = false;
|
|
1016
|
+
}
|
|
946
1017
|
if (this.sendFeatureFlagEvent && !this.flagCallReported[key]) {
|
|
947
1018
|
this.flagCallReported[key] = true;
|
|
948
1019
|
this.capture('$feature_flag_called', {
|
|
949
1020
|
$feature_flag: key,
|
|
950
|
-
$feature_flag_response:
|
|
1021
|
+
$feature_flag_response: response,
|
|
951
1022
|
});
|
|
952
1023
|
}
|
|
953
|
-
// If we have flags we either return the value (true or string) or
|
|
954
|
-
return
|
|
1024
|
+
// If we have flags we either return the value (true or string) or false
|
|
1025
|
+
return response;
|
|
955
1026
|
};
|
|
956
1027
|
PostHogCore.prototype.getFeatureFlags = function () {
|
|
957
1028
|
var flags = this.getPersistedProperty(PostHogPersistedProperty.FeatureFlags);
|
|
@@ -970,35 +1041,26 @@ var PostHogCore = /** @class */ (function () {
|
|
|
970
1041
|
}
|
|
971
1042
|
return flags;
|
|
972
1043
|
};
|
|
973
|
-
PostHogCore.prototype.isFeatureEnabled = function (key
|
|
974
|
-
var
|
|
975
|
-
if (
|
|
976
|
-
|
|
977
|
-
|
|
1044
|
+
PostHogCore.prototype.isFeatureEnabled = function (key) {
|
|
1045
|
+
var response = this.getFeatureFlag(key);
|
|
1046
|
+
if (response === undefined) {
|
|
1047
|
+
return undefined;
|
|
1048
|
+
}
|
|
1049
|
+
return !!response;
|
|
978
1050
|
};
|
|
979
|
-
PostHogCore.prototype.reloadFeatureFlagsAsync = function () {
|
|
1051
|
+
PostHogCore.prototype.reloadFeatureFlagsAsync = function (sendAnonDistinctId) {
|
|
1052
|
+
if (sendAnonDistinctId === void 0) { sendAnonDistinctId = true; }
|
|
980
1053
|
return __awaiter(this, void 0, void 0, function () {
|
|
981
|
-
var _this = this;
|
|
982
1054
|
return __generator(this, function (_a) {
|
|
983
1055
|
switch (_a.label) {
|
|
984
|
-
case 0:
|
|
985
|
-
clearTimeout(this._decideTimer);
|
|
986
|
-
if (this._decidePollInterval) {
|
|
987
|
-
this._decideTimer = safeSetTimeout(function () { return _this.reloadFeatureFlagsAsync(); }, this._decidePollInterval);
|
|
988
|
-
}
|
|
989
|
-
this._decideResponsePromise = undefined;
|
|
990
|
-
return [4 /*yield*/, this.decideAsync()];
|
|
1056
|
+
case 0: return [4 /*yield*/, this.decideAsync(sendAnonDistinctId)];
|
|
991
1057
|
case 1: return [2 /*return*/, (_a.sent()).featureFlags];
|
|
992
1058
|
}
|
|
993
1059
|
});
|
|
994
1060
|
});
|
|
995
1061
|
};
|
|
996
|
-
// When listening to feature flags polling is active
|
|
997
1062
|
PostHogCore.prototype.onFeatureFlags = function (cb) {
|
|
998
1063
|
var _this = this;
|
|
999
|
-
if (!this._decideTimer) {
|
|
1000
|
-
void this.reloadFeatureFlagsAsync();
|
|
1001
|
-
}
|
|
1002
1064
|
return this.on('featureflags', function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1003
1065
|
var flags;
|
|
1004
1066
|
return __generator(this, function (_a) {
|
|
@@ -1010,12 +1072,33 @@ var PostHogCore = /** @class */ (function () {
|
|
|
1010
1072
|
});
|
|
1011
1073
|
}); });
|
|
1012
1074
|
};
|
|
1075
|
+
PostHogCore.prototype.onFeatureFlag = function (key, cb) {
|
|
1076
|
+
var _this = this;
|
|
1077
|
+
return this.on('featureflags', function () { return __awaiter(_this, void 0, void 0, function () {
|
|
1078
|
+
var flagResponse;
|
|
1079
|
+
return __generator(this, function (_a) {
|
|
1080
|
+
flagResponse = this.getFeatureFlag(key);
|
|
1081
|
+
if (flagResponse !== undefined) {
|
|
1082
|
+
cb(flagResponse);
|
|
1083
|
+
}
|
|
1084
|
+
return [2 /*return*/];
|
|
1085
|
+
});
|
|
1086
|
+
}); });
|
|
1087
|
+
};
|
|
1013
1088
|
PostHogCore.prototype.overrideFeatureFlag = function (flags) {
|
|
1014
1089
|
if (flags === null) {
|
|
1015
1090
|
return this.setPersistedProperty(PostHogPersistedProperty.OverrideFeatureFlags, null);
|
|
1016
1091
|
}
|
|
1017
1092
|
return this.setPersistedProperty(PostHogPersistedProperty.OverrideFeatureFlags, flags);
|
|
1018
1093
|
};
|
|
1094
|
+
PostHogCore.prototype._sendFeatureFlags = function (event, properties) {
|
|
1095
|
+
var _this = this;
|
|
1096
|
+
this.reloadFeatureFlagsAsync(false).finally(function () {
|
|
1097
|
+
// Try to enqueue message irrespective of errors during feature flag fetching
|
|
1098
|
+
var payload = _this.buildPayload({ event: event, properties: properties });
|
|
1099
|
+
_this.enqueue('capture', payload);
|
|
1100
|
+
});
|
|
1101
|
+
};
|
|
1019
1102
|
/***
|
|
1020
1103
|
*** QUEUEING AND FLUSHING
|
|
1021
1104
|
***/
|
|
@@ -1044,13 +1127,15 @@ var PostHogCore = /** @class */ (function () {
|
|
|
1044
1127
|
PostHogCore.prototype.flushAsync = function () {
|
|
1045
1128
|
var _this = this;
|
|
1046
1129
|
return new Promise(function (resolve, reject) {
|
|
1047
|
-
_this.flush(function (err, data) {
|
|
1130
|
+
_this.flush(function (err, data) {
|
|
1131
|
+
return err ? reject(err) : resolve(data);
|
|
1132
|
+
});
|
|
1048
1133
|
});
|
|
1049
1134
|
};
|
|
1050
1135
|
PostHogCore.prototype.flush = function (callback) {
|
|
1051
1136
|
var _this = this;
|
|
1052
1137
|
if (this.optedOut) {
|
|
1053
|
-
return callback
|
|
1138
|
+
return callback === null || callback === void 0 ? void 0 : callback();
|
|
1054
1139
|
}
|
|
1055
1140
|
if (this._flushTimer) {
|
|
1056
1141
|
clearTimeout(this._flushTimer);
|
|
@@ -1058,7 +1143,7 @@ var PostHogCore = /** @class */ (function () {
|
|
|
1058
1143
|
}
|
|
1059
1144
|
var queue = this.getPersistedProperty(PostHogPersistedProperty.Queue) || [];
|
|
1060
1145
|
if (!queue.length) {
|
|
1061
|
-
return callback
|
|
1146
|
+
return callback === null || callback === void 0 ? void 0 : callback();
|
|
1062
1147
|
}
|
|
1063
1148
|
var items = queue.splice(0, this.flushAt);
|
|
1064
1149
|
this.setPersistedProperty(PostHogPersistedProperty.Queue, queue);
|
|
@@ -1117,7 +1202,6 @@ var PostHogCore = /** @class */ (function () {
|
|
|
1117
1202
|
return __generator(this, function (_a) {
|
|
1118
1203
|
switch (_a.label) {
|
|
1119
1204
|
case 0:
|
|
1120
|
-
clearTimeout(this._decideTimer);
|
|
1121
1205
|
clearTimeout(this._flushTimer);
|
|
1122
1206
|
return [4 /*yield*/, this.flushAsync()];
|
|
1123
1207
|
case 1:
|
|
@@ -1146,6 +1230,553 @@ var PostHogMemoryStorage = /** @class */ (function () {
|
|
|
1146
1230
|
return PostHogMemoryStorage;
|
|
1147
1231
|
}());
|
|
1148
1232
|
|
|
1233
|
+
var LONG_SCALE = 0xfffffffffffffff;
|
|
1234
|
+
|
|
1235
|
+
var ClientError =
|
|
1236
|
+
/** @class */
|
|
1237
|
+
function (_super) {
|
|
1238
|
+
__extends(ClientError, _super);
|
|
1239
|
+
|
|
1240
|
+
function ClientError(message) {
|
|
1241
|
+
var _this = _super.call(this) || this;
|
|
1242
|
+
|
|
1243
|
+
Error.captureStackTrace(_this, _this.constructor);
|
|
1244
|
+
_this.name = 'ClientError';
|
|
1245
|
+
_this.message = message;
|
|
1246
|
+
Object.setPrototypeOf(_this, ClientError.prototype);
|
|
1247
|
+
return _this;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
return ClientError;
|
|
1251
|
+
}(Error);
|
|
1252
|
+
|
|
1253
|
+
var InconclusiveMatchError =
|
|
1254
|
+
/** @class */
|
|
1255
|
+
function (_super) {
|
|
1256
|
+
__extends(InconclusiveMatchError, _super);
|
|
1257
|
+
|
|
1258
|
+
function InconclusiveMatchError(message) {
|
|
1259
|
+
var _this = _super.call(this, message) || this;
|
|
1260
|
+
|
|
1261
|
+
_this.name = _this.constructor.name;
|
|
1262
|
+
Error.captureStackTrace(_this, _this.constructor); // instanceof doesn't work in ES3 or ES5
|
|
1263
|
+
// https://www.dannyguo.com/blog/how-to-fix-instanceof-not-working-for-custom-errors-in-typescript/
|
|
1264
|
+
// this is the workaround
|
|
1265
|
+
|
|
1266
|
+
Object.setPrototypeOf(_this, InconclusiveMatchError.prototype);
|
|
1267
|
+
return _this;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
return InconclusiveMatchError;
|
|
1271
|
+
}(Error);
|
|
1272
|
+
|
|
1273
|
+
var FeatureFlagsPoller =
|
|
1274
|
+
/** @class */
|
|
1275
|
+
function () {
|
|
1276
|
+
function FeatureFlagsPoller(_a) {
|
|
1277
|
+
var pollingInterval = _a.pollingInterval,
|
|
1278
|
+
personalApiKey = _a.personalApiKey,
|
|
1279
|
+
projectApiKey = _a.projectApiKey,
|
|
1280
|
+
timeout = _a.timeout,
|
|
1281
|
+
host = _a.host;
|
|
1282
|
+
this.pollingInterval = pollingInterval;
|
|
1283
|
+
this.personalApiKey = personalApiKey;
|
|
1284
|
+
this.featureFlags = [];
|
|
1285
|
+
this.groupTypeMapping = {};
|
|
1286
|
+
this.loadedSuccessfullyOnce = false;
|
|
1287
|
+
this.timeout = timeout;
|
|
1288
|
+
this.projectApiKey = projectApiKey;
|
|
1289
|
+
this.host = host;
|
|
1290
|
+
this.poller = undefined;
|
|
1291
|
+
void this.loadFeatureFlags();
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
FeatureFlagsPoller.prototype.getFeatureFlag = function (key, distinctId, groups, personProperties, groupProperties) {
|
|
1295
|
+
if (groups === void 0) {
|
|
1296
|
+
groups = {};
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
if (personProperties === void 0) {
|
|
1300
|
+
personProperties = {};
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
if (groupProperties === void 0) {
|
|
1304
|
+
groupProperties = {};
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1308
|
+
var response, featureFlag, _i, _a, flag;
|
|
1309
|
+
|
|
1310
|
+
return __generator(this, function (_b) {
|
|
1311
|
+
switch (_b.label) {
|
|
1312
|
+
case 0:
|
|
1313
|
+
return [4
|
|
1314
|
+
/*yield*/
|
|
1315
|
+
, this.loadFeatureFlags()];
|
|
1316
|
+
|
|
1317
|
+
case 1:
|
|
1318
|
+
_b.sent();
|
|
1319
|
+
|
|
1320
|
+
response = undefined;
|
|
1321
|
+
featureFlag = undefined;
|
|
1322
|
+
|
|
1323
|
+
if (!this.loadedSuccessfullyOnce) {
|
|
1324
|
+
return [2
|
|
1325
|
+
/*return*/
|
|
1326
|
+
, response];
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
for (_i = 0, _a = this.featureFlags; _i < _a.length; _i++) {
|
|
1330
|
+
flag = _a[_i];
|
|
1331
|
+
|
|
1332
|
+
if (key === flag.key) {
|
|
1333
|
+
featureFlag = flag;
|
|
1334
|
+
break;
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
if (featureFlag !== undefined) {
|
|
1339
|
+
try {
|
|
1340
|
+
response = this.computeFlagLocally(featureFlag, distinctId, groups, personProperties, groupProperties);
|
|
1341
|
+
console.debug("Successfully computed flag locally: ".concat(key, " -> ").concat(response));
|
|
1342
|
+
} catch (e) {
|
|
1343
|
+
if (e instanceof InconclusiveMatchError) {
|
|
1344
|
+
console.debug("Can't compute flag locally: ".concat(key, ": ").concat(e));
|
|
1345
|
+
} else if (e instanceof Error) {
|
|
1346
|
+
console.error("Error computing flag locally: ".concat(key, ": ").concat(e));
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
return [2
|
|
1352
|
+
/*return*/
|
|
1353
|
+
, response];
|
|
1354
|
+
}
|
|
1355
|
+
});
|
|
1356
|
+
});
|
|
1357
|
+
};
|
|
1358
|
+
|
|
1359
|
+
FeatureFlagsPoller.prototype.getAllFlags = function (distinctId, groups, personProperties, groupProperties) {
|
|
1360
|
+
if (groups === void 0) {
|
|
1361
|
+
groups = {};
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
if (personProperties === void 0) {
|
|
1365
|
+
personProperties = {};
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
if (groupProperties === void 0) {
|
|
1369
|
+
groupProperties = {};
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1373
|
+
var response, fallbackToDecide;
|
|
1374
|
+
|
|
1375
|
+
var _this = this;
|
|
1376
|
+
|
|
1377
|
+
return __generator(this, function (_a) {
|
|
1378
|
+
switch (_a.label) {
|
|
1379
|
+
case 0:
|
|
1380
|
+
return [4
|
|
1381
|
+
/*yield*/
|
|
1382
|
+
, this.loadFeatureFlags()];
|
|
1383
|
+
|
|
1384
|
+
case 1:
|
|
1385
|
+
_a.sent();
|
|
1386
|
+
|
|
1387
|
+
response = {};
|
|
1388
|
+
fallbackToDecide = this.featureFlags.length == 0;
|
|
1389
|
+
this.featureFlags.map(function (flag) {
|
|
1390
|
+
try {
|
|
1391
|
+
response[flag.key] = _this.computeFlagLocally(flag, distinctId, groups, personProperties, groupProperties);
|
|
1392
|
+
} catch (e) {
|
|
1393
|
+
if (e instanceof InconclusiveMatchError) ; else if (e instanceof Error) {
|
|
1394
|
+
console.error("Error computing flag locally: ".concat(flag.key, ": ").concat(e));
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
fallbackToDecide = true;
|
|
1398
|
+
}
|
|
1399
|
+
});
|
|
1400
|
+
return [2
|
|
1401
|
+
/*return*/
|
|
1402
|
+
, {
|
|
1403
|
+
response: response,
|
|
1404
|
+
fallbackToDecide: fallbackToDecide
|
|
1405
|
+
}];
|
|
1406
|
+
}
|
|
1407
|
+
});
|
|
1408
|
+
});
|
|
1409
|
+
};
|
|
1410
|
+
|
|
1411
|
+
FeatureFlagsPoller.prototype.computeFlagLocally = function (flag, distinctId, groups, personProperties, groupProperties) {
|
|
1412
|
+
if (groups === void 0) {
|
|
1413
|
+
groups = {};
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
if (personProperties === void 0) {
|
|
1417
|
+
personProperties = {};
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
if (groupProperties === void 0) {
|
|
1421
|
+
groupProperties = {};
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
if (flag.ensure_experience_continuity) {
|
|
1425
|
+
throw new InconclusiveMatchError('Flag has experience continuity enabled');
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
if (!flag.active) {
|
|
1429
|
+
return false;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
var flagFilters = flag.filters || {};
|
|
1433
|
+
var aggregation_group_type_index = flagFilters.aggregation_group_type_index;
|
|
1434
|
+
|
|
1435
|
+
if (aggregation_group_type_index != undefined) {
|
|
1436
|
+
var groupName = this.groupTypeMapping[String(aggregation_group_type_index)];
|
|
1437
|
+
|
|
1438
|
+
if (!groupName) {
|
|
1439
|
+
console.warn("[FEATURE FLAGS] Unknown group type index ".concat(aggregation_group_type_index, " for feature flag ").concat(flag.key));
|
|
1440
|
+
throw new InconclusiveMatchError('Flag has unknown group type index');
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
if (!(groupName in groups)) {
|
|
1444
|
+
console.warn("[FEATURE FLAGS] Can't compute group feature flag: ".concat(flag.key, " without group names passed in"));
|
|
1445
|
+
return false;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
var focusedGroupProperties = groupProperties[groupName];
|
|
1449
|
+
return this.matchFeatureFlagProperties(flag, groups[groupName], focusedGroupProperties);
|
|
1450
|
+
} else {
|
|
1451
|
+
return this.matchFeatureFlagProperties(flag, distinctId, personProperties);
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
|
|
1455
|
+
FeatureFlagsPoller.prototype.matchFeatureFlagProperties = function (flag, distinctId, properties) {
|
|
1456
|
+
var _this = this;
|
|
1457
|
+
|
|
1458
|
+
var flagFilters = flag.filters || {};
|
|
1459
|
+
var flagConditions = flagFilters.groups || [];
|
|
1460
|
+
var isInconclusive = false;
|
|
1461
|
+
var result = undefined;
|
|
1462
|
+
flagConditions.forEach(function (condition) {
|
|
1463
|
+
try {
|
|
1464
|
+
if (_this.isConditionMatch(flag, distinctId, condition, properties)) {
|
|
1465
|
+
result = _this.getMatchingVariant(flag, distinctId) || true;
|
|
1466
|
+
}
|
|
1467
|
+
} catch (e) {
|
|
1468
|
+
if (e instanceof InconclusiveMatchError) {
|
|
1469
|
+
isInconclusive = true;
|
|
1470
|
+
} else {
|
|
1471
|
+
throw e;
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
});
|
|
1475
|
+
|
|
1476
|
+
if (result !== undefined) {
|
|
1477
|
+
return result;
|
|
1478
|
+
} else if (isInconclusive) {
|
|
1479
|
+
throw new InconclusiveMatchError("Can't determine if feature flag is enabled or not with given properties");
|
|
1480
|
+
} // We can only return False when all conditions are False
|
|
1481
|
+
|
|
1482
|
+
|
|
1483
|
+
return false;
|
|
1484
|
+
};
|
|
1485
|
+
|
|
1486
|
+
FeatureFlagsPoller.prototype.isConditionMatch = function (flag, distinctId, condition, properties) {
|
|
1487
|
+
var rolloutPercentage = condition.rollout_percentage;
|
|
1488
|
+
|
|
1489
|
+
if ((condition.properties || []).length > 0) {
|
|
1490
|
+
var matchAll = condition.properties.every(function (property) {
|
|
1491
|
+
return matchProperty(property, properties);
|
|
1492
|
+
});
|
|
1493
|
+
|
|
1494
|
+
if (!matchAll) {
|
|
1495
|
+
return false;
|
|
1496
|
+
} else if (rolloutPercentage == undefined) {
|
|
1497
|
+
// == to include `null` as a match, not just `undefined`
|
|
1498
|
+
return true;
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
if (rolloutPercentage != undefined && _hash(flag.key, distinctId) > rolloutPercentage / 100.0) {
|
|
1503
|
+
return false;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
return true;
|
|
1507
|
+
};
|
|
1508
|
+
|
|
1509
|
+
FeatureFlagsPoller.prototype.getMatchingVariant = function (flag, distinctId) {
|
|
1510
|
+
var hashValue = _hash(flag.key, distinctId, 'variant');
|
|
1511
|
+
|
|
1512
|
+
var matchingVariant = this.variantLookupTable(flag).find(function (variant) {
|
|
1513
|
+
return hashValue >= variant.valueMin && hashValue < variant.valueMax;
|
|
1514
|
+
});
|
|
1515
|
+
|
|
1516
|
+
if (matchingVariant) {
|
|
1517
|
+
return matchingVariant.key;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
return undefined;
|
|
1521
|
+
};
|
|
1522
|
+
|
|
1523
|
+
FeatureFlagsPoller.prototype.variantLookupTable = function (flag) {
|
|
1524
|
+
var _a;
|
|
1525
|
+
|
|
1526
|
+
var lookupTable = [];
|
|
1527
|
+
var valueMin = 0;
|
|
1528
|
+
var valueMax = 0;
|
|
1529
|
+
var flagFilters = flag.filters || {};
|
|
1530
|
+
var multivariates = ((_a = flagFilters.multivariate) === null || _a === void 0 ? void 0 : _a.variants) || [];
|
|
1531
|
+
multivariates.forEach(function (variant) {
|
|
1532
|
+
valueMax = valueMin + variant.rollout_percentage / 100.0;
|
|
1533
|
+
lookupTable.push({
|
|
1534
|
+
valueMin: valueMin,
|
|
1535
|
+
valueMax: valueMax,
|
|
1536
|
+
key: variant.key
|
|
1537
|
+
});
|
|
1538
|
+
valueMin = valueMax;
|
|
1539
|
+
});
|
|
1540
|
+
return lookupTable;
|
|
1541
|
+
};
|
|
1542
|
+
|
|
1543
|
+
FeatureFlagsPoller.prototype.loadFeatureFlags = function (forceReload) {
|
|
1544
|
+
if (forceReload === void 0) {
|
|
1545
|
+
forceReload = false;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1549
|
+
return __generator(this, function (_a) {
|
|
1550
|
+
switch (_a.label) {
|
|
1551
|
+
case 0:
|
|
1552
|
+
if (!(!this.loadedSuccessfullyOnce || forceReload)) return [3
|
|
1553
|
+
/*break*/
|
|
1554
|
+
, 2];
|
|
1555
|
+
return [4
|
|
1556
|
+
/*yield*/
|
|
1557
|
+
, this._loadFeatureFlags()];
|
|
1558
|
+
|
|
1559
|
+
case 1:
|
|
1560
|
+
_a.sent();
|
|
1561
|
+
|
|
1562
|
+
_a.label = 2;
|
|
1563
|
+
|
|
1564
|
+
case 2:
|
|
1565
|
+
return [2
|
|
1566
|
+
/*return*/
|
|
1567
|
+
];
|
|
1568
|
+
}
|
|
1569
|
+
});
|
|
1570
|
+
});
|
|
1571
|
+
};
|
|
1572
|
+
|
|
1573
|
+
FeatureFlagsPoller.prototype._loadFeatureFlags = function () {
|
|
1574
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1575
|
+
var res, responseJson, err_1;
|
|
1576
|
+
|
|
1577
|
+
var _this = this;
|
|
1578
|
+
|
|
1579
|
+
return __generator(this, function (_a) {
|
|
1580
|
+
switch (_a.label) {
|
|
1581
|
+
case 0:
|
|
1582
|
+
if (this.poller) {
|
|
1583
|
+
clearTimeout(this.poller);
|
|
1584
|
+
this.poller = undefined;
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
this.poller = setTimeout(function () {
|
|
1588
|
+
return _this._loadFeatureFlags();
|
|
1589
|
+
}, this.pollingInterval);
|
|
1590
|
+
_a.label = 1;
|
|
1591
|
+
|
|
1592
|
+
case 1:
|
|
1593
|
+
_a.trys.push([1, 4,, 5]);
|
|
1594
|
+
|
|
1595
|
+
return [4
|
|
1596
|
+
/*yield*/
|
|
1597
|
+
, this._requestFeatureFlagDefinitions()];
|
|
1598
|
+
|
|
1599
|
+
case 2:
|
|
1600
|
+
res = _a.sent();
|
|
1601
|
+
|
|
1602
|
+
if (res && res.statusCode === 401) {
|
|
1603
|
+
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");
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
return [4
|
|
1607
|
+
/*yield*/
|
|
1608
|
+
, res.body.json()];
|
|
1609
|
+
|
|
1610
|
+
case 3:
|
|
1611
|
+
responseJson = _a.sent();
|
|
1612
|
+
|
|
1613
|
+
if (!('flags' in responseJson)) {
|
|
1614
|
+
console.error("Invalid response when getting feature flags: ".concat(JSON.stringify(responseJson)));
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
this.featureFlags = responseJson.flags || [];
|
|
1618
|
+
this.groupTypeMapping = responseJson.group_type_mapping || {};
|
|
1619
|
+
this.loadedSuccessfullyOnce = true;
|
|
1620
|
+
return [3
|
|
1621
|
+
/*break*/
|
|
1622
|
+
, 5];
|
|
1623
|
+
|
|
1624
|
+
case 4:
|
|
1625
|
+
err_1 = _a.sent(); // if an error that is not an instance of ClientError is thrown
|
|
1626
|
+
// we silently ignore the error when reloading feature flags
|
|
1627
|
+
|
|
1628
|
+
if (err_1 instanceof ClientError) {
|
|
1629
|
+
throw err_1;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
return [3
|
|
1633
|
+
/*break*/
|
|
1634
|
+
, 5];
|
|
1635
|
+
|
|
1636
|
+
case 5:
|
|
1637
|
+
return [2
|
|
1638
|
+
/*return*/
|
|
1639
|
+
];
|
|
1640
|
+
}
|
|
1641
|
+
});
|
|
1642
|
+
});
|
|
1643
|
+
};
|
|
1644
|
+
|
|
1645
|
+
FeatureFlagsPoller.prototype._requestFeatureFlagDefinitions = function () {
|
|
1646
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1647
|
+
var url, headers, options, res, err_2;
|
|
1648
|
+
return __generator(this, function (_a) {
|
|
1649
|
+
switch (_a.label) {
|
|
1650
|
+
case 0:
|
|
1651
|
+
url = "".concat(this.host, "/api/feature_flag/local_evaluation?token=").concat(this.projectApiKey);
|
|
1652
|
+
headers = {
|
|
1653
|
+
'Content-Type': 'application/json',
|
|
1654
|
+
Authorization: "Bearer ".concat(this.personalApiKey),
|
|
1655
|
+
'user-agent': "posthog-node/".concat(version)
|
|
1656
|
+
};
|
|
1657
|
+
options = {
|
|
1658
|
+
method: 'GET',
|
|
1659
|
+
headers: headers
|
|
1660
|
+
};
|
|
1661
|
+
|
|
1662
|
+
if (this.timeout && typeof this.timeout === 'number') {
|
|
1663
|
+
options.bodyTimeout = this.timeout;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
_a.label = 1;
|
|
1667
|
+
|
|
1668
|
+
case 1:
|
|
1669
|
+
_a.trys.push([1, 3,, 4]);
|
|
1670
|
+
|
|
1671
|
+
return [4
|
|
1672
|
+
/*yield*/
|
|
1673
|
+
, undici.request(url, options)];
|
|
1674
|
+
|
|
1675
|
+
case 2:
|
|
1676
|
+
res = _a.sent();
|
|
1677
|
+
return [3
|
|
1678
|
+
/*break*/
|
|
1679
|
+
, 4];
|
|
1680
|
+
|
|
1681
|
+
case 3:
|
|
1682
|
+
err_2 = _a.sent();
|
|
1683
|
+
throw new Error("Request failed with error: ".concat(err_2));
|
|
1684
|
+
|
|
1685
|
+
case 4:
|
|
1686
|
+
return [2
|
|
1687
|
+
/*return*/
|
|
1688
|
+
, res];
|
|
1689
|
+
}
|
|
1690
|
+
});
|
|
1691
|
+
});
|
|
1692
|
+
};
|
|
1693
|
+
|
|
1694
|
+
FeatureFlagsPoller.prototype.stopPoller = function () {
|
|
1695
|
+
clearTimeout(this.poller);
|
|
1696
|
+
};
|
|
1697
|
+
|
|
1698
|
+
return FeatureFlagsPoller;
|
|
1699
|
+
}(); // # This function takes a distinct_id and a feature flag key and returns a float between 0 and 1.
|
|
1700
|
+
// # Given the same distinct_id and key, it'll always return the same float. These floats are
|
|
1701
|
+
// # uniformly distributed between 0 and 1, so if we want to show this feature to 20% of traffic
|
|
1702
|
+
// # we can do _hash(key, distinct_id) < 0.2
|
|
1703
|
+
|
|
1704
|
+
|
|
1705
|
+
function _hash(key, distinctId, salt) {
|
|
1706
|
+
if (salt === void 0) {
|
|
1707
|
+
salt = '';
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
var sha1Hash = crypto.createHash('sha1');
|
|
1711
|
+
sha1Hash.update("".concat(key, ".").concat(distinctId).concat(salt));
|
|
1712
|
+
return parseInt(sha1Hash.digest('hex').slice(0, 15), 16) / LONG_SCALE;
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
function matchProperty(property, propertyValues) {
|
|
1716
|
+
var key = property.key;
|
|
1717
|
+
var value = property.value;
|
|
1718
|
+
var operator = property.operator || 'exact';
|
|
1719
|
+
|
|
1720
|
+
if (!(key in propertyValues)) {
|
|
1721
|
+
throw new InconclusiveMatchError("Property ".concat(key, " not found in propertyValues"));
|
|
1722
|
+
} else if (operator === 'is_not_set') {
|
|
1723
|
+
throw new InconclusiveMatchError("Operator is_not_set is not supported");
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
var overrideValue = propertyValues[key];
|
|
1727
|
+
|
|
1728
|
+
switch (operator) {
|
|
1729
|
+
case 'exact':
|
|
1730
|
+
return Array.isArray(value) ? value.indexOf(overrideValue) !== -1 : value === overrideValue;
|
|
1731
|
+
|
|
1732
|
+
case 'is_not':
|
|
1733
|
+
return Array.isArray(value) ? value.indexOf(overrideValue) === -1 : value !== overrideValue;
|
|
1734
|
+
|
|
1735
|
+
case 'is_set':
|
|
1736
|
+
return key in propertyValues;
|
|
1737
|
+
|
|
1738
|
+
case 'icontains':
|
|
1739
|
+
return String(overrideValue).toLowerCase().includes(String(value).toLowerCase());
|
|
1740
|
+
|
|
1741
|
+
case 'not_icontains':
|
|
1742
|
+
return !String(overrideValue).toLowerCase().includes(String(value).toLowerCase());
|
|
1743
|
+
|
|
1744
|
+
case 'regex':
|
|
1745
|
+
return isValidRegex(String(value)) && String(overrideValue).match(String(value)) !== null;
|
|
1746
|
+
|
|
1747
|
+
case 'not_regex':
|
|
1748
|
+
return isValidRegex(String(value)) && String(overrideValue).match(String(value)) === null;
|
|
1749
|
+
|
|
1750
|
+
case 'gt':
|
|
1751
|
+
return typeof overrideValue == typeof value && overrideValue > value;
|
|
1752
|
+
|
|
1753
|
+
case 'gte':
|
|
1754
|
+
return typeof overrideValue == typeof value && overrideValue >= value;
|
|
1755
|
+
|
|
1756
|
+
case 'lt':
|
|
1757
|
+
return typeof overrideValue == typeof value && overrideValue < value;
|
|
1758
|
+
|
|
1759
|
+
case 'lte':
|
|
1760
|
+
return typeof overrideValue == typeof value && overrideValue <= value;
|
|
1761
|
+
|
|
1762
|
+
default:
|
|
1763
|
+
console.error("Unknown operator: ".concat(operator));
|
|
1764
|
+
return false;
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
function isValidRegex(regex) {
|
|
1769
|
+
try {
|
|
1770
|
+
new RegExp(regex);
|
|
1771
|
+
return true;
|
|
1772
|
+
} catch (err) {
|
|
1773
|
+
return false;
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
var THIRTY_SECONDS = 30 * 1000;
|
|
1778
|
+
var MAX_CACHE_SIZE = 50 * 1000;
|
|
1779
|
+
|
|
1149
1780
|
var PostHog =
|
|
1150
1781
|
/** @class */
|
|
1151
1782
|
function (_super) {
|
|
@@ -1161,6 +1792,8 @@ function (_super) {
|
|
|
1161
1792
|
options.captureMode = (options === null || options === void 0 ? void 0 : options.captureMode) || 'json';
|
|
1162
1793
|
options.preloadFeatureFlags = false; // Don't preload as this makes no sense without a distinctId
|
|
1163
1794
|
|
|
1795
|
+
options.sendFeatureFlagEvent = false; // Let `posthog-node` handle this on its own, since we're dealing with multiple distinctIDs
|
|
1796
|
+
|
|
1164
1797
|
_this = _super.call(this, apiKey, options) || this;
|
|
1165
1798
|
_this._memoryStorage = new PostHogMemoryStorage();
|
|
1166
1799
|
return _this;
|
|
@@ -1207,20 +1840,25 @@ function () {
|
|
|
1207
1840
|
options = {};
|
|
1208
1841
|
}
|
|
1209
1842
|
|
|
1210
|
-
options.decidePollInterval = 0; // Forcefully set to 0 so we don't auto-reload
|
|
1211
|
-
|
|
1212
1843
|
this._sharedClient = new PostHog(apiKey, options);
|
|
1844
|
+
|
|
1845
|
+
if (options.personalApiKey) {
|
|
1846
|
+
this.featureFlagsPoller = new FeatureFlagsPoller({
|
|
1847
|
+
pollingInterval: typeof options.featureFlagsPollingInterval === 'number' ? options.featureFlagsPollingInterval : THIRTY_SECONDS,
|
|
1848
|
+
personalApiKey: options.personalApiKey,
|
|
1849
|
+
projectApiKey: apiKey,
|
|
1850
|
+
timeout: options.requestTimeout,
|
|
1851
|
+
host: this._sharedClient.host
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
this.distinctIdHasSentFlagCalls = {};
|
|
1856
|
+
this.maxCacheSize = options.maxCacheSize || MAX_CACHE_SIZE;
|
|
1213
1857
|
}
|
|
1214
1858
|
|
|
1215
1859
|
PostHogGlobal.prototype.reInit = function (distinctId) {
|
|
1216
|
-
// Certain properties we want to persist
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
for (var key in PostHogPersistedProperty) {
|
|
1220
|
-
if (!propertiesToKeep.includes(key)) {
|
|
1221
|
-
this._sharedClient.setPersistedProperty(PostHogPersistedProperty[key], null);
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1860
|
+
// Certain properties we want to persist. Queue is persisted always by default.
|
|
1861
|
+
this._sharedClient.reset([PostHogPersistedProperty.OptedOut]);
|
|
1224
1862
|
|
|
1225
1863
|
this._sharedClient.setPersistedProperty(PostHogPersistedProperty.DistinctId, distinctId);
|
|
1226
1864
|
};
|
|
@@ -1237,14 +1875,15 @@ function () {
|
|
|
1237
1875
|
var distinctId = _a.distinctId,
|
|
1238
1876
|
event = _a.event,
|
|
1239
1877
|
properties = _a.properties,
|
|
1240
|
-
groups = _a.groups
|
|
1878
|
+
groups = _a.groups,
|
|
1879
|
+
sendFeatureFlags = _a.sendFeatureFlags;
|
|
1241
1880
|
this.reInit(distinctId);
|
|
1242
1881
|
|
|
1243
1882
|
if (groups) {
|
|
1244
1883
|
this._sharedClient.groups(groups);
|
|
1245
1884
|
}
|
|
1246
1885
|
|
|
1247
|
-
this._sharedClient.capture(event, properties);
|
|
1886
|
+
this._sharedClient.capture(event, properties, sendFeatureFlags || false);
|
|
1248
1887
|
};
|
|
1249
1888
|
|
|
1250
1889
|
PostHogGlobal.prototype.identify = function (_a) {
|
|
@@ -1261,33 +1900,95 @@ function () {
|
|
|
1261
1900
|
this._sharedClient.alias(data.alias);
|
|
1262
1901
|
};
|
|
1263
1902
|
|
|
1264
|
-
PostHogGlobal.prototype.getFeatureFlag = function (key, distinctId,
|
|
1903
|
+
PostHogGlobal.prototype.getFeatureFlag = function (key, distinctId, options) {
|
|
1904
|
+
var _a;
|
|
1905
|
+
|
|
1265
1906
|
return __awaiter(this, void 0, void 0, function () {
|
|
1266
|
-
|
|
1267
|
-
|
|
1907
|
+
var _b, groups, personProperties, groupProperties, _c, onlyEvaluateLocally, sendFeatureFlagEvents, response, flagWasLocallyEvaluated, featureFlagReportedKey;
|
|
1908
|
+
|
|
1909
|
+
return __generator(this, function (_d) {
|
|
1910
|
+
switch (_d.label) {
|
|
1268
1911
|
case 0:
|
|
1912
|
+
_b = options || {}, groups = _b.groups, personProperties = _b.personProperties, groupProperties = _b.groupProperties;
|
|
1913
|
+
_c = options || {}, onlyEvaluateLocally = _c.onlyEvaluateLocally, sendFeatureFlagEvents = _c.sendFeatureFlagEvents; // set defaults
|
|
1914
|
+
|
|
1915
|
+
if (onlyEvaluateLocally == undefined) {
|
|
1916
|
+
onlyEvaluateLocally = false;
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
if (sendFeatureFlagEvents == undefined) {
|
|
1920
|
+
sendFeatureFlagEvents = true;
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
return [4
|
|
1924
|
+
/*yield*/
|
|
1925
|
+
, (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.getFeatureFlag(key, distinctId, groups, personProperties, groupProperties)];
|
|
1926
|
+
|
|
1927
|
+
case 1:
|
|
1928
|
+
response = _d.sent();
|
|
1929
|
+
flagWasLocallyEvaluated = response !== undefined;
|
|
1930
|
+
if (!(!flagWasLocallyEvaluated && !onlyEvaluateLocally)) return [3
|
|
1931
|
+
/*break*/
|
|
1932
|
+
, 3];
|
|
1269
1933
|
this.reInit(distinctId);
|
|
1270
1934
|
|
|
1271
|
-
if (groups) {
|
|
1935
|
+
if (groups != undefined) {
|
|
1272
1936
|
this._sharedClient.groups(groups);
|
|
1273
1937
|
}
|
|
1274
1938
|
|
|
1939
|
+
if (personProperties) {
|
|
1940
|
+
this._sharedClient.personProperties(personProperties);
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
if (groupProperties) {
|
|
1944
|
+
this._sharedClient.groupProperties(groupProperties);
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1275
1947
|
return [4
|
|
1276
1948
|
/*yield*/
|
|
1277
|
-
, this._sharedClient.reloadFeatureFlagsAsync()];
|
|
1949
|
+
, this._sharedClient.reloadFeatureFlagsAsync(false)];
|
|
1278
1950
|
|
|
1279
|
-
case
|
|
1280
|
-
|
|
1951
|
+
case 2:
|
|
1952
|
+
_d.sent();
|
|
1953
|
+
|
|
1954
|
+
response = this._sharedClient.getFeatureFlag(key);
|
|
1955
|
+
_d.label = 3;
|
|
1956
|
+
|
|
1957
|
+
case 3:
|
|
1958
|
+
featureFlagReportedKey = "".concat(key, "_").concat(response);
|
|
1959
|
+
|
|
1960
|
+
if (sendFeatureFlagEvents && (!(distinctId in this.distinctIdHasSentFlagCalls) || !this.distinctIdHasSentFlagCalls[distinctId].includes(featureFlagReportedKey))) {
|
|
1961
|
+
if (Object.keys(this.distinctIdHasSentFlagCalls).length >= this.maxCacheSize) {
|
|
1962
|
+
this.distinctIdHasSentFlagCalls = {};
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
if (Array.isArray(this.distinctIdHasSentFlagCalls[distinctId])) {
|
|
1966
|
+
this.distinctIdHasSentFlagCalls[distinctId].push(featureFlagReportedKey);
|
|
1967
|
+
} else {
|
|
1968
|
+
this.distinctIdHasSentFlagCalls[distinctId] = [featureFlagReportedKey];
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
this.capture({
|
|
1972
|
+
distinctId: distinctId,
|
|
1973
|
+
event: '$feature_flag_called',
|
|
1974
|
+
properties: {
|
|
1975
|
+
$feature_flag: key,
|
|
1976
|
+
$feature_flag_response: response,
|
|
1977
|
+
locally_evaluated: flagWasLocallyEvaluated
|
|
1978
|
+
},
|
|
1979
|
+
groups: groups
|
|
1980
|
+
});
|
|
1981
|
+
}
|
|
1281
1982
|
|
|
1282
1983
|
return [2
|
|
1283
1984
|
/*return*/
|
|
1284
|
-
,
|
|
1985
|
+
, response];
|
|
1285
1986
|
}
|
|
1286
1987
|
});
|
|
1287
1988
|
});
|
|
1288
1989
|
};
|
|
1289
1990
|
|
|
1290
|
-
PostHogGlobal.prototype.isFeatureEnabled = function (key, distinctId,
|
|
1991
|
+
PostHogGlobal.prototype.isFeatureEnabled = function (key, distinctId, options) {
|
|
1291
1992
|
return __awaiter(this, void 0, void 0, function () {
|
|
1292
1993
|
var feat;
|
|
1293
1994
|
return __generator(this, function (_a) {
|
|
@@ -1295,13 +1996,88 @@ function () {
|
|
|
1295
1996
|
case 0:
|
|
1296
1997
|
return [4
|
|
1297
1998
|
/*yield*/
|
|
1298
|
-
, this.getFeatureFlag(key, distinctId,
|
|
1999
|
+
, this.getFeatureFlag(key, distinctId, options)];
|
|
1299
2000
|
|
|
1300
2001
|
case 1:
|
|
1301
2002
|
feat = _a.sent();
|
|
2003
|
+
|
|
2004
|
+
if (feat === undefined) {
|
|
2005
|
+
return [2
|
|
2006
|
+
/*return*/
|
|
2007
|
+
, undefined];
|
|
2008
|
+
}
|
|
2009
|
+
|
|
1302
2010
|
return [2
|
|
1303
2011
|
/*return*/
|
|
1304
|
-
, !!feat ||
|
|
2012
|
+
, !!feat || false];
|
|
2013
|
+
}
|
|
2014
|
+
});
|
|
2015
|
+
});
|
|
2016
|
+
};
|
|
2017
|
+
|
|
2018
|
+
PostHogGlobal.prototype.getAllFlags = function (distinctId, options) {
|
|
2019
|
+
var _a;
|
|
2020
|
+
|
|
2021
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
2022
|
+
var _b, groups, personProperties, groupProperties, onlyEvaluateLocally, localEvaluationResult, response, fallbackToDecide, remoteEvaluationResult;
|
|
2023
|
+
|
|
2024
|
+
return __generator(this, function (_c) {
|
|
2025
|
+
switch (_c.label) {
|
|
2026
|
+
case 0:
|
|
2027
|
+
_b = options || {}, groups = _b.groups, personProperties = _b.personProperties, groupProperties = _b.groupProperties;
|
|
2028
|
+
onlyEvaluateLocally = (options || {}).onlyEvaluateLocally; // set defaults
|
|
2029
|
+
|
|
2030
|
+
if (onlyEvaluateLocally == undefined) {
|
|
2031
|
+
onlyEvaluateLocally = false;
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
return [4
|
|
2035
|
+
/*yield*/
|
|
2036
|
+
, (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.getAllFlags(distinctId, groups, personProperties, groupProperties)];
|
|
2037
|
+
|
|
2038
|
+
case 1:
|
|
2039
|
+
localEvaluationResult = _c.sent();
|
|
2040
|
+
response = {};
|
|
2041
|
+
fallbackToDecide = true;
|
|
2042
|
+
|
|
2043
|
+
if (localEvaluationResult) {
|
|
2044
|
+
response = localEvaluationResult.response;
|
|
2045
|
+
fallbackToDecide = localEvaluationResult.fallbackToDecide;
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
if (!(fallbackToDecide && !onlyEvaluateLocally)) return [3
|
|
2049
|
+
/*break*/
|
|
2050
|
+
, 3];
|
|
2051
|
+
this.reInit(distinctId);
|
|
2052
|
+
|
|
2053
|
+
if (groups) {
|
|
2054
|
+
this._sharedClient.groups(groups);
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
if (personProperties) {
|
|
2058
|
+
this._sharedClient.personProperties(personProperties);
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
if (groupProperties) {
|
|
2062
|
+
this._sharedClient.groupProperties(groupProperties);
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
return [4
|
|
2066
|
+
/*yield*/
|
|
2067
|
+
, this._sharedClient.reloadFeatureFlagsAsync(false)];
|
|
2068
|
+
|
|
2069
|
+
case 2:
|
|
2070
|
+
_c.sent();
|
|
2071
|
+
|
|
2072
|
+
remoteEvaluationResult = this._sharedClient.getFeatureFlags();
|
|
2073
|
+
return [2
|
|
2074
|
+
/*return*/
|
|
2075
|
+
, __assign(__assign({}, response), remoteEvaluationResult)];
|
|
2076
|
+
|
|
2077
|
+
case 3:
|
|
2078
|
+
return [2
|
|
2079
|
+
/*return*/
|
|
2080
|
+
, response];
|
|
1305
2081
|
}
|
|
1306
2082
|
});
|
|
1307
2083
|
});
|
|
@@ -1316,15 +2092,50 @@ function () {
|
|
|
1316
2092
|
};
|
|
1317
2093
|
|
|
1318
2094
|
PostHogGlobal.prototype.reloadFeatureFlags = function () {
|
|
1319
|
-
|
|
2095
|
+
var _a;
|
|
2096
|
+
|
|
2097
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
2098
|
+
return __generator(this, function (_b) {
|
|
2099
|
+
switch (_b.label) {
|
|
2100
|
+
case 0:
|
|
2101
|
+
return [4
|
|
2102
|
+
/*yield*/
|
|
2103
|
+
, (_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.loadFeatureFlags(true)];
|
|
2104
|
+
|
|
2105
|
+
case 1:
|
|
2106
|
+
_b.sent();
|
|
2107
|
+
|
|
2108
|
+
return [2
|
|
2109
|
+
/*return*/
|
|
2110
|
+
];
|
|
2111
|
+
}
|
|
2112
|
+
});
|
|
2113
|
+
});
|
|
2114
|
+
};
|
|
2115
|
+
|
|
2116
|
+
PostHogGlobal.prototype.flush = function () {
|
|
2117
|
+
this._sharedClient.flush();
|
|
1320
2118
|
};
|
|
1321
2119
|
|
|
1322
2120
|
PostHogGlobal.prototype.shutdown = function () {
|
|
1323
|
-
void this.
|
|
2121
|
+
void this.shutdownAsync();
|
|
1324
2122
|
};
|
|
1325
2123
|
|
|
1326
2124
|
PostHogGlobal.prototype.shutdownAsync = function () {
|
|
1327
|
-
|
|
2125
|
+
var _a;
|
|
2126
|
+
|
|
2127
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
2128
|
+
return __generator(this, function (_b) {
|
|
2129
|
+
(_a = this.featureFlagsPoller) === null || _a === void 0 ? void 0 : _a.stopPoller();
|
|
2130
|
+
return [2
|
|
2131
|
+
/*return*/
|
|
2132
|
+
, this._sharedClient.shutdownAsync()];
|
|
2133
|
+
});
|
|
2134
|
+
});
|
|
2135
|
+
};
|
|
2136
|
+
|
|
2137
|
+
PostHogGlobal.prototype.debug = function (enabled) {
|
|
2138
|
+
return this._sharedClient.debug(enabled);
|
|
1328
2139
|
};
|
|
1329
2140
|
|
|
1330
2141
|
return PostHogGlobal;
|