@statsig/client-core 3.3.0-beta.3 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/$_StatsigGlobal.d.ts +1 -1
- package/src/$_StatsigGlobal.js +5 -1
- package/src/NetworkCore.d.ts +2 -7
- package/src/NetworkCore.js +39 -78
- package/src/StatsigClientBase.js +4 -2
- package/src/StatsigMetadata.d.ts +1 -1
- package/src/StatsigMetadata.js +1 -1
- package/src/StatsigTypeFactories.d.ts +1 -1
- package/src/StatsigTypeFactories.js +6 -4
- package/src/index.d.ts +2 -2
- package/src/index.js +2 -2
- package/src/NetworkFallbackResolver.d.ts +0 -20
- package/src/NetworkFallbackResolver.js +0 -208
package/package.json
CHANGED
package/src/$_StatsigGlobal.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { StatsigClientInterface } from './ClientInterfaces';
|
|
|
2
2
|
export type StatsigGlobal = {
|
|
3
3
|
[key: string]: unknown;
|
|
4
4
|
instances?: Record<string, StatsigClientInterface>;
|
|
5
|
-
|
|
5
|
+
firstInstance?: StatsigClientInterface;
|
|
6
6
|
acInstances?: Record<string, unknown>;
|
|
7
7
|
srInstances?: Record<string, unknown>;
|
|
8
8
|
instance: (sdkKey?: string) => StatsigClientInterface | undefined;
|
package/src/$_StatsigGlobal.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var _a, _b, _c;
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports._getInstance = exports._getStatsigGlobalFlag = exports._getStatsigGlobal = void 0;
|
|
6
|
+
const Log_1 = require("./Log");
|
|
6
7
|
const _getStatsigGlobal = () => {
|
|
7
8
|
return __STATSIG__ ? __STATSIG__ : statsigGlobal;
|
|
8
9
|
};
|
|
@@ -14,7 +15,10 @@ exports._getStatsigGlobalFlag = _getStatsigGlobalFlag;
|
|
|
14
15
|
const _getInstance = (sdkKey) => {
|
|
15
16
|
const gbl = (0, exports._getStatsigGlobal)();
|
|
16
17
|
if (!sdkKey) {
|
|
17
|
-
|
|
18
|
+
if (gbl.instances && Object.keys(gbl.instances).length > 1) {
|
|
19
|
+
Log_1.Log.warn('Call made to Statsig global instance without an SDK key but there is more than one client instance. If you are using mulitple clients, please specify the SDK key.');
|
|
20
|
+
}
|
|
21
|
+
return gbl.firstInstance;
|
|
18
22
|
}
|
|
19
23
|
return gbl.instances && gbl.instances[sdkKey];
|
|
20
24
|
};
|
package/src/NetworkCore.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import './$_StatsigGlobal';
|
|
2
|
-
import { ErrorBoundary } from './ErrorBoundary';
|
|
3
2
|
import { NetworkPriority } from './NetworkConfig';
|
|
4
3
|
import { StatsigClientEmitEventFunc } from './StatsigClientBase';
|
|
5
4
|
import { AnyStatsigOptions } from './StatsigOptionsCommon';
|
|
@@ -29,18 +28,14 @@ export declare class NetworkCore {
|
|
|
29
28
|
private readonly _timeout;
|
|
30
29
|
private readonly _netConfig;
|
|
31
30
|
private readonly _options;
|
|
32
|
-
private readonly _fallbackResolver;
|
|
33
|
-
private _errorBoundary;
|
|
34
31
|
constructor(options: AnyStatsigOptions | null, _emitter?: StatsigClientEmitEventFunc | undefined);
|
|
35
|
-
setErrorBoundary(errorBoundary: ErrorBoundary): void;
|
|
36
|
-
isBeaconSupported(): boolean;
|
|
37
|
-
beacon(args: BeaconRequestArgs): Promise<boolean>;
|
|
38
32
|
post(args: RequestArgsWithData): Promise<NetworkResponse | null>;
|
|
39
33
|
get(args: RequestArgs): Promise<NetworkResponse | null>;
|
|
34
|
+
isBeaconSupported(): boolean;
|
|
35
|
+
beacon(args: BeaconRequestArgs): Promise<boolean>;
|
|
40
36
|
private _sendRequest;
|
|
41
37
|
private _getPopulatedURL;
|
|
42
38
|
private _getPopulatedBody;
|
|
43
39
|
private _attemptToEncodeString;
|
|
44
|
-
private _getInternalRequestArgs;
|
|
45
40
|
}
|
|
46
41
|
export {};
|
package/src/NetworkCore.js
CHANGED
|
@@ -15,7 +15,6 @@ 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 NetworkFallbackResolver_1 = require("./NetworkFallbackResolver");
|
|
19
18
|
const SDKType_1 = require("./SDKType");
|
|
20
19
|
const SafeJs_1 = require("./SafeJs");
|
|
21
20
|
const SessionID_1 = require("./SessionID");
|
|
@@ -31,7 +30,6 @@ class NetworkCore {
|
|
|
31
30
|
this._timeout = DEFAULT_TIMEOUT_MS;
|
|
32
31
|
this._netConfig = {};
|
|
33
32
|
this._options = {};
|
|
34
|
-
this._errorBoundary = null;
|
|
35
33
|
if (options) {
|
|
36
34
|
this._options = options;
|
|
37
35
|
}
|
|
@@ -41,13 +39,18 @@ class NetworkCore {
|
|
|
41
39
|
if (this._netConfig.networkTimeoutMs) {
|
|
42
40
|
this._timeout = this._netConfig.networkTimeoutMs;
|
|
43
41
|
}
|
|
44
|
-
this._fallbackResolver = new NetworkFallbackResolver_1.NetworkFallbackResolver(this._options);
|
|
45
42
|
}
|
|
46
|
-
|
|
47
|
-
this
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
post(args) {
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
let body = yield this._getPopulatedBody(args);
|
|
46
|
+
if (args.isStatsigEncodable) {
|
|
47
|
+
body = this._attemptToEncodeString(args, body);
|
|
48
|
+
}
|
|
49
|
+
return this._sendRequest(Object.assign({ method: 'POST', body }, args));
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
get(args) {
|
|
53
|
+
return this._sendRequest(Object.assign({ method: 'GET' }, args));
|
|
51
54
|
}
|
|
52
55
|
isBeaconSupported() {
|
|
53
56
|
return (typeof navigator !== 'undefined' &&
|
|
@@ -58,27 +61,12 @@ class NetworkCore {
|
|
|
58
61
|
if (!_ensureValidSdkKey(args)) {
|
|
59
62
|
return false;
|
|
60
63
|
}
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
const url = yield this._getPopulatedURL(argsInternal);
|
|
64
|
+
const body = yield this._getPopulatedBody(args);
|
|
65
|
+
const url = yield this._getPopulatedURL(args);
|
|
64
66
|
const nav = navigator;
|
|
65
67
|
return nav.sendBeacon.bind(nav)(url, body);
|
|
66
68
|
});
|
|
67
69
|
}
|
|
68
|
-
post(args) {
|
|
69
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
70
|
-
const argsInternal = this._getInternalRequestArgs('POST', args);
|
|
71
|
-
argsInternal.body = yield this._getPopulatedBody(argsInternal, args.data);
|
|
72
|
-
if (args.isStatsigEncodable) {
|
|
73
|
-
argsInternal.body = this._attemptToEncodeString(argsInternal, argsInternal.body);
|
|
74
|
-
}
|
|
75
|
-
return this._sendRequest(argsInternal);
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
get(args) {
|
|
79
|
-
const argsInternal = this._getInternalRequestArgs('GET', args);
|
|
80
|
-
return this._sendRequest(argsInternal);
|
|
81
|
-
}
|
|
82
70
|
_sendRequest(args) {
|
|
83
71
|
var _a, _b, _c;
|
|
84
72
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -90,11 +78,9 @@ class NetworkCore {
|
|
|
90
78
|
}
|
|
91
79
|
const { method, body, retries, attempt } = args;
|
|
92
80
|
const currentAttempt = attempt !== null && attempt !== void 0 ? attempt : 1;
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
}, this._timeout);
|
|
97
|
-
const populatedUrl = yield this._getPopulatedURL(args);
|
|
81
|
+
const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
|
|
82
|
+
const handle = setTimeout(() => controller === null || controller === void 0 ? void 0 : controller.abort(`Timeout of ${this._timeout}ms expired.`), this._timeout);
|
|
83
|
+
const url = yield this._getPopulatedURL(args);
|
|
98
84
|
let response = null;
|
|
99
85
|
const keepalive = (0, VisibilityObserving_1._isUnloading)();
|
|
100
86
|
try {
|
|
@@ -102,35 +88,37 @@ class NetworkCore {
|
|
|
102
88
|
method,
|
|
103
89
|
body,
|
|
104
90
|
headers: Object.assign({}, args.headers),
|
|
105
|
-
signal:
|
|
91
|
+
signal: controller === null || controller === void 0 ? void 0 : controller.signal,
|
|
106
92
|
priority: args.priority,
|
|
107
93
|
keepalive,
|
|
108
94
|
};
|
|
109
|
-
|
|
95
|
+
if (args.isInitialize) {
|
|
96
|
+
Diagnostics_1.Diagnostics._markInitNetworkReqStart(args.sdkKey, {
|
|
97
|
+
attempt: currentAttempt,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
110
100
|
const func = (_a = this._netConfig.networkOverrideFunc) !== null && _a !== void 0 ? _a : fetch;
|
|
111
|
-
response = yield func(
|
|
112
|
-
clearTimeout(
|
|
101
|
+
response = yield func(url, config);
|
|
102
|
+
clearTimeout(handle);
|
|
113
103
|
if (!response.ok) {
|
|
114
104
|
const text = yield response.text().catch(() => 'No Text');
|
|
115
|
-
const err = new Error(`NetworkError: ${
|
|
105
|
+
const err = new Error(`NetworkError: ${url} ${text}`);
|
|
116
106
|
err.name = 'NetworkError';
|
|
117
107
|
throw err;
|
|
118
108
|
}
|
|
119
109
|
const text = yield response.text();
|
|
120
|
-
|
|
121
|
-
|
|
110
|
+
if (args.isInitialize) {
|
|
111
|
+
Diagnostics_1.Diagnostics._markInitNetworkReqEnd(args.sdkKey, Diagnostics_1.Diagnostics._getDiagnosticsData(response, currentAttempt, text));
|
|
112
|
+
}
|
|
122
113
|
return {
|
|
123
114
|
body: text,
|
|
124
115
|
code: response.status,
|
|
125
116
|
};
|
|
126
117
|
}
|
|
127
118
|
catch (error) {
|
|
128
|
-
const errorMessage = _getErrorMessage(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const fallbackUpdated = yield this._fallbackResolver.tryFetchUpdatedFallbackInfo(args.sdkKey, populatedUrl, errorMessage, timedOut);
|
|
132
|
-
if (fallbackUpdated) {
|
|
133
|
-
args.fallbackUrl = this._fallbackResolver.getFallbackUrl(args.sdkKey, args.url);
|
|
119
|
+
const errorMessage = _getErrorMessage(controller, error);
|
|
120
|
+
if (args.isInitialize) {
|
|
121
|
+
Diagnostics_1.Diagnostics._markInitNetworkReqEnd(args.sdkKey, Diagnostics_1.Diagnostics._getDiagnosticsData(response, currentAttempt, '', error));
|
|
134
122
|
}
|
|
135
123
|
if (!retries ||
|
|
136
124
|
currentAttempt > retries ||
|
|
@@ -141,42 +129,40 @@ class NetworkCore {
|
|
|
141
129
|
tag: StatsigClientEventEmitter_1.ErrorTag.NetworkError,
|
|
142
130
|
requestArgs: args,
|
|
143
131
|
});
|
|
144
|
-
Log_1.Log.error(`A networking error occured during ${method} request to ${
|
|
132
|
+
Log_1.Log.error(`A networking error occured during ${method} request to ${url}.`, errorMessage, error);
|
|
145
133
|
return null;
|
|
146
134
|
}
|
|
147
|
-
return this._sendRequest(Object.assign(Object.assign({}, args), { retries, attempt: currentAttempt + 1 }));
|
|
135
|
+
return this._sendRequest(Object.assign(Object.assign({}, args), { retries: retries, attempt: currentAttempt + 1 }));
|
|
148
136
|
}
|
|
149
137
|
});
|
|
150
138
|
}
|
|
151
139
|
_getPopulatedURL(args) {
|
|
152
|
-
var _a;
|
|
153
140
|
return __awaiter(this, void 0, void 0, function* () {
|
|
154
|
-
const url = (_a = args.fallbackUrl) !== null && _a !== void 0 ? _a : args.url;
|
|
155
141
|
const params = Object.assign({ [NetworkConfig_1.NetworkParam.SdkKey]: args.sdkKey, [NetworkConfig_1.NetworkParam.SdkType]: SDKType_1.SDKType._get(args.sdkKey), [NetworkConfig_1.NetworkParam.SdkVersion]: StatsigMetadata_1.SDK_VERSION, [NetworkConfig_1.NetworkParam.Time]: String(Date.now()), [NetworkConfig_1.NetworkParam.SessionID]: SessionID_1.SessionID.get(args.sdkKey) }, args.params);
|
|
156
142
|
const query = Object.keys(params)
|
|
157
143
|
.map((key) => {
|
|
158
144
|
return `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`;
|
|
159
145
|
})
|
|
160
146
|
.join('&');
|
|
161
|
-
return `${url}${query ? `?${query}` : ''}`;
|
|
147
|
+
return `${args.url}${query ? `?${query}` : ''}`;
|
|
162
148
|
});
|
|
163
149
|
}
|
|
164
|
-
_getPopulatedBody(args
|
|
150
|
+
_getPopulatedBody(args) {
|
|
165
151
|
return __awaiter(this, void 0, void 0, function* () {
|
|
166
|
-
const {
|
|
152
|
+
const { data, sdkKey } = args;
|
|
167
153
|
const stableID = StableID_1.StableID.get(sdkKey);
|
|
168
154
|
const sessionID = SessionID_1.SessionID.get(sdkKey);
|
|
169
155
|
const sdkType = SDKType_1.SDKType._get(sdkKey);
|
|
170
156
|
return JSON.stringify(Object.assign(Object.assign({}, data), { statsigMetadata: Object.assign(Object.assign({}, StatsigMetadata_1.StatsigMetadataProvider.get()), { stableID,
|
|
171
157
|
sessionID,
|
|
172
|
-
sdkType
|
|
173
|
-
fallbackUrl }) }));
|
|
158
|
+
sdkType }) }));
|
|
174
159
|
});
|
|
175
160
|
}
|
|
176
161
|
_attemptToEncodeString(args, input) {
|
|
177
162
|
var _a, _b;
|
|
178
163
|
const win = (0, SafeJs_1._getWindowSafe)();
|
|
179
|
-
if (
|
|
164
|
+
if (!args.isStatsigEncodable ||
|
|
165
|
+
this._options.disableStatsigEncoding ||
|
|
180
166
|
(0, __StatsigGlobal_1._getStatsigGlobalFlag)('no-encode') != null ||
|
|
181
167
|
!(win === null || win === void 0 ? void 0 : win.btoa)) {
|
|
182
168
|
return input;
|
|
@@ -191,11 +177,6 @@ class NetworkCore {
|
|
|
191
177
|
return input;
|
|
192
178
|
}
|
|
193
179
|
}
|
|
194
|
-
_getInternalRequestArgs(method, args) {
|
|
195
|
-
const fallbackUrl = this._fallbackResolver.getFallbackUrl(args.sdkKey, args.url);
|
|
196
|
-
return Object.assign(Object.assign({}, args), { method,
|
|
197
|
-
fallbackUrl });
|
|
198
|
-
}
|
|
199
180
|
}
|
|
200
181
|
exports.NetworkCore = NetworkCore;
|
|
201
182
|
const _ensureValidSdkKey = (args) => {
|
|
@@ -218,23 +199,3 @@ function _getErrorMessage(controller, error) {
|
|
|
218
199
|
}
|
|
219
200
|
return 'Unknown Error';
|
|
220
201
|
}
|
|
221
|
-
function _didTimeout(controller) {
|
|
222
|
-
const timeout = (controller === null || controller === void 0 ? void 0 : controller.signal.aborted) &&
|
|
223
|
-
typeof controller.signal.reason === 'string' &&
|
|
224
|
-
controller.signal.reason.includes('Timeout');
|
|
225
|
-
return timeout || false;
|
|
226
|
-
}
|
|
227
|
-
function _tryMarkInitStart(args, attempt) {
|
|
228
|
-
if (!args.isInitialize) {
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
Diagnostics_1.Diagnostics._markInitNetworkReqStart(args.sdkKey, {
|
|
232
|
-
attempt,
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
function _tryMarkInitEnd(args, response, attempt, body, err) {
|
|
236
|
-
if (!args.isInitialize) {
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
Diagnostics_1.Diagnostics._markInitNetworkReqEnd(args.sdkKey, Diagnostics_1.Diagnostics._getDiagnosticsData(response, attempt, body, err));
|
|
240
|
-
}
|
package/src/StatsigClientBase.js
CHANGED
|
@@ -36,9 +36,9 @@ class StatsigClientBase {
|
|
|
36
36
|
this._logger = new EventLogger_1.EventLogger(sdkKey, emitter, network, options);
|
|
37
37
|
this._errorBoundary = new ErrorBoundary_1.ErrorBoundary(sdkKey, options, emitter);
|
|
38
38
|
this._errorBoundary.wrap(this);
|
|
39
|
+
this._errorBoundary.wrap(network);
|
|
39
40
|
this._errorBoundary.wrap(adapter);
|
|
40
41
|
this._errorBoundary.wrap(this._logger);
|
|
41
|
-
network.setErrorBoundary(this._errorBoundary);
|
|
42
42
|
this.dataAdapter = adapter;
|
|
43
43
|
this.dataAdapter.attach(sdkKey, options);
|
|
44
44
|
this.storageProvider = StorageProvider_1.Storage;
|
|
@@ -157,7 +157,9 @@ function _assignGlobalInstance(sdkKey, client) {
|
|
|
157
157
|
Log_1.Log.warn('Creating multiple Statsig clients with the same SDK key can lead to unexpected behavior. Multi-instance support requires different SDK keys.');
|
|
158
158
|
}
|
|
159
159
|
instances[sdkKey] = inst;
|
|
160
|
-
statsigGlobal.
|
|
160
|
+
if (!statsigGlobal.firstInstance) {
|
|
161
|
+
statsigGlobal.firstInstance = inst;
|
|
162
|
+
}
|
|
161
163
|
statsigGlobal.instances = instances;
|
|
162
164
|
__STATSIG__ = statsigGlobal;
|
|
163
165
|
}
|
package/src/StatsigMetadata.d.ts
CHANGED
package/src/StatsigMetadata.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StatsigMetadataProvider = exports.SDK_VERSION = void 0;
|
|
4
|
-
exports.SDK_VERSION = '3.
|
|
4
|
+
exports.SDK_VERSION = '3.4.0';
|
|
5
5
|
let metadata = {
|
|
6
6
|
sdkVersion: exports.SDK_VERSION,
|
|
7
7
|
sdkType: 'js-mono', // js-mono is overwritten by Precomp and OnDevice clients
|
|
@@ -5,4 +5,4 @@ export declare function _makeDynamicConfig(name: string, details: EvaluationDeta
|
|
|
5
5
|
export declare function _makeExperiment(name: string, details: EvaluationDetails, evaluation: DynamicConfigEvaluation | null): Experiment;
|
|
6
6
|
export declare function _makeLayer(name: string, details: EvaluationDetails, evaluation: LayerEvaluation | null, exposeFunc?: (param: string) => void): Layer;
|
|
7
7
|
export declare function _mergeOverride<T extends AnyConfigBasedStatsigType>(original: T, overridden: T | null | undefined, value: Record<string, unknown>, exposeFunc?: (param: string) => void): T;
|
|
8
|
-
export declare function _makeTypedGet(value: Record<string, unknown> | undefined, exposeFunc?: (param: string) => void): TypedGet;
|
|
8
|
+
export declare function _makeTypedGet(name: string, value: Record<string, unknown> | undefined, exposeFunc?: (param: string) => void): TypedGet;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports._makeTypedGet = exports._mergeOverride = exports._makeLayer = exports._makeExperiment = exports._makeDynamicConfig = exports._makeFeatureGate = void 0;
|
|
4
|
+
const Log_1 = require("./Log");
|
|
4
5
|
const TypingUtils_1 = require("./TypingUtils");
|
|
5
6
|
const DEFAULT_RULE = 'default';
|
|
6
7
|
function _makeEvaluation(name, details, evaluation, value) {
|
|
@@ -20,7 +21,7 @@ exports._makeFeatureGate = _makeFeatureGate;
|
|
|
20
21
|
function _makeDynamicConfig(name, details, evaluation) {
|
|
21
22
|
var _a;
|
|
22
23
|
const value = (_a = evaluation === null || evaluation === void 0 ? void 0 : evaluation.value) !== null && _a !== void 0 ? _a : {};
|
|
23
|
-
return Object.assign(Object.assign({}, _makeEvaluation(name, details, evaluation, value)), { get: _makeTypedGet(evaluation === null || evaluation === void 0 ? void 0 : evaluation.value) });
|
|
24
|
+
return Object.assign(Object.assign({}, _makeEvaluation(name, details, evaluation, value)), { get: _makeTypedGet(name, evaluation === null || evaluation === void 0 ? void 0 : evaluation.value) });
|
|
24
25
|
}
|
|
25
26
|
exports._makeDynamicConfig = _makeDynamicConfig;
|
|
26
27
|
function _makeExperiment(name, details, evaluation) {
|
|
@@ -31,14 +32,14 @@ function _makeExperiment(name, details, evaluation) {
|
|
|
31
32
|
exports._makeExperiment = _makeExperiment;
|
|
32
33
|
function _makeLayer(name, details, evaluation, exposeFunc) {
|
|
33
34
|
var _a, _b;
|
|
34
|
-
return Object.assign(Object.assign({}, _makeEvaluation(name, details, evaluation, undefined)), { get: _makeTypedGet(evaluation === null || evaluation === void 0 ? void 0 : evaluation.value, exposeFunc), groupName: (_a = evaluation === null || evaluation === void 0 ? void 0 : evaluation.group_name) !== null && _a !== void 0 ? _a : null, __value: (_b = evaluation === null || evaluation === void 0 ? void 0 : evaluation.value) !== null && _b !== void 0 ? _b : {} });
|
|
35
|
+
return Object.assign(Object.assign({}, _makeEvaluation(name, details, evaluation, undefined)), { get: _makeTypedGet(name, evaluation === null || evaluation === void 0 ? void 0 : evaluation.value, exposeFunc), groupName: (_a = evaluation === null || evaluation === void 0 ? void 0 : evaluation.group_name) !== null && _a !== void 0 ? _a : null, __value: (_b = evaluation === null || evaluation === void 0 ? void 0 : evaluation.value) !== null && _b !== void 0 ? _b : {} });
|
|
35
36
|
}
|
|
36
37
|
exports._makeLayer = _makeLayer;
|
|
37
38
|
function _mergeOverride(original, overridden, value, exposeFunc) {
|
|
38
|
-
return Object.assign(Object.assign(Object.assign({}, original), overridden), { get: _makeTypedGet(value, exposeFunc) });
|
|
39
|
+
return Object.assign(Object.assign(Object.assign({}, original), overridden), { get: _makeTypedGet(original.name, value, exposeFunc) });
|
|
39
40
|
}
|
|
40
41
|
exports._mergeOverride = _mergeOverride;
|
|
41
|
-
function _makeTypedGet(value, exposeFunc) {
|
|
42
|
+
function _makeTypedGet(name, value, exposeFunc) {
|
|
42
43
|
return (param, fallback) => {
|
|
43
44
|
var _a;
|
|
44
45
|
const found = (_a = value === null || value === void 0 ? void 0 : value[param]) !== null && _a !== void 0 ? _a : null;
|
|
@@ -46,6 +47,7 @@ function _makeTypedGet(value, exposeFunc) {
|
|
|
46
47
|
return (fallback !== null && fallback !== void 0 ? fallback : null);
|
|
47
48
|
}
|
|
48
49
|
if (fallback != null && !(0, TypingUtils_1._isTypeMatch)(found, fallback)) {
|
|
50
|
+
Log_1.Log.warn(`Parameter type mismatch. '${name}.${param}' was found to be type '${typeof found}' but fallback/return type is '${typeof fallback}'. See https://docs.statsig.com/client/javascript-sdk/#typed-getters`);
|
|
49
51
|
return (fallback !== null && fallback !== void 0 ? fallback : null);
|
|
50
52
|
}
|
|
51
53
|
exposeFunc === null || exposeFunc === void 0 ? void 0 : exposeFunc(param);
|
package/src/index.d.ts
CHANGED
|
@@ -16,8 +16,8 @@ export * from './EvaluationTypes';
|
|
|
16
16
|
export * from './Hashing';
|
|
17
17
|
export * from './InitializeResponse';
|
|
18
18
|
export * from './Log';
|
|
19
|
-
export * from './NetworkCore';
|
|
20
19
|
export * from './NetworkConfig';
|
|
20
|
+
export * from './NetworkCore';
|
|
21
21
|
export * from './OverrideAdapter';
|
|
22
22
|
export * from './ParamStoreTypes';
|
|
23
23
|
export * from './SafeJs';
|
|
@@ -30,10 +30,10 @@ export * from './StatsigDataAdapter';
|
|
|
30
30
|
export * from './StatsigEvent';
|
|
31
31
|
export * from './StatsigMetadata';
|
|
32
32
|
export * from './StatsigOptionsCommon';
|
|
33
|
+
export * from './StatsigPlugin';
|
|
33
34
|
export * from './StatsigTypeFactories';
|
|
34
35
|
export * from './StatsigTypes';
|
|
35
36
|
export * from './StatsigUser';
|
|
36
|
-
export * from './StatsigPlugin';
|
|
37
37
|
export * from './StorageProvider';
|
|
38
38
|
export * from './TypedJsonParse';
|
|
39
39
|
export * from './TypingUtils';
|
package/src/index.js
CHANGED
|
@@ -38,8 +38,8 @@ __exportStar(require("./EvaluationTypes"), exports);
|
|
|
38
38
|
__exportStar(require("./Hashing"), exports);
|
|
39
39
|
__exportStar(require("./InitializeResponse"), exports);
|
|
40
40
|
__exportStar(require("./Log"), exports);
|
|
41
|
-
__exportStar(require("./NetworkCore"), exports);
|
|
42
41
|
__exportStar(require("./NetworkConfig"), exports);
|
|
42
|
+
__exportStar(require("./NetworkCore"), exports);
|
|
43
43
|
__exportStar(require("./OverrideAdapter"), exports);
|
|
44
44
|
__exportStar(require("./ParamStoreTypes"), exports);
|
|
45
45
|
__exportStar(require("./SafeJs"), exports);
|
|
@@ -52,10 +52,10 @@ __exportStar(require("./StatsigDataAdapter"), exports);
|
|
|
52
52
|
__exportStar(require("./StatsigEvent"), exports);
|
|
53
53
|
__exportStar(require("./StatsigMetadata"), exports);
|
|
54
54
|
__exportStar(require("./StatsigOptionsCommon"), exports);
|
|
55
|
+
__exportStar(require("./StatsigPlugin"), exports);
|
|
55
56
|
__exportStar(require("./StatsigTypeFactories"), exports);
|
|
56
57
|
__exportStar(require("./StatsigTypes"), exports);
|
|
57
58
|
__exportStar(require("./StatsigUser"), exports);
|
|
58
|
-
__exportStar(require("./StatsigPlugin"), exports);
|
|
59
59
|
__exportStar(require("./StorageProvider"), exports);
|
|
60
60
|
__exportStar(require("./TypedJsonParse"), exports);
|
|
61
61
|
__exportStar(require("./TypingUtils"), exports);
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { ErrorBoundary } from './ErrorBoundary';
|
|
2
|
-
import { AnyStatsigOptions } from './StatsigOptionsCommon';
|
|
3
|
-
export type FallbackResolverArgs = {
|
|
4
|
-
fallbackUrl: string | null;
|
|
5
|
-
};
|
|
6
|
-
export declare class NetworkFallbackResolver {
|
|
7
|
-
private _fallbackInfo;
|
|
8
|
-
private _errorBoundary;
|
|
9
|
-
private _networkOverrideFunc?;
|
|
10
|
-
private _cooldowns;
|
|
11
|
-
constructor(options: AnyStatsigOptions);
|
|
12
|
-
setErrorBoundary(errorBoundary: ErrorBoundary): void;
|
|
13
|
-
tryBumpExpiryTime(sdkKey: string, url: string): void;
|
|
14
|
-
getFallbackUrl(sdkKey: string, url: string): string | null;
|
|
15
|
-
tryFetchUpdatedFallbackInfo(sdkKey: string, url: string, errorMessage: string | null, timedOut: boolean): Promise<boolean>;
|
|
16
|
-
private _updateFallbackInfoWithNewUrl;
|
|
17
|
-
private _fetchFallbackUrl;
|
|
18
|
-
}
|
|
19
|
-
export declare function _isDefaultUrl(url: string): boolean;
|
|
20
|
-
export declare function _isDomainFailure(errorMsg: string | null, timedOut: boolean): boolean;
|
|
@@ -1,208 +0,0 @@
|
|
|
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._isDomainFailure = exports._isDefaultUrl = exports.NetworkFallbackResolver = void 0;
|
|
13
|
-
const DnsTxtQuery_1 = require("./DnsTxtQuery");
|
|
14
|
-
const Hashing_1 = require("./Hashing");
|
|
15
|
-
const Log_1 = require("./Log");
|
|
16
|
-
const NetworkConfig_1 = require("./NetworkConfig");
|
|
17
|
-
const StorageProvider_1 = require("./StorageProvider");
|
|
18
|
-
const DEFAULT_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
19
|
-
const COOLDOWN_TIME_MS = 4 * 60 * 60 * 1000; // 4 hours
|
|
20
|
-
class NetworkFallbackResolver {
|
|
21
|
-
constructor(options) {
|
|
22
|
-
var _a;
|
|
23
|
-
this._fallbackInfo = null;
|
|
24
|
-
this._errorBoundary = null;
|
|
25
|
-
this._cooldowns = {};
|
|
26
|
-
this._networkOverrideFunc = (_a = options.networkConfig) === null || _a === void 0 ? void 0 : _a.networkOverrideFunc;
|
|
27
|
-
}
|
|
28
|
-
setErrorBoundary(errorBoundary) {
|
|
29
|
-
this._errorBoundary = errorBoundary;
|
|
30
|
-
}
|
|
31
|
-
tryBumpExpiryTime(sdkKey, url) {
|
|
32
|
-
var _a;
|
|
33
|
-
const domainKey = _getDomainKeyFromEndpoint(url);
|
|
34
|
-
if (!domainKey) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
const info = (_a = this._fallbackInfo) === null || _a === void 0 ? void 0 : _a[domainKey];
|
|
38
|
-
if (!info) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
info.expiryTime = Date.now() + DEFAULT_TTL_MS;
|
|
42
|
-
_tryWriteFallbackInfoToCache(sdkKey, Object.assign(Object.assign({}, this._fallbackInfo), { [domainKey]: info }));
|
|
43
|
-
}
|
|
44
|
-
getFallbackUrl(sdkKey, url) {
|
|
45
|
-
var _a, _b;
|
|
46
|
-
const domainKey = _getDomainKeyFromEndpoint(url);
|
|
47
|
-
if (!_isDefaultUrl(url) || !domainKey) {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
let info = this._fallbackInfo;
|
|
51
|
-
if (info == null) {
|
|
52
|
-
info = (_a = _readFallbackInfoFromCache(sdkKey)) !== null && _a !== void 0 ? _a : {};
|
|
53
|
-
this._fallbackInfo = info;
|
|
54
|
-
}
|
|
55
|
-
const entry = info[domainKey];
|
|
56
|
-
if (!entry || Date.now() > ((_b = entry.expiryTime) !== null && _b !== void 0 ? _b : 0)) {
|
|
57
|
-
delete info[domainKey];
|
|
58
|
-
this._fallbackInfo = info;
|
|
59
|
-
_tryWriteFallbackInfoToCache(sdkKey, this._fallbackInfo);
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
const endpoint = _extractEndpointForUrl(url);
|
|
63
|
-
if (entry.url) {
|
|
64
|
-
return `https://${entry.url}/${endpoint}`;
|
|
65
|
-
}
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
tryFetchUpdatedFallbackInfo(sdkKey, url, errorMessage, timedOut) {
|
|
69
|
-
var _a;
|
|
70
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
-
try {
|
|
72
|
-
const domainKey = _getDomainKeyFromEndpoint(url);
|
|
73
|
-
if (!_isDomainFailure(errorMessage, timedOut) || !domainKey) {
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
if (this._cooldowns[domainKey] &&
|
|
77
|
-
Date.now() < this._cooldowns[domainKey]) {
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
this._cooldowns[domainKey] = Date.now() + COOLDOWN_TIME_MS;
|
|
81
|
-
const newUrl = yield this._fetchFallbackUrl(domainKey);
|
|
82
|
-
if (!newUrl) {
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
this._updateFallbackInfoWithNewUrl(sdkKey, domainKey, newUrl);
|
|
86
|
-
return true;
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
(_a = this._errorBoundary) === null || _a === void 0 ? void 0 : _a.logError('tryFetchUpdatedFallbackInfo', error);
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
_updateFallbackInfoWithNewUrl(sdkKey, domainKey, newUrl) {
|
|
95
|
-
var _a, _b, _c;
|
|
96
|
-
const newFallbackInfo = {
|
|
97
|
-
url: newUrl,
|
|
98
|
-
expiryTime: Date.now() + DEFAULT_TTL_MS,
|
|
99
|
-
previous: [],
|
|
100
|
-
};
|
|
101
|
-
const previousInfo = (_a = this._fallbackInfo) === null || _a === void 0 ? void 0 : _a[domainKey];
|
|
102
|
-
if (previousInfo) {
|
|
103
|
-
newFallbackInfo.previous.push(...previousInfo.previous);
|
|
104
|
-
}
|
|
105
|
-
if (newFallbackInfo.previous.length > 10) {
|
|
106
|
-
newFallbackInfo.previous = [];
|
|
107
|
-
}
|
|
108
|
-
const previousUrl = (_c = (_b = this._fallbackInfo) === null || _b === void 0 ? void 0 : _b[domainKey]) === null || _c === void 0 ? void 0 : _c.url;
|
|
109
|
-
if (previousUrl != null) {
|
|
110
|
-
newFallbackInfo.previous.push(previousUrl);
|
|
111
|
-
}
|
|
112
|
-
this._fallbackInfo = Object.assign(Object.assign({}, this._fallbackInfo), { [domainKey]: newFallbackInfo });
|
|
113
|
-
_tryWriteFallbackInfoToCache(sdkKey, this._fallbackInfo);
|
|
114
|
-
}
|
|
115
|
-
_fetchFallbackUrl(domainKey) {
|
|
116
|
-
var _a, _b, _c, _d, _e, _f;
|
|
117
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
118
|
-
const records = yield (0, DnsTxtQuery_1._fetchTxtRecords)((_a = this._networkOverrideFunc) !== null && _a !== void 0 ? _a : fetch);
|
|
119
|
-
if (records.length === 0) {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
const seen = new Set((_d = (_c = (_b = this._fallbackInfo) === null || _b === void 0 ? void 0 : _b[domainKey]) === null || _c === void 0 ? void 0 : _c.previous) !== null && _d !== void 0 ? _d : []);
|
|
123
|
-
const currentUrl = (_f = (_e = this._fallbackInfo) === null || _e === void 0 ? void 0 : _e[domainKey]) === null || _f === void 0 ? void 0 : _f.url;
|
|
124
|
-
let found = null;
|
|
125
|
-
for (const record of records) {
|
|
126
|
-
const [recordKey, recordUrl] = record.split('=');
|
|
127
|
-
if (!recordUrl || recordKey !== domainKey) {
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
let url = recordUrl;
|
|
131
|
-
if (recordUrl.endsWith('/')) {
|
|
132
|
-
url = recordUrl.slice(0, -1);
|
|
133
|
-
}
|
|
134
|
-
if (!seen.has(recordUrl) && url !== currentUrl) {
|
|
135
|
-
found = url;
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return found;
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
exports.NetworkFallbackResolver = NetworkFallbackResolver;
|
|
144
|
-
function _isDefaultUrl(url) {
|
|
145
|
-
for (const key in NetworkConfig_1.NetworkDefault) {
|
|
146
|
-
if (url.startsWith(NetworkConfig_1.NetworkDefault[key])) {
|
|
147
|
-
return true;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
exports._isDefaultUrl = _isDefaultUrl;
|
|
153
|
-
function _isDomainFailure(errorMsg, timedOut) {
|
|
154
|
-
var _a;
|
|
155
|
-
const lowerErrorMsg = (_a = errorMsg === null || errorMsg === void 0 ? void 0 : errorMsg.toLowerCase()) !== null && _a !== void 0 ? _a : '';
|
|
156
|
-
return (timedOut ||
|
|
157
|
-
lowerErrorMsg.includes('uncaught exception') ||
|
|
158
|
-
lowerErrorMsg.includes('failed to fetch') ||
|
|
159
|
-
lowerErrorMsg.includes('networkerror when attempting to fetch resource'));
|
|
160
|
-
}
|
|
161
|
-
exports._isDomainFailure = _isDomainFailure;
|
|
162
|
-
function _getFallbackInfoStorageKey(sdkKey) {
|
|
163
|
-
return `statsig.network_fallback.${(0, Hashing_1._DJB2)(sdkKey)}`;
|
|
164
|
-
}
|
|
165
|
-
function _tryWriteFallbackInfoToCache(sdkKey, info) {
|
|
166
|
-
const hashKey = _getFallbackInfoStorageKey(sdkKey);
|
|
167
|
-
if (!info || Object.keys(info).length === 0) {
|
|
168
|
-
StorageProvider_1.Storage.removeItem(hashKey);
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
StorageProvider_1.Storage.setItem(hashKey, JSON.stringify(info));
|
|
172
|
-
}
|
|
173
|
-
function _readFallbackInfoFromCache(sdkKey) {
|
|
174
|
-
const hashKey = _getFallbackInfoStorageKey(sdkKey);
|
|
175
|
-
const data = StorageProvider_1.Storage.getItem(hashKey);
|
|
176
|
-
if (!data) {
|
|
177
|
-
return null;
|
|
178
|
-
}
|
|
179
|
-
try {
|
|
180
|
-
return JSON.parse(data);
|
|
181
|
-
}
|
|
182
|
-
catch (_a) {
|
|
183
|
-
Log_1.Log.error('Failed to parse FallbackInfo');
|
|
184
|
-
return null;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
function _extractEndpointForUrl(urlString) {
|
|
188
|
-
try {
|
|
189
|
-
const url = new URL(urlString);
|
|
190
|
-
const endpoint = url.pathname.substring(1);
|
|
191
|
-
return endpoint;
|
|
192
|
-
}
|
|
193
|
-
catch (error) {
|
|
194
|
-
return '';
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
function _getDomainKeyFromEndpoint(endpoint) {
|
|
198
|
-
if (endpoint.includes('initialize')) {
|
|
199
|
-
return 'i';
|
|
200
|
-
}
|
|
201
|
-
if (endpoint.includes('rgstr')) {
|
|
202
|
-
return 'e';
|
|
203
|
-
}
|
|
204
|
-
if (endpoint.includes('download_config_specs')) {
|
|
205
|
-
return 'd';
|
|
206
|
-
}
|
|
207
|
-
return null;
|
|
208
|
-
}
|