@statsig/client-core 3.30.1 → 3.30.2-beta.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statsig/client-core",
3
- "version": "3.30.1",
3
+ "version": "3.30.2-beta.1",
4
4
  "license": "ISC",
5
5
  "homepage": "https://github.com/statsig-io/js-client-monorepo",
6
6
  "repository": {
@@ -0,0 +1,14 @@
1
+ import { EventBatch } from './EventBatch';
2
+ import { StatsigEventInternal } from './StatsigEvent';
3
+ export declare class BatchQueue {
4
+ private _batches;
5
+ private _batchSize;
6
+ constructor(batchSize?: number);
7
+ batchSize(): number;
8
+ requeueBatch(batch: EventBatch): number;
9
+ hasFullBatch(): boolean;
10
+ takeNextBatch(): EventBatch | null;
11
+ takeAllBatches(): EventBatch[];
12
+ createBatches(events: StatsigEventInternal[]): number;
13
+ private _enqueueBatch;
14
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BatchQueue = void 0;
4
+ const EventBatch_1 = require("./EventBatch");
5
+ const EventRetryConstants_1 = require("./EventRetryConstants");
6
+ class BatchQueue {
7
+ constructor(batchSize = EventRetryConstants_1.EventRetryConstants.DEFAULT_BATCH_SIZE) {
8
+ this._batches = [];
9
+ this._batchSize = batchSize;
10
+ }
11
+ batchSize() {
12
+ return this._batchSize;
13
+ }
14
+ requeueBatch(batch) {
15
+ return this._enqueueBatch(batch);
16
+ }
17
+ hasFullBatch() {
18
+ return this._batches.some((batch) => batch.events.length >= this._batchSize);
19
+ }
20
+ takeNextBatch() {
21
+ var _a;
22
+ return (_a = this._batches.shift()) !== null && _a !== void 0 ? _a : null;
23
+ }
24
+ takeAllBatches() {
25
+ const batches = this._batches;
26
+ this._batches = [];
27
+ return batches;
28
+ }
29
+ createBatches(events) {
30
+ let i = 0;
31
+ let droppedCount = 0;
32
+ while (i < events.length) {
33
+ const chunk = events.slice(i, i + this._batchSize);
34
+ droppedCount += this._enqueueBatch(new EventBatch_1.EventBatch(chunk));
35
+ i += this._batchSize;
36
+ }
37
+ return droppedCount;
38
+ }
39
+ _enqueueBatch(batch) {
40
+ this._batches.push(batch);
41
+ let droppedEventCount = 0;
42
+ while (this._batches.length > EventRetryConstants_1.EventRetryConstants.MAX_PENDING_BATCHES) {
43
+ const dropped = this._batches.shift();
44
+ if (dropped) {
45
+ droppedEventCount += dropped.events.length;
46
+ }
47
+ }
48
+ return droppedEventCount;
49
+ }
50
+ }
51
+ exports.BatchQueue = BatchQueue;
@@ -10,6 +10,8 @@ export declare class ErrorBoundary {
10
10
  constructor(_sdkKey: string, _options: AnyStatsigOptions | null, _emitter?: StatsigClientEmitEventFunc | undefined, _lastSeenError?: Error | undefined);
11
11
  wrap(instance: unknown, namePrefix?: string): void;
12
12
  logError(tag: string, error: unknown): void;
13
+ logDroppedEvents(count: number, reason: string, metadata?: Record<string, unknown>): void;
14
+ logEventRequestFailure(count: number, reason: string, flushType: string, statusCode: number): void;
13
15
  getLastSeenErrorAndReset(): Error | null;
14
16
  attachErrorIfNoneExists(error: unknown): void;
15
17
  private _capture;
@@ -44,6 +44,25 @@ class ErrorBoundary {
44
44
  logError(tag, error) {
45
45
  this._onError(tag, error);
46
46
  }
47
+ logDroppedEvents(count, reason, metadata) {
48
+ const extra = {
49
+ eventCount: String(count),
50
+ };
51
+ if (metadata) {
52
+ Object.entries(metadata).forEach(([key, value]) => {
53
+ extra[key] = String(value);
54
+ });
55
+ }
56
+ this._onError(`statsig::log_event_dropped_event_count`, new Error(reason), true, extra);
57
+ }
58
+ logEventRequestFailure(count, reason, flushType, statusCode) {
59
+ const extra = {
60
+ eventCount: String(count),
61
+ flushType: flushType,
62
+ statusCode: String(statusCode),
63
+ };
64
+ this._onError(`statsig::log_event_failed`, new Error(reason), true, extra);
65
+ }
47
66
  getLastSeenErrorAndReset() {
48
67
  const tempError = this._lastSeenError;
49
68
  this._lastSeenError = undefined;
@@ -68,7 +87,7 @@ class ErrorBoundary {
68
87
  return null;
69
88
  }
70
89
  }
71
- _onError(tag, error) {
90
+ _onError(tag, error, bypassDedupe = false, extra) {
72
91
  try {
73
92
  Log_1.Log.warn(`Caught error in ${tag}`, { error });
74
93
  const impl = () => __awaiter(this, void 0, void 0, function* () {
@@ -78,7 +97,7 @@ class ErrorBoundary {
78
97
  const name = isError ? unwrapped.name : 'No Name';
79
98
  const resolvedError = _resolveError(unwrapped);
80
99
  this._lastSeenError = resolvedError;
81
- if (this._seen.has(name)) {
100
+ if (!bypassDedupe && this._seen.has(name)) {
82
101
  return;
83
102
  }
84
103
  this._seen.add(name);
@@ -93,7 +112,8 @@ class ErrorBoundary {
93
112
  const sdkType = SDKType_1.SDKType._get(this._sdkKey);
94
113
  const statsigMetadata = StatsigMetadata_1.StatsigMetadataProvider.get();
95
114
  const info = isError ? unwrapped.stack : _getDescription(unwrapped);
96
- const body = Object.assign({ tag, exception: name, info, statsigOptions: _getStatsigOptionLoggingCopy(this._options) }, Object.assign(Object.assign({}, statsigMetadata), { sdkType }));
115
+ const body = Object.assign({ tag, exception: name, info,
116
+ extra, statsigOptions: _getStatsigOptionLoggingCopy(this._options) }, Object.assign(Object.assign({}, statsigMetadata), { sdkType }));
97
117
  const func = (_f = (_e = (_d = this._options) === null || _d === void 0 ? void 0 : _d.networkConfig) === null || _e === void 0 ? void 0 : _e.networkOverrideFunc) !== null && _f !== void 0 ? _f : fetch;
98
118
  yield func(exports.EXCEPTION_ENDPOINT, {
99
119
  method: 'POST',
@@ -0,0 +1,8 @@
1
+ import { StatsigEventInternal } from './StatsigEvent';
2
+ export declare class EventBatch {
3
+ attempts: number;
4
+ readonly events: StatsigEventInternal[];
5
+ readonly createdAt: number;
6
+ constructor(events: StatsigEventInternal[]);
7
+ incrementAttempts(): void;
8
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EventBatch = void 0;
4
+ class EventBatch {
5
+ constructor(events) {
6
+ this.attempts = 0;
7
+ this.createdAt = Date.now();
8
+ this.events = events;
9
+ }
10
+ incrementAttempts() {
11
+ this.attempts++;
12
+ }
13
+ }
14
+ exports.EventBatch = EventBatch;
@@ -1,3 +1,4 @@
1
+ import { ErrorBoundary } from './ErrorBoundary';
1
2
  import { NetworkCore } from './NetworkCore';
2
3
  import { StatsigClientEmitEventFunc } from './StatsigClientBase';
3
4
  import { StatsigEventInternal } from './StatsigEvent';
@@ -7,18 +8,18 @@ export declare class EventLogger {
7
8
  private _emitter;
8
9
  private _network;
9
10
  private _options;
10
- private _queue;
11
- private _flushIntervalId;
11
+ private _errorBoundary;
12
+ private _pendingEvents;
13
+ private _batchQueue;
14
+ private _flushCoordinator;
12
15
  private _lastExposureTimeMap;
13
16
  private _nonExposedChecks;
14
- private _maxQueueSize;
15
- private _hasRunQuickFlush;
16
- private _creationTime;
17
17
  private _loggingEnabled;
18
18
  private _logEventUrlConfig;
19
+ private _isShuttingDown;
20
+ private _storageKey;
19
21
  private static _safeFlushAndForget;
20
- private static _safeRetryFailedLogs;
21
- constructor(_sdkKey: string, _emitter: StatsigClientEmitEventFunc, _network: NetworkCore, _options: StatsigOptionsCommon<NetworkConfigCommon> | null);
22
+ constructor(_sdkKey: string, _emitter: StatsigClientEmitEventFunc, _network: NetworkCore, _options: StatsigOptionsCommon<NetworkConfigCommon> | null, _errorBoundary: ErrorBoundary);
22
23
  setLogEventCompressionMode(mode: LogEventCompressionMode): void;
23
24
  setLoggingEnabled(loggingEnabled: LoggingEnabledOption): void;
24
25
  enqueue(event: StatsigEventInternal): void;
@@ -27,22 +28,12 @@ export declare class EventLogger {
27
28
  start(): void;
28
29
  stop(): Promise<void>;
29
30
  flush(): Promise<void>;
30
- /**
31
- * We 'Quick Flush' following the very first event enqueued
32
- * within the quick flush window
33
- */
34
- private _quickFlushIfNeeded;
31
+ appendAndResetNonExposedChecks(): void;
35
32
  private _shouldLogEvent;
36
- private _sendEvents;
37
- private _sendEventsViaPost;
38
- private _sendEventsViaBeacon;
39
- private _getRequestData;
40
- private _saveFailedLogsToStorage;
41
- private _getFailedLogsFromStorage;
42
- private _retryFailedLogs;
43
- private _getStorageKey;
44
- private _normalizeAndAppendEvent;
45
- private _appendAndResetNonExposedChecks;
46
33
  private _getCurrentPageUrl;
47
- private _startBackgroundFlushInterval;
34
+ private _getStorageKey;
35
+ private _storeEventToStorage;
36
+ private _getEventsFromStorage;
37
+ private _loadStoredEvents;
38
+ private _normalizeEvent;
48
39
  }
@@ -10,22 +10,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.EventLogger = void 0;
13
+ const BatchedEventsQueue_1 = require("./BatchedEventsQueue");
13
14
  const CacheKey_1 = require("./CacheKey");
15
+ const EventRetryConstants_1 = require("./EventRetryConstants");
16
+ const FlushCoordinator_1 = require("./FlushCoordinator");
14
17
  const Hashing_1 = require("./Hashing");
15
18
  const Log_1 = require("./Log");
16
19
  const NetworkConfig_1 = require("./NetworkConfig");
20
+ const PendingEvents_1 = require("./PendingEvents");
17
21
  const SafeJs_1 = require("./SafeJs");
18
22
  const StatsigEvent_1 = require("./StatsigEvent");
19
23
  const StatsigOptionsCommon_1 = require("./StatsigOptionsCommon");
20
24
  const StorageProvider_1 = require("./StorageProvider");
21
25
  const UrlConfiguration_1 = require("./UrlConfiguration");
22
26
  const VisibilityObserving_1 = require("./VisibilityObserving");
23
- const DEFAULT_QUEUE_SIZE = 100;
24
- const DEFAULT_FLUSH_INTERVAL_MS = 10000;
25
27
  const MAX_DEDUPER_KEYS = 1000;
26
28
  const DEDUPER_WINDOW_DURATION_MS = 600000;
27
- const MAX_FAILED_LOGS = 500;
28
- const QUICK_FLUSH_WINDOW_MS = 200;
29
29
  const EVENT_LOGGER_MAP = {};
30
30
  class EventLogger {
31
31
  static _safeFlushAndForget(sdkKey) {
@@ -34,21 +34,17 @@ class EventLogger {
34
34
  // noop
35
35
  });
36
36
  }
37
- static _safeRetryFailedLogs(sdkKey) {
38
- var _a;
39
- (_a = EVENT_LOGGER_MAP[sdkKey]) === null || _a === void 0 ? void 0 : _a._retryFailedLogs();
40
- }
41
- constructor(_sdkKey, _emitter, _network, _options) {
37
+ constructor(_sdkKey, _emitter, _network, _options, _errorBoundary) {
42
38
  var _a, _b;
43
39
  this._sdkKey = _sdkKey;
44
40
  this._emitter = _emitter;
45
41
  this._network = _network;
46
42
  this._options = _options;
47
- this._queue = [];
43
+ this._errorBoundary = _errorBoundary;
48
44
  this._lastExposureTimeMap = {};
49
45
  this._nonExposedChecks = {};
50
- this._hasRunQuickFlush = false;
51
- this._creationTime = Date.now();
46
+ this._isShuttingDown = false;
47
+ this._storageKey = null;
52
48
  this._loggingEnabled =
53
49
  (_a = _options === null || _options === void 0 ? void 0 : _options.loggingEnabled) !== null && _a !== void 0 ? _a : ((_options === null || _options === void 0 ? void 0 : _options.disableLogging) === true
54
50
  ? StatsigOptionsCommon_1.LoggingEnabledOption.disabled
@@ -56,34 +52,45 @@ class EventLogger {
56
52
  if ((_options === null || _options === void 0 ? void 0 : _options.loggingEnabled) && _options.disableLogging !== undefined) {
57
53
  Log_1.Log.warn('Detected both loggingEnabled and disableLogging options. loggingEnabled takes precedence - please remove disableLogging.');
58
54
  }
59
- this._maxQueueSize = (_b = _options === null || _options === void 0 ? void 0 : _options.loggingBufferMaxSize) !== null && _b !== void 0 ? _b : DEFAULT_QUEUE_SIZE;
60
55
  const config = _options === null || _options === void 0 ? void 0 : _options.networkConfig;
61
56
  this._logEventUrlConfig = new UrlConfiguration_1.UrlConfiguration(NetworkConfig_1.Endpoint._rgstr, config === null || config === void 0 ? void 0 : config.logEventUrl, config === null || config === void 0 ? void 0 : config.api, config === null || config === void 0 ? void 0 : config.logEventFallbackUrls);
57
+ const batchSize = (_b = _options === null || _options === void 0 ? void 0 : _options.loggingBufferMaxSize) !== null && _b !== void 0 ? _b : EventRetryConstants_1.EventRetryConstants.DEFAULT_BATCH_SIZE;
58
+ this._pendingEvents = new PendingEvents_1.PendingEvents(batchSize);
59
+ this._batchQueue = new BatchedEventsQueue_1.BatchQueue(batchSize);
60
+ this._flushCoordinator = new FlushCoordinator_1.FlushCoordinator(this._batchQueue, this._pendingEvents, () => this.appendAndResetNonExposedChecks(), this._sdkKey, this._network, this._emitter, this._logEventUrlConfig, this._options, this._loggingEnabled, this._errorBoundary);
62
61
  }
63
62
  setLogEventCompressionMode(mode) {
64
- this._network.setLogEventCompressionMode(mode);
63
+ this._flushCoordinator.setLogEventCompressionMode(mode);
65
64
  }
66
65
  setLoggingEnabled(loggingEnabled) {
67
- if (this._loggingEnabled === 'disabled' && loggingEnabled !== 'disabled') {
68
- // load any pre consented events into memory
69
- const storageKey = this._getStorageKey();
70
- const events = (0, StorageProvider_1._getObjectFromStorage)(storageKey);
71
- if (events) {
72
- this._queue.push(...events);
66
+ const wasDisabled = this._loggingEnabled === 'disabled';
67
+ const isNowEnabled = loggingEnabled !== 'disabled';
68
+ this._loggingEnabled = loggingEnabled;
69
+ this._flushCoordinator.setLoggingEnabled(loggingEnabled);
70
+ if (wasDisabled && isNowEnabled) {
71
+ const events = this._loadStoredEvents();
72
+ Log_1.Log.debug(`Loaded ${events.length} stored event(s) from storage`);
73
+ if (events.length > 0) {
74
+ events.forEach((event) => {
75
+ this._flushCoordinator.addEvent(event);
76
+ });
77
+ this.flush().catch((error) => {
78
+ Log_1.Log.warn('Failed to flush events after enabling logging:', error);
79
+ });
73
80
  }
74
- StorageProvider_1.Storage.removeItem(storageKey);
75
81
  }
76
- this._loggingEnabled = loggingEnabled;
77
82
  }
78
83
  enqueue(event) {
79
84
  if (!this._shouldLogEvent(event)) {
80
85
  return;
81
86
  }
82
- this._normalizeAndAppendEvent(event);
83
- this._quickFlushIfNeeded();
84
- if (this._queue.length > this._maxQueueSize) {
85
- EventLogger._safeFlushAndForget(this._sdkKey);
87
+ const normalizedEvent = this._normalizeEvent(event);
88
+ if (this._loggingEnabled === 'disabled') {
89
+ this._storeEventToStorage(normalizedEvent);
90
+ return;
86
91
  }
92
+ this._flushCoordinator.addEvent(normalizedEvent);
93
+ this._flushCoordinator.checkQuickFlush();
87
94
  }
88
95
  incrementNonExposureCount(name) {
89
96
  var _a;
@@ -110,47 +117,41 @@ class EventLogger {
110
117
  EventLogger._safeFlushAndForget(this._sdkKey);
111
118
  }
112
119
  else if (visibility === 'foreground') {
113
- EventLogger._safeRetryFailedLogs(this._sdkKey);
120
+ this._flushCoordinator.startScheduledFlushCycle();
114
121
  }
115
122
  });
116
123
  }
117
- this._retryFailedLogs();
118
- this._startBackgroundFlushInterval();
124
+ this._flushCoordinator.loadAndRetryShutdownFailedEvents().catch((error) => {
125
+ Log_1.Log.warn('Failed to load failed shutdown events:', error);
126
+ });
127
+ this._flushCoordinator.startScheduledFlushCycle();
119
128
  }
120
129
  stop() {
121
130
  return __awaiter(this, void 0, void 0, function* () {
122
- if (this._flushIntervalId) {
123
- clearInterval(this._flushIntervalId);
124
- this._flushIntervalId = null;
125
- }
131
+ this._isShuttingDown = true;
132
+ yield this._flushCoordinator.processShutdown();
126
133
  delete EVENT_LOGGER_MAP[this._sdkKey];
127
- yield this.flush();
128
134
  });
129
135
  }
130
136
  flush() {
131
137
  return __awaiter(this, void 0, void 0, function* () {
132
- this._appendAndResetNonExposedChecks();
133
- if (this._queue.length === 0) {
134
- return;
135
- }
136
- const events = this._queue;
137
- this._queue = [];
138
- yield this._sendEvents(events);
138
+ return this._flushCoordinator.processManualFlush();
139
139
  });
140
140
  }
141
- /**
142
- * We 'Quick Flush' following the very first event enqueued
143
- * within the quick flush window
144
- */
145
- _quickFlushIfNeeded() {
146
- if (this._hasRunQuickFlush) {
147
- return;
148
- }
149
- this._hasRunQuickFlush = true;
150
- if (Date.now() - this._creationTime > QUICK_FLUSH_WINDOW_MS) {
141
+ appendAndResetNonExposedChecks() {
142
+ if (Object.keys(this._nonExposedChecks).length === 0) {
151
143
  return;
152
144
  }
153
- setTimeout(() => EventLogger._safeFlushAndForget(this._sdkKey), QUICK_FLUSH_WINDOW_MS);
145
+ const event = this._normalizeEvent({
146
+ eventName: 'statsig::non_exposed_checks',
147
+ user: null,
148
+ time: Date.now(),
149
+ metadata: {
150
+ checks: Object.assign({}, this._nonExposedChecks),
151
+ },
152
+ });
153
+ this._flushCoordinator.addEvent(event);
154
+ this._nonExposedChecks = {};
154
155
  }
155
156
  _shouldLogEvent(event) {
156
157
  var _a;
@@ -185,118 +186,54 @@ class EventLogger {
185
186
  this._lastExposureTimeMap[key] = now;
186
187
  return true;
187
188
  }
188
- _sendEvents(events) {
189
- return __awaiter(this, void 0, void 0, function* () {
190
- var _a, _b;
191
- if (this._loggingEnabled === 'disabled') {
192
- this._saveFailedLogsToStorage(events);
193
- return false;
194
- }
195
- try {
196
- const isClosing = (0, VisibilityObserving_1._isUnloading)();
197
- const shouldUseBeacon = isClosing &&
198
- this._network.isBeaconSupported() &&
199
- ((_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.networkConfig) === null || _b === void 0 ? void 0 : _b.networkOverrideFunc) == null;
200
- this._emitter({
201
- name: 'pre_logs_flushed',
202
- events,
203
- });
204
- const response = shouldUseBeacon
205
- ? this._sendEventsViaBeacon(events)
206
- : yield this._sendEventsViaPost(events);
207
- if (response.success) {
208
- this._emitter({
209
- name: 'logs_flushed',
210
- events,
211
- });
212
- return true;
213
- }
214
- else {
215
- Log_1.Log.warn('Failed to flush events.');
216
- this._saveFailedLogsToStorage(events);
217
- return false;
218
- }
219
- }
220
- catch (_c) {
221
- Log_1.Log.warn('Failed to flush events.');
222
- return false;
223
- }
224
- });
225
- }
226
- _sendEventsViaPost(events) {
227
- return __awaiter(this, void 0, void 0, function* () {
228
- var _a;
229
- const result = yield this._network.post(this._getRequestData(events));
230
- const code = (_a = result === null || result === void 0 ? void 0 : result.code) !== null && _a !== void 0 ? _a : -1;
231
- return { success: code >= 200 && code < 300 };
232
- });
233
- }
234
- _sendEventsViaBeacon(events) {
235
- return {
236
- success: this._network.beacon(this._getRequestData(events)),
237
- };
238
- }
239
- _getRequestData(events) {
240
- return {
241
- sdkKey: this._sdkKey,
242
- data: {
243
- events,
244
- },
245
- urlConfig: this._logEventUrlConfig,
246
- retries: 3,
247
- isCompressable: true,
248
- params: {
249
- [NetworkConfig_1.NetworkParam.EventCount]: String(events.length),
250
- },
251
- credentials: 'same-origin',
252
- };
189
+ _getCurrentPageUrl() {
190
+ var _a;
191
+ if (((_a = this._options) === null || _a === void 0 ? void 0 : _a.includeCurrentPageUrlWithEvents) === false) {
192
+ return;
193
+ }
194
+ return (0, SafeJs_1._getCurrentPageUrlSafe)();
253
195
  }
254
- _saveFailedLogsToStorage(events) {
255
- while (events.length > MAX_FAILED_LOGS) {
256
- events.shift();
196
+ _getStorageKey() {
197
+ if (!this._storageKey) {
198
+ this._storageKey = `statsig.pending_events.${(0, Hashing_1._DJB2)(this._sdkKey)}`;
257
199
  }
200
+ return this._storageKey;
201
+ }
202
+ _storeEventToStorage(event) {
258
203
  const storageKey = this._getStorageKey();
259
204
  try {
260
- const savedEvents = this._getFailedLogsFromStorage(storageKey);
261
- (0, StorageProvider_1._setObjectInStorage)(storageKey, [...savedEvents, ...events]);
205
+ let existingEvents = this._getEventsFromStorage(storageKey);
206
+ existingEvents.push(event);
207
+ if (existingEvents.length > EventRetryConstants_1.EventRetryConstants.MAX_LOCAL_STORAGE) {
208
+ existingEvents = existingEvents.slice(-EventRetryConstants_1.EventRetryConstants.MAX_LOCAL_STORAGE);
209
+ }
210
+ (0, StorageProvider_1._setObjectInStorage)(storageKey, existingEvents);
262
211
  }
263
- catch (_a) {
264
- Log_1.Log.warn('Unable to save failed logs to storage');
212
+ catch (error) {
213
+ Log_1.Log.warn('Unable to save events to storage');
265
214
  }
266
215
  }
267
- _getFailedLogsFromStorage(storageKey) {
268
- let savedEvents = [];
216
+ _getEventsFromStorage(storageKey) {
269
217
  try {
270
- const retrieved = (0, StorageProvider_1._getObjectFromStorage)(storageKey);
271
- if (Array.isArray(retrieved)) {
272
- savedEvents = retrieved;
218
+ const events = (0, StorageProvider_1._getObjectFromStorage)(storageKey);
219
+ if (Array.isArray(events)) {
220
+ return events;
273
221
  }
274
- return savedEvents;
222
+ return [];
275
223
  }
276
224
  catch (_a) {
277
225
  return [];
278
226
  }
279
227
  }
280
- _retryFailedLogs() {
228
+ _loadStoredEvents() {
281
229
  const storageKey = this._getStorageKey();
282
- (() => __awaiter(this, void 0, void 0, function* () {
283
- if (!StorageProvider_1.Storage.isReady()) {
284
- yield StorageProvider_1.Storage.isReadyResolver();
285
- }
286
- const events = (0, StorageProvider_1._getObjectFromStorage)(storageKey);
287
- if (!events) {
288
- return;
289
- }
230
+ const events = this._getEventsFromStorage(storageKey);
231
+ if (events.length > 0) {
290
232
  StorageProvider_1.Storage.removeItem(storageKey);
291
- yield this._sendEvents(events);
292
- }))().catch(() => {
293
- Log_1.Log.warn('Failed to flush stored logs');
294
- });
295
- }
296
- _getStorageKey() {
297
- return `statsig.failed_logs.${(0, Hashing_1._DJB2)(this._sdkKey)}`;
233
+ }
234
+ return events;
298
235
  }
299
- _normalizeAndAppendEvent(event) {
236
+ _normalizeEvent(event) {
300
237
  if (event.user) {
301
238
  event.user = Object.assign({}, event.user);
302
239
  delete event.user.privateAttributes;
@@ -306,44 +243,7 @@ class EventLogger {
306
243
  if (currentPage) {
307
244
  extras.statsigMetadata = { currentPage };
308
245
  }
309
- const final = Object.assign(Object.assign({}, event), extras);
310
- Log_1.Log.debug('Enqueued Event:', final);
311
- this._queue.push(final);
312
- }
313
- _appendAndResetNonExposedChecks() {
314
- if (Object.keys(this._nonExposedChecks).length === 0) {
315
- return;
316
- }
317
- this._normalizeAndAppendEvent({
318
- eventName: 'statsig::non_exposed_checks',
319
- user: null,
320
- time: Date.now(),
321
- metadata: {
322
- checks: Object.assign({}, this._nonExposedChecks),
323
- },
324
- });
325
- this._nonExposedChecks = {};
326
- }
327
- _getCurrentPageUrl() {
328
- var _a;
329
- if (((_a = this._options) === null || _a === void 0 ? void 0 : _a.includeCurrentPageUrlWithEvents) === false) {
330
- return;
331
- }
332
- return (0, SafeJs_1._getCurrentPageUrlSafe)();
333
- }
334
- _startBackgroundFlushInterval() {
335
- var _a, _b;
336
- const flushInterval = (_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.loggingIntervalMs) !== null && _b !== void 0 ? _b : DEFAULT_FLUSH_INTERVAL_MS;
337
- const intervalId = setInterval(() => {
338
- const logger = EVENT_LOGGER_MAP[this._sdkKey];
339
- if (!logger || logger._flushIntervalId !== intervalId) {
340
- clearInterval(intervalId);
341
- }
342
- else {
343
- EventLogger._safeFlushAndForget(this._sdkKey);
344
- }
345
- }, flushInterval);
346
- this._flushIntervalId = intervalId;
246
+ return Object.assign(Object.assign({}, event), extras);
347
247
  }
348
248
  }
349
249
  exports.EventLogger = EventLogger;
@@ -0,0 +1,9 @@
1
+ export declare const EventRetryConstants: {
2
+ readonly MAX_RETRY_ATTEMPTS: 5;
3
+ readonly DEFAULT_BATCH_SIZE: 100;
4
+ readonly MAX_PENDING_BATCHES: 10;
5
+ readonly TICK_INTERVAL_MS: 1000;
6
+ readonly QUICK_FLUSH_WINDOW_MS: 200;
7
+ readonly MAX_LOCAL_STORAGE: 500;
8
+ readonly MAX_QUEUED_EVENTS: number;
9
+ };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EventRetryConstants = void 0;
4
+ exports.EventRetryConstants = {
5
+ MAX_RETRY_ATTEMPTS: 5,
6
+ DEFAULT_BATCH_SIZE: 100,
7
+ MAX_PENDING_BATCHES: 10,
8
+ TICK_INTERVAL_MS: 1000,
9
+ QUICK_FLUSH_WINDOW_MS: 200,
10
+ MAX_LOCAL_STORAGE: 500,
11
+ get MAX_QUEUED_EVENTS() {
12
+ return this.DEFAULT_BATCH_SIZE * this.MAX_PENDING_BATCHES;
13
+ },
14
+ };
@@ -0,0 +1,23 @@
1
+ import { EventBatch } from './EventBatch';
2
+ import { NetworkCore } from './NetworkCore';
3
+ import { StatsigClientEmitEventFunc } from './StatsigClientBase';
4
+ import { LogEventCompressionMode, LoggingEnabledOption, NetworkConfigCommon, StatsigOptionsCommon } from './StatsigOptionsCommon';
5
+ import { UrlConfiguration } from './UrlConfiguration';
6
+ export declare class EventSender {
7
+ private _network;
8
+ private _sdkKey;
9
+ private _options;
10
+ private _logEventUrlConfig;
11
+ private _emitter;
12
+ private _loggingEnabled;
13
+ constructor(sdkKey: string, network: NetworkCore, emitter: StatsigClientEmitEventFunc, logEventUrlConfig: UrlConfiguration, options: StatsigOptionsCommon<NetworkConfigCommon> | null, loggingEnabled: LoggingEnabledOption);
14
+ setLogEventCompressionMode(mode: LogEventCompressionMode): void;
15
+ setLoggingEnabled(enabled: LoggingEnabledOption): void;
16
+ sendBatch(batch: EventBatch): Promise<{
17
+ success: boolean;
18
+ statusCode: number;
19
+ }>;
20
+ private _sendEventsViaPost;
21
+ private _sendEventsViaBeacon;
22
+ private _getRequestData;
23
+ }