@statsig/client-core 3.0.0-beta.5 → 3.1.0

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.0.0-beta.5",
3
+ "version": "3.1.0",
4
4
  "dependencies": {},
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -1,3 +1,4 @@
1
+ import { StatsigUser } from './StatsigUser';
1
2
  export type SpecCondition = {
2
3
  type: string;
3
4
  targetValue: unknown;
@@ -38,4 +39,6 @@ export type DownloadConfigSpecsResponse = {
38
39
  layer_configs: Spec[];
39
40
  time: number;
40
41
  has_updates: boolean;
42
+ sdkInfo?: Record<string, string>;
43
+ user?: StatsigUser;
41
44
  };
@@ -1,4 +1,5 @@
1
1
  import { ParamStoreConfig } from './ParamStoreTypes';
2
+ import { BootstrapMetadata } from './StatsigEvent';
2
3
  import { Flatten } from './TypingUtils';
3
4
  type EvaluationBase<T> = {
4
5
  id_type: string;
@@ -32,9 +33,12 @@ export type EvaluationDetails = {
32
33
  reason: string;
33
34
  lcut?: number;
34
35
  receivedAt?: number;
36
+ warnings?: EvaluationWarning[];
37
+ bootstrapMetadata?: BootstrapMetadata;
35
38
  };
36
39
  export type DetailedStoreResult<T extends AnyEvaluation | ParamStoreConfig> = {
37
40
  result: T | null;
38
41
  details: EvaluationDetails;
39
42
  };
43
+ export type EvaluationWarning = 'PartialUserMatch' | 'StableIDMismatch';
40
44
  export {};
@@ -16,6 +16,8 @@ export declare class EventLogger {
16
16
  private _creationTime;
17
17
  private _isLoggingDisabled;
18
18
  private _logEventUrl;
19
+ private static _safeFlushAndForget;
20
+ private static _safeRetryFailedLogs;
19
21
  constructor(_sdkKey: string, _emitter: StatsigClientEmitEventFunc, _network: NetworkCore, _options: StatsigOptionsCommon<NetworkConfigCommon> | null);
20
22
  setLoggingDisabled(isDisabled: boolean): void;
21
23
  enqueue(event: StatsigEventInternal): void;
@@ -26,13 +26,22 @@ const DEDUPER_WINDOW_DURATION_MS = 60000;
26
26
  const MAX_FAILED_LOGS = 500;
27
27
  const QUICK_FLUSH_WINDOW_MS = 200;
28
28
  const EVENT_LOGGER_MAP = {};
29
- const _safeFlushAndForget = (sdkKey) => {
30
- var _a;
31
- (_a = EVENT_LOGGER_MAP[sdkKey]) === null || _a === void 0 ? void 0 : _a.flush().catch(() => {
32
- // noop
33
- });
34
- };
29
+ var RetryFailedLogsTrigger;
30
+ (function (RetryFailedLogsTrigger) {
31
+ RetryFailedLogsTrigger[RetryFailedLogsTrigger["Startup"] = 0] = "Startup";
32
+ RetryFailedLogsTrigger[RetryFailedLogsTrigger["GainedFocus"] = 1] = "GainedFocus";
33
+ })(RetryFailedLogsTrigger || (RetryFailedLogsTrigger = {}));
35
34
  class EventLogger {
35
+ static _safeFlushAndForget(sdkKey) {
36
+ var _a;
37
+ (_a = EVENT_LOGGER_MAP[sdkKey]) === null || _a === void 0 ? void 0 : _a.flush().catch(() => {
38
+ // noop
39
+ });
40
+ }
41
+ static _safeRetryFailedLogs(sdkKey) {
42
+ var _a;
43
+ (_a = EVENT_LOGGER_MAP[sdkKey]) === null || _a === void 0 ? void 0 : _a._retryFailedLogs(RetryFailedLogsTrigger.GainedFocus);
44
+ }
36
45
  constructor(_sdkKey, _emitter, _network, _options) {
37
46
  var _a;
38
47
  this._sdkKey = _sdkKey;
@@ -59,7 +68,7 @@ class EventLogger {
59
68
  this._normalizeAndAppendEvent(event);
60
69
  this._quickFlushIfNeeded();
61
70
  if (this._queue.length > this._maxQueueSize) {
62
- _safeFlushAndForget(this._sdkKey);
71
+ EventLogger._safeFlushAndForget(this._sdkKey);
63
72
  }
64
73
  }
65
74
  incrementNonExposureCount(name) {
@@ -77,10 +86,13 @@ class EventLogger {
77
86
  EVENT_LOGGER_MAP[this._sdkKey] = this;
78
87
  (0, VisibilityObserving_1._subscribeToVisiblityChanged)((visibility) => {
79
88
  if (visibility === 'background') {
80
- _safeFlushAndForget(this._sdkKey);
89
+ EventLogger._safeFlushAndForget(this._sdkKey);
90
+ }
91
+ else if (visibility === 'foreground') {
92
+ EventLogger._safeRetryFailedLogs(this._sdkKey);
81
93
  }
82
94
  });
83
- this._retryFailedLogs();
95
+ this._retryFailedLogs(RetryFailedLogsTrigger.Startup);
84
96
  this._startBackgroundFlushInterval();
85
97
  }
86
98
  stop() {
@@ -100,7 +112,7 @@ class EventLogger {
100
112
  }
101
113
  const events = this._queue;
102
114
  this._queue = [];
103
- return this._sendEvents(events);
115
+ yield this._sendEvents(events);
104
116
  });
105
117
  }
106
118
  /**
@@ -115,7 +127,7 @@ class EventLogger {
115
127
  if (Date.now() - this._creationTime > QUICK_FLUSH_WINDOW_MS) {
116
128
  return;
117
129
  }
118
- setTimeout(() => _safeFlushAndForget(this._sdkKey), QUICK_FLUSH_WINDOW_MS);
130
+ setTimeout(() => EventLogger._safeFlushAndForget(this._sdkKey), QUICK_FLUSH_WINDOW_MS);
119
131
  }
120
132
  _shouldLogEvent(event) {
121
133
  if ((0, SafeJs_1._isServerEnv)()) {
@@ -150,7 +162,7 @@ class EventLogger {
150
162
  return __awaiter(this, void 0, void 0, function* () {
151
163
  if (this._isLoggingDisabled) {
152
164
  this._saveFailedLogsToStorage(events);
153
- return;
165
+ return false;
154
166
  }
155
167
  try {
156
168
  const isInBackground = !(0, VisibilityObserving_1._isCurrentlyVisible)();
@@ -165,13 +177,17 @@ class EventLogger {
165
177
  name: 'logs_flushed',
166
178
  events,
167
179
  });
180
+ return true;
168
181
  }
169
182
  else {
183
+ Log_1.Log.warn('Failed to flush events.');
170
184
  this._saveFailedLogsToStorage(events);
185
+ return false;
171
186
  }
172
187
  }
173
188
  catch (_c) {
174
189
  Log_1.Log.warn('Failed to flush events.');
190
+ return false;
175
191
  }
176
192
  });
177
193
  }
@@ -216,7 +232,7 @@ class EventLogger {
216
232
  Log_1.Log.warn('Unable to save failed logs to storage');
217
233
  }
218
234
  }
219
- _retryFailedLogs() {
235
+ _retryFailedLogs(trigger) {
220
236
  const storageKey = this._getStorageKey();
221
237
  (() => __awaiter(this, void 0, void 0, function* () {
222
238
  if (!StorageProvider_1.Storage.isReady()) {
@@ -226,8 +242,13 @@ class EventLogger {
226
242
  if (!events) {
227
243
  return;
228
244
  }
229
- StorageProvider_1.Storage.removeItem(storageKey);
230
- yield this._sendEvents(events);
245
+ if (trigger === RetryFailedLogsTrigger.Startup) {
246
+ StorageProvider_1.Storage.removeItem(storageKey);
247
+ }
248
+ const isSuccess = yield this._sendEvents(events);
249
+ if (isSuccess && trigger === RetryFailedLogsTrigger.GainedFocus) {
250
+ StorageProvider_1.Storage.removeItem(storageKey);
251
+ }
231
252
  }))().catch(() => {
232
253
  Log_1.Log.warn('Failed to flush stored logs');
233
254
  });
@@ -279,7 +300,7 @@ class EventLogger {
279
300
  clearInterval(intervalId);
280
301
  }
281
302
  else {
282
- _safeFlushAndForget(this._sdkKey);
303
+ EventLogger._safeFlushAndForget(this._sdkKey);
283
304
  }
284
305
  }, flushInterval);
285
306
  this._flushIntervalId = intervalId;
@@ -20,6 +20,7 @@ export type InitializeResponseWithUpdates = SessionReplayFields & AutoCaptureFie
20
20
  hash_used: 'none' | 'sha256' | 'djb2';
21
21
  derived_fields?: Record<string, unknown>;
22
22
  user?: StatsigUser;
23
+ sdkInfo?: Record<string, string>;
23
24
  };
24
25
  export type InitializeResponse = InitializeResponseWithUpdates | {
25
26
  has_updates: false;
package/src/Log.js CHANGED
@@ -22,22 +22,22 @@ var LogLevel;
22
22
  class Log {
23
23
  static info(...args) {
24
24
  if (this.level >= LogLevel.Info) {
25
- console.info('\x1b[34m%s\x1b[0m', _INFO, ...addTag(args));
25
+ console.info(_INFO, ...addTag(args));
26
26
  }
27
27
  }
28
28
  static debug(...args) {
29
29
  if (this.level >= LogLevel.Debug) {
30
- console.debug('\x1b[32m%s\x1b[0m', DEBUG, ...addTag(args));
30
+ console.debug(DEBUG, ...addTag(args));
31
31
  }
32
32
  }
33
33
  static warn(...args) {
34
34
  if (this.level >= LogLevel.Warn) {
35
- console.warn('\x1b[33m%s\x1b[0m', _WARN, ...addTag(args));
35
+ console.warn(_WARN, ...addTag(args));
36
36
  }
37
37
  }
38
38
  static error(...args) {
39
39
  if (this.level >= LogLevel.Error) {
40
- console.error('\x1b[31m%s\x1b[0m', ERROR, ...addTag(args));
40
+ console.error(ERROR, ...addTag(args));
41
41
  }
42
42
  }
43
43
  }
@@ -15,6 +15,7 @@ type EventNameToEventDataMap = {
15
15
  events: Record<string, unknown>[];
16
16
  };
17
17
  pre_shutdown: object;
18
+ initialization_failure: object;
18
19
  gate_evaluation: {
19
20
  gate: FeatureGate;
20
21
  };
@@ -29,9 +29,10 @@ export type DataAdapterAsyncOptions = {
29
29
  export type DataAdapterSyncOptions = {
30
30
  /**
31
31
  * The flag to disable background cache refresh.
32
- * If set to true, the cache will not be updated in the background and will only use the data adatpter values.
32
+ * If set to true, a network request to update the cache for future sessions will not fired.
33
+ * if "explicitly" set to false, a network request to update the cache for future sessions will be fired, even in bootstrap cases.
33
34
  *
34
- * default: false
35
+ * default: implicit false
35
36
  */
36
37
  readonly disableBackgroundCacheRefresh?: boolean;
37
38
  };
@@ -8,6 +8,11 @@ export type StatsigEvent = {
8
8
  [key: string]: string | undefined;
9
9
  } | null;
10
10
  };
11
+ export type BootstrapMetadata = {
12
+ generatorSDKInfo?: Record<string, string>;
13
+ lcut?: number;
14
+ user?: Record<string, unknown>;
15
+ };
11
16
  export type StatsigEventInternal = Omit<StatsigEvent, 'metadata'> & {
12
17
  user: StatsigUserInternal | null;
13
18
  time: number;
@@ -5,6 +5,9 @@ const CONFIG_EXPOSURE_NAME = 'statsig::config_exposure';
5
5
  const GATE_EXPOSURE_NAME = 'statsig::gate_exposure';
6
6
  const LAYER_EXPOSURE_NAME = 'statsig::layer_exposure';
7
7
  const _createExposure = (eventName, user, details, metadata, secondaryExposures) => {
8
+ if (details.bootstrapMetadata) {
9
+ metadata['bootstrapMetadata'] = details.bootstrapMetadata;
10
+ }
8
11
  return {
9
12
  eventName,
10
13
  user,
@@ -1,4 +1,4 @@
1
- export declare const SDK_VERSION = "3.0.0-beta.5";
1
+ export declare const SDK_VERSION = "3.1.0";
2
2
  export type StatsigMetadata = {
3
3
  readonly [key: string]: string | undefined;
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.0.0-beta.5';
4
+ exports.SDK_VERSION = '3.1.0';
5
5
  let metadata = {
6
6
  sdkVersion: exports.SDK_VERSION,
7
7
  sdkType: 'js-mono', // js-mono is overwritten by Precomp and OnDevice clients