@statsig/client-core 0.0.1-beta.37 → 0.0.1-beta.39

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": "0.0.1-beta.37",
3
+ "version": "0.0.1-beta.39",
4
4
  "dependencies": {},
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -1,11 +1,9 @@
1
- import { ErrorBoundary } from './ErrorBoundary';
2
1
  import { DataAdapterAsyncOptions, DataAdapterResult } from './StatsigDataAdapter';
3
2
  import { AnyStatsigOptions } from './StatsigOptionsCommon';
4
3
  import { StatsigUser } from './StatsigUser';
5
4
  export declare abstract class DataAdapterCore {
6
5
  private _adapterName;
7
6
  private _cacheSuffix;
8
- protected _errorBoundary: ErrorBoundary | null;
9
7
  private _sdkKey;
10
8
  private _inMemoryCache;
11
9
  private _lastModifiedStoreKey;
@@ -21,8 +19,8 @@ export declare abstract class DataAdapterCore {
21
19
  __primeInMemoryCache(cache: Record<string, DataAdapterResult>): void;
22
20
  protected _getDataAsyncImpl(current: DataAdapterResult | null, user?: StatsigUser, options?: DataAdapterAsyncOptions): Promise<DataAdapterResult | null>;
23
21
  protected _prefetchDataImpl(user?: StatsigUser, options?: DataAdapterAsyncOptions): Promise<void>;
24
- protected abstract _fetchFromNetwork(current: string | null, user?: StatsigUser): Promise<string | null>;
25
- private _fetchLatest;
22
+ protected abstract _fetchFromNetwork(current: string | null, user?: StatsigUser, options?: DataAdapterAsyncOptions): Promise<string | null>;
23
+ private _fetchAndPrepFromNetwork;
26
24
  protected _getSdkKey(): string;
27
25
  protected _getCacheKey(user?: StatsigUser): string;
28
26
  protected _addToInMemoryCache(cacheKey: string, result: DataAdapterResult): void;
@@ -10,7 +10,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.DataAdapterCore = void 0;
13
- const ErrorBoundary_1 = require("./ErrorBoundary");
14
13
  const Log_1 = require("./Log");
15
14
  const StatsigDataAdapter_1 = require("./StatsigDataAdapter");
16
15
  const StatsigUser_1 = require("./StatsigUser");
@@ -21,14 +20,12 @@ class DataAdapterCore {
21
20
  constructor(_adapterName, _cacheSuffix) {
22
21
  this._adapterName = _adapterName;
23
22
  this._cacheSuffix = _cacheSuffix;
24
- this._errorBoundary = null;
25
23
  this._sdkKey = null;
26
24
  this._inMemoryCache = {};
27
25
  this._lastModifiedStoreKey = `statsig.last_modified_time.${_cacheSuffix}`;
28
26
  }
29
27
  attach(sdkKey, _options) {
30
28
  this._sdkKey = sdkKey;
31
- this._errorBoundary = new ErrorBoundary_1.ErrorBoundary(sdkKey);
32
29
  }
33
30
  getDataSync(user) {
34
31
  const cacheKey = this._getCacheKey(user);
@@ -63,7 +60,9 @@ class DataAdapterCore {
63
60
  var _a;
64
61
  return __awaiter(this, void 0, void 0, function* () {
65
62
  const cache = current !== null && current !== void 0 ? current : this.getDataSync(user);
66
- const ops = [this._fetchLatest((_a = cache === null || cache === void 0 ? void 0 : cache.data) !== null && _a !== void 0 ? _a : null, user)];
63
+ const ops = [
64
+ this._fetchAndPrepFromNetwork((_a = cache === null || cache === void 0 ? void 0 : cache.data) !== null && _a !== void 0 ? _a : null, user, options),
65
+ ];
67
66
  if (options === null || options === void 0 ? void 0 : options.timeoutMs) {
68
67
  ops.push(new Promise((r) => setTimeout(r, options.timeoutMs)).then(() => {
69
68
  Log_1.Log.debug('Fetching latest value timed out');
@@ -82,9 +81,9 @@ class DataAdapterCore {
82
81
  }
83
82
  });
84
83
  }
85
- _fetchLatest(current, user) {
84
+ _fetchAndPrepFromNetwork(current, user, options) {
86
85
  return __awaiter(this, void 0, void 0, function* () {
87
- const latest = yield this._fetchFromNetwork(current, user);
86
+ const latest = yield this._fetchFromNetwork(current, user, options);
88
87
  if (!latest) {
89
88
  Log_1.Log.debug('No response returned for latest value');
90
89
  return null;
@@ -1,10 +1,12 @@
1
1
  import { StatsigClientEmitEventFunc } from './StatsigClientBase';
2
+ import { AnyStatsigOptions } from './StatsigOptionsCommon';
2
3
  export declare const EXCEPTION_ENDPOINT = "https://statsigapi.net/v1/sdk_exception";
3
4
  export declare class ErrorBoundary {
4
5
  private _sdkKey;
6
+ private _options;
5
7
  private _emitter?;
6
8
  private _seen;
7
- constructor(_sdkKey: string, _emitter?: StatsigClientEmitEventFunc | undefined);
9
+ constructor(_sdkKey: string, _options: AnyStatsigOptions | null, _emitter?: StatsigClientEmitEventFunc | undefined);
8
10
  wrap(instance: unknown): void;
9
11
  capture(tag: string, task: () => unknown): unknown;
10
12
  logError(tag: string, error: unknown): void;
@@ -15,8 +15,9 @@ const SDKType_1 = require("./SDKType");
15
15
  const StatsigMetadata_1 = require("./StatsigMetadata");
16
16
  exports.EXCEPTION_ENDPOINT = 'https://statsigapi.net/v1/sdk_exception';
17
17
  class ErrorBoundary {
18
- constructor(_sdkKey, _emitter) {
18
+ constructor(_sdkKey, _options, _emitter) {
19
19
  this._sdkKey = _sdkKey;
20
+ this._options = _options;
20
21
  this._emitter = _emitter;
21
22
  this._seen = new Set();
22
23
  }
@@ -58,7 +59,7 @@ class ErrorBoundary {
58
59
  try {
59
60
  Log_1.Log.warn(`Caught error in ${tag}`, { error });
60
61
  const impl = () => __awaiter(this, void 0, void 0, function* () {
61
- var _a;
62
+ var _a, _b, _c, _d;
62
63
  const unwrapped = (error !== null && error !== void 0 ? error : Error('[Statsig] Error was empty'));
63
64
  const isError = unwrapped instanceof Error;
64
65
  const name = isError ? unwrapped.name : 'No Name';
@@ -66,6 +67,10 @@ class ErrorBoundary {
66
67
  return;
67
68
  }
68
69
  this._seen.add(name);
70
+ if ((_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.networkConfig) === null || _b === void 0 ? void 0 : _b.preventAllNetworkTraffic) {
71
+ (_c = this._emitter) === null || _c === void 0 ? void 0 : _c.call(this, { name: 'error', error });
72
+ return;
73
+ }
69
74
  const sdkType = SDKType_1.SDKType._get(this._sdkKey);
70
75
  const statsigMetadata = StatsigMetadata_1.StatsigMetadataProvider.get();
71
76
  const info = isError ? unwrapped.stack : _getDescription(unwrapped);
@@ -80,7 +85,7 @@ class ErrorBoundary {
80
85
  },
81
86
  body,
82
87
  });
83
- (_a = this._emitter) === null || _a === void 0 ? void 0 : _a.call(this, { name: 'error', error });
88
+ (_d = this._emitter) === null || _d === void 0 ? void 0 : _d.call(this, { name: 'error', error });
84
89
  });
85
90
  impl()
86
91
  .then(() => {
@@ -3,6 +3,7 @@ export declare const NetworkDefault: {
3
3
  initializeApi: "https://featureassets.org/v1";
4
4
  specsApi: "https://assetsconfigcdn.org/v1";
5
5
  };
6
+ export type NetworkPriority = 'high' | 'low' | 'auto';
6
7
  export declare enum NetworkParam {
7
8
  EventCount = "ec",
8
9
  SdkKey = "k",
@@ -1,9 +1,11 @@
1
1
  import './$_StatsigGlobal';
2
+ import { NetworkPriority } from './NetworkConfig';
2
3
  import { StatsigClientEmitEventFunc } from './StatsigClientBase';
3
4
  import { AnyStatsigOptions } from './StatsigOptionsCommon';
4
5
  type RequestArgs = {
5
6
  sdkKey: string;
6
7
  url: string;
8
+ priority?: NetworkPriority;
7
9
  retries?: number;
8
10
  params?: Record<string, string>;
9
11
  headers?: Record<string, string>;
@@ -15,6 +15,7 @@ const Diagnostics_1 = require("./Diagnostics");
15
15
  const Log_1 = require("./Log");
16
16
  const NetworkConfig_1 = require("./NetworkConfig");
17
17
  const SDKType_1 = require("./SDKType");
18
+ const SafeJs_1 = require("./SafeJs");
18
19
  const SessionID_1 = require("./SessionID");
19
20
  const StableID_1 = require("./StableID");
20
21
  const StatsigMetadata_1 = require("./StatsigMetadata");
@@ -51,23 +52,28 @@ class NetworkCore {
51
52
  });
52
53
  }
53
54
  _sendRequest(args) {
54
- var _a;
55
+ var _a, _b, _c;
55
56
  return __awaiter(this, void 0, void 0, function* () {
56
57
  if (!_ensureValidSdkKey(args)) {
57
58
  return null;
58
59
  }
60
+ if ((_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.networkConfig) === null || _b === void 0 ? void 0 : _b.preventAllNetworkTraffic) {
61
+ return null;
62
+ }
59
63
  const { method, body, retries } = args;
60
64
  const controller = new AbortController();
61
65
  const handle = setTimeout(() => controller.abort(`Timeout of ${this._timeout}ms expired.`), this._timeout);
62
66
  const url = yield this._getPopulatedURL(args);
63
67
  let response = null;
64
68
  try {
65
- response = yield fetch(url, {
69
+ const config = {
66
70
  method,
67
71
  body,
68
72
  headers: Object.assign({}, args.headers),
69
73
  signal: controller.signal,
70
- });
74
+ priority: args.priority,
75
+ };
76
+ response = yield fetch(url, config);
71
77
  clearTimeout(handle);
72
78
  if (!response.ok) {
73
79
  const text = yield response.text().catch(() => 'No Text');
@@ -86,7 +92,7 @@ class NetworkCore {
86
92
  const errorMessage = _getErrorMessage(controller, error);
87
93
  Diagnostics_1.Diagnostics.mark();
88
94
  if (!retries || retries <= 0) {
89
- (_a = this._emitter) === null || _a === void 0 ? void 0 : _a.call(this, { name: 'error', error });
95
+ (_c = this._emitter) === null || _c === void 0 ? void 0 : _c.call(this, { name: 'error', error });
90
96
  Log_1.Log.error(`A networking error occured during ${method} request to ${url}.`, errorMessage, error);
91
97
  return null;
92
98
  }
@@ -118,15 +124,22 @@ class NetworkCore {
118
124
  }
119
125
  _attemptToEncodeString(args, input) {
120
126
  var _a, _b, _c;
121
- if ((__STATSIG__ === null || __STATSIG__ === void 0 ? void 0 : __STATSIG__['no-encode']) != null ||
127
+ const win = (0, SafeJs_1._getWindowSafe)();
128
+ if (!(win === null || win === void 0 ? void 0 : win.btoa) ||
129
+ (__STATSIG__ === null || __STATSIG__ === void 0 ? void 0 : __STATSIG__['no-encode']) != null ||
122
130
  ((_a = this._options) === null || _a === void 0 ? void 0 : _a.disableStatsigEncoding) ||
123
- !args.isStatsigEncodable ||
124
- typeof window === 'undefined' ||
125
- !window.btoa) {
131
+ !args.isStatsigEncodable) {
132
+ return input;
133
+ }
134
+ try {
135
+ const result = (_b = win.btoa(input).split('').reverse().join('')) !== null && _b !== void 0 ? _b : input;
136
+ args.params = Object.assign(Object.assign({}, ((_c = args.params) !== null && _c !== void 0 ? _c : {})), { [NetworkConfig_1.NetworkParam.StatsigEncoded]: '1' });
137
+ return result;
138
+ }
139
+ catch (_d) {
140
+ Log_1.Log.warn('/initialize request encoding failed');
126
141
  return input;
127
142
  }
128
- args.params = Object.assign(Object.assign({}, ((_b = args.params) !== null && _b !== void 0 ? _b : {})), { [NetworkConfig_1.NetworkParam.StatsigEncoded]: '1' });
129
- return (_c = window.btoa(input).split('').reverse().join('')) !== null && _c !== void 0 ? _c : input;
130
143
  }
131
144
  }
132
145
  exports.NetworkCore = NetworkCore;
package/src/SessionID.js CHANGED
@@ -57,17 +57,13 @@ function _bumpSession(session) {
57
57
  }
58
58
  data.lastUpdate = now;
59
59
  _persistToStorage(data, session.sdkKey);
60
- session.data = data;
61
60
  clearTimeout(session.idleTimeoutID);
62
61
  clearTimeout(session.ageTimeoutID);
63
62
  const lifetime = now - data.startTime;
64
63
  const sdkKey = session.sdkKey;
65
- return {
66
- data,
67
- sdkKey,
68
- // idleTimeoutID: _createSessionTimeout(sdkKey, MAX_SESSION_IDLE_TIME),
69
- ageTimeoutID: _createSessionTimeout(sdkKey, MAX_SESSION_AGE - lifetime),
70
- };
64
+ session.idleTimeoutID = _createSessionTimeout(sdkKey, MAX_SESSION_IDLE_TIME);
65
+ session.ageTimeoutID = _createSessionTimeout(sdkKey, MAX_SESSION_AGE - lifetime);
66
+ return session;
71
67
  }
72
68
  function _createSessionTimeout(sdkKey, duration) {
73
69
  return setTimeout(() => {
@@ -31,7 +31,7 @@ class StatsigClientBase {
31
31
  (options === null || options === void 0 ? void 0 : options.disableStorage) && StorageProvider_1.Storage._setDisabled(true);
32
32
  (options === null || options === void 0 ? void 0 : options.overrideStableID) &&
33
33
  StableID_1.StableID.setOverride(options.overrideStableID, sdkKey);
34
- this._errorBoundary = new ErrorBoundary_1.ErrorBoundary(sdkKey, emitter);
34
+ this._errorBoundary = new ErrorBoundary_1.ErrorBoundary(sdkKey, options, emitter);
35
35
  this._errorBoundary.wrap(this);
36
36
  this._errorBoundary.wrap(network);
37
37
  this._errorBoundary.wrap(adapter);
@@ -1,3 +1,4 @@
1
+ import { NetworkPriority } from './NetworkConfig';
1
2
  import type { AnyStatsigOptions, NetworkConfigCommon } from './StatsigOptionsCommon';
2
3
  import { StatsigUser } from './StatsigUser';
3
4
  export type DataSource = 'Uninitialized' | 'Loading' | 'NoValues' | 'Cache' | 'Network' | 'NetworkNotModified' | 'Bootstrap' | 'Prefetch';
@@ -14,15 +15,23 @@ export type DataAdapterAsyncOptions = {
14
15
  * Note: If no timeout is given, the {@link NetworkConfigCommon.networkTimeoutMs|StatsigOptions.networkConfig.networkTimeoutMs} is used.
15
16
  */
16
17
  readonly timeoutMs?: NetworkConfigCommon['networkTimeoutMs'];
18
+ /**
19
+ * The priority that should be applied to the Http request that is fired.
20
+ *
21
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/fetch#priority
22
+ *
23
+ * default: 'auto'
24
+ */
25
+ readonly priority?: NetworkPriority;
17
26
  };
18
27
  export declare const DataAdapterCachePrefix = "statsig.cached";
19
28
  /**
20
29
  * Describes a type that is used during intialize/update operations of a Statsig client.
21
30
  *
22
31
  * See below to find the default adapters, but know that it is possible to create your
23
- * own StatsigDataAdapter and provide it via {@link AnyStatsigOptions.dataAdapter}.
32
+ * own StatsigDataAdapter and provide it via `StatsigOptions.dataAdapter`.
24
33
  *
25
- * Defaults:
34
+ * defaults:
26
35
  *
27
36
  * - {@link StatsigClient} uses {@link EvaluationsDataAdapter}
28
37
  *
@@ -1,4 +1,4 @@
1
- export declare const SDK_VERSION = "0.0.1-beta.37";
1
+ export declare const SDK_VERSION = "0.0.1-beta.39";
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 = '0.0.1-beta.37';
4
+ exports.SDK_VERSION = '0.0.1-beta.39';
5
5
  let metadata = {
6
6
  sdkVersion: exports.SDK_VERSION,
7
7
  sdkType: 'js-mono', // js-mono is overwritten by Precomp and OnDevice clients
@@ -38,6 +38,10 @@ export type NetworkConfigCommon = {
38
38
  * default: `10,000 ms` (10 seconds)
39
39
  */
40
40
  networkTimeoutMs?: number;
41
+ /**
42
+ * Intended for testing purposes. Prevents any network requests being made.
43
+ */
44
+ preventAllNetworkTraffic?: boolean;
41
45
  };
42
46
  /** Options for configuring a Statsig client. */
43
47
  export type StatsigOptionsCommon<NetworkConfig extends NetworkConfigCommon> = StatsigRuntimeMutableOptions & {
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports._setObjectInStorage = exports._getObjectFromStorage = exports.Storage = void 0;
13
13
  const Log_1 = require("./Log");
14
14
  const inMemoryStore = {};
15
+ const _resolve = (input) => Promise.resolve(input);
15
16
  const _inMemoryProvider = {
16
17
  _getProviderName: () => 'InMemory',
17
18
  _getItemSync(key) {
@@ -20,18 +21,18 @@ const _inMemoryProvider = {
20
21
  },
21
22
  _getItem(key) {
22
23
  var _a;
23
- return Promise.resolve((_a = inMemoryStore[key]) !== null && _a !== void 0 ? _a : null);
24
+ return _resolve((_a = inMemoryStore[key]) !== null && _a !== void 0 ? _a : null);
24
25
  },
25
26
  _setItem(key, value) {
26
27
  inMemoryStore[key] = value;
27
- return Promise.resolve();
28
+ return _resolve();
28
29
  },
29
30
  _removeItem(key) {
30
31
  delete inMemoryStore[key];
31
- return Promise.resolve();
32
+ return _resolve();
32
33
  },
33
34
  _getAllKeys() {
34
- return Promise.resolve(Object.keys(inMemoryStore));
35
+ return _resolve(Object.keys(inMemoryStore));
35
36
  },
36
37
  };
37
38
  let _localStorageProvider = null;
@@ -43,19 +44,19 @@ try {
43
44
  return localStorage.getItem(key);
44
45
  },
45
46
  _getItem(key) {
46
- return Promise.resolve(localStorage.getItem(key));
47
+ return _resolve(localStorage.getItem(key));
47
48
  },
48
49
  _setItem(key, value) {
49
50
  localStorage.setItem(key, value);
50
- return Promise.resolve();
51
+ return _resolve();
51
52
  },
52
53
  _removeItem(key) {
53
54
  localStorage.removeItem(key);
54
- return Promise.resolve();
55
+ return _resolve();
55
56
  },
56
57
  _getAllKeys() {
57
58
  const keys = Object.keys(localStorage);
58
- return Promise.resolve(keys);
59
+ return _resolve(keys);
59
60
  },
60
61
  };
61
62
  }