@statsig/client-core 3.32.3 → 3.32.4
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/ErrorBoundary.d.ts +1 -1
- package/src/ErrorBoundary.js +4 -1
- package/src/EventSender.d.ts +7 -4
- package/src/EventSender.js +42 -10
- package/src/FlushCoordinator.js +4 -4
- package/src/NetworkCore.d.ts +5 -2
- package/src/NetworkCore.js +39 -6
- package/src/StatsigMetadata.d.ts +1 -1
- package/src/StatsigMetadata.js +1 -1
package/package.json
CHANGED
package/src/ErrorBoundary.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export declare class ErrorBoundary {
|
|
|
11
11
|
wrap(instance: unknown, namePrefix?: string): void;
|
|
12
12
|
logError(tag: string, error: unknown): void;
|
|
13
13
|
logDroppedEvents(count: number, reason: string, metadata?: Record<string, unknown>): void;
|
|
14
|
-
logEventRequestFailure(count: number, reason: string, flushType: string, statusCode: number, retries: number): void;
|
|
14
|
+
logEventRequestFailure(count: number, reason: string, flushType: string, statusCode: number, retries: number, failurePath?: string): void;
|
|
15
15
|
getLastSeenErrorAndReset(): Error | null;
|
|
16
16
|
attachErrorIfNoneExists(error: unknown): void;
|
|
17
17
|
private _capture;
|
package/src/ErrorBoundary.js
CHANGED
|
@@ -56,7 +56,7 @@ class ErrorBoundary {
|
|
|
56
56
|
}
|
|
57
57
|
this._onError(`statsig::log_event_dropped_event_count`, new Error(reason), true, extra);
|
|
58
58
|
}
|
|
59
|
-
logEventRequestFailure(count, reason, flushType, statusCode, retries) {
|
|
59
|
+
logEventRequestFailure(count, reason, flushType, statusCode, retries, failurePath) {
|
|
60
60
|
const extra = {
|
|
61
61
|
eventCount: String(count),
|
|
62
62
|
flushType: flushType,
|
|
@@ -64,6 +64,9 @@ class ErrorBoundary {
|
|
|
64
64
|
reason: reason,
|
|
65
65
|
retries: String(retries),
|
|
66
66
|
};
|
|
67
|
+
if (failurePath) {
|
|
68
|
+
extra['failurePath'] = failurePath;
|
|
69
|
+
}
|
|
67
70
|
this._onError(`statsig::log_event_failed`, new Error(reason), true, extra);
|
|
68
71
|
}
|
|
69
72
|
getLastSeenErrorAndReset() {
|
package/src/EventSender.d.ts
CHANGED
|
@@ -3,6 +3,11 @@ import { NetworkCore } from './NetworkCore';
|
|
|
3
3
|
import { StatsigClientEmitEventFunc } from './StatsigClientBase';
|
|
4
4
|
import { LogEventCompressionMode, NetworkConfigCommon, StatsigOptionsCommon } from './StatsigOptionsCommon';
|
|
5
5
|
import { UrlConfiguration } from './UrlConfiguration';
|
|
6
|
+
type EventSendResult = {
|
|
7
|
+
success: boolean;
|
|
8
|
+
statusCode: number;
|
|
9
|
+
failurePath?: string;
|
|
10
|
+
};
|
|
6
11
|
export declare class EventSender {
|
|
7
12
|
private _network;
|
|
8
13
|
private _sdkKey;
|
|
@@ -11,11 +16,9 @@ export declare class EventSender {
|
|
|
11
16
|
private _emitter;
|
|
12
17
|
constructor(sdkKey: string, network: NetworkCore, emitter: StatsigClientEmitEventFunc, logEventUrlConfig: UrlConfiguration, options: StatsigOptionsCommon<NetworkConfigCommon> | null);
|
|
13
18
|
setLogEventCompressionMode(mode: LogEventCompressionMode): void;
|
|
14
|
-
sendBatch(batch: EventBatch): Promise<
|
|
15
|
-
success: boolean;
|
|
16
|
-
statusCode: number;
|
|
17
|
-
}>;
|
|
19
|
+
sendBatch(batch: EventBatch): Promise<EventSendResult>;
|
|
18
20
|
private _sendEventsViaPost;
|
|
19
21
|
private _sendEventsViaBeacon;
|
|
20
22
|
private _getRequestData;
|
|
21
23
|
}
|
|
24
|
+
export {};
|
package/src/EventSender.js
CHANGED
|
@@ -12,6 +12,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.EventSender = void 0;
|
|
13
13
|
const Log_1 = require("./Log");
|
|
14
14
|
const NetworkConfig_1 = require("./NetworkConfig");
|
|
15
|
+
const SDKType_1 = require("./SDKType");
|
|
16
|
+
const StatsigMetadata_1 = require("./StatsigMetadata");
|
|
15
17
|
const VisibilityObserving_1 = require("./VisibilityObserving");
|
|
16
18
|
class EventSender {
|
|
17
19
|
constructor(sdkKey, network, emitter, logEventUrlConfig, options) {
|
|
@@ -26,47 +28,75 @@ class EventSender {
|
|
|
26
28
|
}
|
|
27
29
|
sendBatch(batch) {
|
|
28
30
|
return __awaiter(this, void 0, void 0, function* () {
|
|
29
|
-
var _a, _b;
|
|
31
|
+
var _a, _b, _c;
|
|
32
|
+
let failurePath = 'event_sender_unexpected_exception';
|
|
33
|
+
const transportFailure = {};
|
|
30
34
|
try {
|
|
31
35
|
const isClosing = (0, VisibilityObserving_1._isUnloading)();
|
|
32
36
|
const shouldUseBeacon = isClosing &&
|
|
33
37
|
this._network.isBeaconSupported() &&
|
|
34
38
|
((_b = (_a = this._options) === null || _a === void 0 ? void 0 : _a.networkConfig) === null || _b === void 0 ? void 0 : _b.networkOverrideFunc) == null;
|
|
39
|
+
failurePath = 'event_sender_pre_logs_flushed_emitter_exception';
|
|
35
40
|
this._emitter({
|
|
36
41
|
name: 'pre_logs_flushed',
|
|
37
42
|
events: batch.events,
|
|
38
43
|
});
|
|
44
|
+
failurePath = shouldUseBeacon
|
|
45
|
+
? 'event_sender_unexpected_exception'
|
|
46
|
+
: 'event_sender_post_exception';
|
|
39
47
|
const response = shouldUseBeacon
|
|
40
|
-
? this._sendEventsViaBeacon(batch)
|
|
41
|
-
: yield this._sendEventsViaPost(batch);
|
|
48
|
+
? this._sendEventsViaBeacon(batch, transportFailure)
|
|
49
|
+
: yield this._sendEventsViaPost(batch, transportFailure);
|
|
42
50
|
if (response.success) {
|
|
51
|
+
failurePath = 'event_sender_logs_flushed_emitter_exception';
|
|
43
52
|
this._emitter({
|
|
44
53
|
name: 'logs_flushed',
|
|
45
54
|
events: batch.events,
|
|
46
55
|
});
|
|
47
56
|
return response;
|
|
48
57
|
}
|
|
49
|
-
return {
|
|
58
|
+
return {
|
|
59
|
+
success: false,
|
|
60
|
+
statusCode: response.statusCode,
|
|
61
|
+
failurePath: response.failurePath,
|
|
62
|
+
};
|
|
50
63
|
}
|
|
51
64
|
catch (error) {
|
|
52
65
|
Log_1.Log.warn('Failed to send batch:', error);
|
|
53
|
-
return {
|
|
66
|
+
return {
|
|
67
|
+
success: false,
|
|
68
|
+
statusCode: -1,
|
|
69
|
+
failurePath: (_c = transportFailure.path) !== null && _c !== void 0 ? _c : failurePath,
|
|
70
|
+
};
|
|
54
71
|
}
|
|
55
72
|
});
|
|
56
73
|
}
|
|
57
|
-
_sendEventsViaPost(batch) {
|
|
74
|
+
_sendEventsViaPost(batch, failureInfo) {
|
|
58
75
|
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
-
var _a;
|
|
60
|
-
const result = yield this._network.post(this._getRequestData(batch));
|
|
76
|
+
var _a, _b;
|
|
77
|
+
const result = yield this._network.post(this._getRequestData(batch), failureInfo);
|
|
61
78
|
const code = (_a = result === null || result === void 0 ? void 0 : result.code) !== null && _a !== void 0 ? _a : -1;
|
|
79
|
+
if (code === -1) {
|
|
80
|
+
return {
|
|
81
|
+
success: false,
|
|
82
|
+
statusCode: -1,
|
|
83
|
+
failurePath: (_b = failureInfo.path) !== null && _b !== void 0 ? _b : (result === undefined
|
|
84
|
+
? 'event_sender_post_returned_undefined'
|
|
85
|
+
: 'event_sender_post_returned_null'),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
62
88
|
return { success: code >= 200 && code < 300, statusCode: code };
|
|
63
89
|
});
|
|
64
90
|
}
|
|
65
|
-
_sendEventsViaBeacon(batch) {
|
|
66
|
-
|
|
91
|
+
_sendEventsViaBeacon(batch, failureInfo) {
|
|
92
|
+
var _a;
|
|
93
|
+
const success = this._network.beacon(this._getRequestData(batch), failureInfo);
|
|
67
94
|
return {
|
|
68
95
|
success,
|
|
69
96
|
statusCode: success ? 200 : -1,
|
|
97
|
+
failurePath: success
|
|
98
|
+
? undefined
|
|
99
|
+
: (_a = failureInfo.path) !== null && _a !== void 0 ? _a : 'beacon_send_false',
|
|
70
100
|
};
|
|
71
101
|
}
|
|
72
102
|
_getRequestData(batch) {
|
|
@@ -85,6 +115,8 @@ class EventSender {
|
|
|
85
115
|
headers: {
|
|
86
116
|
'statsig-event-count': String(batch.events.length),
|
|
87
117
|
'statsig-retry-count': String(batch.attempts),
|
|
118
|
+
'statsig-sdk-type': SDKType_1.SDKType._get(this._sdkKey),
|
|
119
|
+
'statsig-sdk-version': StatsigMetadata_1.SDK_VERSION,
|
|
88
120
|
},
|
|
89
121
|
credentials: 'same-origin',
|
|
90
122
|
};
|
package/src/FlushCoordinator.js
CHANGED
|
@@ -254,7 +254,7 @@ class FlushCoordinator {
|
|
|
254
254
|
return true;
|
|
255
255
|
}
|
|
256
256
|
this._flushInterval.adjustForFailure();
|
|
257
|
-
this._handleFailure(batch, flushType, result.statusCode);
|
|
257
|
+
this._handleFailure(batch, flushType, result.statusCode, result.failurePath);
|
|
258
258
|
return false;
|
|
259
259
|
});
|
|
260
260
|
}
|
|
@@ -283,7 +283,7 @@ class FlushCoordinator {
|
|
|
283
283
|
const allEvents = this._pendingEvents.takeAll();
|
|
284
284
|
return this._batchQueue.createBatches(allEvents);
|
|
285
285
|
}
|
|
286
|
-
_handleFailure(batch, flushType, statusCode) {
|
|
286
|
+
_handleFailure(batch, flushType, statusCode, failurePath) {
|
|
287
287
|
if (flushType === FlushTypes_1.FlushType.Shutdown) {
|
|
288
288
|
Log_1.Log.warn(`${flushType} flush failed during shutdown. ` +
|
|
289
289
|
`${batch.events.length} event(s) will be saved to storage for retry in next session.`);
|
|
@@ -293,13 +293,13 @@ class FlushCoordinator {
|
|
|
293
293
|
if (!NetworkCore_1.RETRYABLE_CODES.has(statusCode)) {
|
|
294
294
|
Log_1.Log.warn(`${flushType} flush failed after ${batch.attempts} attempt(s). ` +
|
|
295
295
|
`${batch.events.length} event(s) will be dropped. Non-retryable error: ${statusCode}`);
|
|
296
|
-
this._errorBoundary.logEventRequestFailure(batch.events.length, `non-retryable error`, flushType, statusCode, batch.attempts);
|
|
296
|
+
this._errorBoundary.logEventRequestFailure(batch.events.length, `non-retryable error`, flushType, statusCode, batch.attempts, failurePath);
|
|
297
297
|
return;
|
|
298
298
|
}
|
|
299
299
|
if (batch.attempts >= EventRetryConstants_1.EventRetryConstants.MAX_RETRY_ATTEMPTS) {
|
|
300
300
|
Log_1.Log.warn(`${flushType} flush failed after ${batch.attempts} attempt(s). ` +
|
|
301
301
|
`${batch.events.length} event(s) will be dropped.`);
|
|
302
|
-
this._errorBoundary.logEventRequestFailure(batch.events.length, `max retry attempts exceeded`, flushType, statusCode, batch.attempts);
|
|
302
|
+
this._errorBoundary.logEventRequestFailure(batch.events.length, `max retry attempts exceeded`, flushType, statusCode, batch.attempts, failurePath);
|
|
303
303
|
return;
|
|
304
304
|
}
|
|
305
305
|
batch.incrementAttempts();
|
package/src/NetworkCore.d.ts
CHANGED
|
@@ -24,6 +24,9 @@ type DataFlags = {
|
|
|
24
24
|
export type RequestArgsWithData = Flatten<RequestArgs & {
|
|
25
25
|
data: Record<string, unknown>;
|
|
26
26
|
} & DataFlags>;
|
|
27
|
+
export type RequestFailureInfo = {
|
|
28
|
+
path?: string;
|
|
29
|
+
};
|
|
27
30
|
type BeaconRequestArgs = Pick<RequestArgsWithData, 'data' | 'sdkKey' | 'urlConfig' | 'params' | 'isCompressable' | 'attempt'>;
|
|
28
31
|
type NetworkResponse = {
|
|
29
32
|
body: string | null;
|
|
@@ -43,8 +46,8 @@ export declare class NetworkCore {
|
|
|
43
46
|
setErrorBoundary(errorBoundary: ErrorBoundary): void;
|
|
44
47
|
isBeaconSupported(): boolean;
|
|
45
48
|
getLastUsedInitUrlAndReset(): string | null;
|
|
46
|
-
beacon(args: BeaconRequestArgs): boolean;
|
|
47
|
-
post(args: RequestArgsWithData): Promise<NetworkResponse | null>;
|
|
49
|
+
beacon(args: BeaconRequestArgs, failureInfo?: RequestFailureInfo): boolean;
|
|
50
|
+
post(args: RequestArgsWithData, failureInfo?: RequestFailureInfo): Promise<NetworkResponse | null>;
|
|
48
51
|
get(args: RequestArgs): Promise<NetworkResponse | null>;
|
|
49
52
|
private _sendRequest;
|
|
50
53
|
private _getLogEventCompressionMode;
|
package/src/NetworkCore.js
CHANGED
|
@@ -73,40 +73,66 @@ class NetworkCore {
|
|
|
73
73
|
this._lastUsedInitUrl = null;
|
|
74
74
|
return tempUrl;
|
|
75
75
|
}
|
|
76
|
-
beacon(args) {
|
|
76
|
+
beacon(args, failureInfo) {
|
|
77
77
|
if (!_ensureValidSdkKey(args)) {
|
|
78
|
+
if (failureInfo) {
|
|
79
|
+
failureInfo.path = 'beacon_invalid_sdk_key';
|
|
80
|
+
}
|
|
78
81
|
return false;
|
|
79
82
|
}
|
|
80
83
|
const argsInternal = this._getInternalRequestArgs('POST', args);
|
|
81
84
|
const url = this._getPopulatedURL(argsInternal);
|
|
82
85
|
const nav = navigator;
|
|
83
|
-
|
|
86
|
+
try {
|
|
87
|
+
const success = nav.sendBeacon.bind(nav)(url, argsInternal.body);
|
|
88
|
+
if (!success) {
|
|
89
|
+
if (failureInfo) {
|
|
90
|
+
failureInfo.path = 'beacon_send_false';
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return success;
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
if (failureInfo) {
|
|
97
|
+
failureInfo.path = 'beacon_send_exception';
|
|
98
|
+
}
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
84
101
|
}
|
|
85
|
-
post(args) {
|
|
102
|
+
post(args, failureInfo) {
|
|
86
103
|
return __awaiter(this, void 0, void 0, function* () {
|
|
87
104
|
const argsInternal = this._getInternalRequestArgs('POST', args);
|
|
88
105
|
this._tryEncodeBody(argsInternal);
|
|
89
106
|
yield this._tryToCompressBody(argsInternal);
|
|
90
|
-
return this._sendRequest(argsInternal);
|
|
107
|
+
return this._sendRequest(argsInternal, failureInfo);
|
|
91
108
|
});
|
|
92
109
|
}
|
|
93
110
|
get(args) {
|
|
94
111
|
const argsInternal = this._getInternalRequestArgs('GET', args);
|
|
95
112
|
return this._sendRequest(argsInternal);
|
|
96
113
|
}
|
|
97
|
-
_sendRequest(args) {
|
|
114
|
+
_sendRequest(args, failureInfo) {
|
|
98
115
|
return __awaiter(this, void 0, void 0, function* () {
|
|
99
116
|
var _a, _b, _c, _d;
|
|
100
117
|
if (!_ensureValidSdkKey(args)) {
|
|
118
|
+
if (failureInfo) {
|
|
119
|
+
failureInfo.path = 'network_invalid_sdk_key';
|
|
120
|
+
}
|
|
101
121
|
return null;
|
|
102
122
|
}
|
|
103
123
|
if (this._netConfig.preventAllNetworkTraffic) {
|
|
124
|
+
if (failureInfo) {
|
|
125
|
+
failureInfo.path = 'network_prevent_all_network_traffic';
|
|
126
|
+
}
|
|
104
127
|
return null;
|
|
105
128
|
}
|
|
106
129
|
const { method, body, retries, attempt } = args;
|
|
107
130
|
const endpoint = args.urlConfig.endpoint;
|
|
108
131
|
if (this._isRateLimited(endpoint)) {
|
|
109
132
|
Log_1.Log.warn(`Request to ${endpoint} was blocked because you are making requests too frequently.`);
|
|
133
|
+
if (failureInfo) {
|
|
134
|
+
failureInfo.path = 'network_rate_limited';
|
|
135
|
+
}
|
|
110
136
|
return null;
|
|
111
137
|
}
|
|
112
138
|
const currentAttempt = attempt !== null && attempt !== void 0 ? attempt : 1;
|
|
@@ -179,10 +205,17 @@ class NetworkCore {
|
|
|
179
205
|
code: response.status,
|
|
180
206
|
};
|
|
181
207
|
}
|
|
208
|
+
if (response == null) {
|
|
209
|
+
if (failureInfo) {
|
|
210
|
+
failureInfo.path = timedOut
|
|
211
|
+
? 'network_request_timed_out_no_response'
|
|
212
|
+
: 'network_request_exception_no_response';
|
|
213
|
+
}
|
|
214
|
+
}
|
|
182
215
|
return null;
|
|
183
216
|
}
|
|
184
217
|
yield _exponentialBackoff(currentAttempt);
|
|
185
|
-
return this._sendRequest(Object.assign(Object.assign({}, args), { retries, attempt: currentAttempt + 1 }));
|
|
218
|
+
return this._sendRequest(Object.assign(Object.assign({}, args), { retries, attempt: currentAttempt + 1 }), failureInfo);
|
|
186
219
|
}
|
|
187
220
|
});
|
|
188
221
|
}
|
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.32.
|
|
4
|
+
exports.SDK_VERSION = '3.32.4';
|
|
5
5
|
let metadata = {
|
|
6
6
|
sdkVersion: exports.SDK_VERSION,
|
|
7
7
|
sdkType: 'js-mono', // js-mono is overwritten by Precomp and OnDevice clients
|