@statsig/client-core 3.31.1-beta.2 → 3.31.1-beta.3
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/package.json +1 -1
- package/src/EventLogger.js +3 -2
- package/src/FlushCoordinator.js +6 -0
- package/src/SessionID.d.ts +3 -3
- package/src/SessionID.js +82 -60
- package/src/StatsigMetadata.d.ts +1 -1
- package/src/StatsigMetadata.js +1 -1
package/package.json
CHANGED
package/src/EventLogger.js
CHANGED
|
@@ -142,16 +142,17 @@ class EventLogger {
|
|
|
142
142
|
if (Object.keys(this._nonExposedChecks).length === 0) {
|
|
143
143
|
return;
|
|
144
144
|
}
|
|
145
|
+
const checks = Object.assign({}, this._nonExposedChecks);
|
|
146
|
+
this._nonExposedChecks = {};
|
|
145
147
|
const event = this._normalizeEvent({
|
|
146
148
|
eventName: 'statsig::non_exposed_checks',
|
|
147
149
|
user: null,
|
|
148
150
|
time: Date.now(),
|
|
149
151
|
metadata: {
|
|
150
|
-
checks
|
|
152
|
+
checks,
|
|
151
153
|
},
|
|
152
154
|
});
|
|
153
155
|
this._flushCoordinator.addEvent(event);
|
|
154
|
-
this._nonExposedChecks = {};
|
|
155
156
|
}
|
|
156
157
|
_shouldLogEvent(event) {
|
|
157
158
|
var _a;
|
package/src/FlushCoordinator.js
CHANGED
|
@@ -17,6 +17,7 @@ const FlushTypes_1 = require("./FlushTypes");
|
|
|
17
17
|
const Hashing_1 = require("./Hashing");
|
|
18
18
|
const Log_1 = require("./Log");
|
|
19
19
|
const NetworkCore_1 = require("./NetworkCore");
|
|
20
|
+
const SessionID_1 = require("./SessionID");
|
|
20
21
|
const StorageProvider_1 = require("./StorageProvider");
|
|
21
22
|
class FlushCoordinator {
|
|
22
23
|
constructor(batchQueue, pendingEvents, onPrepareFlush,
|
|
@@ -50,6 +51,9 @@ class FlushCoordinator {
|
|
|
50
51
|
}
|
|
51
52
|
addEvent(event) {
|
|
52
53
|
this._pendingEvents.addToPendingEventsQueue(event);
|
|
54
|
+
if (this._currentFlushPromise) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
53
57
|
if (this._pendingEvents.hasEventsForFullBatch()) {
|
|
54
58
|
this.processLimitFlush();
|
|
55
59
|
}
|
|
@@ -179,11 +183,13 @@ class FlushCoordinator {
|
|
|
179
183
|
const cooldownDelay = Math.max(0, this._flushInterval.getTimeUntilNextFlush());
|
|
180
184
|
this._cooldownTimer = setTimeout(() => {
|
|
181
185
|
this._cooldownTimer = null;
|
|
186
|
+
SessionID_1.StatsigSession.checkForIdleSession(this._sdkKey);
|
|
182
187
|
this._attemptScheduledFlush();
|
|
183
188
|
}, cooldownDelay);
|
|
184
189
|
const maxIntervalDelay = Math.max(0, this._flushInterval.getTimeTillMaxInterval());
|
|
185
190
|
this._maxIntervalTimer = setTimeout(() => {
|
|
186
191
|
this._maxIntervalTimer = null;
|
|
192
|
+
SessionID_1.StatsigSession.checkForIdleSession(this._sdkKey);
|
|
187
193
|
this._attemptScheduledFlush();
|
|
188
194
|
}, maxIntervalDelay);
|
|
189
195
|
}
|
package/src/SessionID.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
type SessionTimeoutID = ReturnType<typeof setTimeout>;
|
|
2
1
|
type SessionData = {
|
|
3
2
|
sessionID: string;
|
|
4
3
|
startTime: number;
|
|
@@ -7,8 +6,8 @@ type SessionData = {
|
|
|
7
6
|
export type StatsigSession = {
|
|
8
7
|
data: SessionData;
|
|
9
8
|
sdkKey: string;
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
lastPersistedAt: number;
|
|
10
|
+
storageKey: string;
|
|
12
11
|
};
|
|
13
12
|
export declare const SessionID: {
|
|
14
13
|
get: (sdkKey: string) => string;
|
|
@@ -16,5 +15,6 @@ export declare const SessionID: {
|
|
|
16
15
|
export declare const StatsigSession: {
|
|
17
16
|
get: (sdkKey: string, bumpSession?: boolean) => StatsigSession;
|
|
18
17
|
overrideInitialSessionID: (override: string, sdkKey: string) => void;
|
|
18
|
+
checkForIdleSession: (sdkKey: string) => void;
|
|
19
19
|
};
|
|
20
20
|
export {};
|
package/src/SessionID.js
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StatsigSession = exports.SessionID = void 0;
|
|
4
|
-
const __StatsigGlobal_1 = require("./$_StatsigGlobal");
|
|
5
4
|
const CacheKey_1 = require("./CacheKey");
|
|
6
5
|
const Log_1 = require("./Log");
|
|
7
6
|
const StorageProvider_1 = require("./StorageProvider");
|
|
8
7
|
const UUID_1 = require("./UUID");
|
|
8
|
+
const VisibilityObserving_1 = require("./VisibilityObserving");
|
|
9
9
|
const MAX_SESSION_IDLE_TIME = 30 * 60 * 1000; // 30 minutes
|
|
10
10
|
const MAX_SESSION_AGE = 4 * 60 * 60 * 1000; // 4 hours
|
|
11
|
-
const
|
|
11
|
+
const PERSIST_THROTTLE_MS = 15000;
|
|
12
|
+
const SESSION_MAP = {};
|
|
13
|
+
(0, VisibilityObserving_1._subscribeToVisiblityChanged)((visibility) => {
|
|
14
|
+
if (visibility === 'background') {
|
|
15
|
+
Object.values(SESSION_MAP).forEach((session) => _persistNow(session));
|
|
16
|
+
}
|
|
17
|
+
});
|
|
12
18
|
exports.SessionID = {
|
|
13
19
|
get: (sdkKey) => {
|
|
14
20
|
return exports.StatsigSession.get(sdkKey).data.sessionID;
|
|
@@ -16,72 +22,59 @@ exports.SessionID = {
|
|
|
16
22
|
};
|
|
17
23
|
exports.StatsigSession = {
|
|
18
24
|
get: (sdkKey, bumpSession = true) => {
|
|
19
|
-
if (
|
|
20
|
-
|
|
25
|
+
if (SESSION_MAP[sdkKey] == null) {
|
|
26
|
+
SESSION_MAP[sdkKey] = _loadOrCreateSharedSession(sdkKey);
|
|
21
27
|
}
|
|
22
|
-
const session =
|
|
23
|
-
return
|
|
28
|
+
const session = SESSION_MAP[sdkKey];
|
|
29
|
+
return _maybeBumpSession(session, bumpSession);
|
|
24
30
|
},
|
|
25
31
|
overrideInitialSessionID: (override, sdkKey) => {
|
|
26
|
-
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
const session = {
|
|
34
|
+
data: {
|
|
35
|
+
sessionID: override,
|
|
36
|
+
startTime: now,
|
|
37
|
+
lastUpdate: now,
|
|
38
|
+
},
|
|
39
|
+
sdkKey,
|
|
40
|
+
lastPersistedAt: Date.now(),
|
|
41
|
+
storageKey: _getSessionIDStorageKey(sdkKey),
|
|
42
|
+
};
|
|
43
|
+
_persistNow(session);
|
|
44
|
+
SESSION_MAP[sdkKey] = session;
|
|
45
|
+
},
|
|
46
|
+
checkForIdleSession: (sdkKey) => {
|
|
47
|
+
const session = SESSION_MAP[sdkKey];
|
|
48
|
+
if (!session) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const sessionExpired = _checkForExpiredSession(session);
|
|
52
|
+
if (sessionExpired) {
|
|
53
|
+
_persistNow(session);
|
|
54
|
+
}
|
|
27
55
|
},
|
|
28
56
|
};
|
|
29
|
-
function
|
|
30
|
-
let data = _loadFromStorage(sdkKey);
|
|
57
|
+
function _maybeBumpSession(session, allowSessionBump) {
|
|
31
58
|
const now = Date.now();
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
startTime: now,
|
|
36
|
-
lastUpdate: now,
|
|
37
|
-
};
|
|
59
|
+
const sessionExpired = _checkForExpiredSession(session);
|
|
60
|
+
if (sessionExpired) {
|
|
61
|
+
_persistNow(session);
|
|
38
62
|
}
|
|
39
|
-
|
|
40
|
-
data
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function _overrideSessionId(override, sdkKey) {
|
|
45
|
-
const now = Date.now();
|
|
46
|
-
return {
|
|
47
|
-
data: {
|
|
48
|
-
sessionID: override,
|
|
49
|
-
startTime: now,
|
|
50
|
-
lastUpdate: now,
|
|
51
|
-
},
|
|
52
|
-
sdkKey,
|
|
53
|
-
};
|
|
63
|
+
else if (allowSessionBump) {
|
|
64
|
+
session.data.lastUpdate = now;
|
|
65
|
+
_persistThrottled(session);
|
|
66
|
+
}
|
|
67
|
+
return session;
|
|
54
68
|
}
|
|
55
|
-
function
|
|
69
|
+
function _checkForExpiredSession(session) {
|
|
56
70
|
var _a;
|
|
57
|
-
const now = Date.now();
|
|
58
71
|
const data = session.data;
|
|
59
|
-
const sdkKey = session.sdkKey;
|
|
60
72
|
const sessionExpired = _isIdle(data) || _hasRunTooLong(data);
|
|
61
73
|
if (sessionExpired) {
|
|
62
|
-
data
|
|
63
|
-
|
|
74
|
+
session.data = _newSessionData();
|
|
75
|
+
(_a = __STATSIG__ === null || __STATSIG__ === void 0 ? void 0 : __STATSIG__.instance(session.sdkKey)) === null || _a === void 0 ? void 0 : _a.$emt({ name: 'session_expired' });
|
|
64
76
|
}
|
|
65
|
-
|
|
66
|
-
_persistToStorage(data, session.sdkKey);
|
|
67
|
-
clearTimeout(session.idleTimeoutID);
|
|
68
|
-
clearTimeout(session.ageTimeoutID);
|
|
69
|
-
const lifetime = now - data.startTime;
|
|
70
|
-
session.idleTimeoutID = _createSessionTimeout(sdkKey, MAX_SESSION_IDLE_TIME);
|
|
71
|
-
session.ageTimeoutID = _createSessionTimeout(sdkKey, MAX_SESSION_AGE - lifetime);
|
|
72
|
-
if (sessionExpired) {
|
|
73
|
-
(_a = __STATSIG__ === null || __STATSIG__ === void 0 ? void 0 : __STATSIG__.instance(sdkKey)) === null || _a === void 0 ? void 0 : _a.$emt({ name: 'session_expired' });
|
|
74
|
-
}
|
|
75
|
-
return session;
|
|
76
|
-
}
|
|
77
|
-
function _createSessionTimeout(sdkKey, duration) {
|
|
78
|
-
return setTimeout(() => {
|
|
79
|
-
var _a;
|
|
80
|
-
const client = (_a = (0, __StatsigGlobal_1._getStatsigGlobal)()) === null || _a === void 0 ? void 0 : _a.instance(sdkKey);
|
|
81
|
-
if (client) {
|
|
82
|
-
client.$emt({ name: 'session_expired' });
|
|
83
|
-
}
|
|
84
|
-
}, duration);
|
|
77
|
+
return sessionExpired;
|
|
85
78
|
}
|
|
86
79
|
function _isIdle({ lastUpdate }) {
|
|
87
80
|
return Date.now() - lastUpdate > MAX_SESSION_IDLE_TIME;
|
|
@@ -92,16 +85,45 @@ function _hasRunTooLong({ startTime }) {
|
|
|
92
85
|
function _getSessionIDStorageKey(sdkKey) {
|
|
93
86
|
return `statsig.session_id.${(0, CacheKey_1._getStorageKey)(sdkKey)}`;
|
|
94
87
|
}
|
|
95
|
-
function
|
|
96
|
-
const storageKey = _getSessionIDStorageKey(sdkKey);
|
|
88
|
+
function _persistNow(session) {
|
|
97
89
|
try {
|
|
98
|
-
(0, StorageProvider_1._setObjectInStorage)(storageKey, session);
|
|
90
|
+
(0, StorageProvider_1._setObjectInStorage)(session.storageKey, session.data);
|
|
91
|
+
session.lastPersistedAt = Date.now();
|
|
99
92
|
}
|
|
100
93
|
catch (e) {
|
|
101
94
|
Log_1.Log.warn('Failed to save SessionID');
|
|
102
95
|
}
|
|
103
96
|
}
|
|
104
|
-
function
|
|
97
|
+
function _persistThrottled(session) {
|
|
98
|
+
const now = Date.now();
|
|
99
|
+
if (now - session.lastPersistedAt > PERSIST_THROTTLE_MS) {
|
|
100
|
+
_persistNow(session);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function _loadSessionFromStorage(storageKey) {
|
|
104
|
+
const data = (0, StorageProvider_1._getObjectFromStorage)(storageKey);
|
|
105
|
+
return data;
|
|
106
|
+
}
|
|
107
|
+
function _loadOrCreateSharedSession(sdkKey) {
|
|
105
108
|
const storageKey = _getSessionIDStorageKey(sdkKey);
|
|
106
|
-
|
|
109
|
+
const existing = _loadSessionFromStorage(storageKey);
|
|
110
|
+
if (existing &&
|
|
111
|
+
existing.sessionID &&
|
|
112
|
+
existing.startTime &&
|
|
113
|
+
existing.lastUpdate) {
|
|
114
|
+
return { data: existing, sdkKey, lastPersistedAt: 0, storageKey };
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
data: _newSessionData(),
|
|
118
|
+
sdkKey,
|
|
119
|
+
lastPersistedAt: 0,
|
|
120
|
+
storageKey,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function _newSessionData() {
|
|
124
|
+
return {
|
|
125
|
+
sessionID: (0, UUID_1.getUUID)(),
|
|
126
|
+
startTime: Date.now(),
|
|
127
|
+
lastUpdate: Date.now(),
|
|
128
|
+
};
|
|
107
129
|
}
|
package/src/StatsigMetadata.d.ts
CHANGED
package/src/StatsigMetadata.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StatsigMetadataProvider = exports.SDK_VERSION = void 0;
|
|
4
|
-
exports.SDK_VERSION = '3.31.1-beta.
|
|
4
|
+
exports.SDK_VERSION = '3.31.1-beta.3';
|
|
5
5
|
let metadata = {
|
|
6
6
|
sdkVersion: exports.SDK_VERSION,
|
|
7
7
|
sdkType: 'js-mono', // js-mono is overwritten by Precomp and OnDevice clients
|