@statsig/client-core 3.15.4 → 3.16.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.15.4",
3
+ "version": "3.16.0",
4
4
  "license": "ISC",
5
5
  "homepage": "https://github.com/statsig-io/js-client-monorepo",
6
6
  "repository": {
@@ -1,7 +1,7 @@
1
1
  import { NetworkCore } from './NetworkCore';
2
2
  import { StatsigClientEmitEventFunc } from './StatsigClientBase';
3
3
  import { StatsigEventInternal } from './StatsigEvent';
4
- import { NetworkConfigCommon, StatsigOptionsCommon } from './StatsigOptionsCommon';
4
+ import { LogEventCompressionMode, LoggingEnabledOption, NetworkConfigCommon, StatsigOptionsCommon } from './StatsigOptionsCommon';
5
5
  export declare class EventLogger {
6
6
  private _sdkKey;
7
7
  private _emitter;
@@ -14,12 +14,13 @@ export declare class EventLogger {
14
14
  private _maxQueueSize;
15
15
  private _hasRunQuickFlush;
16
16
  private _creationTime;
17
- private _isLoggingDisabled;
17
+ private _loggingEnabled;
18
18
  private _logEventUrlConfig;
19
19
  private static _safeFlushAndForget;
20
20
  private static _safeRetryFailedLogs;
21
21
  constructor(_sdkKey: string, _emitter: StatsigClientEmitEventFunc, _network: NetworkCore, _options: StatsigOptionsCommon<NetworkConfigCommon> | null);
22
- setLoggingDisabled(isDisabled: boolean): void;
22
+ setLogEventCompressionMode(mode: LogEventCompressionMode): void;
23
+ setLoggingEnabled(loggingEnabled: LoggingEnabledOption): void;
23
24
  enqueue(event: StatsigEventInternal): void;
24
25
  incrementNonExposureCount(name: string): void;
25
26
  reset(): void;
@@ -16,6 +16,7 @@ const Log_1 = require("./Log");
16
16
  const NetworkConfig_1 = require("./NetworkConfig");
17
17
  const SafeJs_1 = require("./SafeJs");
18
18
  const StatsigEvent_1 = require("./StatsigEvent");
19
+ const StatsigOptionsCommon_1 = require("./StatsigOptionsCommon");
19
20
  const StorageProvider_1 = require("./StorageProvider");
20
21
  const UrlConfiguration_1 = require("./UrlConfiguration");
21
22
  const VisibilityObserving_1 = require("./VisibilityObserving");
@@ -42,7 +43,7 @@ class EventLogger {
42
43
  (_a = EVENT_LOGGER_MAP[sdkKey]) === null || _a === void 0 ? void 0 : _a._retryFailedLogs(RetryFailedLogsTrigger.GainedFocus);
43
44
  }
44
45
  constructor(_sdkKey, _emitter, _network, _options) {
45
- var _a;
46
+ var _a, _b;
46
47
  this._sdkKey = _sdkKey;
47
48
  this._emitter = _emitter;
48
49
  this._network = _network;
@@ -52,13 +53,22 @@ class EventLogger {
52
53
  this._nonExposedChecks = {};
53
54
  this._hasRunQuickFlush = false;
54
55
  this._creationTime = Date.now();
55
- this._isLoggingDisabled = (_options === null || _options === void 0 ? void 0 : _options.disableLogging) === true;
56
- this._maxQueueSize = (_a = _options === null || _options === void 0 ? void 0 : _options.loggingBufferMaxSize) !== null && _a !== void 0 ? _a : DEFAULT_QUEUE_SIZE;
56
+ this._loggingEnabled =
57
+ (_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
58
+ ? StatsigOptionsCommon_1.LoggingEnabledOption.disabled
59
+ : StatsigOptionsCommon_1.LoggingEnabledOption.browserOnly);
60
+ if ((_options === null || _options === void 0 ? void 0 : _options.loggingEnabled) && _options.disableLogging !== undefined) {
61
+ Log_1.Log.warn('Detected both loggingEnabled and disableLogging options. loggingEnabled takes precedence - please remove disableLogging.');
62
+ }
63
+ this._maxQueueSize = (_b = _options === null || _options === void 0 ? void 0 : _options.loggingBufferMaxSize) !== null && _b !== void 0 ? _b : DEFAULT_QUEUE_SIZE;
57
64
  const config = _options === null || _options === void 0 ? void 0 : _options.networkConfig;
58
65
  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);
59
66
  }
60
- setLoggingDisabled(isDisabled) {
61
- this._isLoggingDisabled = isDisabled;
67
+ setLogEventCompressionMode(mode) {
68
+ this._network.setLogEventCompressionMode(mode);
69
+ }
70
+ setLoggingEnabled(loggingEnabled) {
71
+ this._loggingEnabled = loggingEnabled;
62
72
  }
63
73
  enqueue(event) {
64
74
  if (!this._shouldLogEvent(event)) {
@@ -79,18 +89,22 @@ class EventLogger {
79
89
  this._lastExposureTimeMap = {};
80
90
  }
81
91
  start() {
82
- if ((0, SafeJs_1._isServerEnv)()) {
83
- return; // do not run in server environments
92
+ var _a;
93
+ const isServerEnv = (0, SafeJs_1._isServerEnv)();
94
+ if (isServerEnv && ((_a = this._options) === null || _a === void 0 ? void 0 : _a.loggingEnabled) !== 'always') {
95
+ return;
84
96
  }
85
97
  EVENT_LOGGER_MAP[this._sdkKey] = this;
86
- (0, VisibilityObserving_1._subscribeToVisiblityChanged)((visibility) => {
87
- if (visibility === 'background') {
88
- EventLogger._safeFlushAndForget(this._sdkKey);
89
- }
90
- else if (visibility === 'foreground') {
91
- EventLogger._safeRetryFailedLogs(this._sdkKey);
92
- }
93
- });
98
+ if (!isServerEnv) {
99
+ (0, VisibilityObserving_1._subscribeToVisiblityChanged)((visibility) => {
100
+ if (visibility === 'background') {
101
+ EventLogger._safeFlushAndForget(this._sdkKey);
102
+ }
103
+ else if (visibility === 'foreground') {
104
+ EventLogger._safeRetryFailedLogs(this._sdkKey);
105
+ }
106
+ });
107
+ }
94
108
  this._retryFailedLogs(RetryFailedLogsTrigger.Startup);
95
109
  this._startBackgroundFlushInterval();
96
110
  }
@@ -130,8 +144,9 @@ class EventLogger {
130
144
  setTimeout(() => EventLogger._safeFlushAndForget(this._sdkKey), QUICK_FLUSH_WINDOW_MS);
131
145
  }
132
146
  _shouldLogEvent(event) {
133
- if ((0, SafeJs_1._isServerEnv)()) {
134
- return false; // do not run in server environments
147
+ var _a;
148
+ if (((_a = this._options) === null || _a === void 0 ? void 0 : _a.loggingEnabled) !== 'always' && (0, SafeJs_1._isServerEnv)()) {
149
+ return false;
135
150
  }
136
151
  if (!(0, StatsigEvent_1._isExposureEvent)(event)) {
137
152
  return true;
@@ -164,7 +179,7 @@ class EventLogger {
164
179
  _sendEvents(events) {
165
180
  var _a, _b;
166
181
  return __awaiter(this, void 0, void 0, function* () {
167
- if (this._isLoggingDisabled) {
182
+ if (this._loggingEnabled === 'disabled') {
168
183
  this._saveFailedLogsToStorage(events);
169
184
  return false;
170
185
  }
@@ -2,7 +2,7 @@ import './$_StatsigGlobal';
2
2
  import { ErrorBoundary } from './ErrorBoundary';
3
3
  import { NetworkPriority } from './NetworkConfig';
4
4
  import { StatsigClientEmitEventFunc } from './StatsigClientBase';
5
- import { AnyStatsigOptions } from './StatsigOptionsCommon';
5
+ import { AnyStatsigOptions, LogEventCompressionMode } from './StatsigOptionsCommon';
6
6
  import { Flatten } from './TypingUtils';
7
7
  import { UrlConfiguration } from './UrlConfiguration';
8
8
  type RequestArgs = {
@@ -37,6 +37,7 @@ export declare class NetworkCore {
37
37
  private _leakyBucket;
38
38
  private _lastUsedInitUrl;
39
39
  constructor(options: AnyStatsigOptions | null, _emitter?: StatsigClientEmitEventFunc | undefined);
40
+ setLogEventCompressionMode(mode: LogEventCompressionMode): void;
40
41
  setErrorBoundary(errorBoundary: ErrorBoundary): void;
41
42
  isBeaconSupported(): boolean;
42
43
  getLastUsedInitUrlAndReset(): string | null;
@@ -44,6 +45,7 @@ export declare class NetworkCore {
44
45
  post(args: RequestArgsWithData): Promise<NetworkResponse | null>;
45
46
  get(args: RequestArgs): Promise<NetworkResponse | null>;
46
47
  private _sendRequest;
48
+ private _getLogEventCompressionMode;
47
49
  private _isRateLimited;
48
50
  private _getPopulatedURL;
49
51
  private _tryEncodeBody;
@@ -23,6 +23,7 @@ const SessionID_1 = require("./SessionID");
23
23
  const StableID_1 = require("./StableID");
24
24
  const StatsigClientEventEmitter_1 = require("./StatsigClientEventEmitter");
25
25
  const StatsigMetadata_1 = require("./StatsigMetadata");
26
+ const StatsigOptionsCommon_1 = require("./StatsigOptionsCommon");
26
27
  const VisibilityObserving_1 = require("./VisibilityObserving");
27
28
  const DEFAULT_TIMEOUT_MS = 10000;
28
29
  const BACKOFF_BASE_MS = 500;
@@ -50,6 +51,10 @@ class NetworkCore {
50
51
  this._timeout = this._netConfig.networkTimeoutMs;
51
52
  }
52
53
  this._fallbackResolver = new NetworkFallbackResolver_1.NetworkFallbackResolver(this._options);
54
+ this.setLogEventCompressionMode(this._getLogEventCompressionMode(options));
55
+ }
56
+ setLogEventCompressionMode(mode) {
57
+ this._options.logEventCompressionMode = mode;
53
58
  }
54
59
  setErrorBoundary(errorBoundary) {
55
60
  this._errorBoundary = errorBoundary;
@@ -172,6 +177,18 @@ class NetworkCore {
172
177
  }
173
178
  });
174
179
  }
180
+ _getLogEventCompressionMode(options) {
181
+ // Handle backward compatibility for deprecated disableCompression flag
182
+ let compressionMode = options === null || options === void 0 ? void 0 : options.logEventCompressionMode;
183
+ if (!compressionMode && (options === null || options === void 0 ? void 0 : options.disableCompression) === true) {
184
+ compressionMode = StatsigOptionsCommon_1.LogEventCompressionMode.Disabled;
185
+ }
186
+ // Default to enabled if unset
187
+ if (!compressionMode) {
188
+ compressionMode = StatsigOptionsCommon_1.LogEventCompressionMode.Enabled;
189
+ }
190
+ return compressionMode;
191
+ }
175
192
  _isRateLimited(endpoint) {
176
193
  var _a;
177
194
  const now = Date.now();
@@ -293,19 +310,28 @@ function _allowCompression(args, options) {
293
310
  if (!args.isCompressable) {
294
311
  return false;
295
312
  }
296
- if (options.disableCompression) {
297
- return false;
298
- }
299
- if ((args.urlConfig.customUrl != null || args.urlConfig.fallbackUrls != null) &&
300
- SDKFlags_1.SDKFlags.get(args.sdkKey, 'enable_log_event_compression') !== true) {
301
- return false;
302
- }
313
+ // Never compress if 'no-compress' is set globally or required APIs are unavailable
303
314
  if ((0, __StatsigGlobal_1._getStatsigGlobalFlag)('no-compress') != null ||
304
315
  typeof CompressionStream === 'undefined' ||
305
316
  typeof TextEncoder === 'undefined') {
306
317
  return false;
307
318
  }
308
- return true;
319
+ const isProxy = args.urlConfig.customUrl != null || args.urlConfig.fallbackUrls != null;
320
+ const flagEnabled = SDKFlags_1.SDKFlags.get(args.sdkKey, 'enable_log_event_compression') === true;
321
+ switch (options.logEventCompressionMode) {
322
+ case StatsigOptionsCommon_1.LogEventCompressionMode.Disabled:
323
+ return false;
324
+ case StatsigOptionsCommon_1.LogEventCompressionMode.Enabled:
325
+ // Only compress through proxy if flag is explicitly on
326
+ if (isProxy && !flagEnabled) {
327
+ return false;
328
+ }
329
+ return true;
330
+ case StatsigOptionsCommon_1.LogEventCompressionMode.Forced:
331
+ return true;
332
+ default:
333
+ return false;
334
+ }
309
335
  }
310
336
  function _getErrorMessage(controller, error) {
311
337
  if ((controller === null || controller === void 0 ? void 0 : controller.signal.aborted) &&
@@ -19,6 +19,7 @@ const MemoKey_1 = require("./MemoKey");
19
19
  const SafeJs_1 = require("./SafeJs");
20
20
  const SessionID_1 = require("./SessionID");
21
21
  const StableID_1 = require("./StableID");
22
+ const StatsigOptionsCommon_1 = require("./StatsigOptionsCommon");
22
23
  const StorageProvider_1 = require("./StorageProvider");
23
24
  const MAX_MEMO_CACHE_SIZE = 3000;
24
25
  class StatsigClientBase {
@@ -59,9 +60,13 @@ class StatsigClientBase {
59
60
  * @param {StatsigRuntimeMutableOptions} options - The configuration options that dictate the runtime behavior of the SDK.
60
61
  */
61
62
  updateRuntimeOptions(options) {
62
- if (options.disableLogging != null) {
63
+ if (options.loggingEnabled) {
64
+ this._options.loggingEnabled = options.loggingEnabled;
65
+ this._logger.setLoggingEnabled(options.loggingEnabled);
66
+ }
67
+ else if (options.disableLogging != null) {
63
68
  this._options.disableLogging = options.disableLogging;
64
- this._logger.setLoggingDisabled(options.disableLogging);
69
+ this._logger.setLoggingEnabled(options.disableLogging ? 'disabled' : 'browser-only');
65
70
  }
66
71
  if (options.disableStorage != null) {
67
72
  this._options.disableStorage = options.disableStorage;
@@ -71,6 +76,12 @@ class StatsigClientBase {
71
76
  this._options.enableCookies = options.enableCookies;
72
77
  StableID_1.StableID._setCookiesEnabled(this._sdkKey, options.enableCookies);
73
78
  }
79
+ if (options.logEventCompressionMode) {
80
+ this._logger.setLogEventCompressionMode(options.logEventCompressionMode);
81
+ }
82
+ else if (options.disableCompression) {
83
+ this._logger.setLogEventCompressionMode(StatsigOptionsCommon_1.LogEventCompressionMode.Disabled);
84
+ }
74
85
  }
75
86
  /**
76
87
  * Flushes any currently queued events.
@@ -1,4 +1,4 @@
1
- export declare const SDK_VERSION = "3.15.4";
1
+ export declare const SDK_VERSION = "3.16.0";
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.15.4';
4
+ exports.SDK_VERSION = '3.16.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
@@ -6,8 +6,18 @@ import { StorageProvider } from './StorageProvider';
6
6
  export type StatsigRuntimeMutableOptions = {
7
7
  /**
8
8
  * Prevents sending any events over the network.
9
+ * @deprecated Set {@link StatsigRuntimeMutableOptions.loggingEnabled} to "disabled" instead
9
10
  */
10
11
  disableLogging?: boolean;
12
+ /**
13
+ * Controls when to enable or disable logging:
14
+ * - "disabled": Prevents sending any events over the network.
15
+ * - "browser-only": Only sends events in browser environments.
16
+ * - "always": Skip browser checks and always logs events
17
+ *
18
+ * @default "browser-only"
19
+ */
20
+ loggingEnabled?: LoggingEnabledOption;
11
21
  /**
12
22
  * Prevents writing anything to storage.
13
23
  *
@@ -15,6 +25,7 @@ export type StatsigRuntimeMutableOptions = {
15
25
  */
16
26
  disableStorage?: boolean;
17
27
  /**
28
+ * @deprecated Use `logEventCompressionMode` instead.
18
29
  * Whether or not Statsig should compress JSON bodies for network requests where possible.
19
30
  *
20
31
  * default: `false`
@@ -24,6 +35,15 @@ export type StatsigRuntimeMutableOptions = {
24
35
  * Opt in cookie usage.
25
36
  */
26
37
  enableCookies?: boolean;
38
+ /**
39
+ * Controls JSON body compression for network requests.
40
+ * - `disabled`: Never compress
41
+ * - `enabled`: Compress unless using a proxy
42
+ * - `forced`: Always compress, even with a proxy
43
+ *
44
+ * default: `enabled`
45
+ */
46
+ logEventCompressionMode?: LogEventCompressionMode;
27
47
  };
28
48
  export type NetworkConfigCommon = {
29
49
  /**
@@ -67,12 +87,6 @@ export type NetworkConfigCommon = {
67
87
  };
68
88
  /** Options for configuring a Statsig client. */
69
89
  export type StatsigOptionsCommon<NetworkConfig extends NetworkConfigCommon> = StatsigRuntimeMutableOptions & {
70
- /**
71
- * Whether or not Statsig should compress JSON bodies for network requests where possible.
72
- *
73
- * default: `false`
74
- */
75
- disableCompression?: boolean;
76
90
  /**
77
91
  * When true, the SDK will not generate a stableID for the user. Useful when bootstrapping from a server without a StableID.
78
92
  *
@@ -149,3 +163,18 @@ export type StatsigEnvironment = {
149
163
  tier?: string;
150
164
  [key: string]: string | undefined;
151
165
  };
166
+ export declare const LogEventCompressionMode: {
167
+ /** Do not compress request bodies */
168
+ readonly Disabled: "d";
169
+ /** Compress request bodies unless a network proxy is configured */
170
+ readonly Enabled: "e";
171
+ /** Always compress request bodies, even when a proxy is configured */
172
+ readonly Forced: "f";
173
+ };
174
+ export type LogEventCompressionMode = (typeof LogEventCompressionMode)[keyof typeof LogEventCompressionMode];
175
+ export declare const LoggingEnabledOption: {
176
+ readonly disabled: "disabled";
177
+ readonly browserOnly: "browser-only";
178
+ readonly always: "always";
179
+ };
180
+ export type LoggingEnabledOption = (typeof LoggingEnabledOption)[keyof typeof LoggingEnabledOption];
@@ -1,2 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoggingEnabledOption = exports.LogEventCompressionMode = void 0;
4
+ exports.LogEventCompressionMode = {
5
+ /** Do not compress request bodies */
6
+ Disabled: 'd',
7
+ /** Compress request bodies unless a network proxy is configured */
8
+ Enabled: 'e',
9
+ /** Always compress request bodies, even when a proxy is configured */
10
+ Forced: 'f',
11
+ };
12
+ exports.LoggingEnabledOption = {
13
+ disabled: 'disabled',
14
+ browserOnly: 'browser-only',
15
+ always: 'always',
16
+ };
@@ -39,15 +39,20 @@ catch (error) {
39
39
  }
40
40
  let _main = _localStorageProvider !== null && _localStorageProvider !== void 0 ? _localStorageProvider : _inMemoryProvider;
41
41
  let _current = _main;
42
- function _inMemoryBreaker(get) {
42
+ function _inMemoryBreaker(action) {
43
43
  try {
44
- return get();
44
+ return action();
45
45
  }
46
46
  catch (error) {
47
47
  if (error instanceof Error && error.name === 'SecurityError') {
48
48
  exports.Storage._setProvider(_inMemoryProvider);
49
49
  return null;
50
50
  }
51
+ if (error instanceof Error && error.name === 'QuotaExceededError') {
52
+ const allKeys = exports.Storage.getAllKeys();
53
+ const statsigKeys = allKeys.filter((key) => key.startsWith('statsig.'));
54
+ error.message = `${error.message}. Statsig Keys: ${statsigKeys.length}`;
55
+ }
51
56
  throw error;
52
57
  }
53
58
  }
@@ -56,7 +61,7 @@ exports.Storage = {
56
61
  isReadyResolver: () => _current.isReadyResolver(),
57
62
  getProviderName: () => _current.getProviderName(),
58
63
  getItem: (key) => _inMemoryBreaker(() => _current.getItem(key)),
59
- setItem: (key, value) => _current.setItem(key, value),
64
+ setItem: (key, value) => _inMemoryBreaker(() => _current.setItem(key, value)),
60
65
  removeItem: (key) => _current.removeItem(key),
61
66
  getAllKeys: () => _current.getAllKeys(),
62
67
  // StorageProviderManagment