@statsig/client-core 3.9.1 → 3.10.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.9.1",
3
+ "version": "3.10.0",
4
4
  "dependencies": {},
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -8,11 +8,12 @@ import { EvaluationsDataAdapter, SpecsDataAdapter } from './StatsigDataAdapter';
8
8
  import { StatsigEvent } from './StatsigEvent';
9
9
  import { AnyStatsigOptions, StatsigRuntimeMutableOptions } from './StatsigOptionsCommon';
10
10
  import { DynamicConfig, Experiment, FeatureGate, Layer, ParameterStore } from './StatsigTypes';
11
+ import { StatsigUpdateDetails } from './StatsigUpdateDetails';
11
12
  import { StatsigUser } from './StatsigUser';
12
13
  import { Flatten } from './TypingUtils';
13
14
  export interface StatsigClientCommonInterface extends StatsigClientEventEmitterInterface {
14
- initializeSync(): void;
15
- initializeAsync(): Promise<void>;
15
+ initializeSync(): StatsigUpdateDetails;
16
+ initializeAsync(): Promise<StatsigUpdateDetails>;
16
17
  shutdown(): Promise<void>;
17
18
  flush(): Promise<void>;
18
19
  updateRuntimeOptions(options: StatsigRuntimeMutableOptions): void;
@@ -45,8 +46,8 @@ export type PrecomputedEvaluationsContext = Flatten<CommonContext & {
45
46
  export interface PrecomputedEvaluationsInterface extends StatsigClientCommonInterface {
46
47
  readonly dataAdapter: EvaluationsDataAdapter;
47
48
  getContext(): PrecomputedEvaluationsContext;
48
- updateUserSync(user: StatsigUser): void;
49
- updateUserAsync(user: StatsigUser): Promise<void>;
49
+ updateUserSync(user: StatsigUser): StatsigUpdateDetails;
50
+ updateUserAsync(user: StatsigUser): Promise<StatsigUpdateDetails>;
50
51
  checkGate(name: string, options?: FeatureGateEvaluationOptions): boolean;
51
52
  getFeatureGate(name: string, options?: FeatureGateEvaluationOptions): FeatureGate;
52
53
  getDynamicConfig(name: string, options?: DynamicConfigEvaluationOptions): DynamicConfig;
@@ -42,7 +42,7 @@ export declare const Diagnostics: {
42
42
  attempt: number;
43
43
  error?: Record<string, unknown> | undefined;
44
44
  };
45
- _enqueueDiagnosticsEvent(user: StatsigUserInternal | null, logger: EventLogger, sdk: string, options: StatsigOptionsCommon<NetworkConfigCommon> | null): void;
45
+ _enqueueDiagnosticsEvent(user: StatsigUserInternal | null, logger: EventLogger, sdk: string, options: StatsigOptionsCommon<NetworkConfigCommon> | null): number;
46
46
  };
47
47
  interface InitializeDataType {
48
48
  process: {
@@ -60,8 +60,9 @@ exports.Diagnostics = {
60
60
  _enqueueDiagnosticsEvent(user, logger, sdk, options) {
61
61
  const markers = exports.Diagnostics._getMarkers(sdk);
62
62
  if (markers == null || markers.length <= 0) {
63
- return;
63
+ return -1;
64
64
  }
65
+ const overallInitDuration = markers[markers.length - 1].timestamp - markers[0].timestamp;
65
66
  exports.Diagnostics._clearMarkers(sdk);
66
67
  const event = _makeDiagnosticsEvent(user, {
67
68
  context: 'initialize',
@@ -69,6 +70,7 @@ exports.Diagnostics = {
69
70
  statsigOptions: options,
70
71
  });
71
72
  logger.enqueue(event);
73
+ return overallInitDuration;
72
74
  },
73
75
  };
74
76
  function _createMarker(data, action, key, step) {
@@ -5,10 +5,13 @@ export declare class ErrorBoundary {
5
5
  private _sdkKey;
6
6
  private _options;
7
7
  private _emitter?;
8
+ private _lastSeenError?;
8
9
  private _seen;
9
- constructor(_sdkKey: string, _options: AnyStatsigOptions | null, _emitter?: StatsigClientEmitEventFunc | undefined);
10
+ constructor(_sdkKey: string, _options: AnyStatsigOptions | null, _emitter?: StatsigClientEmitEventFunc | undefined, _lastSeenError?: Error | undefined);
10
11
  wrap(instance: unknown): void;
11
12
  logError(tag: string, error: unknown): void;
13
+ getLastSeenErrorAndReset(): Error | null;
14
+ attachErrorIfNoneExists(error: unknown): void;
12
15
  private _capture;
13
16
  private _onError;
14
17
  }
@@ -16,10 +16,11 @@ const StatsigMetadata_1 = require("./StatsigMetadata");
16
16
  exports.EXCEPTION_ENDPOINT = 'https://statsigapi.net/v1/sdk_exception';
17
17
  const UNKNOWN_ERROR = '[Statsig] UnknownError';
18
18
  class ErrorBoundary {
19
- constructor(_sdkKey, _options, _emitter) {
19
+ constructor(_sdkKey, _options, _emitter, _lastSeenError) {
20
20
  this._sdkKey = _sdkKey;
21
21
  this._options = _options;
22
22
  this._emitter = _emitter;
23
+ this._lastSeenError = _lastSeenError;
23
24
  this._seen = new Set();
24
25
  }
25
26
  wrap(instance) {
@@ -43,6 +44,17 @@ class ErrorBoundary {
43
44
  logError(tag, error) {
44
45
  this._onError(tag, error);
45
46
  }
47
+ getLastSeenErrorAndReset() {
48
+ const tempError = this._lastSeenError;
49
+ this._lastSeenError = undefined;
50
+ return tempError !== null && tempError !== void 0 ? tempError : null;
51
+ }
52
+ attachErrorIfNoneExists(error) {
53
+ if (this._lastSeenError) {
54
+ return;
55
+ }
56
+ this._lastSeenError = _resolveError(error);
57
+ }
46
58
  _capture(tag, task) {
47
59
  try {
48
60
  const res = task();
@@ -64,6 +76,8 @@ class ErrorBoundary {
64
76
  const unwrapped = (error ? error : Error(UNKNOWN_ERROR));
65
77
  const isError = unwrapped instanceof Error;
66
78
  const name = isError ? unwrapped.name : 'No Name';
79
+ const resolvedError = _resolveError(unwrapped);
80
+ this._lastSeenError = resolvedError;
67
81
  if (this._seen.has(name)) {
68
82
  return;
69
83
  }
@@ -111,6 +125,17 @@ class ErrorBoundary {
111
125
  }
112
126
  }
113
127
  exports.ErrorBoundary = ErrorBoundary;
128
+ function _resolveError(error) {
129
+ if (error instanceof Error) {
130
+ return error;
131
+ }
132
+ else if (typeof error === 'string') {
133
+ return new Error(error);
134
+ }
135
+ else {
136
+ return new Error('An unknown error occurred.');
137
+ }
138
+ }
114
139
  function _getDescription(obj) {
115
140
  try {
116
141
  return JSON.stringify(obj);
@@ -35,12 +35,12 @@ export type EvaluationDetails = {
35
35
  reason: string;
36
36
  lcut?: number;
37
37
  receivedAt?: number;
38
- warnings?: EvaluationWarning[];
38
+ warnings?: StatsigWarnings[];
39
39
  bootstrapMetadata?: BootstrapMetadata;
40
40
  };
41
41
  export type DetailedStoreResult<T extends AnyEvaluation | ParamStoreConfig> = {
42
42
  result: T | null;
43
43
  details: EvaluationDetails;
44
44
  };
45
- export type EvaluationWarning = 'PartialUserMatch' | 'StableIDMismatch';
45
+ export type StatsigWarnings = 'PartialUserMatch' | 'StableIDMismatch' | 'MultipleInitializations' | 'NoCachedValues';
46
46
  export {};
@@ -26,15 +26,17 @@ type NetworkResponse = {
26
26
  };
27
27
  export declare class NetworkCore {
28
28
  private _emitter?;
29
+ protected _errorBoundary: ErrorBoundary | null;
29
30
  private readonly _timeout;
30
31
  private readonly _netConfig;
31
32
  private readonly _options;
32
33
  private readonly _fallbackResolver;
33
34
  private _leakyBucket;
34
- private _errorBoundary;
35
+ private _lastUsedInitUrl;
35
36
  constructor(options: AnyStatsigOptions | null, _emitter?: StatsigClientEmitEventFunc | undefined);
36
37
  setErrorBoundary(errorBoundary: ErrorBoundary): void;
37
38
  isBeaconSupported(): boolean;
39
+ getLastUsedInitUrlAndReset(): string | null;
38
40
  beacon(args: BeaconRequestArgs): Promise<boolean>;
39
41
  post(args: RequestArgsWithData): Promise<NetworkResponse | null>;
40
42
  get(args: RequestArgs): Promise<NetworkResponse | null>;
@@ -33,11 +33,12 @@ const RETRYABLE_CODES = new Set([408, 500, 502, 503, 504, 522, 524, 599]);
33
33
  class NetworkCore {
34
34
  constructor(options, _emitter) {
35
35
  this._emitter = _emitter;
36
+ this._errorBoundary = null;
36
37
  this._timeout = DEFAULT_TIMEOUT_MS;
37
38
  this._netConfig = {};
38
39
  this._options = {};
39
40
  this._leakyBucket = {};
40
- this._errorBoundary = null;
41
+ this._lastUsedInitUrl = null;
41
42
  if (options) {
42
43
  this._options = options;
43
44
  }
@@ -59,6 +60,11 @@ class NetworkCore {
59
60
  return (typeof navigator !== 'undefined' &&
60
61
  typeof navigator.sendBeacon === 'function');
61
62
  }
63
+ getLastUsedInitUrlAndReset() {
64
+ const tempUrl = this._lastUsedInitUrl;
65
+ this._lastUsedInitUrl = null;
66
+ return tempUrl;
67
+ }
62
68
  beacon(args) {
63
69
  return __awaiter(this, void 0, void 0, function* () {
64
70
  if (!_ensureValidSdkKey(args)) {
@@ -86,7 +92,7 @@ class NetworkCore {
86
92
  return this._sendRequest(argsInternal);
87
93
  }
88
94
  _sendRequest(args) {
89
- var _a, _b, _c;
95
+ var _a, _b, _c, _d;
90
96
  return __awaiter(this, void 0, void 0, function* () {
91
97
  if (!_ensureValidSdkKey(args)) {
92
98
  return null;
@@ -157,7 +163,9 @@ class NetworkCore {
157
163
  tag: StatsigClientEventEmitter_1.ErrorTag.NetworkError,
158
164
  requestArgs: args,
159
165
  });
160
- Log_1.Log.error(`A networking error occured during ${method} request to ${populatedUrl}.`, errorMessage, error);
166
+ const formattedErrorMsg = `A networking error occurred during ${method} request to ${populatedUrl}.`;
167
+ Log_1.Log.error(formattedErrorMsg, errorMessage, error);
168
+ (_d = this._errorBoundary) === null || _d === void 0 ? void 0 : _d.attachErrorIfNoneExists(formattedErrorMsg);
161
169
  return null;
162
170
  }
163
171
  yield _exponentialBackoff(currentAttempt);
@@ -187,6 +195,10 @@ class NetworkCore {
187
195
  var _a;
188
196
  return __awaiter(this, void 0, void 0, function* () {
189
197
  const url = (_a = args.fallbackUrl) !== null && _a !== void 0 ? _a : args.urlConfig.getUrl();
198
+ if (args.urlConfig.endpoint === NetworkConfig_1.Endpoint._initialize ||
199
+ args.urlConfig.endpoint === NetworkConfig_1.Endpoint._download_config_specs) {
200
+ this._lastUsedInitUrl = url;
201
+ }
190
202
  const params = Object.assign({ [NetworkConfig_1.NetworkParam.SdkKey]: args.sdkKey, [NetworkConfig_1.NetworkParam.SdkType]: SDKType_1.SDKType._get(args.sdkKey), [NetworkConfig_1.NetworkParam.SdkVersion]: StatsigMetadata_1.SDK_VERSION, [NetworkConfig_1.NetworkParam.Time]: String(Date.now()), [NetworkConfig_1.NetworkParam.SessionID]: SessionID_1.SessionID.get(args.sdkKey) }, args.params);
191
203
  const query = Object.keys(params)
192
204
  .map((key) => {
@@ -8,6 +8,7 @@ import { AnyStatsigClientEvent, StatsigClientEventCallback, StatsigClientEventEm
8
8
  import { DataAdapterResult, EvaluationsDataAdapter, SpecsDataAdapter } from './StatsigDataAdapter';
9
9
  import { StatsigEventInternal } from './StatsigEvent';
10
10
  import { AnyStatsigOptions, StatsigRuntimeMutableOptions } from './StatsigOptionsCommon';
11
+ import { StatsigUpdateDetails } from './StatsigUpdateDetails';
11
12
  import { StorageProvider } from './StorageProvider';
12
13
  export type StatsigClientEmitEventFunc = (event: AnyStatsigClientEvent) => void;
13
14
  export type StatsigContext = {
@@ -25,7 +26,7 @@ export declare abstract class StatsigClientBase<TAdapter extends EvaluationsData
25
26
  protected readonly _options: AnyStatsigOptions;
26
27
  protected readonly _errorBoundary: ErrorBoundary;
27
28
  protected readonly _logger: EventLogger;
28
- protected _initializePromise: Promise<void> | null;
29
+ protected _initializePromise: Promise<StatsigUpdateDetails> | null;
29
30
  protected _memoCache: Record<string, unknown>;
30
31
  private _listeners;
31
32
  constructor(sdkKey: string, adapter: TAdapter, network: NetworkCore, options: AnyStatsigOptions | null);
@@ -1,4 +1,4 @@
1
- export declare const SDK_VERSION = "3.9.1";
1
+ export declare const SDK_VERSION = "3.10.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.9.1';
4
+ exports.SDK_VERSION = '3.10.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
@@ -0,0 +1,14 @@
1
+ import { StatsigWarnings } from './EvaluationTypes';
2
+ import { DataSource } from './StatsigDataAdapter';
3
+ export type StatsigUpdateDetails = {
4
+ duration: number;
5
+ source: DataSource;
6
+ success: boolean;
7
+ error: Error | null;
8
+ sourceUrl: string | null;
9
+ warnings?: StatsigWarnings[];
10
+ };
11
+ export declare const createUpdateDetails: (success: boolean, source: DataSource, initDuration: number, error: Error | null, sourceUrl: string | null, warnings?: StatsigWarnings[]) => StatsigUpdateDetails;
12
+ export declare const UPDATE_DETAIL_ERROR_MESSAGES: {
13
+ NO_NETWORK_DATA: string;
14
+ };
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UPDATE_DETAIL_ERROR_MESSAGES = exports.createUpdateDetails = void 0;
4
+ const createUpdateDetails = (success, source, initDuration, error, sourceUrl, warnings) => {
5
+ return {
6
+ duration: initDuration,
7
+ source,
8
+ success,
9
+ error,
10
+ sourceUrl,
11
+ warnings,
12
+ };
13
+ };
14
+ exports.createUpdateDetails = createUpdateDetails;
15
+ exports.UPDATE_DETAIL_ERROR_MESSAGES = {
16
+ NO_NETWORK_DATA: 'No data was returned from the network. This may be due to a network timeout if a timeout value was specified in the options or ad blocker error.',
17
+ };
package/src/index.d.ts CHANGED
@@ -40,4 +40,5 @@ export * from './TypingUtils';
40
40
  export * from './UrlConfiguration';
41
41
  export * from './UUID';
42
42
  export * from './VisibilityObserving';
43
+ export * from './StatsigUpdateDetails';
43
44
  export { EventLogger, Storage, Log, Diagnostics };
package/src/index.js CHANGED
@@ -62,5 +62,6 @@ __exportStar(require("./TypingUtils"), exports);
62
62
  __exportStar(require("./UrlConfiguration"), exports);
63
63
  __exportStar(require("./UUID"), exports);
64
64
  __exportStar(require("./VisibilityObserving"), exports);
65
+ __exportStar(require("./StatsigUpdateDetails"), exports);
65
66
  __STATSIG__ = Object.assign(Object.assign({}, (__STATSIG__ !== null && __STATSIG__ !== void 0 ? __STATSIG__ : {})), { Log: Log_1.Log,
66
67
  SDK_VERSION: StatsigMetadata_1.SDK_VERSION });