@statsig/client-core 1.6.0 → 1.8.0-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": "1.6.0",
3
+ "version": "1.8.0-beta.1",
4
4
  "dependencies": {},
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -21,18 +21,14 @@ export type CommonContext = {
21
21
  sdkKey: string;
22
22
  options: AnyStatsigOptions;
23
23
  errorBoundary: ErrorBoundary;
24
- };
25
- export type AsyncCommonContext = {
26
24
  session: StatsigSession;
27
25
  stableID: string;
28
26
  };
29
27
  export type OnDeviceEvaluationsContext = CommonContext & {
30
28
  values: DownloadConfigSpecsResponse | null;
31
29
  };
32
- export type OnDeviceEvaluationsAsyncContext = OnDeviceEvaluationsContext & AsyncCommonContext;
33
30
  export interface OnDeviceEvaluationsInterface extends StatsigClientCommonInterface {
34
31
  readonly dataAdapter: SpecsDataAdapter;
35
- getAsyncContext(): Promise<OnDeviceEvaluationsAsyncContext>;
36
32
  getContext(): OnDeviceEvaluationsContext;
37
33
  checkGate(name: string, user: StatsigUser, options?: FeatureGateEvaluationOptions): boolean;
38
34
  getFeatureGate(name: string, user: StatsigUser, options?: FeatureGateEvaluationOptions): FeatureGate;
@@ -46,10 +42,8 @@ export type PrecomputedEvaluationsContext = Flatten<CommonContext & {
46
42
  values: InitializeResponseWithUpdates | null;
47
43
  user: StatsigUser;
48
44
  }>;
49
- export type PrecomputedEvaluationsAsyncContext = Flatten<AsyncCommonContext & PrecomputedEvaluationsContext>;
50
45
  export interface PrecomputedEvaluationsInterface extends StatsigClientCommonInterface {
51
46
  readonly dataAdapter: EvaluationsDataAdapter;
52
- getAsyncContext(): Promise<PrecomputedEvaluationsAsyncContext>;
53
47
  getContext(): PrecomputedEvaluationsContext;
54
48
  updateUserSync(user: StatsigUser): void;
55
49
  updateUserAsync(user: StatsigUser): Promise<void>;
@@ -118,7 +118,7 @@ class DataAdapterCore {
118
118
  }
119
119
  _loadFromCache(cacheKey) {
120
120
  var _a;
121
- const cache = (_a = StorageProvider_1.Storage._getItemSync) === null || _a === void 0 ? void 0 : _a.call(StorageProvider_1.Storage, cacheKey);
121
+ const cache = (_a = StorageProvider_1.Storage._getItem) === null || _a === void 0 ? void 0 : _a.call(StorageProvider_1.Storage, cacheKey);
122
122
  if (cache == null) {
123
123
  return null;
124
124
  }
@@ -1,3 +1,67 @@
1
- export declare abstract class Diagnostics {
2
- static mark(): void;
1
+ import { EvaluationDetails } from './EvaluationTypes';
2
+ import { EventLogger } from './EventLogger';
3
+ import { NetworkConfigCommon, StatsigOptionsCommon } from './StatsigOptionsCommon';
4
+ import { StatsigUserInternal } from './StatsigUser';
5
+ export type KeyType = 'initialize' | 'overall';
6
+ export type StepType = 'process' | 'network_request';
7
+ export type ActionType = 'start' | 'end';
8
+ export interface Marker {
9
+ key: KeyType;
10
+ action: ActionType;
11
+ timestamp: number;
12
+ step?: StepType;
13
+ statusCode?: number;
14
+ success?: boolean;
15
+ url?: string;
16
+ idListCount?: number;
17
+ sdkRegion?: string | null;
18
+ markerID?: string;
19
+ attempt?: number;
20
+ isRetry?: boolean;
21
+ configName?: string;
22
+ message?: string | null;
23
+ evaluationDetails?: EvaluationDetails;
24
+ error?: Record<string, unknown>;
25
+ isDelta?: boolean;
3
26
  }
27
+ export declare const Diagnostics: {
28
+ _getMarkers: (sdkKey: string) => Marker[] | undefined;
29
+ _markInitOverallStart: (sdkKey: string) => void;
30
+ _markInitOverallEnd: (sdkKey: string, success: boolean, evaluationDetails?: EvaluationDetails) => void;
31
+ _markInitNetworkReqStart: (sdkKey: string, data: InitializeDataType['networkRequest']['start']) => void;
32
+ _markInitNetworkReqEnd: (sdkKey: string, data: InitializeDataType['networkRequest']['end']) => void;
33
+ _markInitProcessStart: (sdkKey: string) => void;
34
+ _markInitProcessEnd: (sdkKey: string, data: InitializeDataType['process']['end']) => void;
35
+ _clearMarkers: (sdkKey: string) => void;
36
+ _formatError(e: unknown): Record<string, unknown> | undefined;
37
+ _getDiagnosticsData(res: Response | null, attempt: number, body: string, e?: unknown): {
38
+ success: boolean;
39
+ isDelta?: boolean | undefined;
40
+ sdkRegion?: string | null | undefined;
41
+ statusCode?: number | undefined;
42
+ attempt: number;
43
+ error?: Record<string, unknown> | undefined;
44
+ };
45
+ _enqueueDiagnosticsEvent(user: StatsigUserInternal | null, logger: EventLogger, sdk: string, options: StatsigOptionsCommon<NetworkConfigCommon> | null): void;
46
+ };
47
+ interface InitializeDataType {
48
+ process: {
49
+ end: {
50
+ success: boolean;
51
+ };
52
+ };
53
+ networkRequest: {
54
+ start: {
55
+ attempt: number;
56
+ };
57
+ end: {
58
+ success: boolean;
59
+ attempt: number;
60
+ isDelta?: boolean;
61
+ sdkRegion?: string | null;
62
+ statusCode?: number;
63
+ error?: Record<string, unknown>;
64
+ };
65
+ };
66
+ }
67
+ export {};
@@ -1,9 +1,98 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Diagnostics = void 0;
4
- class Diagnostics {
5
- static mark() {
6
- //
4
+ const MARKER_MAP = new Map();
5
+ const ACT_START = 'start';
6
+ const ACT_END = 'end';
7
+ const DIAGNOSTICS_EVENT = 'statsig::diagnostics';
8
+ exports.Diagnostics = {
9
+ _getMarkers: (sdkKey) => {
10
+ return MARKER_MAP.get(sdkKey);
11
+ },
12
+ _markInitOverallStart: (sdkKey) => {
13
+ _addMarker(sdkKey, _createMarker({}, ACT_START));
14
+ },
15
+ _markInitOverallEnd: (sdkKey, success, evaluationDetails) => {
16
+ _addMarker(sdkKey, _createMarker({
17
+ success,
18
+ error: success
19
+ ? undefined
20
+ : { name: 'InitializeError', message: 'Failed to initialize' },
21
+ evaluationDetails,
22
+ }, ACT_END));
23
+ },
24
+ _markInitNetworkReqStart: (sdkKey, data) => {
25
+ _addMarker(sdkKey, _createMarker(data, ACT_START));
26
+ },
27
+ _markInitNetworkReqEnd: (sdkKey, data) => {
28
+ _addMarker(sdkKey, _createMarker(data, ACT_END));
29
+ },
30
+ _markInitProcessStart: (sdkKey) => {
31
+ _addMarker(sdkKey, _createMarker({}, ACT_START));
32
+ },
33
+ _markInitProcessEnd: (sdkKey, data) => {
34
+ _addMarker(sdkKey, _createMarker(data, ACT_END));
35
+ },
36
+ _clearMarkers: (sdkKey) => {
37
+ MARKER_MAP.delete(sdkKey);
38
+ },
39
+ _formatError(e) {
40
+ if (!(e && typeof e === 'object')) {
41
+ return;
42
+ }
43
+ return {
44
+ code: _safeGetField(e, 'code'),
45
+ name: _safeGetField(e, 'name'),
46
+ message: _safeGetField(e, 'message'),
47
+ };
48
+ },
49
+ _getDiagnosticsData(res, attempt, body, e) {
50
+ var _a;
51
+ return {
52
+ success: (res === null || res === void 0 ? void 0 : res.ok) === true,
53
+ statusCode: res === null || res === void 0 ? void 0 : res.status,
54
+ sdkRegion: (_a = res === null || res === void 0 ? void 0 : res.headers) === null || _a === void 0 ? void 0 : _a.get('x-statsig-region'),
55
+ isDelta: body.includes('"is_delta":true') === true ? true : undefined,
56
+ attempt,
57
+ error: exports.Diagnostics._formatError(e),
58
+ };
59
+ },
60
+ _enqueueDiagnosticsEvent(user, logger, sdk, options) {
61
+ const markers = exports.Diagnostics._getMarkers(sdk);
62
+ if (markers == null || markers.length <= 0) {
63
+ return;
64
+ }
65
+ exports.Diagnostics._clearMarkers(sdk);
66
+ const event = _makeDiagnosticsEvent(user, {
67
+ context: 'initialize',
68
+ markers: markers.slice(),
69
+ statsigOptions: options,
70
+ });
71
+ logger.enqueue(event);
72
+ },
73
+ };
74
+ function _createMarker(data, action) {
75
+ return Object.assign({ key: 'initialize', action: action, timestamp: Date.now() }, data);
76
+ }
77
+ function _makeDiagnosticsEvent(user, data) {
78
+ const latencyEvent = {
79
+ eventName: DIAGNOSTICS_EVENT,
80
+ user,
81
+ value: null,
82
+ metadata: data,
83
+ time: Date.now(),
84
+ };
85
+ return latencyEvent;
86
+ }
87
+ function _addMarker(sdkKey, marker) {
88
+ var _a;
89
+ const markers = (_a = MARKER_MAP.get(sdkKey)) !== null && _a !== void 0 ? _a : [];
90
+ markers.push(marker);
91
+ MARKER_MAP.set(sdkKey, markers);
92
+ }
93
+ function _safeGetField(data, field) {
94
+ if (field in data) {
95
+ return data[field];
7
96
  }
97
+ return undefined;
8
98
  }
9
- exports.Diagnostics = Diagnostics;
@@ -21,7 +21,8 @@ export declare class EventLogger {
21
21
  enqueue(event: StatsigEventInternal): void;
22
22
  incrementNonExposureCount(name: string): void;
23
23
  reset(): void;
24
- shutdown(): Promise<void>;
24
+ start(): void;
25
+ stop(): Promise<void>;
25
26
  flush(): Promise<void>;
26
27
  /**
27
28
  * We 'Quick Flush' following the very first event enqueued
@@ -10,6 +10,7 @@ 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 CacheKey_1 = require("./CacheKey");
13
14
  const Hashing_1 = require("./Hashing");
14
15
  const Log_1 = require("./Log");
15
16
  const NetworkConfig_1 = require("./NetworkConfig");
@@ -43,18 +44,10 @@ class EventLogger {
43
44
  this._nonExposedChecks = {};
44
45
  this._hasRunQuickFlush = false;
45
46
  this._creationTime = Date.now();
46
- EVENT_LOGGER_MAP[_sdkKey] = this;
47
47
  this._isLoggingDisabled = (_options === null || _options === void 0 ? void 0 : _options.disableLogging) === true;
48
48
  this._maxQueueSize = (_a = _options === null || _options === void 0 ? void 0 : _options.loggingBufferMaxSize) !== null && _a !== void 0 ? _a : DEFAULT_QUEUE_SIZE;
49
49
  const config = _options === null || _options === void 0 ? void 0 : _options.networkConfig;
50
50
  this._logEventUrl = (0, UrlOverrides_1._getOverridableUrl)(config === null || config === void 0 ? void 0 : config.logEventUrl, config === null || config === void 0 ? void 0 : config.api, '/rgstr', NetworkConfig_1.NetworkDefault.eventsApi);
51
- (0, VisibilityObserving_1._subscribeToVisiblityChanged)((visibility) => {
52
- if (visibility === 'background') {
53
- _safeFlushAndForget(_sdkKey);
54
- }
55
- });
56
- this._retryFailedLogs();
57
- this._startBackgroundFlushInterval();
58
51
  }
59
52
  setLoggingDisabled(isDisabled) {
60
53
  this._isLoggingDisabled = isDisabled;
@@ -77,7 +70,20 @@ class EventLogger {
77
70
  reset() {
78
71
  this._lastExposureTimeMap = {};
79
72
  }
80
- shutdown() {
73
+ start() {
74
+ if ((0, SafeJs_1._isServerEnv)()) {
75
+ return; // do not run in server environments
76
+ }
77
+ EVENT_LOGGER_MAP[this._sdkKey] = this;
78
+ (0, VisibilityObserving_1._subscribeToVisiblityChanged)((visibility) => {
79
+ if (visibility === 'background') {
80
+ _safeFlushAndForget(this._sdkKey);
81
+ }
82
+ });
83
+ this._retryFailedLogs();
84
+ this._startBackgroundFlushInterval();
85
+ }
86
+ stop() {
81
87
  return __awaiter(this, void 0, void 0, function* () {
82
88
  if (this._flushIntervalId) {
83
89
  clearInterval(this._flushIntervalId);
@@ -112,14 +118,18 @@ class EventLogger {
112
118
  setTimeout(() => _safeFlushAndForget(this._sdkKey), QUICK_FLUSH_WINDOW_MS);
113
119
  }
114
120
  _shouldLogEvent(event) {
121
+ if ((0, SafeJs_1._isServerEnv)()) {
122
+ return false; // do not run in server environments
123
+ }
115
124
  if (!(0, StatsigEvent_1._isExposureEvent)(event)) {
116
125
  return true;
117
126
  }
118
127
  const user = event.user ? event.user : { statsigEnvironment: undefined };
128
+ const userKey = (0, CacheKey_1._getUserStorageKey)(this._sdkKey, user);
119
129
  const metadata = event.metadata ? event.metadata : {};
120
130
  const key = [
121
131
  event.eventName,
122
- user.userID,
132
+ userKey,
123
133
  metadata['gate'],
124
134
  metadata['config'],
125
135
  metadata['ruleID'],
@@ -199,18 +209,21 @@ class EventLogger {
199
209
  events.shift();
200
210
  }
201
211
  const storageKey = this._getStorageKey();
202
- (0, StorageProvider_1._setObjectInStorage)(storageKey, events).catch(() => {
212
+ try {
213
+ (0, StorageProvider_1._setObjectInStorage)(storageKey, events);
214
+ }
215
+ catch (_a) {
203
216
  Log_1.Log.warn('Unable to save failed logs to storage');
204
- });
217
+ }
205
218
  }
206
219
  _retryFailedLogs() {
207
220
  const storageKey = this._getStorageKey();
208
221
  (() => __awaiter(this, void 0, void 0, function* () {
209
- const events = yield (0, StorageProvider_1._getObjectFromStorage)(storageKey);
222
+ const events = (0, StorageProvider_1._getObjectFromStorage)(storageKey);
210
223
  if (!events) {
211
224
  return;
212
225
  }
213
- yield StorageProvider_1.Storage._removeItem(storageKey);
226
+ StorageProvider_1.Storage._removeItem(storageKey);
214
227
  yield this._sendEvents(events);
215
228
  }))().catch(() => {
216
229
  Log_1.Log.warn('Failed to flush stored logs');
@@ -256,9 +269,6 @@ class EventLogger {
256
269
  }
257
270
  _startBackgroundFlushInterval() {
258
271
  var _a, _b;
259
- if ((0, SafeJs_1._isServerEnv)()) {
260
- return; // do not run in server environments
261
- }
262
272
  const flushInterval = (_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.loggingIntervalMs) !== null && _b !== void 0 ? _b : DEFAULT_FLUSH_INTERVAL_MS;
263
273
  const intervalId = setInterval(() => {
264
274
  const logger = EVENT_LOGGER_MAP[this._sdkKey];
@@ -5,7 +5,12 @@ type SessionReplayFields = {
5
5
  can_record_session?: boolean;
6
6
  session_recording_rate?: number;
7
7
  };
8
- export type InitializeResponseWithUpdates = SessionReplayFields & {
8
+ type AutoCaptureFields = {
9
+ auto_capture_settings?: {
10
+ disabled_events: Record<string, boolean>;
11
+ };
12
+ };
13
+ export type InitializeResponseWithUpdates = SessionReplayFields & AutoCaptureFields & {
9
14
  feature_gates: Record<string, GateEvaluation>;
10
15
  dynamic_configs: Record<string, DynamicConfigEvaluation>;
11
16
  layer_configs: Record<string, LayerEvaluation>;
@@ -8,6 +8,8 @@ type RequestArgs = {
8
8
  url: string;
9
9
  priority?: NetworkPriority;
10
10
  retries?: number;
11
+ attempt?: number;
12
+ isInitialize?: boolean;
11
13
  params?: Record<string, string>;
12
14
  headers?: Record<string, string>;
13
15
  };
@@ -16,7 +18,7 @@ export type RequestArgsWithData = Flatten<RequestArgs & {
16
18
  isStatsigEncodable?: boolean;
17
19
  isCompressable?: boolean;
18
20
  }>;
19
- type BeaconRequestArgs = Pick<RequestArgsWithData, 'data' | 'sdkKey' | 'url' | 'params' | 'isCompressable'>;
21
+ type BeaconRequestArgs = Pick<RequestArgsWithData, 'data' | 'sdkKey' | 'url' | 'params' | 'isCompressable' | 'attempt'>;
20
22
  type NetworkResponse = {
21
23
  body: string | null;
22
24
  code: number;
@@ -26,6 +28,7 @@ export declare class NetworkCore {
26
28
  private readonly _timeout;
27
29
  private readonly _netConfig;
28
30
  private readonly _options;
31
+ private _proxy;
29
32
  constructor(options: AnyStatsigOptions | null, _emitter?: StatsigClientEmitEventFunc | undefined);
30
33
  post(args: RequestArgsWithData): Promise<NetworkResponse | null>;
31
34
  get(args: RequestArgs): Promise<NetworkResponse | null>;
@@ -35,5 +38,6 @@ export declare class NetworkCore {
35
38
  private _getPopulatedURL;
36
39
  private _getPopulatedBody;
37
40
  private _attemptToEncodeString;
41
+ private _getNetworkProxyArgs;
38
42
  }
39
43
  export {};
@@ -15,6 +15,7 @@ const __StatsigGlobal_1 = require("./$_StatsigGlobal");
15
15
  const Diagnostics_1 = require("./Diagnostics");
16
16
  const Log_1 = require("./Log");
17
17
  const NetworkConfig_1 = require("./NetworkConfig");
18
+ const NetworkProxy_1 = require("./NetworkProxy");
18
19
  const SDKType_1 = require("./SDKType");
19
20
  const SafeJs_1 = require("./SafeJs");
20
21
  const SessionID_1 = require("./SessionID");
@@ -22,6 +23,7 @@ const StableID_1 = require("./StableID");
22
23
  const StatsigMetadata_1 = require("./StatsigMetadata");
23
24
  const VisibilityObserving_1 = require("./VisibilityObserving");
24
25
  const DEFAULT_TIMEOUT_MS = 10000;
26
+ const RETRYABLE_CODES = new Set([408, 500, 502, 503, 504, 522, 524, 599]);
25
27
  class NetworkCore {
26
28
  constructor(options, _emitter) {
27
29
  this._emitter = _emitter;
@@ -37,14 +39,16 @@ class NetworkCore {
37
39
  if (this._netConfig.networkTimeoutMs) {
38
40
  this._timeout = this._netConfig.networkTimeoutMs;
39
41
  }
42
+ this._proxy = new NetworkProxy_1.NetworkProxy(this._options);
40
43
  }
41
44
  post(args) {
42
45
  return __awaiter(this, void 0, void 0, function* () {
43
- let body = yield this._getPopulatedBody(args);
46
+ const proxyConfigArgs = this._getNetworkProxyArgs(args);
47
+ let body = yield this._getPopulatedBody(Object.assign(Object.assign({}, args), proxyConfigArgs));
44
48
  if (args.isStatsigEncodable) {
45
49
  body = this._attemptToEncodeString(args, body);
46
50
  }
47
- return this._sendRequest(Object.assign({ method: 'POST', body }, args));
51
+ return this._sendRequest(Object.assign(Object.assign({ method: 'POST', body }, proxyConfigArgs), args));
48
52
  });
49
53
  }
50
54
  get(args) {
@@ -59,14 +63,15 @@ class NetworkCore {
59
63
  if (!_ensureValidSdkKey(args)) {
60
64
  return false;
61
65
  }
62
- const body = yield this._getPopulatedBody(args);
63
- const url = yield this._getPopulatedURL(args);
66
+ const networkProxyArgs = this._getNetworkProxyArgs(args);
67
+ const body = yield this._getPopulatedBody(Object.assign(Object.assign({}, args), networkProxyArgs));
68
+ const url = yield this._getPopulatedURL(Object.assign(Object.assign({}, args), networkProxyArgs));
64
69
  const nav = navigator;
65
70
  return nav.sendBeacon.bind(nav)(url, body);
66
71
  });
67
72
  }
68
73
  _sendRequest(args) {
69
- var _a, _b;
74
+ var _a, _b, _c, _d;
70
75
  return __awaiter(this, void 0, void 0, function* () {
71
76
  if (!_ensureValidSdkKey(args)) {
72
77
  return null;
@@ -74,10 +79,14 @@ class NetworkCore {
74
79
  if (this._netConfig.preventAllNetworkTraffic) {
75
80
  return null;
76
81
  }
77
- const { method, body, retries } = args;
82
+ const { method, body, retries, attempt } = args;
83
+ const currentAttempt = attempt !== null && attempt !== void 0 ? attempt : 1;
78
84
  const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
79
- const handle = setTimeout(() => controller === null || controller === void 0 ? void 0 : controller.abort(`Timeout of ${this._timeout}ms expired.`), this._timeout);
80
- const url = yield this._getPopulatedURL(args);
85
+ const handle = setTimeout(() => {
86
+ controller === null || controller === void 0 ? void 0 : controller.abort(`Timeout of ${this._timeout}ms expired.`);
87
+ }, this._timeout);
88
+ const proxyUrl = (_a = args.proxyUrl) !== null && _a !== void 0 ? _a : this._proxy.getProxyUrl(args.sdkKey, args.url);
89
+ const url = yield this._getPopulatedURL(Object.assign({ proxyUrl }, args));
81
90
  let response = null;
82
91
  const keepalive = (0, VisibilityObserving_1._isUnloading)();
83
92
  try {
@@ -89,7 +98,12 @@ class NetworkCore {
89
98
  priority: args.priority,
90
99
  keepalive,
91
100
  };
92
- const func = (_a = this._netConfig.networkOverrideFunc) !== null && _a !== void 0 ? _a : fetch;
101
+ if (args.isInitialize) {
102
+ Diagnostics_1.Diagnostics._markInitNetworkReqStart(args.sdkKey, {
103
+ attempt: currentAttempt,
104
+ });
105
+ }
106
+ const func = (_b = this._netConfig.networkOverrideFunc) !== null && _b !== void 0 ? _b : fetch;
93
107
  response = yield func(url, config);
94
108
  clearTimeout(handle);
95
109
  if (!response.ok) {
@@ -99,7 +113,9 @@ class NetworkCore {
99
113
  throw err;
100
114
  }
101
115
  const text = yield response.text();
102
- Diagnostics_1.Diagnostics.mark();
116
+ if (args.isInitialize) {
117
+ Diagnostics_1.Diagnostics._markInitNetworkReqEnd(args.sdkKey, Diagnostics_1.Diagnostics._getDiagnosticsData(response, currentAttempt, text));
118
+ }
103
119
  return {
104
120
  body: text,
105
121
  code: response.status,
@@ -107,25 +123,33 @@ class NetworkCore {
107
123
  }
108
124
  catch (error) {
109
125
  const errorMessage = _getErrorMessage(controller, error);
110
- Diagnostics_1.Diagnostics.mark();
111
- if (!retries || retries <= 0) {
112
- (_b = this._emitter) === null || _b === void 0 ? void 0 : _b.call(this, { name: 'error', error });
126
+ const timedOut = _didTimeout(controller);
127
+ if (args.isInitialize) {
128
+ Diagnostics_1.Diagnostics._markInitNetworkReqEnd(args.sdkKey, Diagnostics_1.Diagnostics._getDiagnosticsData(response, currentAttempt, '', error));
129
+ }
130
+ yield this._proxy.attemptToUpdateProxyUrl(args.sdkKey, errorMessage, timedOut);
131
+ if (!retries ||
132
+ currentAttempt > retries ||
133
+ !RETRYABLE_CODES.has((_c = response === null || response === void 0 ? void 0 : response.status) !== null && _c !== void 0 ? _c : 500)) {
134
+ (_d = this._emitter) === null || _d === void 0 ? void 0 : _d.call(this, { name: 'error', error });
113
135
  Log_1.Log.error(`A networking error occured during ${method} request to ${url}.`, errorMessage, error);
114
136
  return null;
115
137
  }
116
- return this._sendRequest(Object.assign(Object.assign({}, args), { retries: retries - 1 }));
138
+ return this._sendRequest(Object.assign(Object.assign({}, args), { retries: retries, attempt: currentAttempt + 1 }));
117
139
  }
118
140
  });
119
141
  }
120
142
  _getPopulatedURL(args) {
143
+ var _a;
121
144
  return __awaiter(this, void 0, void 0, function* () {
145
+ const url = (_a = args.proxyUrl) !== null && _a !== void 0 ? _a : args.url;
122
146
  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]: yield SessionID_1.SessionID.get(args.sdkKey) }, args.params);
123
147
  const query = Object.keys(params)
124
148
  .map((key) => {
125
149
  return `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`;
126
150
  })
127
151
  .join('&');
128
- return `${args.url}${query ? `?${query}` : ''}`;
152
+ return `${url}${query ? `?${query}` : ''}`;
129
153
  });
130
154
  }
131
155
  _getPopulatedBody(args) {
@@ -136,7 +160,7 @@ class NetworkCore {
136
160
  const sdkType = SDKType_1.SDKType._get(sdkKey);
137
161
  return JSON.stringify(Object.assign(Object.assign({}, data), { statsigMetadata: Object.assign(Object.assign({}, StatsigMetadata_1.StatsigMetadataProvider.get()), { stableID,
138
162
  sessionID,
139
- sdkType }) }));
163
+ sdkType, proxyUrl: args.proxyUrl }) }));
140
164
  });
141
165
  }
142
166
  _attemptToEncodeString(args, input) {
@@ -158,6 +182,12 @@ class NetworkCore {
158
182
  return input;
159
183
  }
160
184
  }
185
+ _getNetworkProxyArgs(args) {
186
+ const proxyUrl = this._proxy.getProxyUrl(args.sdkKey, args.url);
187
+ return {
188
+ proxyUrl: proxyUrl !== null && proxyUrl !== void 0 ? proxyUrl : null,
189
+ };
190
+ }
161
191
  }
162
192
  exports.NetworkCore = NetworkCore;
163
193
  const _ensureValidSdkKey = (args) => {
@@ -180,3 +210,9 @@ function _getErrorMessage(controller, error) {
180
210
  }
181
211
  return 'Unknown Error';
182
212
  }
213
+ function _didTimeout(controller) {
214
+ const timeout = (controller === null || controller === void 0 ? void 0 : controller.signal.aborted) &&
215
+ typeof controller.signal.reason === 'string' &&
216
+ controller.signal.reason.includes('Timeout');
217
+ return timeout || false;
218
+ }
@@ -0,0 +1,14 @@
1
+ import { NetworkArgs } from './NetworkConfig';
2
+ import { AnyStatsigOptions } from './StatsigOptionsCommon';
3
+ export declare class NetworkProxy {
4
+ private _options;
5
+ private _proxyUrl;
6
+ private _expiryTime;
7
+ private _overrideFn;
8
+ constructor(_options: AnyStatsigOptions);
9
+ setOverrideFunc(networkOverrideFunc?: (url: string, args: NetworkArgs) => Promise<Response>): void;
10
+ getProxyUrl(sdkKey: string, url: string): string | null;
11
+ attemptToUpdateProxyUrl(sdkKey: string, errorMessage: string | null, timedOut: boolean): Promise<void>;
12
+ private _fetchProxyUrl;
13
+ private _getTxtEntries;
14
+ }
@@ -0,0 +1,199 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.NetworkProxy = void 0;
13
+ const Hashing_1 = require("./Hashing");
14
+ const NetworkConfig_1 = require("./NetworkConfig");
15
+ const StorageProvider_1 = require("./StorageProvider");
16
+ const TypedJsonParse_1 = require("./TypedJsonParse");
17
+ const DNS_QUERY_ENDPOINT = 'https://cloudflare-dns.com/dns-query';
18
+ const DNS_QUERY_DOMAIN = 'featureregistry.org';
19
+ const DEFAULT_TTL = 72 * 60 * 60 * 1000; // 72 hours
20
+ class NetworkProxy {
21
+ constructor(_options) {
22
+ this._options = _options;
23
+ this._proxyUrl = null;
24
+ this._expiryTime = 0;
25
+ this._overrideFn = undefined;
26
+ if (_options.networkConfig) {
27
+ const netConfig = _options.networkConfig;
28
+ this.setOverrideFunc(netConfig.networkOverrideFunc);
29
+ }
30
+ }
31
+ setOverrideFunc(networkOverrideFunc) {
32
+ this._overrideFn = networkOverrideFunc;
33
+ }
34
+ getProxyUrl(sdkKey, url) {
35
+ if (!_isDefaultUrl(url)) {
36
+ return null;
37
+ }
38
+ const endpoint = getEndpoint(url);
39
+ if (this._expiryTime > 0 && Date.now() > this._expiryTime) {
40
+ this._proxyUrl = null;
41
+ this._expiryTime = 0;
42
+ return this._proxyUrl;
43
+ }
44
+ if (this._proxyUrl) {
45
+ return this._proxyUrl + endpoint;
46
+ }
47
+ const hashkey = _getProxyStorageKey(sdkKey);
48
+ const cacheProxy = _getProxyFromCache(hashkey);
49
+ if (cacheProxy) {
50
+ this._proxyUrl = cacheProxy.url;
51
+ this._expiryTime = cacheProxy.expiryTime;
52
+ return this._proxyUrl + endpoint;
53
+ }
54
+ return null;
55
+ }
56
+ attemptToUpdateProxyUrl(sdkKey, errorMessage, timedOut) {
57
+ return __awaiter(this, void 0, void 0, function* () {
58
+ if (!_containsUnresolvedDomain(errorMessage, timedOut)) {
59
+ return;
60
+ }
61
+ const hashkey = _getProxyStorageKey(sdkKey);
62
+ const fetchedProxyUrl = yield this._fetchProxyUrl();
63
+ if (!fetchedProxyUrl) {
64
+ return;
65
+ }
66
+ this._proxyUrl = fetchedProxyUrl;
67
+ this._expiryTime = Date.now() + DEFAULT_TTL;
68
+ StorageProvider_1.Storage._setItem(hashkey, JSON.stringify({ url: this._proxyUrl, expiryTime: this._expiryTime }));
69
+ });
70
+ }
71
+ _fetchProxyUrl() {
72
+ return __awaiter(this, void 0, void 0, function* () {
73
+ const txtEntries = yield this._getTxtEntries(DNS_QUERY_DOMAIN);
74
+ if (txtEntries.length === 0) {
75
+ return null;
76
+ }
77
+ return _findClosestProxy(txtEntries);
78
+ });
79
+ }
80
+ _getTxtEntries(domain) {
81
+ var _a;
82
+ return __awaiter(this, void 0, void 0, function* () {
83
+ const body = _encodeDomain(domain);
84
+ const func = (_a = this._overrideFn) !== null && _a !== void 0 ? _a : fetch;
85
+ const res = yield func(DNS_QUERY_ENDPOINT, {
86
+ method: 'POST',
87
+ headers: {
88
+ 'Content-Type': 'application/dns-message',
89
+ Accept: 'application/dns-message',
90
+ },
91
+ body,
92
+ });
93
+ if (!res.ok) {
94
+ return [];
95
+ }
96
+ const arrBuff = yield res.arrayBuffer();
97
+ return _decodeDnsResponse(arrBuff);
98
+ });
99
+ }
100
+ }
101
+ exports.NetworkProxy = NetworkProxy;
102
+ function _getProxyStorageKey(sdkKey) {
103
+ return `statsig.proxy.${(0, Hashing_1._DJB2)(sdkKey)}`;
104
+ }
105
+ function _getProxyFromCache(hashKey) {
106
+ const cacheProxyStr = StorageProvider_1.Storage._getItem(hashKey);
107
+ if (!cacheProxyStr) {
108
+ return null;
109
+ }
110
+ const cacheProxy = (0, TypedJsonParse_1._typedJsonParse)(cacheProxyStr, 'url', 'cacheProxy');
111
+ if (cacheProxy && Date.now() < cacheProxy.expiryTime) {
112
+ return cacheProxy;
113
+ }
114
+ return null;
115
+ }
116
+ function _decodeDnsResponse(arrBuff) {
117
+ const respArr = Array.from(new Uint8Array(arrBuff));
118
+ let nextIndex = respArr.indexOf(0xc0);
119
+ const entries = [];
120
+ while (nextIndex > -1 && nextIndex < respArr.length - 2) {
121
+ const offset = respArr[nextIndex + 1];
122
+ if (respArr.length < nextIndex + offset + 1) {
123
+ break;
124
+ }
125
+ const count = respArr[nextIndex + offset];
126
+ const entry = respArr.slice(nextIndex + offset + 1, nextIndex + offset + count + 1);
127
+ entries.push(entry.map((e) => String.fromCharCode(e)).join(''));
128
+ nextIndex = respArr.indexOf(0xc0, nextIndex + offset + count);
129
+ }
130
+ return entries;
131
+ }
132
+ function _encodeDomain(domain) {
133
+ const bin = [
134
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135
+ ];
136
+ const entries = domain.split('.');
137
+ for (const entry of entries) {
138
+ bin.push(entry.length);
139
+ for (const char of entry) {
140
+ bin.push(char.charCodeAt(0));
141
+ }
142
+ }
143
+ bin.push(...[0x00, 0x00, 0x10, 0x00, 0x01]);
144
+ return Uint8Array.from(bin);
145
+ }
146
+ function _findClosestProxy(txtEntries) {
147
+ const [proxyList, closestIndex] = _extractProxyListFromTxt(txtEntries);
148
+ if (proxyList.length === 0) {
149
+ return null;
150
+ }
151
+ return proxyList.length > closestIndex
152
+ ? proxyList[closestIndex]
153
+ : proxyList[0];
154
+ }
155
+ function _extractProxyListFromTxt(txtEntries) {
156
+ let closestDistance = 1440;
157
+ let closestIndex = 0;
158
+ const proxyList = [];
159
+ const localTimezoneOffset = new Date().getTimezoneOffset() + 720;
160
+ for (const entry of txtEntries) {
161
+ const [key, value] = entry.split('=');
162
+ proxyList.push(value);
163
+ const tzoneOffsetStr = key === null || key === void 0 ? void 0 : key.split('_')[1];
164
+ const tzoneOffset = parseInt(tzoneOffsetStr);
165
+ if (tzoneOffset && !Number.isNaN(tzoneOffset)) {
166
+ const dist = Math.abs(tzoneOffset - localTimezoneOffset);
167
+ if (dist < closestDistance) {
168
+ closestIndex = proxyList.length - 1;
169
+ closestDistance = dist;
170
+ }
171
+ }
172
+ }
173
+ return [proxyList, closestIndex];
174
+ }
175
+ function _isDefaultUrl(url) {
176
+ for (const key in NetworkConfig_1.NetworkDefault) {
177
+ if (url.startsWith(NetworkConfig_1.NetworkDefault[key])) {
178
+ return true;
179
+ }
180
+ }
181
+ return false;
182
+ }
183
+ function _containsUnresolvedDomain(errorMsg, timedOut) {
184
+ const lowerErrorMsg = (errorMsg === null || errorMsg === void 0 ? void 0 : errorMsg.toLowerCase()) || '';
185
+ return (timedOut ||
186
+ lowerErrorMsg.includes('uncaught exception') ||
187
+ lowerErrorMsg.includes('failed to fetch') ||
188
+ lowerErrorMsg.includes('networkerror when attempting to fetch resource'));
189
+ }
190
+ function getEndpoint(urlString) {
191
+ try {
192
+ const url = new URL(urlString);
193
+ const endpoint = url.pathname.substring(1);
194
+ return endpoint;
195
+ }
196
+ catch (error) {
197
+ return '';
198
+ }
199
+ }
@@ -11,10 +11,10 @@ export type StatsigSession = {
11
11
  idleTimeoutID?: SessionTimeoutID;
12
12
  };
13
13
  export declare const SessionID: {
14
- get: (sdkKey: string) => Promise<string>;
14
+ get: (sdkKey: string) => string;
15
15
  };
16
16
  export declare const StatsigSession: {
17
- get: (sdkKey: string) => Promise<StatsigSession>;
17
+ get: (sdkKey: string) => StatsigSession;
18
18
  overrideInitialSessionID: (override: string, sdkKey: string) => void;
19
19
  };
20
20
  export {};
package/src/SessionID.js CHANGED
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.StatsigSession = exports.SessionID = void 0;
13
4
  const CacheKey_1 = require("./CacheKey");
@@ -18,49 +9,47 @@ const MAX_SESSION_IDLE_TIME = 30 * 60 * 1000; // 30 minutes
18
9
  const MAX_SESSION_AGE = 4 * 60 * 60 * 1000; // 4 hours
19
10
  const PROMISE_MAP = {};
20
11
  exports.SessionID = {
21
- get: (sdkKey) => __awaiter(void 0, void 0, void 0, function* () {
22
- return exports.StatsigSession.get(sdkKey).then((x) => x.data.sessionID);
23
- }),
12
+ get: (sdkKey) => {
13
+ return exports.StatsigSession.get(sdkKey).data.sessionID;
14
+ },
24
15
  };
25
16
  exports.StatsigSession = {
26
- get: (sdkKey) => __awaiter(void 0, void 0, void 0, function* () {
17
+ get: (sdkKey) => {
27
18
  if (PROMISE_MAP[sdkKey] == null) {
28
19
  PROMISE_MAP[sdkKey] = _loadSession(sdkKey);
29
20
  }
30
- const session = yield PROMISE_MAP[sdkKey];
21
+ const session = PROMISE_MAP[sdkKey];
31
22
  return _bumpSession(session);
32
- }),
23
+ },
33
24
  overrideInitialSessionID: (override, sdkKey) => {
34
25
  PROMISE_MAP[sdkKey] = _overrideSessionId(override, sdkKey);
35
26
  },
36
27
  };
37
28
  function _loadSession(sdkKey) {
38
- return __awaiter(this, void 0, void 0, function* () {
39
- let data = yield _loadFromStorage(sdkKey);
40
- const now = Date.now();
41
- if (!data) {
42
- data = {
43
- sessionID: (0, UUID_1.getUUID)(),
44
- startTime: now,
45
- lastUpdate: now,
46
- };
47
- }
48
- return {
49
- data,
50
- sdkKey,
29
+ let data = _loadFromStorage(sdkKey);
30
+ const now = Date.now();
31
+ if (!data) {
32
+ data = {
33
+ sessionID: (0, UUID_1.getUUID)(),
34
+ startTime: now,
35
+ lastUpdate: now,
51
36
  };
52
- });
37
+ }
38
+ return {
39
+ data,
40
+ sdkKey,
41
+ };
53
42
  }
54
43
  function _overrideSessionId(override, sdkKey) {
55
44
  const now = Date.now();
56
- return Promise.resolve({
45
+ return {
57
46
  data: {
58
47
  sessionID: override,
59
48
  startTime: now,
60
49
  lastUpdate: now,
61
50
  },
62
51
  sdkKey,
63
- });
52
+ };
64
53
  }
65
54
  function _bumpSession(session) {
66
55
  const now = Date.now();
@@ -98,9 +87,12 @@ function _getSessionIDStorageKey(sdkKey) {
98
87
  }
99
88
  function _persistToStorage(session, sdkKey) {
100
89
  const storageKey = _getSessionIDStorageKey(sdkKey);
101
- (0, StorageProvider_1._setObjectInStorage)(storageKey, session).catch(() => {
90
+ try {
91
+ (0, StorageProvider_1._setObjectInStorage)(storageKey, session);
92
+ }
93
+ catch (e) {
102
94
  Log_1.Log.warn('Failed to save SessionID');
103
- });
95
+ }
104
96
  }
105
97
  function _loadFromStorage(sdkKey) {
106
98
  const storageKey = _getSessionIDStorageKey(sdkKey);
package/src/StableID.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export declare const StableID: {
2
- get: (sdkKey: string) => Promise<string>;
2
+ get: (sdkKey: string) => string;
3
3
  setOverride: (override: string, sdkKey: string) => void;
4
4
  };
package/src/StableID.js CHANGED
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.StableID = void 0;
13
4
  const CacheKey_1 = require("./CacheKey");
@@ -16,21 +7,19 @@ const StorageProvider_1 = require("./StorageProvider");
16
7
  const UUID_1 = require("./UUID");
17
8
  const PROMISE_MAP = {};
18
9
  exports.StableID = {
19
- get: (sdkKey) => __awaiter(void 0, void 0, void 0, function* () {
10
+ get: (sdkKey) => {
20
11
  if (PROMISE_MAP[sdkKey] == null) {
21
- PROMISE_MAP[sdkKey] = _loadFromStorage(sdkKey).then((stableID) => {
22
- if (stableID != null) {
23
- return stableID;
24
- }
25
- const newStableID = (0, UUID_1.getUUID)();
26
- _persistToStorage(newStableID, sdkKey);
27
- return newStableID;
28
- });
12
+ let stableID = _loadFromStorage(sdkKey);
13
+ if (stableID == null) {
14
+ stableID = (0, UUID_1.getUUID)();
15
+ _persistToStorage(stableID, sdkKey);
16
+ }
17
+ PROMISE_MAP[sdkKey] = stableID;
29
18
  }
30
19
  return PROMISE_MAP[sdkKey];
31
- }),
20
+ },
32
21
  setOverride: (override, sdkKey) => {
33
- PROMISE_MAP[sdkKey] = Promise.resolve(override);
22
+ PROMISE_MAP[sdkKey] = override;
34
23
  _persistToStorage(override, sdkKey);
35
24
  },
36
25
  };
@@ -39,9 +28,12 @@ function _getStableIDStorageKey(sdkKey) {
39
28
  }
40
29
  function _persistToStorage(stableID, sdkKey) {
41
30
  const storageKey = _getStableIDStorageKey(sdkKey);
42
- (0, StorageProvider_1._setObjectInStorage)(storageKey, stableID).catch(() => {
31
+ try {
32
+ (0, StorageProvider_1._setObjectInStorage)(storageKey, stableID);
33
+ }
34
+ catch (e) {
43
35
  Log_1.Log.warn('Failed to save StableID');
44
- });
36
+ }
45
37
  }
46
38
  function _loadFromStorage(sdkKey) {
47
39
  const storageKey = _getStableIDStorageKey(sdkKey);
@@ -18,11 +18,11 @@ export type StatsigContext = {
18
18
  export declare abstract class StatsigClientBase<TAdapter extends EvaluationsDataAdapter | SpecsDataAdapter> implements StatsigClientEventEmitterInterface {
19
19
  loadingStatus: StatsigLoadingStatus;
20
20
  readonly dataAdapter: TAdapter;
21
+ readonly overrideAdapter: OverrideAdapter | null;
21
22
  protected readonly _sdkKey: string;
22
23
  protected readonly _options: AnyStatsigOptions;
23
24
  protected readonly _errorBoundary: ErrorBoundary;
24
25
  protected readonly _logger: EventLogger;
25
- protected readonly _overrideAdapter: OverrideAdapter | null;
26
26
  private _listeners;
27
27
  constructor(sdkKey: string, adapter: TAdapter, network: NetworkCore, options: AnyStatsigOptions | null);
28
28
  /**
@@ -30,7 +30,7 @@ class StatsigClientBase {
30
30
  SessionID_1.StatsigSession.overrideInitialSessionID(options.initialSessionID, sdkKey);
31
31
  this._sdkKey = sdkKey;
32
32
  this._options = options !== null && options !== void 0 ? options : {};
33
- this._overrideAdapter = (_a = options === null || options === void 0 ? void 0 : options.overrideAdapter) !== null && _a !== void 0 ? _a : null;
33
+ this.overrideAdapter = (_a = options === null || options === void 0 ? void 0 : options.overrideAdapter) !== null && _a !== void 0 ? _a : null;
34
34
  this._logger = new EventLogger_1.EventLogger(sdkKey, emitter, network, options);
35
35
  this._errorBoundary = new ErrorBoundary_1.ErrorBoundary(sdkKey, options, emitter);
36
36
  this._errorBoundary.wrap(this);
@@ -83,7 +83,7 @@ class StatsigClientBase {
83
83
  shutdown() {
84
84
  return __awaiter(this, void 0, void 0, function* () {
85
85
  this.$emt({ name: 'pre_shutdown' });
86
- yield this._logger.shutdown();
86
+ yield this._logger.stop();
87
87
  });
88
88
  }
89
89
  /**
@@ -1,4 +1,4 @@
1
- export declare const SDK_VERSION = "1.6.0";
1
+ export declare const SDK_VERSION = "1.8.0-beta.1";
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 = '1.6.0';
4
+ exports.SDK_VERSION = '1.8.0-beta.1';
5
5
  let metadata = {
6
6
  sdkVersion: exports.SDK_VERSION,
7
7
  sdkType: 'js-mono', // js-mono is overwritten by Precomp and OnDevice clients
@@ -1,16 +1,15 @@
1
1
  export type StorageProvider = {
2
2
  _getProviderName: () => string;
3
- _getItem: (key: string) => Promise<string | null>;
4
- _setItem: (key: string, value: string) => Promise<void>;
5
- _removeItem: (key: string) => Promise<void>;
6
- _getAllKeys: () => Promise<readonly string[]>;
7
- _getItemSync?: (key: string) => string | null;
3
+ _getItem: (key: string) => string | null;
4
+ _setItem: (key: string, value: string) => void;
5
+ _removeItem: (key: string) => void;
6
+ _getAllKeys: () => readonly string[];
8
7
  };
9
8
  type StorageProviderManagment = {
10
9
  _setProvider: (newProvider: StorageProvider) => void;
11
10
  _setDisabled: (isDisabled: boolean) => void;
12
11
  };
13
12
  export declare const Storage: StorageProvider & StorageProviderManagment;
14
- export declare function _getObjectFromStorage<T>(key: string): Promise<T | null>;
15
- export declare function _setObjectInStorage(key: string, obj: unknown): Promise<void>;
13
+ export declare function _getObjectFromStorage<T>(key: string): T | null;
14
+ export declare function _setObjectInStorage(key: string, obj: unknown): void;
16
15
  export {};
@@ -1,26 +1,19 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports._setObjectInStorage = exports._getObjectFromStorage = exports.Storage = void 0;
13
4
  const Log_1 = require("./Log");
14
5
  const SafeJs_1 = require("./SafeJs");
15
6
  const inMemoryStore = {};
16
- const _resolve = (input) => Promise.resolve(input);
17
7
  const _inMemoryProvider = {
18
8
  _getProviderName: () => 'InMemory',
19
- _getItemSync: (key) => inMemoryStore[key] ? inMemoryStore[key] : null,
20
- _getItem: (key) => _resolve(inMemoryStore[key] ? inMemoryStore[key] : null),
21
- _setItem: (key, value) => ((inMemoryStore[key] = value), _resolve()),
22
- _removeItem: (key) => (delete inMemoryStore[key], _resolve()),
23
- _getAllKeys: () => _resolve(Object.keys(inMemoryStore)),
9
+ _getItem: (key) => inMemoryStore[key] ? inMemoryStore[key] : null,
10
+ _setItem: (key, value) => {
11
+ inMemoryStore[key] = value;
12
+ },
13
+ _removeItem: (key) => {
14
+ delete inMemoryStore[key];
15
+ },
16
+ _getAllKeys: () => Object.keys(inMemoryStore),
24
17
  };
25
18
  let _localStorageProvider = null;
26
19
  try {
@@ -30,11 +23,10 @@ try {
30
23
  typeof win.localStorage.getItem === 'function') {
31
24
  _localStorageProvider = {
32
25
  _getProviderName: () => 'LocalStorage',
33
- _getItemSync: (key) => win.localStorage.getItem(key),
34
- _getItem: (key) => _resolve(win.localStorage.getItem(key)),
35
- _setItem: (key, value) => (win.localStorage.setItem(key, value), _resolve()),
36
- _removeItem: (key) => (win.localStorage.removeItem(key), _resolve()),
37
- _getAllKeys: () => _resolve(Object.keys(win.localStorage)),
26
+ _getItem: (key) => win.localStorage.getItem(key),
27
+ _setItem: (key, value) => win.localStorage.setItem(key, value),
28
+ _removeItem: (key) => win.localStorage.removeItem(key),
29
+ _getAllKeys: () => Object.keys(win.localStorage),
38
30
  };
39
31
  }
40
32
  }
@@ -57,8 +49,7 @@ function _inMemoryBreaker(get) {
57
49
  }
58
50
  exports.Storage = {
59
51
  _getProviderName: () => _current._getProviderName(),
60
- _getItem: (key) => __awaiter(void 0, void 0, void 0, function* () { return _inMemoryBreaker(() => _current._getItem(key)); }),
61
- _getItemSync: (key) => _inMemoryBreaker(() => _current._getItemSync ? _current._getItemSync(key) : null),
52
+ _getItem: (key) => _inMemoryBreaker(() => _current._getItem(key)),
62
53
  _setItem: (key, value) => _current._setItem(key, value),
63
54
  _removeItem: (key) => _current._removeItem(key),
64
55
  _getAllKeys: () => _current._getAllKeys(),
@@ -77,15 +68,11 @@ exports.Storage = {
77
68
  },
78
69
  };
79
70
  function _getObjectFromStorage(key) {
80
- return __awaiter(this, void 0, void 0, function* () {
81
- const value = yield exports.Storage._getItem(key);
82
- return JSON.parse(value !== null && value !== void 0 ? value : 'null');
83
- });
71
+ const value = exports.Storage._getItem(key);
72
+ return JSON.parse(value !== null && value !== void 0 ? value : 'null');
84
73
  }
85
74
  exports._getObjectFromStorage = _getObjectFromStorage;
86
75
  function _setObjectInStorage(key, obj) {
87
- return __awaiter(this, void 0, void 0, function* () {
88
- yield exports.Storage._setItem(key, JSON.stringify(obj));
89
- });
76
+ exports.Storage._setItem(key, JSON.stringify(obj));
90
77
  }
91
78
  exports._setObjectInStorage = _setObjectInStorage;
package/src/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /** Statsig Global should go first */
2
2
  import './$_StatsigGlobal';
3
+ import { Diagnostics } from './Diagnostics';
3
4
  import { EventLogger } from './EventLogger';
4
5
  import { Log } from './Log';
5
6
  import { Storage } from './StorageProvider';
@@ -7,6 +8,7 @@ export * from './$_StatsigGlobal';
7
8
  export * from './CacheKey';
8
9
  export * from './ClientInterfaces';
9
10
  export * from './DataAdapterCore';
11
+ export * from './Diagnostics';
10
12
  export * from './DownloadConfigSpecsResponse';
11
13
  export * from './ErrorBoundary';
12
14
  export * from './EvaluationOptions';
@@ -37,4 +39,4 @@ export * from './TypingUtils';
37
39
  export * from './UrlOverrides';
38
40
  export * from './UUID';
39
41
  export * from './VisibilityObserving';
40
- export { EventLogger, Storage, Log };
42
+ export { EventLogger, Storage, Log, Diagnostics };
package/src/index.js CHANGED
@@ -14,9 +14,11 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.Log = exports.Storage = exports.EventLogger = void 0;
17
+ exports.Diagnostics = exports.Log = exports.Storage = exports.EventLogger = void 0;
18
18
  /** Statsig Global should go first */
19
19
  require("./$_StatsigGlobal");
20
+ const Diagnostics_1 = require("./Diagnostics");
21
+ Object.defineProperty(exports, "Diagnostics", { enumerable: true, get: function () { return Diagnostics_1.Diagnostics; } });
20
22
  const EventLogger_1 = require("./EventLogger");
21
23
  Object.defineProperty(exports, "EventLogger", { enumerable: true, get: function () { return EventLogger_1.EventLogger; } });
22
24
  const Log_1 = require("./Log");
@@ -28,6 +30,7 @@ __exportStar(require("./$_StatsigGlobal"), exports);
28
30
  __exportStar(require("./CacheKey"), exports);
29
31
  __exportStar(require("./ClientInterfaces"), exports);
30
32
  __exportStar(require("./DataAdapterCore"), exports);
33
+ __exportStar(require("./Diagnostics"), exports);
31
34
  __exportStar(require("./DownloadConfigSpecsResponse"), exports);
32
35
  __exportStar(require("./ErrorBoundary"), exports);
33
36
  __exportStar(require("./EvaluationOptions"), exports);