@statsig/client-core 3.4.0-beta.1 → 3.5.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/DownloadConfigSpecsResponse.d.ts +1 -0
- package/src/EvaluationTypes.d.ts +2 -0
- package/src/EventLogger.d.ts +1 -1
- package/src/EventLogger.js +3 -3
- package/src/NetworkConfig.d.ts +9 -3
- package/src/NetworkConfig.js +9 -4
- package/src/NetworkCore.d.ts +3 -3
- package/src/NetworkCore.js +8 -8
- package/src/NetworkFallbackResolver.d.ts +8 -6
- package/src/NetworkFallbackResolver.js +66 -76
- package/src/StatsigEvent.js +24 -9
- package/src/StatsigMetadata.d.ts +1 -1
- package/src/StatsigMetadata.js +1 -1
- package/src/StatsigOptionsCommon.d.ts +4 -0
- package/src/UrlConfiguration.d.ts +11 -0
- package/src/UrlConfiguration.js +33 -0
- package/src/index.d.ts +1 -1
- package/src/index.js +1 -1
- package/src/UrlOverrides.d.ts +0 -1
- package/src/UrlOverrides.js +0 -15
package/package.json
CHANGED
package/src/EvaluationTypes.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ type EvaluationBase<T> = {
|
|
|
7
7
|
rule_id: string;
|
|
8
8
|
secondary_exposures: SecondaryExposure[];
|
|
9
9
|
value: T;
|
|
10
|
+
version?: string;
|
|
10
11
|
};
|
|
11
12
|
export type SecondaryExposure = {
|
|
12
13
|
gate: string;
|
|
@@ -21,6 +22,7 @@ export type ExperimentEvaluation = Flatten<EvaluationBase<Record<string, unknown
|
|
|
21
22
|
is_device_based: boolean;
|
|
22
23
|
is_experiment_active?: boolean;
|
|
23
24
|
is_user_in_experiment?: boolean;
|
|
25
|
+
passed?: boolean;
|
|
24
26
|
}>;
|
|
25
27
|
export type DynamicConfigEvaluation = ExperimentEvaluation;
|
|
26
28
|
export type LayerEvaluation = Flatten<Omit<ExperimentEvaluation, 'id_type'> & {
|
package/src/EventLogger.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare class EventLogger {
|
|
|
15
15
|
private _hasRunQuickFlush;
|
|
16
16
|
private _creationTime;
|
|
17
17
|
private _isLoggingDisabled;
|
|
18
|
-
private
|
|
18
|
+
private _logEventUrlConfig;
|
|
19
19
|
private static _safeFlushAndForget;
|
|
20
20
|
private static _safeRetryFailedLogs;
|
|
21
21
|
constructor(_sdkKey: string, _emitter: StatsigClientEmitEventFunc, _network: NetworkCore, _options: StatsigOptionsCommon<NetworkConfigCommon> | null);
|
package/src/EventLogger.js
CHANGED
|
@@ -17,7 +17,7 @@ const NetworkConfig_1 = require("./NetworkConfig");
|
|
|
17
17
|
const SafeJs_1 = require("./SafeJs");
|
|
18
18
|
const StatsigEvent_1 = require("./StatsigEvent");
|
|
19
19
|
const StorageProvider_1 = require("./StorageProvider");
|
|
20
|
-
const
|
|
20
|
+
const UrlConfiguration_1 = require("./UrlConfiguration");
|
|
21
21
|
const VisibilityObserving_1 = require("./VisibilityObserving");
|
|
22
22
|
const DEFAULT_QUEUE_SIZE = 50;
|
|
23
23
|
const DEFAULT_FLUSH_INTERVAL_MS = 10000;
|
|
@@ -55,7 +55,7 @@ class EventLogger {
|
|
|
55
55
|
this._isLoggingDisabled = (_options === null || _options === void 0 ? void 0 : _options.disableLogging) === true;
|
|
56
56
|
this._maxQueueSize = (_a = _options === null || _options === void 0 ? void 0 : _options.loggingBufferMaxSize) !== null && _a !== void 0 ? _a : DEFAULT_QUEUE_SIZE;
|
|
57
57
|
const config = _options === null || _options === void 0 ? void 0 : _options.networkConfig;
|
|
58
|
-
this.
|
|
58
|
+
this._logEventUrlConfig = new UrlConfiguration_1.UrlConfiguration(NetworkConfig_1.Endpoint._rgstr, config === null || config === void 0 ? void 0 : config.logEventUrl, config === null || config === void 0 ? void 0 : config.api, config === null || config === void 0 ? void 0 : config.logEventFallbackUrls);
|
|
59
59
|
}
|
|
60
60
|
setLoggingDisabled(isDisabled) {
|
|
61
61
|
this._isLoggingDisabled = isDisabled;
|
|
@@ -212,7 +212,7 @@ class EventLogger {
|
|
|
212
212
|
data: {
|
|
213
213
|
events,
|
|
214
214
|
},
|
|
215
|
-
|
|
215
|
+
urlConfig: this._logEventUrlConfig,
|
|
216
216
|
retries: 3,
|
|
217
217
|
isCompressable: true,
|
|
218
218
|
params: {
|
package/src/NetworkConfig.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
export declare const Endpoint: {
|
|
2
|
+
readonly _initialize: "initialize";
|
|
3
|
+
readonly _rgstr: "rgstr";
|
|
4
|
+
readonly _download_config_specs: "download_config_specs";
|
|
5
|
+
};
|
|
6
|
+
export type Endpoint = (typeof Endpoint)[keyof typeof Endpoint];
|
|
1
7
|
export declare const NetworkDefault: {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
8
|
+
rgstr: "https://prodregistryv2.org/v1";
|
|
9
|
+
initialize: "https://featureassets.org/v1";
|
|
10
|
+
download_config_specs: "https://assetsconfigcdn.org/v1";
|
|
5
11
|
};
|
|
6
12
|
export type NetworkPriority = 'high' | 'low' | 'auto';
|
|
7
13
|
export type NetworkArgs = RequestInit & {
|
package/src/NetworkConfig.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NetworkParam = exports.NetworkDefault = void 0;
|
|
3
|
+
exports.NetworkParam = exports.NetworkDefault = exports.Endpoint = void 0;
|
|
4
|
+
exports.Endpoint = {
|
|
5
|
+
_initialize: 'initialize',
|
|
6
|
+
_rgstr: 'rgstr',
|
|
7
|
+
_download_config_specs: 'download_config_specs',
|
|
8
|
+
};
|
|
4
9
|
exports.NetworkDefault = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
[exports.Endpoint._rgstr]: 'https://prodregistryv2.org/v1',
|
|
11
|
+
[exports.Endpoint._initialize]: 'https://featureassets.org/v1',
|
|
12
|
+
[exports.Endpoint._download_config_specs]: 'https://assetsconfigcdn.org/v1',
|
|
8
13
|
};
|
|
9
14
|
exports.NetworkParam = {
|
|
10
15
|
EventCount: 'ec',
|
package/src/NetworkCore.d.ts
CHANGED
|
@@ -4,13 +4,13 @@ import { NetworkPriority } from './NetworkConfig';
|
|
|
4
4
|
import { StatsigClientEmitEventFunc } from './StatsigClientBase';
|
|
5
5
|
import { AnyStatsigOptions } from './StatsigOptionsCommon';
|
|
6
6
|
import { Flatten } from './TypingUtils';
|
|
7
|
+
import { UrlConfiguration } from './UrlConfiguration';
|
|
7
8
|
type RequestArgs = {
|
|
8
9
|
sdkKey: string;
|
|
9
|
-
|
|
10
|
+
urlConfig: UrlConfiguration;
|
|
10
11
|
priority?: NetworkPriority;
|
|
11
12
|
retries?: number;
|
|
12
13
|
attempt?: number;
|
|
13
|
-
isInitialize?: boolean;
|
|
14
14
|
params?: Record<string, string>;
|
|
15
15
|
headers?: Record<string, string>;
|
|
16
16
|
};
|
|
@@ -19,7 +19,7 @@ export type RequestArgsWithData = Flatten<RequestArgs & {
|
|
|
19
19
|
isStatsigEncodable?: boolean;
|
|
20
20
|
isCompressable?: boolean;
|
|
21
21
|
}>;
|
|
22
|
-
type BeaconRequestArgs = Pick<RequestArgsWithData, 'data' | 'sdkKey' | '
|
|
22
|
+
type BeaconRequestArgs = Pick<RequestArgsWithData, 'data' | 'sdkKey' | 'urlConfig' | 'params' | 'isCompressable' | 'attempt'>;
|
|
23
23
|
type NetworkResponse = {
|
|
24
24
|
body: string | null;
|
|
25
25
|
code: number;
|
package/src/NetworkCore.js
CHANGED
|
@@ -118,7 +118,7 @@ class NetworkCore {
|
|
|
118
118
|
}
|
|
119
119
|
const text = yield response.text();
|
|
120
120
|
_tryMarkInitEnd(args, response, currentAttempt, text);
|
|
121
|
-
this._fallbackResolver.tryBumpExpiryTime(args.sdkKey,
|
|
121
|
+
this._fallbackResolver.tryBumpExpiryTime(args.sdkKey, args.urlConfig);
|
|
122
122
|
return {
|
|
123
123
|
body: text,
|
|
124
124
|
code: response.status,
|
|
@@ -128,9 +128,9 @@ class NetworkCore {
|
|
|
128
128
|
const errorMessage = _getErrorMessage(abortController, error);
|
|
129
129
|
const timedOut = _didTimeout(abortController);
|
|
130
130
|
_tryMarkInitEnd(args, response, currentAttempt, '', error);
|
|
131
|
-
const fallbackUpdated = yield this._fallbackResolver.tryFetchUpdatedFallbackInfo(args.sdkKey,
|
|
131
|
+
const fallbackUpdated = yield this._fallbackResolver.tryFetchUpdatedFallbackInfo(args.sdkKey, args.urlConfig, errorMessage, timedOut);
|
|
132
132
|
if (fallbackUpdated) {
|
|
133
|
-
args.fallbackUrl = this._fallbackResolver.
|
|
133
|
+
args.fallbackUrl = this._fallbackResolver.getActiveFallbackUrl(args.sdkKey, args.urlConfig);
|
|
134
134
|
}
|
|
135
135
|
if (!retries ||
|
|
136
136
|
currentAttempt > retries ||
|
|
@@ -151,7 +151,7 @@ class NetworkCore {
|
|
|
151
151
|
_getPopulatedURL(args) {
|
|
152
152
|
var _a;
|
|
153
153
|
return __awaiter(this, void 0, void 0, function* () {
|
|
154
|
-
const url = (_a = args.fallbackUrl) !== null && _a !== void 0 ? _a : args.
|
|
154
|
+
const url = (_a = args.fallbackUrl) !== null && _a !== void 0 ? _a : args.urlConfig.getUrl();
|
|
155
155
|
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
156
|
const query = Object.keys(params)
|
|
157
157
|
.map((key) => {
|
|
@@ -187,12 +187,12 @@ class NetworkCore {
|
|
|
187
187
|
return result;
|
|
188
188
|
}
|
|
189
189
|
catch (_c) {
|
|
190
|
-
Log_1.Log.warn(
|
|
190
|
+
Log_1.Log.warn(`Request encoding failed for ${args.urlConfig.getUrl()}`);
|
|
191
191
|
return input;
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
_getInternalRequestArgs(method, args) {
|
|
195
|
-
const fallbackUrl = this._fallbackResolver.
|
|
195
|
+
const fallbackUrl = this._fallbackResolver.getActiveFallbackUrl(args.sdkKey, args.urlConfig);
|
|
196
196
|
return Object.assign(Object.assign({}, args), { method,
|
|
197
197
|
fallbackUrl });
|
|
198
198
|
}
|
|
@@ -225,7 +225,7 @@ function _didTimeout(controller) {
|
|
|
225
225
|
return timeout || false;
|
|
226
226
|
}
|
|
227
227
|
function _tryMarkInitStart(args, attempt) {
|
|
228
|
-
if (
|
|
228
|
+
if (args.urlConfig.endpoint !== NetworkConfig_1.Endpoint._initialize) {
|
|
229
229
|
return;
|
|
230
230
|
}
|
|
231
231
|
Diagnostics_1.Diagnostics._markInitNetworkReqStart(args.sdkKey, {
|
|
@@ -233,7 +233,7 @@ function _tryMarkInitStart(args, attempt) {
|
|
|
233
233
|
});
|
|
234
234
|
}
|
|
235
235
|
function _tryMarkInitEnd(args, response, attempt, body, err) {
|
|
236
|
-
if (
|
|
236
|
+
if (args.urlConfig.endpoint !== NetworkConfig_1.Endpoint._initialize) {
|
|
237
237
|
return;
|
|
238
238
|
}
|
|
239
239
|
Diagnostics_1.Diagnostics._markInitNetworkReqEnd(args.sdkKey, Diagnostics_1.Diagnostics._getDiagnosticsData(response, attempt, body, err));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ErrorBoundary } from './ErrorBoundary';
|
|
2
2
|
import { AnyStatsigOptions } from './StatsigOptionsCommon';
|
|
3
|
+
import { UrlConfiguration } from './UrlConfiguration';
|
|
3
4
|
export type FallbackResolverArgs = {
|
|
4
5
|
fallbackUrl: string | null;
|
|
5
6
|
};
|
|
@@ -7,14 +8,15 @@ export declare class NetworkFallbackResolver {
|
|
|
7
8
|
private _fallbackInfo;
|
|
8
9
|
private _errorBoundary;
|
|
9
10
|
private _networkOverrideFunc?;
|
|
10
|
-
private
|
|
11
|
+
private _dnsQueryCooldowns;
|
|
11
12
|
constructor(options: AnyStatsigOptions);
|
|
12
13
|
setErrorBoundary(errorBoundary: ErrorBoundary): void;
|
|
13
|
-
tryBumpExpiryTime(sdkKey: string,
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
tryBumpExpiryTime(sdkKey: string, urlConfig: UrlConfiguration): void;
|
|
15
|
+
getActiveFallbackUrl(sdkKey: string, urlConfig: UrlConfiguration): string | null;
|
|
16
|
+
getFallbackFromProvided(url: string): string | null;
|
|
17
|
+
tryFetchUpdatedFallbackInfo(sdkKey: string, urlConfig: UrlConfiguration, errorMessage: string | null, timedOut: boolean): Promise<boolean>;
|
|
16
18
|
private _updateFallbackInfoWithNewUrl;
|
|
17
|
-
private
|
|
19
|
+
private _tryFetchFallbackUrlsFromNetwork;
|
|
20
|
+
private _pickNewFallbackUrl;
|
|
18
21
|
}
|
|
19
|
-
export declare function _isDefaultUrl(url: string): boolean;
|
|
20
22
|
export declare function _isDomainFailure(errorMsg: string | null, timedOut: boolean): boolean;
|
|
@@ -9,11 +9,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports._isDomainFailure = exports.
|
|
12
|
+
exports._isDomainFailure = exports.NetworkFallbackResolver = void 0;
|
|
13
13
|
const DnsTxtQuery_1 = require("./DnsTxtQuery");
|
|
14
14
|
const Hashing_1 = require("./Hashing");
|
|
15
15
|
const Log_1 = require("./Log");
|
|
16
|
-
const NetworkConfig_1 = require("./NetworkConfig");
|
|
17
16
|
const StorageProvider_1 = require("./StorageProvider");
|
|
18
17
|
const DEFAULT_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
19
18
|
const COOLDOWN_TIME_MS = 4 * 60 * 60 * 1000; // 4 hours
|
|
@@ -22,134 +21,138 @@ class NetworkFallbackResolver {
|
|
|
22
21
|
var _a;
|
|
23
22
|
this._fallbackInfo = null;
|
|
24
23
|
this._errorBoundary = null;
|
|
25
|
-
this.
|
|
24
|
+
this._dnsQueryCooldowns = {};
|
|
26
25
|
this._networkOverrideFunc = (_a = options.networkConfig) === null || _a === void 0 ? void 0 : _a.networkOverrideFunc;
|
|
27
26
|
}
|
|
28
27
|
setErrorBoundary(errorBoundary) {
|
|
29
28
|
this._errorBoundary = errorBoundary;
|
|
30
29
|
}
|
|
31
|
-
tryBumpExpiryTime(sdkKey,
|
|
30
|
+
tryBumpExpiryTime(sdkKey, urlConfig) {
|
|
32
31
|
var _a;
|
|
33
|
-
const
|
|
34
|
-
if (!domainKey) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
const info = (_a = this._fallbackInfo) === null || _a === void 0 ? void 0 : _a[domainKey];
|
|
32
|
+
const info = (_a = this._fallbackInfo) === null || _a === void 0 ? void 0 : _a[urlConfig.endpoint];
|
|
38
33
|
if (!info) {
|
|
39
34
|
return;
|
|
40
35
|
}
|
|
41
36
|
info.expiryTime = Date.now() + DEFAULT_TTL_MS;
|
|
42
|
-
_tryWriteFallbackInfoToCache(sdkKey, Object.assign(Object.assign({}, this._fallbackInfo), { [
|
|
37
|
+
_tryWriteFallbackInfoToCache(sdkKey, Object.assign(Object.assign({}, this._fallbackInfo), { [urlConfig.endpoint]: info }));
|
|
43
38
|
}
|
|
44
|
-
|
|
39
|
+
getActiveFallbackUrl(sdkKey, urlConfig) {
|
|
45
40
|
var _a, _b;
|
|
46
|
-
const domainKey = _getDomainKeyFromEndpoint(url);
|
|
47
|
-
if (!_isDefaultUrl(url) || !domainKey) {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
41
|
let info = this._fallbackInfo;
|
|
51
42
|
if (info == null) {
|
|
52
43
|
info = (_a = _readFallbackInfoFromCache(sdkKey)) !== null && _a !== void 0 ? _a : {};
|
|
53
44
|
this._fallbackInfo = info;
|
|
54
45
|
}
|
|
55
|
-
const entry = info[
|
|
46
|
+
const entry = info[urlConfig.endpoint];
|
|
56
47
|
if (!entry || Date.now() > ((_b = entry.expiryTime) !== null && _b !== void 0 ? _b : 0)) {
|
|
57
|
-
delete info[
|
|
48
|
+
delete info[urlConfig.endpoint];
|
|
58
49
|
this._fallbackInfo = info;
|
|
59
50
|
_tryWriteFallbackInfoToCache(sdkKey, this._fallbackInfo);
|
|
60
51
|
return null;
|
|
61
52
|
}
|
|
62
|
-
const endpoint = _extractEndpointForUrl(url);
|
|
63
53
|
if (entry.url) {
|
|
64
|
-
return
|
|
54
|
+
return entry.url;
|
|
65
55
|
}
|
|
66
56
|
return null;
|
|
67
57
|
}
|
|
68
|
-
|
|
69
|
-
|
|
58
|
+
getFallbackFromProvided(url) {
|
|
59
|
+
const path = _extractPathFromUrl(url);
|
|
60
|
+
if (path) {
|
|
61
|
+
return url.replace(path, '');
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
tryFetchUpdatedFallbackInfo(sdkKey, urlConfig, errorMessage, timedOut) {
|
|
66
|
+
var _a, _b;
|
|
70
67
|
return __awaiter(this, void 0, void 0, function* () {
|
|
71
68
|
try {
|
|
72
|
-
|
|
73
|
-
if (!_isDomainFailure(errorMessage, timedOut) || !domainKey) {
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
if (this._cooldowns[domainKey] &&
|
|
77
|
-
Date.now() < this._cooldowns[domainKey]) {
|
|
69
|
+
if (!_isDomainFailure(errorMessage, timedOut)) {
|
|
78
70
|
return false;
|
|
79
71
|
}
|
|
80
|
-
|
|
81
|
-
const
|
|
72
|
+
const canUseNetworkFallbacks = urlConfig.customUrl == null && urlConfig.fallbackUrls == null;
|
|
73
|
+
const urls = canUseNetworkFallbacks
|
|
74
|
+
? yield this._tryFetchFallbackUrlsFromNetwork(urlConfig)
|
|
75
|
+
: urlConfig.fallbackUrls;
|
|
76
|
+
const newUrl = this._pickNewFallbackUrl((_a = this._fallbackInfo) === null || _a === void 0 ? void 0 : _a[urlConfig.endpoint], urls);
|
|
82
77
|
if (!newUrl) {
|
|
83
78
|
return false;
|
|
84
79
|
}
|
|
85
|
-
this._updateFallbackInfoWithNewUrl(sdkKey,
|
|
80
|
+
this._updateFallbackInfoWithNewUrl(sdkKey, urlConfig.endpoint, newUrl);
|
|
86
81
|
return true;
|
|
87
82
|
}
|
|
88
83
|
catch (error) {
|
|
89
|
-
(
|
|
84
|
+
(_b = this._errorBoundary) === null || _b === void 0 ? void 0 : _b.logError('tryFetchUpdatedFallbackInfo', error);
|
|
90
85
|
return false;
|
|
91
86
|
}
|
|
92
87
|
});
|
|
93
88
|
}
|
|
94
|
-
_updateFallbackInfoWithNewUrl(sdkKey,
|
|
89
|
+
_updateFallbackInfoWithNewUrl(sdkKey, endpoint, newUrl) {
|
|
95
90
|
var _a, _b, _c;
|
|
96
91
|
const newFallbackInfo = {
|
|
97
92
|
url: newUrl,
|
|
98
93
|
expiryTime: Date.now() + DEFAULT_TTL_MS,
|
|
99
94
|
previous: [],
|
|
100
95
|
};
|
|
101
|
-
const previousInfo = (_a = this._fallbackInfo) === null || _a === void 0 ? void 0 : _a[
|
|
96
|
+
const previousInfo = (_a = this._fallbackInfo) === null || _a === void 0 ? void 0 : _a[endpoint];
|
|
102
97
|
if (previousInfo) {
|
|
103
98
|
newFallbackInfo.previous.push(...previousInfo.previous);
|
|
104
99
|
}
|
|
105
100
|
if (newFallbackInfo.previous.length > 10) {
|
|
106
101
|
newFallbackInfo.previous = [];
|
|
107
102
|
}
|
|
108
|
-
const previousUrl = (_c = (_b = this._fallbackInfo) === null || _b === void 0 ? void 0 : _b[
|
|
103
|
+
const previousUrl = (_c = (_b = this._fallbackInfo) === null || _b === void 0 ? void 0 : _b[endpoint]) === null || _c === void 0 ? void 0 : _c.url;
|
|
109
104
|
if (previousUrl != null) {
|
|
110
105
|
newFallbackInfo.previous.push(previousUrl);
|
|
111
106
|
}
|
|
112
|
-
this._fallbackInfo = Object.assign(Object.assign({}, this._fallbackInfo), { [
|
|
107
|
+
this._fallbackInfo = Object.assign(Object.assign({}, this._fallbackInfo), { [endpoint]: newFallbackInfo });
|
|
113
108
|
_tryWriteFallbackInfoToCache(sdkKey, this._fallbackInfo);
|
|
114
109
|
}
|
|
115
|
-
|
|
116
|
-
var _a
|
|
110
|
+
_tryFetchFallbackUrlsFromNetwork(urlConfig) {
|
|
111
|
+
var _a;
|
|
117
112
|
return __awaiter(this, void 0, void 0, function* () {
|
|
118
|
-
const
|
|
119
|
-
if (
|
|
113
|
+
const cooldown = this._dnsQueryCooldowns[urlConfig.endpoint];
|
|
114
|
+
if (cooldown && Date.now() < cooldown) {
|
|
120
115
|
return null;
|
|
121
116
|
}
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
117
|
+
this._dnsQueryCooldowns[urlConfig.endpoint] = Date.now() + COOLDOWN_TIME_MS;
|
|
118
|
+
const result = [];
|
|
119
|
+
const records = yield (0, DnsTxtQuery_1._fetchTxtRecords)((_a = this._networkOverrideFunc) !== null && _a !== void 0 ? _a : fetch);
|
|
120
|
+
const path = _extractPathFromUrl(urlConfig.defaultUrl);
|
|
125
121
|
for (const record of records) {
|
|
126
|
-
|
|
127
|
-
if (!recordUrl || recordKey !== domainKey) {
|
|
122
|
+
if (!record.startsWith(urlConfig.endpointDnsKey + '=')) {
|
|
128
123
|
continue;
|
|
129
124
|
}
|
|
130
|
-
|
|
131
|
-
if (
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
125
|
+
const parts = record.split('=');
|
|
126
|
+
if (parts.length > 1) {
|
|
127
|
+
let baseUrl = parts[1];
|
|
128
|
+
if (baseUrl.endsWith('/')) {
|
|
129
|
+
baseUrl = baseUrl.slice(0, -1);
|
|
130
|
+
}
|
|
131
|
+
result.push(`https://${baseUrl}${path}`);
|
|
137
132
|
}
|
|
138
133
|
}
|
|
139
|
-
return
|
|
134
|
+
return result;
|
|
140
135
|
});
|
|
141
136
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
137
|
+
_pickNewFallbackUrl(currentFallbackInfo, urls) {
|
|
138
|
+
var _a;
|
|
139
|
+
if (urls == null) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
const previouslyUsed = new Set((_a = currentFallbackInfo === null || currentFallbackInfo === void 0 ? void 0 : currentFallbackInfo.previous) !== null && _a !== void 0 ? _a : []);
|
|
143
|
+
const currentFallbackUrl = currentFallbackInfo === null || currentFallbackInfo === void 0 ? void 0 : currentFallbackInfo.url;
|
|
144
|
+
let found = null;
|
|
145
|
+
for (const loopUrl of urls) {
|
|
146
|
+
const url = loopUrl.endsWith('/') ? loopUrl.slice(0, -1) : loopUrl;
|
|
147
|
+
if (!previouslyUsed.has(loopUrl) && url !== currentFallbackUrl) {
|
|
148
|
+
found = url;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
148
151
|
}
|
|
152
|
+
return found;
|
|
149
153
|
}
|
|
150
|
-
return false;
|
|
151
154
|
}
|
|
152
|
-
exports.
|
|
155
|
+
exports.NetworkFallbackResolver = NetworkFallbackResolver;
|
|
153
156
|
function _isDomainFailure(errorMsg, timedOut) {
|
|
154
157
|
var _a;
|
|
155
158
|
const lowerErrorMsg = (_a = errorMsg === null || errorMsg === void 0 ? void 0 : errorMsg.toLowerCase()) !== null && _a !== void 0 ? _a : '';
|
|
@@ -184,25 +187,12 @@ function _readFallbackInfoFromCache(sdkKey) {
|
|
|
184
187
|
return null;
|
|
185
188
|
}
|
|
186
189
|
}
|
|
187
|
-
function
|
|
190
|
+
function _extractPathFromUrl(urlString) {
|
|
188
191
|
try {
|
|
189
192
|
const url = new URL(urlString);
|
|
190
|
-
|
|
191
|
-
return endpoint;
|
|
193
|
+
return url.pathname;
|
|
192
194
|
}
|
|
193
195
|
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';
|
|
196
|
+
return null;
|
|
206
197
|
}
|
|
207
|
-
return null;
|
|
208
198
|
}
|
package/src/StatsigEvent.js
CHANGED
|
@@ -22,24 +22,35 @@ const _isExposureEvent = ({ eventName, }) => {
|
|
|
22
22
|
};
|
|
23
23
|
exports._isExposureEvent = _isExposureEvent;
|
|
24
24
|
const _createGateExposure = (user, gate) => {
|
|
25
|
-
var _a, _b;
|
|
26
|
-
|
|
25
|
+
var _a, _b, _c;
|
|
26
|
+
const metadata = {
|
|
27
27
|
gate: gate.name,
|
|
28
28
|
gateValue: String(gate.value),
|
|
29
29
|
ruleID: gate.ruleID,
|
|
30
|
-
}
|
|
30
|
+
};
|
|
31
|
+
if (((_a = gate.__evaluation) === null || _a === void 0 ? void 0 : _a.version) != null) {
|
|
32
|
+
metadata['configVersion'] = gate.__evaluation.version;
|
|
33
|
+
}
|
|
34
|
+
return _createExposure(GATE_EXPOSURE_NAME, user, gate.details, metadata, (_c = (_b = gate.__evaluation) === null || _b === void 0 ? void 0 : _b.secondary_exposures) !== null && _c !== void 0 ? _c : []);
|
|
31
35
|
};
|
|
32
36
|
exports._createGateExposure = _createGateExposure;
|
|
33
37
|
const _createConfigExposure = (user, config) => {
|
|
34
|
-
var _a, _b;
|
|
35
|
-
|
|
38
|
+
var _a, _b, _c, _d;
|
|
39
|
+
const metadata = {
|
|
36
40
|
config: config.name,
|
|
37
41
|
ruleID: config.ruleID,
|
|
38
|
-
}
|
|
42
|
+
};
|
|
43
|
+
if (((_a = config.__evaluation) === null || _a === void 0 ? void 0 : _a.version) != null) {
|
|
44
|
+
metadata['configVersion'] = config.__evaluation.version;
|
|
45
|
+
}
|
|
46
|
+
if (((_b = config.__evaluation) === null || _b === void 0 ? void 0 : _b.passed) != null) {
|
|
47
|
+
metadata['rulePassed'] = String(config.__evaluation.passed);
|
|
48
|
+
}
|
|
49
|
+
return _createExposure(CONFIG_EXPOSURE_NAME, user, config.details, metadata, (_d = (_c = config.__evaluation) === null || _c === void 0 ? void 0 : _c.secondary_exposures) !== null && _d !== void 0 ? _d : []);
|
|
39
50
|
};
|
|
40
51
|
exports._createConfigExposure = _createConfigExposure;
|
|
41
52
|
const _createLayerParameterExposure = (user, layer, parameterName) => {
|
|
42
|
-
var _a, _b, _c;
|
|
53
|
+
var _a, _b, _c, _d;
|
|
43
54
|
const evaluation = layer.__evaluation;
|
|
44
55
|
const isExplicit = ((_a = evaluation === null || evaluation === void 0 ? void 0 : evaluation.explicit_parameters) === null || _a === void 0 ? void 0 : _a.includes(parameterName)) === true;
|
|
45
56
|
let allocatedExperiment = '';
|
|
@@ -48,13 +59,17 @@ const _createLayerParameterExposure = (user, layer, parameterName) => {
|
|
|
48
59
|
allocatedExperiment = (_c = evaluation.allocated_experiment_name) !== null && _c !== void 0 ? _c : '';
|
|
49
60
|
secondaryExposures = evaluation.secondary_exposures;
|
|
50
61
|
}
|
|
51
|
-
|
|
62
|
+
const metadata = {
|
|
52
63
|
config: layer.name,
|
|
53
64
|
parameterName,
|
|
54
65
|
ruleID: layer.ruleID,
|
|
55
66
|
allocatedExperiment,
|
|
56
67
|
isExplicitParameter: String(isExplicit),
|
|
57
|
-
}
|
|
68
|
+
};
|
|
69
|
+
if (((_d = layer.__evaluation) === null || _d === void 0 ? void 0 : _d.version) != null) {
|
|
70
|
+
metadata['configVersion'] = layer.__evaluation.version;
|
|
71
|
+
}
|
|
72
|
+
return _createExposure(LAYER_EXPOSURE_NAME, user, layer.details, metadata, secondaryExposures);
|
|
58
73
|
};
|
|
59
74
|
exports._createLayerParameterExposure = _createLayerParameterExposure;
|
|
60
75
|
const _addEvaluationDetailsToMetadata = (details, metadata) => {
|
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.5.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
|
|
@@ -27,6 +27,10 @@ export type NetworkConfigCommon = {
|
|
|
27
27
|
* default: `https://featuregates.org/v1/initialize`
|
|
28
28
|
*/
|
|
29
29
|
logEventUrl?: string;
|
|
30
|
+
/**
|
|
31
|
+
* A list of URLs to try if the primary logEventUrl fails.
|
|
32
|
+
*/
|
|
33
|
+
logEventFallbackUrls?: string[];
|
|
30
34
|
/**
|
|
31
35
|
* Overrides the default networking layer used by the Statsig client.
|
|
32
36
|
* By default, the client use `fetch`, but overriding this
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Endpoint } from './NetworkConfig';
|
|
2
|
+
export type EndpointDnsKey = 'i' | 'e' | 'd';
|
|
3
|
+
export declare class UrlConfiguration {
|
|
4
|
+
readonly endpoint: Endpoint;
|
|
5
|
+
readonly endpointDnsKey: EndpointDnsKey;
|
|
6
|
+
readonly defaultUrl: string;
|
|
7
|
+
readonly customUrl: string | null;
|
|
8
|
+
readonly fallbackUrls: string[] | null;
|
|
9
|
+
constructor(endpoint: Endpoint, customUrl: string | undefined | null, customApi: string | undefined | null, fallbackUrls: string[] | undefined | null);
|
|
10
|
+
getUrl(): string;
|
|
11
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UrlConfiguration = void 0;
|
|
4
|
+
const NetworkConfig_1 = require("./NetworkConfig");
|
|
5
|
+
const ENDPOINT_DNS_KEY_MAP = {
|
|
6
|
+
[NetworkConfig_1.Endpoint._initialize]: 'i',
|
|
7
|
+
[NetworkConfig_1.Endpoint._rgstr]: 'e',
|
|
8
|
+
[NetworkConfig_1.Endpoint._download_config_specs]: 'd',
|
|
9
|
+
};
|
|
10
|
+
class UrlConfiguration {
|
|
11
|
+
constructor(endpoint, customUrl, customApi, fallbackUrls) {
|
|
12
|
+
this.customUrl = null;
|
|
13
|
+
this.fallbackUrls = null;
|
|
14
|
+
this.endpoint = endpoint;
|
|
15
|
+
this.endpointDnsKey = ENDPOINT_DNS_KEY_MAP[endpoint];
|
|
16
|
+
if (customUrl) {
|
|
17
|
+
this.customUrl = customUrl;
|
|
18
|
+
}
|
|
19
|
+
if (!customUrl && customApi) {
|
|
20
|
+
this.customUrl = `${customApi}/${endpoint}`;
|
|
21
|
+
}
|
|
22
|
+
if (fallbackUrls) {
|
|
23
|
+
this.fallbackUrls = fallbackUrls;
|
|
24
|
+
}
|
|
25
|
+
const defaultApi = NetworkConfig_1.NetworkDefault[endpoint];
|
|
26
|
+
this.defaultUrl = `${defaultApi}/${endpoint}`;
|
|
27
|
+
}
|
|
28
|
+
getUrl() {
|
|
29
|
+
var _a;
|
|
30
|
+
return (_a = this.customUrl) !== null && _a !== void 0 ? _a : this.defaultUrl;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.UrlConfiguration = UrlConfiguration;
|
package/src/index.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export * from './StatsigUser';
|
|
|
37
37
|
export * from './StorageProvider';
|
|
38
38
|
export * from './TypedJsonParse';
|
|
39
39
|
export * from './TypingUtils';
|
|
40
|
-
export * from './
|
|
40
|
+
export * from './UrlConfiguration';
|
|
41
41
|
export * from './UUID';
|
|
42
42
|
export * from './VisibilityObserving';
|
|
43
43
|
export { EventLogger, Storage, Log, Diagnostics };
|
package/src/index.js
CHANGED
|
@@ -59,7 +59,7 @@ __exportStar(require("./StatsigUser"), exports);
|
|
|
59
59
|
__exportStar(require("./StorageProvider"), exports);
|
|
60
60
|
__exportStar(require("./TypedJsonParse"), exports);
|
|
61
61
|
__exportStar(require("./TypingUtils"), exports);
|
|
62
|
-
__exportStar(require("./
|
|
62
|
+
__exportStar(require("./UrlConfiguration"), exports);
|
|
63
63
|
__exportStar(require("./UUID"), exports);
|
|
64
64
|
__exportStar(require("./VisibilityObserving"), exports);
|
|
65
65
|
__STATSIG__ = Object.assign(Object.assign({}, (__STATSIG__ !== null && __STATSIG__ !== void 0 ? __STATSIG__ : {})), { Log: Log_1.Log,
|
package/src/UrlOverrides.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function _getOverridableUrl(overrideUrl: string | undefined, overrideApi: string | undefined, defaultEndpoint: string, defaultApi: string): string;
|
package/src/UrlOverrides.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports._getOverridableUrl = void 0;
|
|
4
|
-
function _getOverridableUrl(overrideUrl, overrideApi, defaultEndpoint, defaultApi) {
|
|
5
|
-
if (overrideUrl) {
|
|
6
|
-
return overrideUrl;
|
|
7
|
-
}
|
|
8
|
-
else if (overrideApi) {
|
|
9
|
-
return `${overrideApi}${defaultEndpoint}`;
|
|
10
|
-
}
|
|
11
|
-
else {
|
|
12
|
-
return `${defaultApi}${defaultEndpoint}`;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
exports._getOverridableUrl = _getOverridableUrl;
|