@statsig/client-core 3.31.1 → 3.31.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statsig/client-core",
3
- "version": "3.31.1",
3
+ "version": "3.31.2",
4
4
  "license": "ISC",
5
5
  "homepage": "https://github.com/statsig-io/js-client-monorepo",
6
6
  "repository": {
@@ -15,6 +15,7 @@ const Hashing_1 = require("./Hashing");
15
15
  const Log_1 = require("./Log");
16
16
  const NetworkConfig_1 = require("./NetworkConfig");
17
17
  const SafeJs_1 = require("./SafeJs");
18
+ const SessionID_1 = require("./SessionID");
18
19
  const StatsigEvent_1 = require("./StatsigEvent");
19
20
  const StatsigOptionsCommon_1 = require("./StatsigOptionsCommon");
20
21
  const StorageProvider_1 = require("./StorageProvider");
@@ -341,6 +342,7 @@ class EventLogger {
341
342
  }
342
343
  else {
343
344
  EventLogger._safeFlushAndForget(this._sdkKey);
345
+ SessionID_1.StatsigSession.checkForIdleSession(this._sdkKey);
344
346
  }
345
347
  }, flushInterval);
346
348
  this._flushIntervalId = intervalId;
@@ -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
- ageTimeoutID?: SessionTimeoutID;
11
- idleTimeoutID?: SessionTimeoutID;
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 PROMISE_MAP = {};
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 (PROMISE_MAP[sdkKey] == null) {
20
- PROMISE_MAP[sdkKey] = _loadSession(sdkKey);
25
+ if (SESSION_MAP[sdkKey] == null) {
26
+ SESSION_MAP[sdkKey] = _loadOrCreateSharedSession(sdkKey);
21
27
  }
22
- const session = PROMISE_MAP[sdkKey];
23
- return bumpSession ? _bumpSession(session) : session;
28
+ const session = SESSION_MAP[sdkKey];
29
+ return _maybeBumpSession(session, bumpSession);
24
30
  },
25
31
  overrideInitialSessionID: (override, sdkKey) => {
26
- PROMISE_MAP[sdkKey] = _overrideSessionId(override, sdkKey);
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 _loadSession(sdkKey) {
30
- let data = _loadFromStorage(sdkKey);
57
+ function _maybeBumpSession(session, allowSessionBump) {
31
58
  const now = Date.now();
32
- if (!data) {
33
- data = {
34
- sessionID: (0, UUID_1.getUUID)(),
35
- startTime: now,
36
- lastUpdate: now,
37
- };
59
+ const sessionExpired = _checkForExpiredSession(session);
60
+ if (sessionExpired) {
61
+ _persistNow(session);
38
62
  }
39
- return {
40
- data,
41
- sdkKey,
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 _bumpSession(session) {
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.sessionID = (0, UUID_1.getUUID)();
63
- data.startTime = now;
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
- data.lastUpdate = now;
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 _persistToStorage(session, sdkKey) {
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 _loadFromStorage(sdkKey) {
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
- return (0, StorageProvider_1._getObjectFromStorage)(storageKey);
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
  }
@@ -1,4 +1,4 @@
1
- export declare const SDK_VERSION = "3.31.1";
1
+ export declare const SDK_VERSION = "3.31.2";
2
2
  export type StatsigMetadata = {
3
3
  readonly [key: string]: string | undefined | null;
4
4
  readonly appVersion?: string;
@@ -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';
4
+ exports.SDK_VERSION = '3.31.2';
5
5
  let metadata = {
6
6
  sdkVersion: exports.SDK_VERSION,
7
7
  sdkType: 'js-mono', // js-mono is overwritten by Precomp and OnDevice clients