@statsig/client-core 0.0.1-beta.3 → 0.0.1-beta.30
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/README.md +1 -1
- package/package.json +1 -1
- package/src/$_StatsigGlobal.d.ts +7 -1
- package/src/$_StatsigGlobal.js +15 -12
- package/src/ClientInterfaces.d.ts +47 -14
- package/src/DataAdapterCore.d.ts +32 -0
- package/src/DataAdapterCore.js +167 -0
- package/src/Diagnostics.js +24 -26
- package/src/DownloadConfigSpecsResponse.d.ts +41 -0
- package/src/ErrorBoundary.d.ts +1 -0
- package/src/ErrorBoundary.js +41 -86
- package/src/EvaluationOptions.d.ts +20 -0
- package/src/EvaluationOptions.js +2 -0
- package/src/EvaluationTypes.d.ts +39 -0
- package/src/EvaluationTypes.js +2 -0
- package/src/EventLogger.d.ts +21 -8
- package/src/EventLogger.js +206 -228
- package/src/Hashing.d.ts +2 -1
- package/src/Hashing.js +25 -6
- package/src/InitializeResponse.d.ts +18 -0
- package/src/InitializeResponse.js +2 -0
- package/src/Log.js +15 -34
- package/src/Monitoring.d.ts +1 -2
- package/src/Monitoring.js +68 -27
- package/src/NetworkCore.d.ts +17 -6
- package/src/NetworkCore.js +115 -166
- package/src/NetworkDefaults.d.ts +5 -0
- package/src/NetworkDefaults.js +8 -0
- package/src/NetworkParams.d.ts +9 -0
- package/src/NetworkParams.js +13 -0
- package/src/OverrideAdapter.d.ts +9 -0
- package/src/OverrideAdapter.js +2 -0
- package/src/SDKType.d.ts +8 -0
- package/src/SDKType.js +19 -0
- package/src/SafeJs.d.ts +4 -0
- package/src/SafeJs.js +27 -0
- package/src/SessionID.d.ts +10 -1
- package/src/SessionID.js +86 -6
- package/src/StableID.js +24 -53
- package/src/StatsigClientBase.d.ts +57 -28
- package/src/StatsigClientBase.js +110 -238
- package/src/StatsigClientEventEmitter.d.ts +64 -28
- package/src/StatsigDataAdapter.d.ts +89 -0
- package/src/StatsigDataAdapter.js +4 -0
- package/src/StatsigEvent.d.ts +10 -19
- package/src/StatsigEvent.js +50 -41
- package/src/StatsigMetadata.d.ts +1 -1
- package/src/StatsigMetadata.js +7 -18
- package/src/StatsigOptionsCommon.d.ts +68 -17
- package/src/StatsigTypeFactories.d.ts +6 -0
- package/src/StatsigTypeFactories.js +50 -0
- package/src/StatsigTypes.d.ts +29 -18
- package/src/StatsigTypes.js +0 -29
- package/src/StatsigUser.d.ts +2 -5
- package/src/StatsigUser.js +10 -18
- package/src/StorageProvider.d.ts +12 -7
- package/src/StorageProvider.js +58 -67
- package/src/TypedJsonParse.d.ts +8 -0
- package/src/TypedJsonParse.js +27 -0
- package/src/UUID.js +9 -5
- package/src/UrlOverrides.d.ts +1 -0
- package/src/UrlOverrides.js +15 -0
- package/src/UtitlityTypes.d.ts +3 -0
- package/src/UtitlityTypes.js +2 -0
- package/src/VisibilityObserving.d.ts +8 -0
- package/src/VisibilityObserving.js +30 -0
- package/src/index.d.ts +21 -4
- package/src/index.js +31 -17
- package/src/StatsigDataProvider.d.ts +0 -9
- package/src/VisibilityChangeObserver.d.ts +0 -13
- package/src/VisibilityChangeObserver.js +0 -48
- package/src/__tests__/MockLocalStorage.d.ts +0 -9
- package/src/__tests__/MockLocalStorage.js +0 -37
- /package/src/{StatsigDataProvider.js → DownloadConfigSpecsResponse.js} +0 -0
package/README.md
CHANGED
package/package.json
CHANGED
package/src/$_StatsigGlobal.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { StatsigClientInterface } from './ClientInterfaces';
|
|
1
2
|
export type StatsigGlobal = {
|
|
2
3
|
[key: string]: unknown;
|
|
3
|
-
instances?:
|
|
4
|
+
instances?: Record<string, StatsigClientInterface>;
|
|
5
|
+
lastInstance?: StatsigClientInterface;
|
|
6
|
+
acInstances?: Record<string, unknown>;
|
|
7
|
+
srInstances?: Record<string, unknown>;
|
|
8
|
+
instance?: (sdkKey: string) => StatsigClientInterface | undefined;
|
|
4
9
|
};
|
|
5
10
|
declare global {
|
|
6
11
|
let __STATSIG__: StatsigGlobal | undefined;
|
|
@@ -8,3 +13,4 @@ declare global {
|
|
|
8
13
|
__STATSIG__: StatsigGlobal | undefined;
|
|
9
14
|
}
|
|
10
15
|
}
|
|
16
|
+
export declare const _getStatsigGlobal: () => StatsigGlobal;
|
package/src/$_StatsigGlobal.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
3
|
+
var _a, _b, _c;
|
|
2
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
5
|
+
exports._getStatsigGlobal = void 0;
|
|
6
|
+
const GLOBAL_KEY = '__STATSIG__';
|
|
7
|
+
const _window = typeof window !== 'undefined' ? window : {};
|
|
8
|
+
const _global = typeof global !== 'undefined' ? global : {};
|
|
9
|
+
const _globalThis = typeof globalThis !== 'undefined' ? globalThis : {};
|
|
10
|
+
const statsigGlobal = (_c = (_b = (_a = _window[GLOBAL_KEY]) !== null && _a !== void 0 ? _a : _global[GLOBAL_KEY]) !== null && _b !== void 0 ? _b : _globalThis[GLOBAL_KEY]) !== null && _c !== void 0 ? _c : {};
|
|
11
|
+
_window[GLOBAL_KEY] = statsigGlobal;
|
|
12
|
+
_global[GLOBAL_KEY] = statsigGlobal;
|
|
13
|
+
_globalThis[GLOBAL_KEY] = statsigGlobal;
|
|
14
|
+
const _getStatsigGlobal = () => {
|
|
15
|
+
return __STATSIG__ !== null && __STATSIG__ !== void 0 ? __STATSIG__ : statsigGlobal;
|
|
16
|
+
};
|
|
17
|
+
exports._getStatsigGlobal = _getStatsigGlobal;
|
|
@@ -1,28 +1,61 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DownloadConfigSpecsResponse } from './DownloadConfigSpecsResponse';
|
|
2
|
+
import { DynamicConfigEvaluationOptions, ExperimentEvaluationOptions, FeatureGateEvaluationOptions, LayerEvaluationOptions } from './EvaluationOptions';
|
|
3
|
+
import { InitializeResponseWithUpdates } from './InitializeResponse';
|
|
2
4
|
import { StatsigClientEventEmitterInterface } from './StatsigClientEventEmitter';
|
|
5
|
+
import { EvaluationsDataAdapter, SpecsDataAdapter } from './StatsigDataAdapter';
|
|
3
6
|
import { StatsigEvent } from './StatsigEvent';
|
|
7
|
+
import { AnyStatsigOptions, StatsigRuntimeMutableOptions } from './StatsigOptionsCommon';
|
|
4
8
|
import { DynamicConfig, Experiment, FeatureGate, Layer } from './StatsigTypes';
|
|
5
9
|
import { StatsigUser } from './StatsigUser';
|
|
10
|
+
import { Flatten } from './UtitlityTypes';
|
|
6
11
|
export interface StatsigClientCommonInterface extends StatsigClientEventEmitterInterface {
|
|
7
|
-
|
|
12
|
+
initializeSync(): void;
|
|
13
|
+
initializeAsync(): Promise<void>;
|
|
8
14
|
shutdown(): Promise<void>;
|
|
15
|
+
flush(): Promise<void>;
|
|
16
|
+
updateRuntimeOptions(options: StatsigRuntimeMutableOptions): void;
|
|
9
17
|
}
|
|
18
|
+
export type CommonContext = {
|
|
19
|
+
sdkKey: string;
|
|
20
|
+
options: AnyStatsigOptions;
|
|
21
|
+
};
|
|
22
|
+
export type AsyncCommonContext = {
|
|
23
|
+
sessionID: string;
|
|
24
|
+
stableID: string;
|
|
25
|
+
};
|
|
26
|
+
export type OnDeviceEvaluationsContext = CommonContext & {
|
|
27
|
+
values: DownloadConfigSpecsResponse | null;
|
|
28
|
+
};
|
|
29
|
+
export type OnDeviceEvaluationsAsyncContext = OnDeviceEvaluationsContext & AsyncCommonContext;
|
|
10
30
|
export interface OnDeviceEvaluationsInterface extends StatsigClientCommonInterface {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
31
|
+
readonly dataAdapter: SpecsDataAdapter;
|
|
32
|
+
getAsyncContext(): Promise<OnDeviceEvaluationsAsyncContext>;
|
|
33
|
+
getContext(): OnDeviceEvaluationsContext;
|
|
34
|
+
checkGate(name: string, user: StatsigUser, options?: FeatureGateEvaluationOptions): boolean;
|
|
35
|
+
getFeatureGate(name: string, user: StatsigUser, options?: FeatureGateEvaluationOptions): FeatureGate;
|
|
36
|
+
getDynamicConfig(name: string, user: StatsigUser, options?: DynamicConfigEvaluationOptions): DynamicConfig;
|
|
37
|
+
getExperiment(name: string, user: StatsigUser, options?: ExperimentEvaluationOptions): Experiment;
|
|
38
|
+
getLayer(name: string, user: StatsigUser, options?: LayerEvaluationOptions): Layer;
|
|
16
39
|
logEvent(event: StatsigEvent, user: StatsigUser): void;
|
|
40
|
+
logEvent(eventName: string, user: StatsigUser, value?: string | number, metadata?: Record<string, string>): void;
|
|
17
41
|
}
|
|
42
|
+
export type PrecomputedEvaluationsContext = Flatten<CommonContext & {
|
|
43
|
+
values: InitializeResponseWithUpdates | null;
|
|
44
|
+
user: StatsigUser;
|
|
45
|
+
}>;
|
|
46
|
+
export type PrecomputedEvaluationsAsyncContext = Flatten<AsyncCommonContext & PrecomputedEvaluationsContext>;
|
|
18
47
|
export interface PrecomputedEvaluationsInterface extends StatsigClientCommonInterface {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
48
|
+
readonly dataAdapter: EvaluationsDataAdapter;
|
|
49
|
+
getAsyncContext(): Promise<PrecomputedEvaluationsAsyncContext>;
|
|
50
|
+
getContext(): PrecomputedEvaluationsContext;
|
|
51
|
+
updateUserSync(user: StatsigUser): void;
|
|
52
|
+
updateUserAsync(user: StatsigUser): Promise<void>;
|
|
53
|
+
checkGate(name: string, options?: FeatureGateEvaluationOptions): boolean;
|
|
54
|
+
getFeatureGate(name: string, options?: FeatureGateEvaluationOptions): FeatureGate;
|
|
55
|
+
getDynamicConfig(name: string, options?: DynamicConfigEvaluationOptions): DynamicConfig;
|
|
56
|
+
getExperiment(name: string, options?: ExperimentEvaluationOptions): Experiment;
|
|
57
|
+
getLayer(name: string, options?: LayerEvaluationOptions): Layer;
|
|
26
58
|
logEvent(event: StatsigEvent): void;
|
|
59
|
+
logEvent(eventName: string, value?: string | number, metadata?: Record<string, string>): void;
|
|
27
60
|
}
|
|
28
61
|
export type StatsigClientInterface = OnDeviceEvaluationsInterface | PrecomputedEvaluationsInterface;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ErrorBoundary } from './ErrorBoundary';
|
|
2
|
+
import { DataAdapterResult } from './StatsigDataAdapter';
|
|
3
|
+
import { AnyStatsigOptions } from './StatsigOptionsCommon';
|
|
4
|
+
import { StatsigUser } from './StatsigUser';
|
|
5
|
+
export declare abstract class DataAdapterCore {
|
|
6
|
+
private _adapterName;
|
|
7
|
+
private _cacheSuffix;
|
|
8
|
+
protected _errorBoundary: ErrorBoundary | null;
|
|
9
|
+
private _sdkKey;
|
|
10
|
+
private _inMemoryCache;
|
|
11
|
+
private _lastModifiedStoreKey;
|
|
12
|
+
protected constructor(_adapterName: string, _cacheSuffix: string);
|
|
13
|
+
attach(sdkKey: string, _options: AnyStatsigOptions | null): void;
|
|
14
|
+
getDataSync(user?: StatsigUser | undefined): DataAdapterResult | null;
|
|
15
|
+
getDataAsync(current: DataAdapterResult | null, user?: StatsigUser): Promise<DataAdapterResult | null>;
|
|
16
|
+
prefetchData(user?: StatsigUser | undefined): Promise<void>;
|
|
17
|
+
setData(data: string, user?: StatsigUser): void;
|
|
18
|
+
/**
|
|
19
|
+
* (Internal Use Only) - Used by \@statsig/react-native-bindings to prime the cache from AsyncStorage
|
|
20
|
+
*
|
|
21
|
+
* @param {Record<string, DataAdapterResult>} cache The values to merge into _inMemoryCache
|
|
22
|
+
*/
|
|
23
|
+
__primeInMemoryCache(cache: Record<string, DataAdapterResult>): void;
|
|
24
|
+
protected abstract _fetchFromNetwork(current: string | null, user?: StatsigUser): Promise<string | null>;
|
|
25
|
+
private _fetchLatest;
|
|
26
|
+
protected _getSdkKey(): string;
|
|
27
|
+
protected _getCacheKey(user?: StatsigUser): string;
|
|
28
|
+
protected _addToInMemoryCache(cacheKey: string, result: DataAdapterResult): void;
|
|
29
|
+
private _loadFromCache;
|
|
30
|
+
private _writeToCache;
|
|
31
|
+
private _runLocalStorageCacheEviction;
|
|
32
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
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.DataAdapterCore = void 0;
|
|
13
|
+
const ErrorBoundary_1 = require("./ErrorBoundary");
|
|
14
|
+
const Log_1 = require("./Log");
|
|
15
|
+
const Monitoring_1 = require("./Monitoring");
|
|
16
|
+
const StatsigDataAdapter_1 = require("./StatsigDataAdapter");
|
|
17
|
+
const StatsigUser_1 = require("./StatsigUser");
|
|
18
|
+
const StorageProvider_1 = require("./StorageProvider");
|
|
19
|
+
const TypedJsonParse_1 = require("./TypedJsonParse");
|
|
20
|
+
const CACHE_LIMIT = 10;
|
|
21
|
+
class DataAdapterCore {
|
|
22
|
+
constructor(_adapterName, _cacheSuffix) {
|
|
23
|
+
this._adapterName = _adapterName;
|
|
24
|
+
this._cacheSuffix = _cacheSuffix;
|
|
25
|
+
this._errorBoundary = null;
|
|
26
|
+
this._sdkKey = null;
|
|
27
|
+
this._inMemoryCache = {};
|
|
28
|
+
this._lastModifiedStoreKey = `statsig.last_modified_time.${_cacheSuffix}`;
|
|
29
|
+
}
|
|
30
|
+
attach(sdkKey, _options) {
|
|
31
|
+
this._sdkKey = sdkKey;
|
|
32
|
+
this._errorBoundary = new ErrorBoundary_1.ErrorBoundary(sdkKey);
|
|
33
|
+
(0, Monitoring_1.monitorClass)(this._errorBoundary, this);
|
|
34
|
+
}
|
|
35
|
+
getDataSync(user) {
|
|
36
|
+
const cacheKey = this._getCacheKey(user);
|
|
37
|
+
const result = this._inMemoryCache[cacheKey];
|
|
38
|
+
if (result) {
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
const cache = this._loadFromCache(cacheKey);
|
|
42
|
+
if (cache) {
|
|
43
|
+
this._addToInMemoryCache(cacheKey, cache);
|
|
44
|
+
return this._inMemoryCache[cacheKey];
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
getDataAsync(current, user) {
|
|
49
|
+
var _a;
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
const cache = current !== null && current !== void 0 ? current : this.getDataSync(user);
|
|
52
|
+
const latest = yield this._fetchLatest((_a = cache === null || cache === void 0 ? void 0 : cache.data) !== null && _a !== void 0 ? _a : null, user);
|
|
53
|
+
const cacheKey = this._getCacheKey(user);
|
|
54
|
+
if (latest) {
|
|
55
|
+
this._addToInMemoryCache(cacheKey, latest);
|
|
56
|
+
}
|
|
57
|
+
if ((latest === null || latest === void 0 ? void 0 : latest.source) === 'Network' ||
|
|
58
|
+
(latest === null || latest === void 0 ? void 0 : latest.source) === 'NetworkNotModified') {
|
|
59
|
+
yield this._writeToCache(cacheKey, latest);
|
|
60
|
+
}
|
|
61
|
+
return latest;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
prefetchData(user) {
|
|
65
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
66
|
+
const cacheKey = this._getCacheKey(user);
|
|
67
|
+
const result = yield this.getDataAsync(null, user);
|
|
68
|
+
if (result) {
|
|
69
|
+
this._addToInMemoryCache(cacheKey, Object.assign(Object.assign({}, result), { source: 'Prefetch' }));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
setData(data, user) {
|
|
74
|
+
const cacheKey = this._getCacheKey(user);
|
|
75
|
+
this._addToInMemoryCache(cacheKey, {
|
|
76
|
+
source: 'Bootstrap',
|
|
77
|
+
data,
|
|
78
|
+
receivedAt: Date.now(),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* (Internal Use Only) - Used by \@statsig/react-native-bindings to prime the cache from AsyncStorage
|
|
83
|
+
*
|
|
84
|
+
* @param {Record<string, DataAdapterResult>} cache The values to merge into _inMemoryCache
|
|
85
|
+
*/
|
|
86
|
+
__primeInMemoryCache(cache) {
|
|
87
|
+
this._inMemoryCache = Object.assign(Object.assign({}, this._inMemoryCache), cache);
|
|
88
|
+
}
|
|
89
|
+
_fetchLatest(current, user) {
|
|
90
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
91
|
+
const latest = yield this._fetchFromNetwork(current, user);
|
|
92
|
+
if (!latest) {
|
|
93
|
+
Log_1.Log.debug('No response returned for latest value');
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const response = (0, TypedJsonParse_1.typedJsonParse)(latest, 'has_updates', 'Failure while attempting to persist latest value');
|
|
97
|
+
if (current && (response === null || response === void 0 ? void 0 : response.has_updates) === false) {
|
|
98
|
+
return {
|
|
99
|
+
source: 'NetworkNotModified',
|
|
100
|
+
data: current,
|
|
101
|
+
receivedAt: Date.now(),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if ((response === null || response === void 0 ? void 0 : response.has_updates) !== true) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
return { source: 'Network', data: latest, receivedAt: Date.now() };
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
_getSdkKey() {
|
|
111
|
+
if (this._sdkKey != null) {
|
|
112
|
+
return this._sdkKey;
|
|
113
|
+
}
|
|
114
|
+
Log_1.Log.error(`${this._adapterName} is not attached to a Client`);
|
|
115
|
+
return '';
|
|
116
|
+
}
|
|
117
|
+
_getCacheKey(user) {
|
|
118
|
+
const key = (0, StatsigUser_1.getUserStorageKey)(this._getSdkKey(), user);
|
|
119
|
+
return `${StatsigDataAdapter_1.DataAdapterCachePrefix}.${this._cacheSuffix}.${key}`;
|
|
120
|
+
}
|
|
121
|
+
_addToInMemoryCache(cacheKey, result) {
|
|
122
|
+
const entries = Object.entries(this._inMemoryCache);
|
|
123
|
+
if (entries.length < CACHE_LIMIT) {
|
|
124
|
+
this._inMemoryCache[cacheKey] = result;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const [oldest] = entries.reduce((acc, curr) => {
|
|
128
|
+
return curr[1] < acc[1] ? curr : acc;
|
|
129
|
+
});
|
|
130
|
+
delete this._inMemoryCache[oldest];
|
|
131
|
+
this._inMemoryCache[cacheKey] = result;
|
|
132
|
+
}
|
|
133
|
+
_loadFromCache(cacheKey) {
|
|
134
|
+
var _a;
|
|
135
|
+
const cache = (_a = StorageProvider_1.Storage._getItemSync) === null || _a === void 0 ? void 0 : _a.call(StorageProvider_1.Storage, cacheKey);
|
|
136
|
+
if (cache == null) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
const result = (0, TypedJsonParse_1.typedJsonParse)(cache, 'source', 'Failed to parse cached result');
|
|
140
|
+
return result ? Object.assign(Object.assign({}, result), { source: 'Cache' }) : null;
|
|
141
|
+
}
|
|
142
|
+
_writeToCache(cacheKey, result) {
|
|
143
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
144
|
+
yield StorageProvider_1.Storage._setItem(cacheKey, JSON.stringify(result));
|
|
145
|
+
yield this._runLocalStorageCacheEviction(cacheKey);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
_runLocalStorageCacheEviction(cacheKey) {
|
|
149
|
+
var _a;
|
|
150
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
151
|
+
const lastModifiedTimeMap = (_a = (yield (0, StorageProvider_1._getObjectFromStorage)(this._lastModifiedStoreKey))) !== null && _a !== void 0 ? _a : {};
|
|
152
|
+
lastModifiedTimeMap[cacheKey] = Date.now();
|
|
153
|
+
const entries = Object.entries(lastModifiedTimeMap);
|
|
154
|
+
if (entries.length <= CACHE_LIMIT) {
|
|
155
|
+
yield (0, StorageProvider_1._setObjectInStorage)(this._lastModifiedStoreKey, lastModifiedTimeMap);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const oldest = entries.reduce((acc, current) => {
|
|
159
|
+
return current[1] < acc[1] ? current : acc;
|
|
160
|
+
});
|
|
161
|
+
delete lastModifiedTimeMap[oldest[0]];
|
|
162
|
+
yield StorageProvider_1.Storage._removeItem(oldest[0]);
|
|
163
|
+
yield (0, StorageProvider_1._setObjectInStorage)(this._lastModifiedStoreKey, lastModifiedTimeMap);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
exports.DataAdapterCore = DataAdapterCore;
|
package/src/Diagnostics.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Diagnostics = exports.captureDiagnostics = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
const Log_1 = require("./Log");
|
|
5
|
+
const NetworkDefaults_1 = require("./NetworkDefaults");
|
|
6
|
+
const SUPPORTS_PERFORMANCE_API = typeof performance !== 'undefined' && typeof performance.mark !== 'undefined';
|
|
7
|
+
let markers = [];
|
|
7
8
|
function captureDiagnostics(func, task) {
|
|
8
|
-
Diagnostics.mark(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Diagnostics.mark(
|
|
12
|
-
maybeFlush(
|
|
9
|
+
Diagnostics.mark(`${func}:start`);
|
|
10
|
+
const result = task();
|
|
11
|
+
const markEnd = () => {
|
|
12
|
+
Diagnostics.mark(`${func}:end`);
|
|
13
|
+
maybeFlush(`${func}:end`);
|
|
13
14
|
};
|
|
14
15
|
if (result && result instanceof Promise) {
|
|
15
|
-
return result.finally(
|
|
16
|
+
return result.finally(() => markEnd());
|
|
16
17
|
}
|
|
17
18
|
else {
|
|
18
19
|
markEnd();
|
|
@@ -20,32 +21,29 @@ function captureDiagnostics(func, task) {
|
|
|
20
21
|
return result;
|
|
21
22
|
}
|
|
22
23
|
exports.captureDiagnostics = captureDiagnostics;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
Diagnostics.mark = function (tag, metadata) {
|
|
24
|
+
class Diagnostics {
|
|
25
|
+
static mark(tag, metadata) {
|
|
27
26
|
if (!SUPPORTS_PERFORMANCE_API) {
|
|
28
27
|
return;
|
|
29
28
|
}
|
|
30
|
-
|
|
29
|
+
const marker = performance.mark(tag, { detail: metadata });
|
|
31
30
|
markers.push(marker);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
}
|
|
32
|
+
static flush() {
|
|
33
|
+
const resources = performance
|
|
35
34
|
.getEntriesByType('resource')
|
|
36
|
-
.filter(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
markers
|
|
41
|
-
resources
|
|
35
|
+
.filter((resource) => resource.name.startsWith(NetworkDefaults_1.NetworkDefault.initializeApi) ||
|
|
36
|
+
resource.name.startsWith(NetworkDefaults_1.NetworkDefault.specsApi) ||
|
|
37
|
+
resource.name.startsWith(NetworkDefaults_1.NetworkDefault.eventsApi));
|
|
38
|
+
const payload = {
|
|
39
|
+
markers,
|
|
40
|
+
resources,
|
|
42
41
|
};
|
|
43
42
|
// TODO: Send as log to Statsig
|
|
44
43
|
Log_1.Log.debug('Diagnostics', payload, JSON.stringify(payload));
|
|
45
44
|
markers = [];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
}());
|
|
45
|
+
}
|
|
46
|
+
}
|
|
49
47
|
exports.Diagnostics = Diagnostics;
|
|
50
48
|
function maybeFlush(tag) {
|
|
51
49
|
if (tag.startsWith('initialize:')) {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type SpecCondition = {
|
|
2
|
+
type: string;
|
|
3
|
+
targetValue: unknown;
|
|
4
|
+
operator: string | null;
|
|
5
|
+
field: string | null;
|
|
6
|
+
additionalValues: Record<string, unknown> | null;
|
|
7
|
+
idType: string;
|
|
8
|
+
};
|
|
9
|
+
export type SpecRule = {
|
|
10
|
+
name: string;
|
|
11
|
+
passPercentage: number;
|
|
12
|
+
conditions: SpecCondition[];
|
|
13
|
+
returnValue: unknown;
|
|
14
|
+
id: string;
|
|
15
|
+
salt: string;
|
|
16
|
+
idType: string;
|
|
17
|
+
configDelegate: string | null;
|
|
18
|
+
isExperimentGroup?: boolean;
|
|
19
|
+
groupName?: string;
|
|
20
|
+
};
|
|
21
|
+
export type Spec = {
|
|
22
|
+
name: string;
|
|
23
|
+
type: string;
|
|
24
|
+
salt: string;
|
|
25
|
+
defaultValue: unknown;
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
idType: string;
|
|
28
|
+
rules: SpecRule[];
|
|
29
|
+
entity: string;
|
|
30
|
+
explicitParameters: string[] | null;
|
|
31
|
+
hasSharedParams: boolean;
|
|
32
|
+
isActive?: boolean;
|
|
33
|
+
targetAppIDs?: string[];
|
|
34
|
+
};
|
|
35
|
+
export type DownloadConfigSpecsResponse = {
|
|
36
|
+
feature_gates: Spec[];
|
|
37
|
+
dynamic_configs: Spec[];
|
|
38
|
+
layer_configs: Spec[];
|
|
39
|
+
time: number;
|
|
40
|
+
has_updates: boolean;
|
|
41
|
+
};
|
package/src/ErrorBoundary.d.ts
CHANGED
package/src/ErrorBoundary.js
CHANGED
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __assign = (this && this.__assign) || function () {
|
|
3
|
-
__assign = Object.assign || function(t) {
|
|
4
|
-
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
-
s = arguments[i];
|
|
6
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
-
t[p] = s[p];
|
|
8
|
-
}
|
|
9
|
-
return t;
|
|
10
|
-
};
|
|
11
|
-
return __assign.apply(this, arguments);
|
|
12
|
-
};
|
|
13
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -19,49 +8,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
19
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
9
|
});
|
|
21
10
|
};
|
|
22
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
24
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
-
function step(op) {
|
|
27
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
-
switch (op[0]) {
|
|
32
|
-
case 0: case 1: t = op; break;
|
|
33
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
-
default:
|
|
37
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
-
if (t[2]) _.ops.pop();
|
|
42
|
-
_.trys.pop(); continue;
|
|
43
|
-
}
|
|
44
|
-
op = body.call(thisArg, _);
|
|
45
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
12
|
exports.ErrorBoundary = exports.EXCEPTION_ENDPOINT = void 0;
|
|
51
|
-
|
|
52
|
-
|
|
13
|
+
const Log_1 = require("./Log");
|
|
14
|
+
const SDKType_1 = require("./SDKType");
|
|
15
|
+
const StatsigMetadata_1 = require("./StatsigMetadata");
|
|
53
16
|
exports.EXCEPTION_ENDPOINT = 'https://statsigapi.net/v1/sdk_exception';
|
|
54
|
-
|
|
55
|
-
|
|
17
|
+
class ErrorBoundary {
|
|
18
|
+
constructor(_sdkKey) {
|
|
56
19
|
this._sdkKey = _sdkKey;
|
|
57
20
|
this._seen = new Set();
|
|
58
21
|
}
|
|
59
|
-
|
|
60
|
-
var _this = this;
|
|
22
|
+
capture(tag, task, emitter) {
|
|
61
23
|
try {
|
|
62
|
-
|
|
24
|
+
const res = task();
|
|
63
25
|
if (res && res instanceof Promise) {
|
|
64
|
-
return res.catch(
|
|
26
|
+
return res.catch((err) => this._onError(tag, err, emitter));
|
|
65
27
|
}
|
|
66
28
|
return res;
|
|
67
29
|
}
|
|
@@ -69,57 +31,50 @@ var ErrorBoundary = /** @class */ (function () {
|
|
|
69
31
|
this._onError(tag, error, emitter);
|
|
70
32
|
return null;
|
|
71
33
|
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
34
|
+
}
|
|
35
|
+
logError(tag, error) {
|
|
36
|
+
this._onError(tag, error);
|
|
37
|
+
}
|
|
38
|
+
_onError(tag, error, emitter) {
|
|
75
39
|
try {
|
|
76
|
-
Log_1.Log.warn(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
'Content-Type': 'application/json',
|
|
99
|
-
},
|
|
100
|
-
body: body,
|
|
101
|
-
})];
|
|
102
|
-
case 1:
|
|
103
|
-
_a.sent();
|
|
104
|
-
emitter === null || emitter === void 0 ? void 0 : emitter({ event: 'error', error: error });
|
|
105
|
-
return [2 /*return*/];
|
|
106
|
-
}
|
|
40
|
+
Log_1.Log.warn(`Caught error in ${tag}`, { error });
|
|
41
|
+
const impl = () => __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
const unwrapped = (error !== null && error !== void 0 ? error : Error('[Statsig] Error was empty'));
|
|
43
|
+
const isError = unwrapped instanceof Error;
|
|
44
|
+
const name = isError ? unwrapped.name : 'No Name';
|
|
45
|
+
if (this._seen.has(name)) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
this._seen.add(name);
|
|
49
|
+
const sdkType = SDKType_1.SDKType._get(this._sdkKey);
|
|
50
|
+
const statsigMetadata = StatsigMetadata_1.StatsigMetadataProvider.get();
|
|
51
|
+
const info = isError ? unwrapped.stack : _getDescription(unwrapped);
|
|
52
|
+
const body = JSON.stringify(Object.assign({ tag, exception: name, info }, Object.assign(Object.assign({}, statsigMetadata), { sdkType })));
|
|
53
|
+
yield fetch(exports.EXCEPTION_ENDPOINT, {
|
|
54
|
+
method: 'POST',
|
|
55
|
+
headers: {
|
|
56
|
+
'STATSIG-API-KEY': this._sdkKey,
|
|
57
|
+
'STATSIG-SDK-TYPE': String(sdkType),
|
|
58
|
+
'STATSIG-SDK-VERSION': String(statsigMetadata.sdkVersion),
|
|
59
|
+
'Content-Type': 'application/json',
|
|
60
|
+
},
|
|
61
|
+
body,
|
|
107
62
|
});
|
|
108
|
-
|
|
63
|
+
emitter === null || emitter === void 0 ? void 0 : emitter({ name: 'error', error });
|
|
64
|
+
});
|
|
109
65
|
impl()
|
|
110
|
-
.then(
|
|
66
|
+
.then(() => {
|
|
111
67
|
/* noop */
|
|
112
68
|
})
|
|
113
|
-
.catch(
|
|
69
|
+
.catch(() => {
|
|
114
70
|
/* noop */
|
|
115
71
|
});
|
|
116
72
|
}
|
|
117
73
|
catch (_error) {
|
|
118
74
|
/* noop */
|
|
119
75
|
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
}());
|
|
76
|
+
}
|
|
77
|
+
}
|
|
123
78
|
exports.ErrorBoundary = ErrorBoundary;
|
|
124
79
|
function _getDescription(obj) {
|
|
125
80
|
try {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type EvaluationOptionsCommon = {
|
|
2
|
+
/**
|
|
3
|
+
* Prevents an exposure log being created for this check.
|
|
4
|
+
*
|
|
5
|
+
* default: `false`
|
|
6
|
+
*/
|
|
7
|
+
disableExposureLog?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type FeatureGateEvaluationOptions = EvaluationOptionsCommon & {};
|
|
10
|
+
export type DynamicConfigEvaluationOptions = EvaluationOptionsCommon & {};
|
|
11
|
+
export type ExperimentEvaluationOptions = EvaluationOptionsCommon & {
|
|
12
|
+
/**
|
|
13
|
+
* Provide a map of values to be used across checks
|
|
14
|
+
*
|
|
15
|
+
* @requires {@link @statsig/js-user-persisted-storage}
|
|
16
|
+
* @see {@link https://docs.statsig.com/client/concepts/persistent_assignment#example-usage}
|
|
17
|
+
*/
|
|
18
|
+
userPersistedValues?: unknown;
|
|
19
|
+
};
|
|
20
|
+
export type LayerEvaluationOptions = EvaluationOptionsCommon & {};
|