@statsig/client-core 0.0.1-beta.2 → 0.0.1-beta.20
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.js +8 -12
- package/src/ClientInterfaces.d.ts +20 -13
- package/src/DataAdapterCore.d.ts +32 -0
- package/src/DataAdapterCore.js +167 -0
- package/src/Diagnostics.js +21 -26
- package/src/ErrorBoundary.d.ts +1 -0
- package/src/ErrorBoundary.js +39 -86
- package/src/EvaluationOptions.d.ts +20 -0
- package/src/EvaluationTypes.d.ts +39 -0
- package/src/EvaluationTypes.js +2 -0
- package/src/EventLogger.d.ts +17 -4
- package/src/EventLogger.js +186 -225
- package/src/Hashing.d.ts +1 -0
- package/src/Hashing.js +23 -4
- package/src/Log.js +15 -34
- package/src/Monitoring.d.ts +1 -2
- package/src/Monitoring.js +68 -27
- package/src/NetworkCore.d.ts +13 -5
- package/src/NetworkCore.js +96 -164
- package/src/OverrideAdapter.d.ts +16 -0
- package/src/OverrideAdapter.js +24 -0
- package/src/SessionID.js +3 -3
- package/src/StableID.js +23 -52
- package/src/StatsigClientBase.d.ts +20 -29
- package/src/StatsigClientBase.js +57 -247
- package/src/StatsigClientEventEmitter.d.ts +55 -28
- package/src/StatsigDataAdapter.d.ts +89 -0
- package/src/StatsigDataAdapter.js +4 -0
- package/src/StatsigEvent.d.ts +9 -18
- package/src/StatsigEvent.js +40 -31
- package/src/StatsigMetadata.js +5 -16
- package/src/StatsigOptionsCommon.d.ts +42 -12
- package/src/StatsigTypes.d.ts +23 -15
- package/src/StatsigTypes.js +23 -16
- package/src/StatsigUser.d.ts +1 -0
- package/src/StatsigUser.js +12 -20
- package/src/StorageProvider.d.ts +7 -2
- package/src/StorageProvider.js +53 -62
- package/src/TypedJsonParse.d.ts +8 -0
- package/src/TypedJsonParse.js +27 -0
- package/src/UUID.js +5 -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/VisibilityChangeObserver.js +18 -24
- package/src/__tests__/MockLocalStorage.js +18 -19
- package/src/index.d.ts +12 -3
- package/src/index.js +18 -16
- package/src/StatsigDataProvider.d.ts +0 -9
- /package/src/{StatsigDataProvider.js → EvaluationOptions.js} +0 -0
package/README.md
CHANGED
package/package.json
CHANGED
package/src/$_StatsigGlobal.js
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var _a, _b, _c;
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
if (typeof globalThis !== 'undefined') {
|
|
12
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
|
|
13
|
-
globalThis.__STATSIG__ = statsigGlobal;
|
|
14
|
-
}
|
|
4
|
+
const _window = typeof window !== 'undefined' ? window : {};
|
|
5
|
+
const _global = typeof global !== 'undefined' ? global : {};
|
|
6
|
+
const _globalThis = typeof globalThis !== 'undefined' ? globalThis : {};
|
|
7
|
+
const statsigGlobal = (_c = (_b = (_a = _window.__STATSIG__) !== null && _a !== void 0 ? _a : _global.__STATSIG__) !== null && _b !== void 0 ? _b : _globalThis.__STATSIG__) !== null && _c !== void 0 ? _c : {};
|
|
8
|
+
_window.__STATSIG__ = statsigGlobal;
|
|
9
|
+
_global.__STATSIG__ = statsigGlobal;
|
|
10
|
+
_globalThis.__STATSIG__ = statsigGlobal;
|
|
@@ -1,28 +1,35 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DynamicConfigEvaluationOptions, ExperimentEvaluationOptions, FeatureGateEvaluationOptions, LayerEvaluationOptions } from './EvaluationOptions';
|
|
2
2
|
import { StatsigClientEventEmitterInterface } from './StatsigClientEventEmitter';
|
|
3
|
+
import { EvaluationsDataAdapter, SpecsDataAdapter } from './StatsigDataAdapter';
|
|
3
4
|
import { StatsigEvent } from './StatsigEvent';
|
|
5
|
+
import { StatsigRuntimeMutableOptions } from './StatsigOptionsCommon';
|
|
4
6
|
import { DynamicConfig, Experiment, FeatureGate, Layer } from './StatsigTypes';
|
|
5
7
|
import { StatsigUser } from './StatsigUser';
|
|
6
8
|
export interface StatsigClientCommonInterface extends StatsigClientEventEmitterInterface {
|
|
7
|
-
|
|
9
|
+
initializeSync(): void;
|
|
10
|
+
initializeAsync(): Promise<void>;
|
|
8
11
|
shutdown(): Promise<void>;
|
|
12
|
+
updateRuntimeOptions(options: StatsigRuntimeMutableOptions): void;
|
|
9
13
|
}
|
|
10
14
|
export interface OnDeviceEvaluationsInterface extends StatsigClientCommonInterface {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
readonly dataAdapter: SpecsDataAdapter;
|
|
16
|
+
checkGate(name: string, user: StatsigUser, options?: FeatureGateEvaluationOptions): boolean;
|
|
17
|
+
getFeatureGate(name: string, user: StatsigUser, options?: FeatureGateEvaluationOptions): FeatureGate;
|
|
18
|
+
getDynamicConfig(name: string, user: StatsigUser, options?: DynamicConfigEvaluationOptions): DynamicConfig;
|
|
19
|
+
getExperiment(name: string, user: StatsigUser, options?: ExperimentEvaluationOptions): Experiment;
|
|
20
|
+
getLayer(name: string, user: StatsigUser, options?: LayerEvaluationOptions): Layer;
|
|
16
21
|
logEvent(event: StatsigEvent, user: StatsigUser): void;
|
|
17
22
|
}
|
|
18
23
|
export interface PrecomputedEvaluationsInterface extends StatsigClientCommonInterface {
|
|
24
|
+
readonly dataAdapter: EvaluationsDataAdapter;
|
|
19
25
|
getCurrentUser(): StatsigUser;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
updateUserSync(user: StatsigUser): void;
|
|
27
|
+
updateUserAsync(user: StatsigUser): Promise<void>;
|
|
28
|
+
checkGate(name: string, options?: FeatureGateEvaluationOptions): boolean;
|
|
29
|
+
getFeatureGate(name: string, options?: FeatureGateEvaluationOptions): FeatureGate;
|
|
30
|
+
getDynamicConfig(name: string, options?: DynamicConfigEvaluationOptions): DynamicConfig;
|
|
31
|
+
getExperiment(name: string, options?: ExperimentEvaluationOptions): Experiment;
|
|
32
|
+
getLayer(name: string, options?: LayerEvaluationOptions): Layer;
|
|
26
33
|
logEvent(event: StatsigEvent): void;
|
|
27
34
|
}
|
|
28
35
|
export type StatsigClientInterface = OnDeviceEvaluationsInterface | PrecomputedEvaluationsInterface;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ErrorBoundary } from './ErrorBoundary';
|
|
2
|
+
import { DataAdapterResult } from './StatsigDataAdapter';
|
|
3
|
+
import { StatsigOptionsCommon } 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: StatsigOptionsCommon | 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,18 @@
|
|
|
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 SUPPORTS_PERFORMANCE_API = typeof performance !== 'undefined' && typeof performance.mark !== 'undefined';
|
|
6
|
+
let markers = [];
|
|
7
7
|
function captureDiagnostics(func, task) {
|
|
8
|
-
Diagnostics.mark(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Diagnostics.mark(
|
|
12
|
-
maybeFlush(
|
|
8
|
+
Diagnostics.mark(`${func}:start`);
|
|
9
|
+
const result = task();
|
|
10
|
+
const markEnd = () => {
|
|
11
|
+
Diagnostics.mark(`${func}:end`);
|
|
12
|
+
maybeFlush(`${func}:end`);
|
|
13
13
|
};
|
|
14
14
|
if (result && result instanceof Promise) {
|
|
15
|
-
return result.finally(
|
|
15
|
+
return result.finally(() => markEnd());
|
|
16
16
|
}
|
|
17
17
|
else {
|
|
18
18
|
markEnd();
|
|
@@ -20,32 +20,27 @@ function captureDiagnostics(func, task) {
|
|
|
20
20
|
return result;
|
|
21
21
|
}
|
|
22
22
|
exports.captureDiagnostics = captureDiagnostics;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
Diagnostics.mark = function (tag, metadata) {
|
|
23
|
+
class Diagnostics {
|
|
24
|
+
static mark(tag, metadata) {
|
|
27
25
|
if (!SUPPORTS_PERFORMANCE_API) {
|
|
28
26
|
return;
|
|
29
27
|
}
|
|
30
|
-
|
|
28
|
+
const marker = performance.mark(tag, { detail: metadata });
|
|
31
29
|
markers.push(marker);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
}
|
|
31
|
+
static flush() {
|
|
32
|
+
const resources = performance
|
|
35
33
|
.getEntriesByType('resource')
|
|
36
|
-
.filter(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
markers: markers,
|
|
41
|
-
resources: resources,
|
|
34
|
+
.filter((resource) => resource.name.startsWith('https://api.statsig.com'));
|
|
35
|
+
const payload = {
|
|
36
|
+
markers,
|
|
37
|
+
resources,
|
|
42
38
|
};
|
|
43
39
|
// TODO: Send as log to Statsig
|
|
44
40
|
Log_1.Log.debug('Diagnostics', payload, JSON.stringify(payload));
|
|
45
41
|
markers = [];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
}());
|
|
42
|
+
}
|
|
43
|
+
}
|
|
49
44
|
exports.Diagnostics = Diagnostics;
|
|
50
45
|
function maybeFlush(tag) {
|
|
51
46
|
if (tag.startsWith('initialize:')) {
|
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,21 @@ 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 StatsigMetadata_1 = require("./StatsigMetadata");
|
|
53
15
|
exports.EXCEPTION_ENDPOINT = 'https://statsigapi.net/v1/sdk_exception';
|
|
54
|
-
|
|
55
|
-
|
|
16
|
+
class ErrorBoundary {
|
|
17
|
+
constructor(_sdkKey) {
|
|
56
18
|
this._sdkKey = _sdkKey;
|
|
57
19
|
this._seen = new Set();
|
|
58
20
|
}
|
|
59
|
-
|
|
60
|
-
var _this = this;
|
|
21
|
+
capture(tag, task, emitter) {
|
|
61
22
|
try {
|
|
62
|
-
|
|
23
|
+
const res = task();
|
|
63
24
|
if (res && res instanceof Promise) {
|
|
64
|
-
return res.catch(
|
|
25
|
+
return res.catch((err) => this._onError(tag, err, emitter));
|
|
65
26
|
}
|
|
66
27
|
return res;
|
|
67
28
|
}
|
|
@@ -69,57 +30,49 @@ var ErrorBoundary = /** @class */ (function () {
|
|
|
69
30
|
this._onError(tag, error, emitter);
|
|
70
31
|
return null;
|
|
71
32
|
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
33
|
+
}
|
|
34
|
+
logError(tag, error) {
|
|
35
|
+
this._onError(tag, error);
|
|
36
|
+
}
|
|
37
|
+
_onError(tag, error, emitter) {
|
|
75
38
|
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
|
-
'STATSIG-SDK-VERSION': String(statsigMetadata.sdkVersion),
|
|
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
|
-
}
|
|
39
|
+
Log_1.Log.warn(`Caught error in ${tag}`, { error });
|
|
40
|
+
const impl = () => __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
const unwrapped = (error !== null && error !== void 0 ? error : Error('[Statsig] Error was empty'));
|
|
42
|
+
const isError = unwrapped instanceof Error;
|
|
43
|
+
const name = isError ? unwrapped.name : 'No Name';
|
|
44
|
+
if (this._seen.has(name)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
this._seen.add(name);
|
|
48
|
+
const statsigMetadata = StatsigMetadata_1.StatsigMetadataProvider.get();
|
|
49
|
+
const info = isError ? unwrapped.stack : _getDescription(unwrapped);
|
|
50
|
+
const body = JSON.stringify(Object.assign({ tag, exception: name, info }, statsigMetadata));
|
|
51
|
+
yield fetch(exports.EXCEPTION_ENDPOINT, {
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers: {
|
|
54
|
+
'STATSIG-API-KEY': this._sdkKey,
|
|
55
|
+
'STATSIG-SDK-TYPE': String(statsigMetadata.sdkType),
|
|
56
|
+
'STATSIG-SDK-VERSION': String(statsigMetadata.sdkVersion),
|
|
57
|
+
'Content-Type': 'application/json',
|
|
58
|
+
},
|
|
59
|
+
body,
|
|
107
60
|
});
|
|
108
|
-
|
|
61
|
+
emitter === null || emitter === void 0 ? void 0 : emitter({ name: 'error', error });
|
|
62
|
+
});
|
|
109
63
|
impl()
|
|
110
|
-
.then(
|
|
64
|
+
.then(() => {
|
|
111
65
|
/* noop */
|
|
112
66
|
})
|
|
113
|
-
.catch(
|
|
67
|
+
.catch(() => {
|
|
114
68
|
/* noop */
|
|
115
69
|
});
|
|
116
70
|
}
|
|
117
71
|
catch (_error) {
|
|
118
72
|
/* noop */
|
|
119
73
|
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
}());
|
|
74
|
+
}
|
|
75
|
+
}
|
|
123
76
|
exports.ErrorBoundary = ErrorBoundary;
|
|
124
77
|
function _getDescription(obj) {
|
|
125
78
|
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 & {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Flatten } from './UtitlityTypes';
|
|
2
|
+
type EvaluationBase<T> = {
|
|
3
|
+
id_type: string;
|
|
4
|
+
name: string;
|
|
5
|
+
rule_id: string;
|
|
6
|
+
secondary_exposures: SecondaryExposure[];
|
|
7
|
+
value: T;
|
|
8
|
+
};
|
|
9
|
+
export type SecondaryExposure = {
|
|
10
|
+
gate: string;
|
|
11
|
+
gateValue: string;
|
|
12
|
+
ruleID: string;
|
|
13
|
+
};
|
|
14
|
+
export type GateEvaluation = EvaluationBase<boolean>;
|
|
15
|
+
export type ExperimentEvaluation = Flatten<EvaluationBase<Record<string, unknown>> & {
|
|
16
|
+
group_name?: string;
|
|
17
|
+
group: string;
|
|
18
|
+
id_type: string;
|
|
19
|
+
is_device_based: boolean;
|
|
20
|
+
is_experiment_active?: boolean;
|
|
21
|
+
is_user_in_experiment?: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
export type DynamicConfigEvaluation = ExperimentEvaluation;
|
|
24
|
+
export type LayerEvaluation = Flatten<Omit<ExperimentEvaluation, 'id_type'> & {
|
|
25
|
+
allocated_experiment_name: string;
|
|
26
|
+
explicit_parameters: string[];
|
|
27
|
+
undelegated_secondary_exposures?: SecondaryExposure[];
|
|
28
|
+
}>;
|
|
29
|
+
export type AnyEvaluation = GateEvaluation | ExperimentEvaluation | DynamicConfigEvaluation | LayerEvaluation;
|
|
30
|
+
export type EvaluationDetails = {
|
|
31
|
+
reason: string;
|
|
32
|
+
lcut?: number;
|
|
33
|
+
receivedAt?: number;
|
|
34
|
+
};
|
|
35
|
+
export type DetailedEvaluation<T extends AnyEvaluation> = {
|
|
36
|
+
evaluation: T | null;
|
|
37
|
+
details: EvaluationDetails;
|
|
38
|
+
};
|
|
39
|
+
export {};
|
package/src/EventLogger.d.ts
CHANGED
|
@@ -10,22 +10,35 @@ export declare class EventLogger {
|
|
|
10
10
|
private _options;
|
|
11
11
|
private _queue;
|
|
12
12
|
private _flushTimer;
|
|
13
|
-
private
|
|
13
|
+
private _lastExposureTimeMap;
|
|
14
|
+
private _nonExposedChecks;
|
|
14
15
|
private _maxQueueSize;
|
|
15
|
-
private
|
|
16
|
+
private _hasRunQuickFlush;
|
|
17
|
+
private _creationTime;
|
|
18
|
+
private _isLoggingDisabled;
|
|
19
|
+
private _logEventUrl;
|
|
20
|
+
private _logEventBeaconUrl;
|
|
16
21
|
constructor(_sdkKey: string, _emitter: StatsigClientEmitEventFunc, _network: NetworkCore, _options: StatsigOptionsCommon | null);
|
|
22
|
+
setLoggingDisabled(isDisabled: boolean): void;
|
|
17
23
|
enqueue(event: StatsigEventInternal): void;
|
|
24
|
+
incrementNonExposureCount(name: string): void;
|
|
18
25
|
reset(): void;
|
|
19
26
|
onVisibilityChanged(visibility: Visibility): void;
|
|
20
27
|
shutdown(): Promise<void>;
|
|
28
|
+
flush(): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* We 'Quick Flush' following the very first event enqueued
|
|
31
|
+
* within the quick flush window
|
|
32
|
+
*/
|
|
33
|
+
private _quickFlushIfNeeded;
|
|
21
34
|
private _shouldLogEvent;
|
|
22
35
|
private _flushAndForget;
|
|
23
|
-
private _flush;
|
|
24
36
|
private _sendEvents;
|
|
25
37
|
private _sendEventsViaPost;
|
|
26
38
|
private _sendEventsViaBeacon;
|
|
27
|
-
private _isBeaconSupported;
|
|
28
39
|
private _saveFailedLogsToStorage;
|
|
29
40
|
private _retryFailedLogs;
|
|
30
41
|
private _getStorageKey;
|
|
42
|
+
private _normalizeAndAppendEvent;
|
|
43
|
+
private _appendAndResetNonExposedChecks;
|
|
31
44
|
}
|