Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@statsig/client-core

Package Overview
Dependencies
Maintainers
11
Versions
193
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@statsig/client-core - npm Package Compare versions

Comparing version
3.32.5
to
3.32.6
+1
-1
package.json
{
"name": "@statsig/client-core",
"version": "3.32.5",
"version": "3.32.6",
"license": "ISC",

@@ -5,0 +5,0 @@ "homepage": "https://github.com/statsig-io/js-client-monorepo",

@@ -14,3 +14,3 @@ import { StatsigClientEmitEventFunc } from './StatsigClientBase';

logDroppedEvents(count: number, reason: string, metadata?: Record<string, unknown>): void;
logEventRequestFailure(count: number, reason: string, flushType: string, statusCode: number, retries: number, failurePath?: string, failureErrorMessage?: string): void;
logEventRequestFailure(count: number, reason: string, flushType: string, statusCode: number, retries: number, failurePath?: string, failureErrorMessage?: string, failureDiagnosticBucket?: string, failureDiagnosticMetadata?: Record<string, string>): void;
getLastSeenErrorAndReset(): Error | null;

@@ -17,0 +17,0 @@ attachErrorIfNoneExists(error: unknown): void;

@@ -59,3 +59,3 @@ "use strict";

}
logEventRequestFailure(count, reason, flushType, statusCode, retries, failurePath, failureErrorMessage) {
logEventRequestFailure(count, reason, flushType, statusCode, retries, failurePath, failureErrorMessage, failureDiagnosticBucket, failureDiagnosticMetadata) {
const extra = {

@@ -75,2 +75,14 @@ eventCount: String(count),

}
if (typeof failureDiagnosticBucket === 'string' &&
failureDiagnosticBucket.length > 0) {
extra['failureDiagnosticBucket'] = failureDiagnosticBucket;
}
if (failureDiagnosticMetadata) {
Object.keys(failureDiagnosticMetadata).forEach((key) => {
const value = failureDiagnosticMetadata[key];
if (value.length > 0) {
extra[`failureDiagnostic_${key}`] = value;
}
});
}
this._onError(`statsig::log_event_failed`, new Error(reason), true, extra);

@@ -128,4 +140,5 @@ }

const body = Object.assign(Object.assign({ tag, exception: name, info, statsigOptions: _getStatsigOptionLoggingCopy(this._options) }, Object.assign(Object.assign({}, statsigMetadata), { sdkType })), (extra !== null && extra !== void 0 ? extra : {}));
const func = (_f = (_e = (_d = this._options) === null || _d === void 0 ? void 0 : _d.networkConfig) === null || _e === void 0 ? void 0 : _e.networkOverrideFunc) !== null && _f !== void 0 ? _f : fetch;
yield func(exports.EXCEPTION_ENDPOINT, {
const networkConfig = (_d = this._options) === null || _d === void 0 ? void 0 : _d.networkConfig;
const func = (_e = networkConfig === null || networkConfig === void 0 ? void 0 : networkConfig.networkOverrideFunc) !== null && _e !== void 0 ? _e : fetch;
yield func((_f = networkConfig === null || networkConfig === void 0 ? void 0 : networkConfig.sdkExceptionUrl) !== null && _f !== void 0 ? _f : exports.EXCEPTION_ENDPOINT, {
method: 'POST',

@@ -132,0 +145,0 @@ headers: {

export declare const EventRetryConstants: {
readonly MAX_RETRY_ATTEMPTS: 5;
readonly MAX_RETRY_ATTEMPTS: 8;
readonly DEFAULT_BATCH_SIZE: 100;
readonly MAX_PENDING_BATCHES: 30;
readonly MAX_PENDING_BATCHES: 40;
readonly TICK_INTERVAL_MS: 1000;

@@ -6,0 +6,0 @@ readonly QUICK_FLUSH_WINDOW_MS: 200;

@@ -5,5 +5,5 @@ "use strict";

exports.EventRetryConstants = {
MAX_RETRY_ATTEMPTS: 5,
MAX_RETRY_ATTEMPTS: 8,
DEFAULT_BATCH_SIZE: 100,
MAX_PENDING_BATCHES: 30,
MAX_PENDING_BATCHES: 40,
TICK_INTERVAL_MS: 1000,

@@ -10,0 +10,0 @@ QUICK_FLUSH_WINDOW_MS: 200,

@@ -11,2 +11,4 @@ import { EventBatch } from './EventBatch';

failureErrorMessage?: string;
failureDiagnosticBucket?: string;
failureDiagnosticMetadata?: Record<string, string>;
};

@@ -13,0 +15,0 @@ export declare class EventSender {

@@ -58,4 +58,8 @@ "use strict";

}
return Object.assign({ success: false, statusCode: response.statusCode, failurePath: response.failurePath }, (response.failureErrorMessage
return Object.assign(Object.assign(Object.assign({ success: false, statusCode: response.statusCode, failurePath: response.failurePath }, (response.failureErrorMessage
? { failureErrorMessage: response.failureErrorMessage }
: {})), (response.failureDiagnosticBucket
? { failureDiagnosticBucket: response.failureDiagnosticBucket }
: {})), (response.failureDiagnosticMetadata
? { failureDiagnosticMetadata: response.failureDiagnosticMetadata }
: {}));

@@ -65,4 +69,8 @@ }

Log_1.Log.warn('Failed to send batch:', error);
return Object.assign({ success: false, statusCode: -1, failurePath: (_c = transportFailure.path) !== null && _c !== void 0 ? _c : failurePath }, (transportFailure.errorMessage
return Object.assign(Object.assign(Object.assign({ success: false, statusCode: -1, failurePath: (_c = transportFailure.path) !== null && _c !== void 0 ? _c : failurePath }, (transportFailure.errorMessage
? { failureErrorMessage: transportFailure.errorMessage }
: {})), (transportFailure.diagnosticBucket
? { failureDiagnosticBucket: transportFailure.diagnosticBucket }
: {})), (transportFailure.diagnosticMetadata
? { failureDiagnosticMetadata: transportFailure.diagnosticMetadata }
: {}));

@@ -78,6 +86,10 @@ }

if (code === -1) {
return Object.assign({ success: false, statusCode: -1, failurePath: (_b = failureInfo.path) !== null && _b !== void 0 ? _b : (result === undefined
return Object.assign(Object.assign(Object.assign({ success: false, statusCode: -1, failurePath: (_b = failureInfo.path) !== null && _b !== void 0 ? _b : (result === undefined
? 'event_sender_post_returned_undefined'
: 'event_sender_post_returned_null') }, (failureInfo.errorMessage
? { failureErrorMessage: failureInfo.errorMessage }
: {})), (failureInfo.diagnosticBucket
? { failureDiagnosticBucket: failureInfo.diagnosticBucket }
: {})), (failureInfo.diagnosticMetadata
? { failureDiagnosticMetadata: failureInfo.diagnosticMetadata }
: {}));

@@ -91,6 +103,10 @@ }

const success = this._network.beacon(this._getRequestData(batch), failureInfo);
return Object.assign({ success, statusCode: success ? 200 : -1, failurePath: success
return Object.assign(Object.assign(Object.assign({ success, statusCode: success ? 200 : -1, failurePath: success
? undefined
: (_a = failureInfo.path) !== null && _a !== void 0 ? _a : 'beacon_send_false' }, (!success && failureInfo.errorMessage
? { failureErrorMessage: failureInfo.errorMessage }
: {})), (!success && failureInfo.diagnosticBucket
? { failureDiagnosticBucket: failureInfo.diagnosticBucket }
: {})), (!success && failureInfo.diagnosticMetadata
? { failureDiagnosticMetadata: failureInfo.diagnosticMetadata }
: {}));

@@ -97,0 +113,0 @@ }

@@ -264,3 +264,3 @@ "use strict";

this._flushInterval.adjustForFailure();
this._handleFailure(batch, flushType, result.statusCode, result.failurePath, result.failureErrorMessage);
this._handleFailure(batch, flushType, result.statusCode, result.failurePath, result.failureErrorMessage, result.failureDiagnosticBucket, result.failureDiagnosticMetadata);
return false;

@@ -305,3 +305,3 @@ });

}
_handleFailure(batch, flushType, statusCode, failurePath, failureErrorMessage) {
_handleFailure(batch, flushType, statusCode, failurePath, failureErrorMessage, failureDiagnosticBucket, failureDiagnosticMetadata) {
if (flushType === FlushTypes_1.FlushType.Shutdown) {

@@ -314,11 +314,13 @@ Log_1.Log.warn(`${flushType} flush failed during shutdown. ` +

if (!this._isRetryableBatch(statusCode, failurePath)) {
const reason = `non-retryable error`;
Log_1.Log.warn(`${flushType} flush failed after ${batch.attempts} attempt(s). ` +
`${batch.events.length} event(s) will be dropped. Non-retryable error: ${statusCode}`);
this._errorBoundary.logEventRequestFailure(batch.events.length, `non-retryable error`, flushType, statusCode, batch.attempts, failurePath, failureErrorMessage);
this._errorBoundary.logEventRequestFailure(batch.events.length, reason, flushType, statusCode, batch.attempts, failurePath, failureErrorMessage, failureDiagnosticBucket, failureDiagnosticMetadata);
return;
}
if (batch.attempts >= EventRetryConstants_1.EventRetryConstants.MAX_RETRY_ATTEMPTS) {
const reason = `max retry attempts exceeded`;
Log_1.Log.warn(`${flushType} flush failed after ${batch.attempts} attempt(s). ` +
`${batch.events.length} event(s) will be dropped.`);
this._errorBoundary.logEventRequestFailure(batch.events.length, `max retry attempts exceeded`, flushType, statusCode, batch.attempts, failurePath, failureErrorMessage);
this._errorBoundary.logEventRequestFailure(batch.events.length, reason, flushType, statusCode, batch.attempts, failurePath, failureErrorMessage, failureDiagnosticBucket, failureDiagnosticMetadata);
return;

@@ -325,0 +327,0 @@ }

@@ -30,2 +30,4 @@ import './$_StatsigGlobal';

errorMessage?: string;
diagnosticBucket?: string;
diagnosticMetadata?: Record<string, string>;
};

@@ -32,0 +34,0 @@ type BeaconRequestArgs = Pick<RequestArgsWithData, 'data' | 'sdkKey' | 'urlConfig' | 'params' | 'isCompressable' | 'attempt'>;

@@ -141,2 +141,3 @@ "use strict";

const populatedUrl = this._getPopulatedURL(args);
const startTime = Date.now();
let response = null;

@@ -217,2 +218,10 @@ const keepalive = (0, VisibilityObserving_1._isUnloading)();

}
try {
const diagnostics = _getNoResponseDiagnostics(args, populatedUrl, timedOut, Date.now() - startTime);
failureInfo.diagnosticBucket = diagnostics.bucket;
failureInfo.diagnosticMetadata = diagnostics.metadata;
}
catch (_e) {
// Diagnostics should not affect request failure handling.
}
}

@@ -394,2 +403,85 @@ }

}
function _getNoResponseDiagnostics(args, populatedUrl, timedOut, elapsedMs) {
var _a, _b, _c;
const win = (0, SafeJs_1._getWindowSafe)();
const doc = win === null || win === void 0 ? void 0 : win.document;
const nav = typeof navigator !== 'undefined' ? navigator : null;
const isUnloading = (0, VisibilityObserving_1._isUnloading)();
const online = nav && typeof nav.onLine === 'boolean' ? String(nav.onLine) : 'unknown';
const visibilityState = (_a = doc === null || doc === void 0 ? void 0 : doc.visibilityState) !== null && _a !== void 0 ? _a : 'unknown';
const hasCustomHeaders = Object.keys((_b = args.headers) !== null && _b !== void 0 ? _b : {}).length > 0;
const crossOrigin = _isCrossOrigin(populatedUrl, (_c = win === null || win === void 0 ? void 0 : win.location) === null || _c === void 0 ? void 0 : _c.origin);
const hasCustomUrl = args.urlConfig.customUrl != null;
const hasFallbackUrl = args.fallbackUrl != null;
const elapsedMsBucket = _bucketNumber(elapsedMs, [250, 1000, 5000, 10000]);
const bodySizeBucket = _bucketNumber(_getBodySize(args.body), [16384, 65536, 262144, 1048576]);
let bucket = 'unknown_no_response';
if (timedOut) {
bucket = 'timeout';
}
else if (online === 'false') {
bucket = 'browser_offline';
}
else if (isUnloading) {
bucket = 'page_unloading';
}
else if (visibilityState === 'hidden') {
bucket = 'page_hidden';
}
else if (crossOrigin && hasCustomHeaders) {
bucket = 'cross_origin_custom_headers_preflight_risk';
}
else if (hasCustomUrl || hasFallbackUrl) {
bucket = 'custom_url_no_response';
}
else if (elapsedMs < 250) {
bucket = 'immediate_network_rejection';
}
return {
bucket,
metadata: {
elapsedMsBucket,
bodySizeBucket,
online,
visibilityState,
isUnloading: String(isUnloading),
crossOrigin: String(crossOrigin),
hasCustomUrl: String(hasCustomUrl),
},
};
}
function _isCrossOrigin(url, currentOrigin) {
if (!currentOrigin) {
return true;
}
return (!url.startsWith(`${currentOrigin}/`) &&
!url.startsWith(`${currentOrigin}?`) &&
url !== currentOrigin);
}
function _getBodySize(body) {
if (body == null) {
return 0;
}
if (typeof body === 'string') {
return body.length;
}
if (body instanceof Uint8Array) {
return body.byteLength;
}
if (typeof Blob !== 'undefined' && body instanceof Blob) {
return body.size;
}
return -1;
}
function _bucketNumber(value, thresholds) {
if (value < 0) {
return 'unknown';
}
for (const threshold of thresholds) {
if (value < threshold) {
return `<${threshold}`;
}
}
return `>=${thresholds[thresholds.length - 1]}`;
}
function _tryMarkInitStart(args, attempt) {

@@ -396,0 +488,0 @@ if (args.urlConfig.endpoint !== NetworkConfig_1.Endpoint._initialize) {

@@ -1,2 +0,2 @@

export declare const SDK_VERSION = "3.32.5";
export declare const SDK_VERSION = "3.32.6";
export type StatsigMetadata = {

@@ -3,0 +3,0 @@ readonly [key: string]: string | undefined | null;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StatsigMetadataProvider = exports.SDK_VERSION = void 0;
exports.SDK_VERSION = '3.32.5';
exports.SDK_VERSION = '3.32.6';
let metadata = {

@@ -6,0 +6,0 @@ sdkVersion: exports.SDK_VERSION,

@@ -61,2 +61,8 @@ import { LogLevel } from './Log';

/**
* The URL used to report SDK exceptions via a POST request.
*
* default: `https://statsigapi.net/v1/sdk_exception`
*/
sdkExceptionUrl?: string;
/**
* A list of URLs to try if the primary logEventUrl fails.

@@ -63,0 +69,0 @@ */