@statsig/client-core 0.0.1-beta.3 → 0.0.1-beta.31
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/README.md +1 -1
- package/package.json +1 -1
- package/src/$_StatsigGlobal.d.ts +8 -1
- package/src/$_StatsigGlobal.js +22 -12
- package/src/ClientInterfaces.d.ts +47 -14
- package/src/DataAdapterCore.d.ts +32 -0
- package/src/DataAdapterCore.js +167 -0
- package/src/Diagnostics.js +24 -26
- package/src/DownloadConfigSpecsResponse.d.ts +41 -0
- package/src/ErrorBoundary.d.ts +1 -0
- package/src/ErrorBoundary.js +41 -86
- package/src/EvaluationOptions.d.ts +20 -0
- package/src/EvaluationOptions.js +2 -0
- package/src/EvaluationTypes.d.ts +39 -0
- package/src/EvaluationTypes.js +2 -0
- package/src/EventLogger.d.ts +21 -8
- package/src/EventLogger.js +206 -228
- package/src/Hashing.d.ts +2 -1
- package/src/Hashing.js +25 -6
- package/src/InitializeResponse.d.ts +18 -0
- package/src/InitializeResponse.js +2 -0
- package/src/Log.js +15 -34
- package/src/Monitoring.d.ts +1 -2
- package/src/Monitoring.js +68 -27
- package/src/NetworkCore.d.ts +17 -6
- package/src/NetworkCore.js +128 -166
- package/src/NetworkDefaults.d.ts +5 -0
- package/src/NetworkDefaults.js +8 -0
- package/src/NetworkParams.d.ts +9 -0
- package/src/NetworkParams.js +13 -0
- package/src/OverrideAdapter.d.ts +9 -0
- package/src/OverrideAdapter.js +2 -0
- package/src/SDKType.d.ts +8 -0
- package/src/SDKType.js +19 -0
- package/src/SafeJs.d.ts +4 -0
- package/src/SafeJs.js +27 -0
- package/src/SessionID.d.ts +10 -1
- package/src/SessionID.js +86 -6
- package/src/StableID.js +24 -53
- package/src/StatsigClientBase.d.ts +57 -28
- package/src/StatsigClientBase.js +114 -238
- package/src/StatsigClientEventEmitter.d.ts +65 -28
- package/src/StatsigDataAdapter.d.ts +89 -0
- package/src/StatsigDataAdapter.js +4 -0
- package/src/StatsigEvent.d.ts +10 -19
- package/src/StatsigEvent.js +50 -41
- package/src/StatsigMetadata.d.ts +1 -1
- package/src/StatsigMetadata.js +7 -18
- package/src/StatsigOptionsCommon.d.ts +68 -17
- package/src/StatsigTypeFactories.d.ts +6 -0
- package/src/StatsigTypeFactories.js +50 -0
- package/src/StatsigTypes.d.ts +29 -18
- package/src/StatsigTypes.js +0 -29
- package/src/StatsigUser.d.ts +2 -5
- package/src/StatsigUser.js +10 -18
- package/src/StorageProvider.d.ts +12 -7
- package/src/StorageProvider.js +58 -67
- package/src/TypedJsonParse.d.ts +8 -0
- package/src/TypedJsonParse.js +27 -0
- package/src/UUID.js +9 -5
- package/src/UrlOverrides.d.ts +1 -0
- package/src/UrlOverrides.js +15 -0
- package/src/UtitlityTypes.d.ts +3 -0
- package/src/UtitlityTypes.js +2 -0
- package/src/VisibilityObserving.d.ts +8 -0
- package/src/VisibilityObserving.js +30 -0
- package/src/index.d.ts +21 -4
- package/src/index.js +31 -17
- package/src/StatsigDataProvider.d.ts +0 -9
- package/src/VisibilityChangeObserver.d.ts +0 -13
- package/src/VisibilityChangeObserver.js +0 -48
- package/src/__tests__/MockLocalStorage.d.ts +0 -9
- package/src/__tests__/MockLocalStorage.js +0 -37
- /package/src/{StatsigDataProvider.js → DownloadConfigSpecsResponse.js} +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type EvaluationOptionsCommon = {
|
|
2
|
+
/**
|
|
3
|
+
* Prevents an exposure log being created for this check.
|
|
4
|
+
*
|
|
5
|
+
* default: `false`
|
|
6
|
+
*/
|
|
7
|
+
disableExposureLog?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type FeatureGateEvaluationOptions = EvaluationOptionsCommon & {};
|
|
10
|
+
export type DynamicConfigEvaluationOptions = EvaluationOptionsCommon & {};
|
|
11
|
+
export type ExperimentEvaluationOptions = EvaluationOptionsCommon & {
|
|
12
|
+
/**
|
|
13
|
+
* Provide a map of values to be used across checks
|
|
14
|
+
*
|
|
15
|
+
* @requires {@link @statsig/js-user-persisted-storage}
|
|
16
|
+
* @see {@link https://docs.statsig.com/client/concepts/persistent_assignment#example-usage}
|
|
17
|
+
*/
|
|
18
|
+
userPersistedValues?: unknown;
|
|
19
|
+
};
|
|
20
|
+
export type LayerEvaluationOptions = EvaluationOptionsCommon & {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Flatten } from './UtitlityTypes';
|
|
2
|
+
type EvaluationBase<T> = {
|
|
3
|
+
id_type: string;
|
|
4
|
+
name: string;
|
|
5
|
+
rule_id: string;
|
|
6
|
+
secondary_exposures: SecondaryExposure[];
|
|
7
|
+
value: T;
|
|
8
|
+
};
|
|
9
|
+
export type SecondaryExposure = {
|
|
10
|
+
gate: string;
|
|
11
|
+
gateValue: string;
|
|
12
|
+
ruleID: string;
|
|
13
|
+
};
|
|
14
|
+
export type GateEvaluation = EvaluationBase<boolean>;
|
|
15
|
+
export type ExperimentEvaluation = Flatten<EvaluationBase<Record<string, unknown>> & {
|
|
16
|
+
group_name?: string;
|
|
17
|
+
group: string;
|
|
18
|
+
id_type: string;
|
|
19
|
+
is_device_based: boolean;
|
|
20
|
+
is_experiment_active?: boolean;
|
|
21
|
+
is_user_in_experiment?: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
export type DynamicConfigEvaluation = ExperimentEvaluation;
|
|
24
|
+
export type LayerEvaluation = Flatten<Omit<ExperimentEvaluation, 'id_type'> & {
|
|
25
|
+
allocated_experiment_name: string;
|
|
26
|
+
explicit_parameters: string[];
|
|
27
|
+
undelegated_secondary_exposures?: SecondaryExposure[];
|
|
28
|
+
}>;
|
|
29
|
+
export type AnyEvaluation = GateEvaluation | ExperimentEvaluation | DynamicConfigEvaluation | LayerEvaluation;
|
|
30
|
+
export type EvaluationDetails = {
|
|
31
|
+
reason: string;
|
|
32
|
+
lcut?: number;
|
|
33
|
+
receivedAt?: number;
|
|
34
|
+
};
|
|
35
|
+
export type DetailedEvaluation<T extends AnyEvaluation> = {
|
|
36
|
+
evaluation: T | null;
|
|
37
|
+
details: EvaluationDetails;
|
|
38
|
+
};
|
|
39
|
+
export {};
|
package/src/EventLogger.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { NetworkCore } from './NetworkCore';
|
|
2
2
|
import { StatsigClientEmitEventFunc } from './StatsigClientBase';
|
|
3
3
|
import { StatsigEventInternal } from './StatsigEvent';
|
|
4
|
-
import { StatsigOptionsCommon } from './StatsigOptionsCommon';
|
|
5
|
-
import { Visibility } from './VisibilityChangeObserver';
|
|
4
|
+
import { NetworkConfigCommon, StatsigOptionsCommon } from './StatsigOptionsCommon';
|
|
6
5
|
export declare class EventLogger {
|
|
7
6
|
private _sdkKey;
|
|
8
7
|
private _emitter;
|
|
@@ -10,22 +9,36 @@ export declare class EventLogger {
|
|
|
10
9
|
private _options;
|
|
11
10
|
private _queue;
|
|
12
11
|
private _flushTimer;
|
|
13
|
-
private
|
|
12
|
+
private _lastExposureTimeMap;
|
|
13
|
+
private _nonExposedChecks;
|
|
14
14
|
private _maxQueueSize;
|
|
15
|
-
private
|
|
16
|
-
|
|
15
|
+
private _hasRunQuickFlush;
|
|
16
|
+
private _creationTime;
|
|
17
|
+
private _isLoggingDisabled;
|
|
18
|
+
private _logEventUrl;
|
|
19
|
+
private _logEventBeaconUrl;
|
|
20
|
+
constructor(_sdkKey: string, _emitter: StatsigClientEmitEventFunc, _network: NetworkCore, _options: StatsigOptionsCommon<NetworkConfigCommon> | null);
|
|
21
|
+
setLoggingDisabled(isDisabled: boolean): void;
|
|
17
22
|
enqueue(event: StatsigEventInternal): void;
|
|
23
|
+
incrementNonExposureCount(name: string): void;
|
|
18
24
|
reset(): void;
|
|
19
|
-
onVisibilityChanged(visibility: Visibility): void;
|
|
20
25
|
shutdown(): Promise<void>;
|
|
26
|
+
flush(): Promise<void>;
|
|
27
|
+
private _onVisibilityChanged;
|
|
28
|
+
/**
|
|
29
|
+
* We 'Quick Flush' following the very first event enqueued
|
|
30
|
+
* within the quick flush window
|
|
31
|
+
*/
|
|
32
|
+
private _quickFlushIfNeeded;
|
|
21
33
|
private _shouldLogEvent;
|
|
22
34
|
private _flushAndForget;
|
|
23
|
-
private _flush;
|
|
24
35
|
private _sendEvents;
|
|
25
36
|
private _sendEventsViaPost;
|
|
26
37
|
private _sendEventsViaBeacon;
|
|
27
|
-
private _isBeaconSupported;
|
|
28
38
|
private _saveFailedLogsToStorage;
|
|
29
39
|
private _retryFailedLogs;
|
|
30
40
|
private _getStorageKey;
|
|
41
|
+
private _normalizeAndAppendEvent;
|
|
42
|
+
private _appendAndResetNonExposedChecks;
|
|
43
|
+
private _getCurrentPageUrl;
|
|
31
44
|
}
|
package/src/EventLogger.js
CHANGED
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __assign = (this && this.__assign) || function () {
|
|
3
|
-
__assign = Object.assign || function(t) {
|
|
4
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
-
s = arguments[i];
|
|
6
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
-
t[p] = s[p];
|
|
8
|
-
}
|
|
9
|
-
return t;
|
|
10
|
-
};
|
|
11
|
-
return __assign.apply(this, arguments);
|
|
12
|
-
};
|
|
13
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -19,267 +8,256 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
19
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
9
|
});
|
|
21
10
|
};
|
|
22
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
24
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
-
function step(op) {
|
|
27
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
-
switch (op[0]) {
|
|
32
|
-
case 0: case 1: t = op; break;
|
|
33
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
-
default:
|
|
37
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
-
if (t[2]) _.ops.pop();
|
|
42
|
-
_.trys.pop(); continue;
|
|
43
|
-
}
|
|
44
|
-
op = body.call(thisArg, _);
|
|
45
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
12
|
exports.EventLogger = void 0;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
13
|
+
const Hashing_1 = require("./Hashing");
|
|
14
|
+
const Log_1 = require("./Log");
|
|
15
|
+
const NetworkDefaults_1 = require("./NetworkDefaults");
|
|
16
|
+
const NetworkParams_1 = require("./NetworkParams");
|
|
17
|
+
const StatsigEvent_1 = require("./StatsigEvent");
|
|
18
|
+
const StorageProvider_1 = require("./StorageProvider");
|
|
19
|
+
const TypedJsonParse_1 = require("./TypedJsonParse");
|
|
20
|
+
const UrlOverrides_1 = require("./UrlOverrides");
|
|
21
|
+
const VisibilityObserving_1 = require("./VisibilityObserving");
|
|
22
|
+
const DEFAULT_QUEUE_SIZE = 50;
|
|
23
|
+
const DEFAULT_FLUSH_INTERVAL_MS = 10000;
|
|
24
|
+
const MAX_DEDUPER_KEYS = 1000;
|
|
25
|
+
const DEDUPER_WINDOW_DURATION_MS = 60000;
|
|
26
|
+
const MAX_FAILED_LOGS = 500;
|
|
27
|
+
const QUICK_FLUSH_WINDOW_MS = 200;
|
|
28
|
+
class EventLogger {
|
|
29
|
+
constructor(_sdkKey, _emitter, _network, _options) {
|
|
66
30
|
var _a, _b;
|
|
67
31
|
this._sdkKey = _sdkKey;
|
|
68
32
|
this._emitter = _emitter;
|
|
69
33
|
this._network = _network;
|
|
70
34
|
this._options = _options;
|
|
71
35
|
this._queue = [];
|
|
72
|
-
this.
|
|
36
|
+
this._lastExposureTimeMap = {};
|
|
37
|
+
this._nonExposedChecks = {};
|
|
38
|
+
this._hasRunQuickFlush = false;
|
|
39
|
+
this._creationTime = Date.now();
|
|
40
|
+
this._isLoggingDisabled = (_options === null || _options === void 0 ? void 0 : _options.disableLogging) === true;
|
|
73
41
|
this._maxQueueSize = (_a = _options === null || _options === void 0 ? void 0 : _options.loggingBufferMaxSize) !== null && _a !== void 0 ? _a : DEFAULT_QUEUE_SIZE;
|
|
74
|
-
|
|
75
|
-
this._flushTimer = setInterval(
|
|
76
|
-
|
|
77
|
-
this.
|
|
42
|
+
const flushInterval = (_b = _options === null || _options === void 0 ? void 0 : _options.loggingIntervalMs) !== null && _b !== void 0 ? _b : DEFAULT_FLUSH_INTERVAL_MS;
|
|
43
|
+
this._flushTimer = setInterval(() => this._flushAndForget(), flushInterval);
|
|
44
|
+
const config = _options === null || _options === void 0 ? void 0 : _options.networkConfig;
|
|
45
|
+
this._logEventUrl = (0, UrlOverrides_1._getOverridableUrl)(config === null || config === void 0 ? void 0 : config.logEventUrl, config === null || config === void 0 ? void 0 : config.api, '/rgstr', NetworkDefaults_1.NetworkDefault.eventsApi);
|
|
46
|
+
this._logEventBeaconUrl = (0, UrlOverrides_1._getOverridableUrl)(config === null || config === void 0 ? void 0 : config.logEventBeaconUrl, config === null || config === void 0 ? void 0 : config.api, '/log_event_beacon', NetworkDefaults_1.NetworkDefault.eventsApi);
|
|
47
|
+
(0, VisibilityObserving_1._subscribeToVisiblityChanged)(this._onVisibilityChanged.bind(this));
|
|
78
48
|
this._retryFailedLogs();
|
|
79
49
|
}
|
|
80
|
-
|
|
50
|
+
setLoggingDisabled(isDisabled) {
|
|
51
|
+
this._isLoggingDisabled = isDisabled;
|
|
52
|
+
}
|
|
53
|
+
enqueue(event) {
|
|
81
54
|
if (!this._shouldLogEvent(event)) {
|
|
82
55
|
return;
|
|
83
56
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
delete event.user.privateAttributes;
|
|
87
|
-
}
|
|
88
|
-
var _a = StatsigMetadata_1.StatsigMetadataProvider.get(), sdkType = _a.sdkType, sdkVersion = _a.sdkVersion;
|
|
89
|
-
this._queue.push(__assign(__assign({}, event), { statsigMetadata: { sdkType: sdkType, sdkVersion: sdkVersion } }));
|
|
57
|
+
this._normalizeAndAppendEvent(event);
|
|
58
|
+
this._quickFlushIfNeeded();
|
|
90
59
|
if (this._queue.length > this._maxQueueSize) {
|
|
91
60
|
this._flushAndForget();
|
|
92
61
|
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
62
|
+
}
|
|
63
|
+
incrementNonExposureCount(name) {
|
|
64
|
+
var _a;
|
|
65
|
+
const current = (_a = this._nonExposedChecks[name]) !== null && _a !== void 0 ? _a : 0;
|
|
66
|
+
this._nonExposedChecks[name] = current + 1;
|
|
67
|
+
}
|
|
68
|
+
reset() {
|
|
69
|
+
this._lastExposureTimeMap = {};
|
|
70
|
+
}
|
|
71
|
+
shutdown() {
|
|
72
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
if (this._flushTimer) {
|
|
74
|
+
clearInterval(this._flushTimer);
|
|
75
|
+
this._flushTimer = null;
|
|
76
|
+
}
|
|
77
|
+
yield this.flush();
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
flush() {
|
|
81
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
this._appendAndResetNonExposedChecks();
|
|
83
|
+
if (this._queue.length === 0) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const events = this._queue;
|
|
87
|
+
this._queue = [];
|
|
88
|
+
yield this._sendEvents(events);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
_onVisibilityChanged(visibility) {
|
|
98
92
|
if (visibility === 'background') {
|
|
99
93
|
this._flushAndForget();
|
|
100
94
|
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
});
|
|
118
|
-
};
|
|
119
|
-
EventLogger.prototype._shouldLogEvent = function (event) {
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* We 'Quick Flush' following the very first event enqueued
|
|
98
|
+
* within the quick flush window
|
|
99
|
+
*/
|
|
100
|
+
_quickFlushIfNeeded() {
|
|
101
|
+
if (this._hasRunQuickFlush) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
this._hasRunQuickFlush = true;
|
|
105
|
+
if (Date.now() - this._creationTime > QUICK_FLUSH_WINDOW_MS) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
setTimeout(() => this._flushAndForget(), QUICK_FLUSH_WINDOW_MS);
|
|
109
|
+
}
|
|
110
|
+
_shouldLogEvent(event) {
|
|
120
111
|
var _a, _b, _c, _d;
|
|
121
|
-
if (!(0, StatsigEvent_1.
|
|
112
|
+
if (!(0, StatsigEvent_1._isExposureEvent)(event)) {
|
|
122
113
|
return true;
|
|
123
114
|
}
|
|
124
|
-
|
|
115
|
+
const key = [
|
|
125
116
|
event.eventName,
|
|
126
117
|
(_a = event.user) === null || _a === void 0 ? void 0 : _a.userID,
|
|
127
118
|
(_b = event.metadata) === null || _b === void 0 ? void 0 : _b['gate'],
|
|
128
119
|
(_c = event.metadata) === null || _c === void 0 ? void 0 : _c['config'],
|
|
129
120
|
(_d = event.metadata) === null || _d === void 0 ? void 0 : _d['ruleID'],
|
|
130
121
|
].join('|');
|
|
131
|
-
|
|
132
|
-
|
|
122
|
+
const previous = this._lastExposureTimeMap[key];
|
|
123
|
+
const now = Date.now();
|
|
133
124
|
if (previous && now - previous < DEDUPER_WINDOW_DURATION_MS) {
|
|
134
125
|
return false;
|
|
135
126
|
}
|
|
136
|
-
if (Object.keys(this.
|
|
137
|
-
this.
|
|
127
|
+
if (Object.keys(this._lastExposureTimeMap).length > MAX_DEDUPER_KEYS) {
|
|
128
|
+
this._lastExposureTimeMap = {};
|
|
138
129
|
}
|
|
139
|
-
this.
|
|
130
|
+
this._lastExposureTimeMap[key] = now;
|
|
140
131
|
return true;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
this.
|
|
132
|
+
}
|
|
133
|
+
_flushAndForget() {
|
|
134
|
+
this.flush().catch(() => {
|
|
144
135
|
// noop
|
|
145
136
|
});
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
};
|
|
166
|
-
EventLogger.prototype._sendEvents = function (events) {
|
|
167
|
-
var _a, _b;
|
|
168
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
169
|
-
var isInForeground, api, response, _c, _d;
|
|
170
|
-
return __generator(this, function (_e) {
|
|
171
|
-
switch (_e.label) {
|
|
172
|
-
case 0:
|
|
173
|
-
_e.trys.push([0, 4, , 5]);
|
|
174
|
-
isInForeground = VisibilityChangeObserver_1.VisibilityChangeObserver.isCurrentlyVisible();
|
|
175
|
-
api = (_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.api) !== null && _b !== void 0 ? _b : DEFAULT_API;
|
|
176
|
-
if (!(!isInForeground && this._isBeaconSupported())) return [3 /*break*/, 1];
|
|
177
|
-
_c = this._sendEventsViaBeacon(api, events);
|
|
178
|
-
return [3 /*break*/, 3];
|
|
179
|
-
case 1: return [4 /*yield*/, this._sendEventsViaPost(api, events)];
|
|
180
|
-
case 2:
|
|
181
|
-
_c = _e.sent();
|
|
182
|
-
_e.label = 3;
|
|
183
|
-
case 3:
|
|
184
|
-
response = _c;
|
|
185
|
-
if (response.success) {
|
|
186
|
-
this._emitter({
|
|
187
|
-
event: 'logs_flushed',
|
|
188
|
-
events: events,
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
this._saveFailedLogsToStorage(events);
|
|
193
|
-
}
|
|
194
|
-
return [3 /*break*/, 5];
|
|
195
|
-
case 4:
|
|
196
|
-
_d = _e.sent();
|
|
197
|
-
Log_1.Log.warn('Failed to flush events.');
|
|
198
|
-
return [3 /*break*/, 5];
|
|
199
|
-
case 5: return [2 /*return*/];
|
|
137
|
+
}
|
|
138
|
+
_sendEvents(events) {
|
|
139
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
140
|
+
if (this._isLoggingDisabled) {
|
|
141
|
+
this._saveFailedLogsToStorage(events);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const isInForeground = (0, VisibilityObserving_1._isCurrentlyVisible)();
|
|
146
|
+
const response = !isInForeground && this._network.isBeaconSupported()
|
|
147
|
+
? yield this._sendEventsViaBeacon(events)
|
|
148
|
+
: yield this._sendEventsViaPost(events);
|
|
149
|
+
if (response.success) {
|
|
150
|
+
this._emitter({
|
|
151
|
+
name: 'logs_flushed',
|
|
152
|
+
events,
|
|
153
|
+
});
|
|
200
154
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
};
|
|
204
|
-
EventLogger.prototype._sendEventsViaPost = function (api, events) {
|
|
205
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
206
|
-
var result;
|
|
207
|
-
return __generator(this, function (_a) {
|
|
208
|
-
switch (_a.label) {
|
|
209
|
-
case 0: return [4 /*yield*/, this._network.post({
|
|
210
|
-
sdkKey: this._sdkKey,
|
|
211
|
-
data: {
|
|
212
|
-
events: events,
|
|
213
|
-
},
|
|
214
|
-
url: "".concat(api, "/rgstr"),
|
|
215
|
-
retries: 3,
|
|
216
|
-
headers: {
|
|
217
|
-
'Content-Type': 'application/json',
|
|
218
|
-
'STATSIG-EVENT-COUNT': String(events.length),
|
|
219
|
-
},
|
|
220
|
-
})];
|
|
221
|
-
case 1:
|
|
222
|
-
result = _a.sent();
|
|
223
|
-
if (result) {
|
|
224
|
-
return [2 /*return*/, JSON.parse(result)];
|
|
225
|
-
}
|
|
226
|
-
return [2 /*return*/, { success: false }];
|
|
155
|
+
else {
|
|
156
|
+
this._saveFailedLogsToStorage(events);
|
|
227
157
|
}
|
|
228
|
-
}
|
|
158
|
+
}
|
|
159
|
+
catch (_a) {
|
|
160
|
+
Log_1.Log.warn('Failed to flush events.');
|
|
161
|
+
}
|
|
229
162
|
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return {
|
|
233
|
-
|
|
163
|
+
}
|
|
164
|
+
_sendEventsViaPost(events) {
|
|
165
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
166
|
+
const result = yield this._network.post({
|
|
234
167
|
sdkKey: this._sdkKey,
|
|
235
168
|
data: {
|
|
236
|
-
events
|
|
169
|
+
events,
|
|
237
170
|
},
|
|
238
|
-
url:
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
171
|
+
url: this._logEventUrl,
|
|
172
|
+
retries: 3,
|
|
173
|
+
params: {
|
|
174
|
+
[NetworkParams_1.NetworkParam.EventCount]: String(events.length),
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
const response = (result === null || result === void 0 ? void 0 : result.body)
|
|
178
|
+
? (0, TypedJsonParse_1.typedJsonParse)(result.body, 'success', 'Failed to parse SendEventsResponse')
|
|
179
|
+
: null;
|
|
180
|
+
return { success: (response === null || response === void 0 ? void 0 : response.success) === true };
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
_sendEventsViaBeacon(events) {
|
|
184
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
185
|
+
return {
|
|
186
|
+
success: yield this._network.beacon({
|
|
187
|
+
sdkKey: this._sdkKey,
|
|
188
|
+
data: {
|
|
189
|
+
events,
|
|
190
|
+
},
|
|
191
|
+
url: this._logEventBeaconUrl,
|
|
192
|
+
}),
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
_saveFailedLogsToStorage(events) {
|
|
197
|
+
while (events.length > MAX_FAILED_LOGS) {
|
|
198
|
+
events.shift();
|
|
251
199
|
}
|
|
252
|
-
|
|
253
|
-
(0, StorageProvider_1.
|
|
200
|
+
const storageKey = this._getStorageKey();
|
|
201
|
+
(0, StorageProvider_1._setObjectInStorage)(storageKey, events).catch(() => {
|
|
254
202
|
Log_1.Log.warn('Unable to save failed logs to storage');
|
|
255
203
|
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
|
|
204
|
+
}
|
|
205
|
+
_retryFailedLogs() {
|
|
206
|
+
const storageKey = this._getStorageKey();
|
|
207
|
+
(() => __awaiter(this, void 0, void 0, function* () {
|
|
208
|
+
const events = yield (0, StorageProvider_1._getObjectFromStorage)(storageKey);
|
|
209
|
+
if (!events) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
yield StorageProvider_1.Storage._removeItem(storageKey);
|
|
213
|
+
yield this._sendEvents(events);
|
|
214
|
+
}))().catch(() => {
|
|
215
|
+
Log_1.Log.warn('Failed to flush stored logs');
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
_getStorageKey() {
|
|
219
|
+
return `statsig.failed_logs.${(0, Hashing_1.DJB2)(this._sdkKey)}`;
|
|
220
|
+
}
|
|
221
|
+
_normalizeAndAppendEvent(event) {
|
|
222
|
+
if (event.user) {
|
|
223
|
+
event.user = Object.assign({}, event.user);
|
|
224
|
+
delete event.user.privateAttributes;
|
|
225
|
+
}
|
|
226
|
+
const extras = {};
|
|
227
|
+
const currentPage = this._getCurrentPageUrl();
|
|
228
|
+
if (currentPage) {
|
|
229
|
+
extras.statsigMetadata = { currentPage };
|
|
230
|
+
}
|
|
231
|
+
this._queue.push(Object.assign(Object.assign({}, event), extras));
|
|
232
|
+
}
|
|
233
|
+
_appendAndResetNonExposedChecks() {
|
|
234
|
+
if (Object.keys(this._nonExposedChecks).length === 0) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
this._normalizeAndAppendEvent({
|
|
238
|
+
eventName: 'statsig::non_exposed_checks',
|
|
239
|
+
user: null,
|
|
240
|
+
time: Date.now(),
|
|
241
|
+
metadata: {
|
|
242
|
+
checks: Object.assign({}, this._nonExposedChecks),
|
|
243
|
+
},
|
|
278
244
|
});
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
245
|
+
this._nonExposedChecks = {};
|
|
246
|
+
}
|
|
247
|
+
_getCurrentPageUrl() {
|
|
248
|
+
var _a;
|
|
249
|
+
if (((_a = this._options) === null || _a === void 0 ? void 0 : _a.includeCurrentPageUrlWithEvents) === false) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (typeof window === 'undefined' || typeof window.location !== 'object') {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
return window.location.href.split(/[?#]/)[0];
|
|
257
|
+
}
|
|
258
|
+
catch (_b) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
285
263
|
exports.EventLogger = EventLogger;
|
package/src/Hashing.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export declare
|
|
1
|
+
export declare const DJB2: (value: string) => string;
|
|
2
|
+
export declare const DJB2Object: (value: Record<string, unknown> | null) => string;
|
package/src/Hashing.js
CHANGED
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DJB2 = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
for (
|
|
7
|
-
|
|
3
|
+
exports.DJB2Object = exports.DJB2 = void 0;
|
|
4
|
+
const DJB2 = (value) => {
|
|
5
|
+
let hash = 0;
|
|
6
|
+
for (let i = 0; i < value.length; i++) {
|
|
7
|
+
const character = value.charCodeAt(i);
|
|
8
8
|
hash = (hash << 5) - hash + character;
|
|
9
9
|
hash = hash & hash; // Convert to 32bit integer
|
|
10
10
|
}
|
|
11
11
|
return String(hash >>> 0);
|
|
12
|
-
}
|
|
12
|
+
};
|
|
13
13
|
exports.DJB2 = DJB2;
|
|
14
|
+
const DJB2Object = (value) => {
|
|
15
|
+
return (0, exports.DJB2)(JSON.stringify(_getSortedObject(value)));
|
|
16
|
+
};
|
|
17
|
+
exports.DJB2Object = DJB2Object;
|
|
18
|
+
const _getSortedObject = (object) => {
|
|
19
|
+
if (object == null) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const keys = Object.keys(object).sort();
|
|
23
|
+
const sortedObject = {};
|
|
24
|
+
keys.forEach((key) => {
|
|
25
|
+
let value = object[key];
|
|
26
|
+
if (value instanceof Object) {
|
|
27
|
+
value = _getSortedObject(value);
|
|
28
|
+
}
|
|
29
|
+
sortedObject[key] = value;
|
|
30
|
+
});
|
|
31
|
+
return sortedObject;
|
|
32
|
+
};
|