Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Socket
Sign inDemoInstall

@datadog/browser-core

Package Overview
Dependencies
Maintainers
1
Versions
258
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@datadog/browser-core - npm Package Compare versions

Comparing version 4.17.2 to 4.18.1

2

cjs/boot/init.js

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

var publicApi = (0, utils_1.assign)({
version: "4.17.2",
version: "4.18.1",
// This API method is intentionally not monitored, since the only thing executed is the

@@ -12,0 +12,0 @@ // user-provided 'callback'. All SDK usages executed in the callback should be monitored, and

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

var parameters = 'ddsource=browser' +
"&ddtags=".concat(encodeURIComponent(["sdk_version:".concat("4.17.2")].concat(tags).join(','))) +
"&ddtags=".concat(encodeURIComponent(["sdk_version:".concat("4.18.1")].concat(tags).join(','))) +
"&dd-api-key=".concat(clientToken) +
"&dd-evp-origin-version=".concat(encodeURIComponent("4.17.2")) +
"&dd-evp-origin-version=".concat(encodeURIComponent("4.18.1")) +
'&dd-evp-origin=browser' +

@@ -33,0 +33,0 @@ "&dd-request-id=".concat((0, utils_1.generateUUID)());

@@ -1,7 +0,1 @@

/**
* LIMITATION:
* For NPM setup, this feature flag singleton is shared between RUM and Logs product.
* This means that an experimental flag set on the RUM product will be set on the Logs product.
* So keep in mind that in certain configurations, your experimental feature flag may affect other products.
*/
export declare function updateExperimentalFeatures(enabledFeatures: string[] | undefined): void;

@@ -8,0 +2,0 @@ export declare function isExperimentalFeatureEnabled(featureName: string): boolean;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getExperimentalFeatures = exports.resetExperimentalFeatures = exports.isExperimentalFeatureEnabled = exports.updateExperimentalFeatures = void 0;
/**

@@ -8,4 +10,4 @@ * LIMITATION:

*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.getExperimentalFeatures = exports.resetExperimentalFeatures = exports.isExperimentalFeatureEnabled = exports.updateExperimentalFeatures = void 0;
var utils_1 = require("../../tools/utils");
var display_1 = require("../../tools/display");
var enabledExperimentalFeatures;

@@ -23,2 +25,5 @@ function updateExperimentalFeatures(enabledFeatures) {

.forEach(function (flag) {
if ((0, utils_1.includes)(flag, '-')) {
display_1.display.warn("please use snake case for '".concat(flag, "'"));
}
enabledExperimentalFeatures.add(flag);

@@ -25,0 +30,0 @@ });

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

service: 'browser-sdk',
version: "4.17.2",
version: "4.18.1",
source: 'browser',

@@ -43,0 +43,0 @@ _dd: {

@@ -11,3 +11,3 @@ export { Configuration, InitConfiguration, buildCookieOptions, validateAndBuildConfiguration, DefaultPrivacyLevel, EndpointBuilder, isExperimentalFeatureEnabled, updateExperimentalFeatures, resetExperimentalFeatures, } from './domain/configuration';

export { SESSION_TIME_OUT_DELAY, } from './domain/session/sessionConstants';
export { HttpRequest, Batch, canUseEventBridge, getEventBridge, startBatchWithReplica } from './transport';
export { HttpRequest, createHttpRequest, Batch, canUseEventBridge, getEventBridge, startBatchWithReplica, } from './transport';
export * from './tools/display';

@@ -14,0 +14,0 @@ export * from './tools/urlPolyfill';

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

Object.defineProperty(exports, "__esModule", { value: true });
exports.createContextManager = exports.catchUserErrors = exports.BoundedBuffer = exports.initConsoleObservable = exports.initFetchObservable = exports.initXhrObservable = exports.COOKIE_ACCESS_DELAY = exports.deleteCookie = exports.setCookie = exports.getCookie = exports.areCookiesAuthorized = exports.getFileFromStackTraceString = exports.toStackTraceString = exports.createHandlingStack = exports.formatUnknownError = exports.ErrorSource = exports.instrumentSetter = exports.instrumentMethodAndCallOriginal = exports.instrumentMethod = exports.startBatchWithReplica = exports.getEventBridge = exports.canUseEventBridge = exports.Batch = exports.HttpRequest = exports.SESSION_TIME_OUT_DELAY = exports.stopSessionManager = exports.startSessionManager = exports.Observable = exports.setDebugMode = exports.callMonitored = exports.monitor = exports.monitored = exports.isTelemetryReplicationAllowed = exports.resetTelemetry = exports.startFakeTelemetry = exports.addTelemetryError = exports.addTelemetryDebug = exports.startTelemetry = exports.RawReportType = exports.initReportObservable = exports.makePublicApi = exports.defineGlobal = exports.computeStackTrace = exports.trackRuntimeError = exports.resetExperimentalFeatures = exports.updateExperimentalFeatures = exports.isExperimentalFeatureEnabled = exports.DefaultPrivacyLevel = exports.validateAndBuildConfiguration = exports.buildCookieOptions = void 0;
exports.createContextManager = exports.catchUserErrors = exports.BoundedBuffer = exports.initConsoleObservable = exports.initFetchObservable = exports.initXhrObservable = exports.COOKIE_ACCESS_DELAY = exports.deleteCookie = exports.setCookie = exports.getCookie = exports.areCookiesAuthorized = exports.getFileFromStackTraceString = exports.toStackTraceString = exports.createHandlingStack = exports.formatUnknownError = exports.ErrorSource = exports.instrumentSetter = exports.instrumentMethodAndCallOriginal = exports.instrumentMethod = exports.startBatchWithReplica = exports.getEventBridge = exports.canUseEventBridge = exports.Batch = exports.createHttpRequest = exports.SESSION_TIME_OUT_DELAY = exports.stopSessionManager = exports.startSessionManager = exports.Observable = exports.setDebugMode = exports.callMonitored = exports.monitor = exports.monitored = exports.isTelemetryReplicationAllowed = exports.resetTelemetry = exports.startFakeTelemetry = exports.addTelemetryError = exports.addTelemetryDebug = exports.startTelemetry = exports.RawReportType = exports.initReportObservable = exports.makePublicApi = exports.defineGlobal = exports.computeStackTrace = exports.trackRuntimeError = exports.resetExperimentalFeatures = exports.updateExperimentalFeatures = exports.isExperimentalFeatureEnabled = exports.DefaultPrivacyLevel = exports.validateAndBuildConfiguration = exports.buildCookieOptions = void 0;
exports.getSyntheticsResultId = exports.getSyntheticsTestId = exports.willSyntheticsInjectRum = exports.SESSION_COOKIE_NAME = exports.CLEAR_OLD_CONTEXTS_INTERVAL = exports.ContextHistory = exports.limitModification = void 0;

@@ -58,3 +58,3 @@ var configuration_1 = require("./domain/configuration");

var transport_1 = require("./transport");
Object.defineProperty(exports, "HttpRequest", { enumerable: true, get: function () { return transport_1.HttpRequest; } });
Object.defineProperty(exports, "createHttpRequest", { enumerable: true, get: function () { return transport_1.createHttpRequest; } });
Object.defineProperty(exports, "Batch", { enumerable: true, get: function () { return transport_1.Batch; } });

@@ -61,0 +61,0 @@ Object.defineProperty(exports, "canUseEventBridge", { enumerable: true, get: function () { return transport_1.canUseEventBridge; } });

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

var instrumentationWrapper = function () {
if (typeof instrumentation !== 'function') {
return undefined;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return

@@ -12,0 +15,0 @@ return instrumentation.apply(this, arguments);

@@ -17,3 +17,4 @@ import type { Context } from '../tools/context';

upsert(message: Context, key: string): void;
flush(): void;
flush(sendFn?: (data: string | FormData, bytesCount: number) => void): void;
flushOnExit(): void;
computeBytesCount(candidate: string): number;

@@ -28,3 +29,3 @@ private addOrUpdate;

private flushPeriodically;
private flushOnVisibilityHidden;
private setupFlushOnExit;
}

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

this.bufferMessagesCount = 0;
this.flushOnVisibilityHidden();
this.setupFlushOnExit();
this.flushPeriodically();

@@ -33,3 +33,4 @@ }

};
Batch.prototype.flush = function () {
Batch.prototype.flush = function (sendFn) {
if (sendFn === void 0) { sendFn = this.request.send; }
if (this.bufferMessagesCount !== 0) {

@@ -42,5 +43,8 @@ var messages = this.pushOnlyBuffer.concat((0, utils_1.objectValues)(this.upsertBuffer));

this.bufferMessagesCount = 0;
this.request.send(messages.join('\n'), bytesCount);
sendFn(messages.join('\n'), bytesCount);
}
};
Batch.prototype.flushOnExit = function () {
this.flush(this.request.sendOnExit);
};
Batch.prototype.computeBytesCount = function (candidate) {

@@ -119,3 +123,3 @@ // Accurate bytes count computations can degrade performances when there is a lot of events to process

};
Batch.prototype.flushOnVisibilityHidden = function () {
Batch.prototype.setupFlushOnExit = function () {
var _this = this;

@@ -139,3 +143,3 @@ /**

if (document.visibilityState === 'hidden') {
_this.flush();
_this.flushOnExit();
}

@@ -148,3 +152,3 @@ });

*/
(0, utils_1.addEventListener)(window, "beforeunload" /* BEFORE_UNLOAD */, function () { return _this.flush(); });
(0, utils_1.addEventListener)(window, "beforeunload" /* BEFORE_UNLOAD */, function () { return _this.flushOnExit(); });
}

@@ -151,0 +155,0 @@ };

@@ -10,7 +10,10 @@ import type { EndpointBuilder } from '../domain/configuration';

*/
export declare class HttpRequest {
private endpointBuilder;
private bytesLimit;
constructor(endpointBuilder: EndpointBuilder, bytesLimit: number);
send(data: string | FormData, bytesCount: number): void;
}
export declare type HttpRequest = ReturnType<typeof createHttpRequest>;
export declare function createHttpRequest(endpointBuilder: EndpointBuilder, bytesLimit: number): {
send: (data: string | FormData, bytesCount: number) => void;
/**
* Since fetch keepalive behaves like regular fetch on Firefox,
* keep using sendBeaconStrategy on exit
*/
sendOnExit: (data: string | FormData, bytesCount: number) => void;
};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HttpRequest = void 0;
exports.createHttpRequest = void 0;
var telemetry_1 = require("../domain/telemetry");
/**
* Use POST request without content type to:
* - avoid CORS preflight requests
* - allow usage of sendBeacon
*
* multiple elements are sent separated by \n in order
* to be parsed correctly without content type header
*/
var HttpRequest = /** @class */ (function () {
function HttpRequest(endpointBuilder, bytesLimit) {
this.endpointBuilder = endpointBuilder;
this.bytesLimit = bytesLimit;
}
HttpRequest.prototype.send = function (data, bytesCount) {
var url = this.endpointBuilder.build();
var canUseBeacon = !!navigator.sendBeacon && bytesCount < this.bytesLimit;
var monitor_1 = require("../tools/monitor");
function createHttpRequest(endpointBuilder, bytesLimit) {
function sendBeaconStrategy(data, bytesCount) {
var url = endpointBuilder.build();
var canUseBeacon = !!navigator.sendBeacon && bytesCount < bytesLimit;
if (canUseBeacon) {

@@ -32,9 +21,43 @@ try {

}
sendXHR(url, data);
}
function fetchKeepAliveStrategy(data, bytesCount) {
var url = endpointBuilder.build();
var canUseKeepAlive = isKeepAliveSupported() && bytesCount < bytesLimit;
if (canUseKeepAlive) {
fetch(url, { method: 'POST', body: data, keepalive: true }).catch((0, monitor_1.monitor)(function () {
// failed to queue the request
sendXHR(url, data);
}));
}
else {
sendXHR(url, data);
}
}
function isKeepAliveSupported() {
// Request can throw, cf https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#errors
try {
return window.Request && 'keepalive' in new Request('http://a');
}
catch (_a) {
return false;
}
}
function sendXHR(url, data) {
var request = new XMLHttpRequest();
request.open('POST', url, true);
request.send(data);
}
return {
send: function (data, bytesCount) {
fetchKeepAliveStrategy(data, bytesCount);
},
/**
* Since fetch keepalive behaves like regular fetch on Firefox,
* keep using sendBeaconStrategy on exit
*/
sendOnExit: sendBeaconStrategy,
};
return HttpRequest;
}());
exports.HttpRequest = HttpRequest;
}
exports.createHttpRequest = createHttpRequest;
var hasReportedBeaconError = false;

@@ -41,0 +64,0 @@ function reportBeaconError(e) {

@@ -1,4 +0,4 @@

export { HttpRequest } from './httpRequest';
export { HttpRequest, createHttpRequest } from './httpRequest';
export { Batch } from './batch';
export { canUseEventBridge, getEventBridge, BrowserWindowWithEventBridge } from './eventBridge';
export { startBatchWithReplica } from './startBatchWithReplica';
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.startBatchWithReplica = exports.getEventBridge = exports.canUseEventBridge = exports.Batch = exports.HttpRequest = void 0;
exports.startBatchWithReplica = exports.getEventBridge = exports.canUseEventBridge = exports.Batch = exports.createHttpRequest = void 0;
var httpRequest_1 = require("./httpRequest");
Object.defineProperty(exports, "HttpRequest", { enumerable: true, get: function () { return httpRequest_1.HttpRequest; } });
Object.defineProperty(exports, "createHttpRequest", { enumerable: true, get: function () { return httpRequest_1.createHttpRequest; } });
var batch_1 = require("./batch");

@@ -7,0 +7,0 @@ Object.defineProperty(exports, "Batch", { enumerable: true, get: function () { return batch_1.Batch; } });

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

function createBatch(endpointBuilder) {
return new batch_1.Batch(new httpRequest_1.HttpRequest(endpointBuilder, configuration.batchBytesLimit), configuration.batchMessagesLimit, configuration.batchBytesLimit, configuration.messageBytesLimit, configuration.flushTimeout);
return new batch_1.Batch((0, httpRequest_1.createHttpRequest)(endpointBuilder, configuration.batchBytesLimit), configuration.batchMessagesLimit, configuration.batchBytesLimit, configuration.messageBytesLimit, configuration.flushTimeout);
}

@@ -16,0 +16,0 @@ return {

@@ -6,3 +6,3 @@ import { catchUserErrors } from '../tools/catchUserErrors';

var publicApi = assign({
version: "4.17.2",
version: "4.18.1",
// This API method is intentionally not monitored, since the only thing executed is the

@@ -9,0 +9,0 @@ // user-provided 'callback'. All SDK usages executed in the callback should be monitored, and

@@ -25,5 +25,5 @@ import { timeStampNow } from '../../tools/timeUtils';

var parameters = 'ddsource=browser' +
"&ddtags=".concat(encodeURIComponent(["sdk_version:".concat("4.17.2")].concat(tags).join(','))) +
"&ddtags=".concat(encodeURIComponent(["sdk_version:".concat("4.18.1")].concat(tags).join(','))) +
"&dd-api-key=".concat(clientToken) +
"&dd-evp-origin-version=".concat(encodeURIComponent("4.17.2")) +
"&dd-evp-origin-version=".concat(encodeURIComponent("4.18.1")) +
'&dd-evp-origin=browser' +

@@ -30,0 +30,0 @@ "&dd-request-id=".concat(generateUUID());

@@ -1,7 +0,1 @@

/**
* LIMITATION:
* For NPM setup, this feature flag singleton is shared between RUM and Logs product.
* This means that an experimental flag set on the RUM product will be set on the Logs product.
* So keep in mind that in certain configurations, your experimental feature flag may affect other products.
*/
export declare function updateExperimentalFeatures(enabledFeatures: string[] | undefined): void;

@@ -8,0 +2,0 @@ export declare function isExperimentalFeatureEnabled(featureName: string): boolean;

@@ -7,2 +7,4 @@ /**

*/
import { includes } from '../../tools/utils';
import { display } from '../../tools/display';
var enabledExperimentalFeatures;

@@ -20,2 +22,5 @@ export function updateExperimentalFeatures(enabledFeatures) {

.forEach(function (flag) {
if (includes(flag, '-')) {
display.warn("please use snake case for '".concat(flag, "'"));
}
enabledExperimentalFeatures.add(flag);

@@ -22,0 +27,0 @@ });

@@ -37,3 +37,3 @@ import { ConsoleApiName } from '../../tools/display';

service: 'browser-sdk',
version: "4.17.2",
version: "4.18.1",
source: 'browser',

@@ -40,0 +40,0 @@ _dd: {

@@ -11,3 +11,3 @@ export { Configuration, InitConfiguration, buildCookieOptions, validateAndBuildConfiguration, DefaultPrivacyLevel, EndpointBuilder, isExperimentalFeatureEnabled, updateExperimentalFeatures, resetExperimentalFeatures, } from './domain/configuration';

export { SESSION_TIME_OUT_DELAY, } from './domain/session/sessionConstants';
export { HttpRequest, Batch, canUseEventBridge, getEventBridge, startBatchWithReplica } from './transport';
export { HttpRequest, createHttpRequest, Batch, canUseEventBridge, getEventBridge, startBatchWithReplica, } from './transport';
export * from './tools/display';

@@ -14,0 +14,0 @@ export * from './tools/urlPolyfill';

@@ -14,3 +14,3 @@ export { buildCookieOptions, validateAndBuildConfiguration, DefaultPrivacyLevel, isExperimentalFeatureEnabled, updateExperimentalFeatures, resetExperimentalFeatures, } from './domain/configuration';

} from './domain/session/sessionConstants';
export { HttpRequest, Batch, canUseEventBridge, getEventBridge, startBatchWithReplica } from './transport';
export { createHttpRequest, Batch, canUseEventBridge, getEventBridge, startBatchWithReplica, } from './transport';
export * from './tools/display';

@@ -17,0 +17,0 @@ export * from './tools/urlPolyfill';

@@ -7,2 +7,5 @@ import { callMonitored, monitor } from './monitor';

var instrumentationWrapper = function () {
if (typeof instrumentation !== 'function') {
return undefined;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return

@@ -9,0 +12,0 @@ return instrumentation.apply(this, arguments);

@@ -17,3 +17,4 @@ import type { Context } from '../tools/context';

upsert(message: Context, key: string): void;
flush(): void;
flush(sendFn?: (data: string | FormData, bytesCount: number) => void): void;
flushOnExit(): void;
computeBytesCount(candidate: string): number;

@@ -28,3 +29,3 @@ private addOrUpdate;

private flushPeriodically;
private flushOnVisibilityHidden;
private setupFlushOnExit;
}

@@ -20,3 +20,3 @@ import { display } from '../tools/display';

this.bufferMessagesCount = 0;
this.flushOnVisibilityHidden();
this.setupFlushOnExit();
this.flushPeriodically();

@@ -30,3 +30,4 @@ }

};
Batch.prototype.flush = function () {
Batch.prototype.flush = function (sendFn) {
if (sendFn === void 0) { sendFn = this.request.send; }
if (this.bufferMessagesCount !== 0) {

@@ -39,5 +40,8 @@ var messages = this.pushOnlyBuffer.concat(objectValues(this.upsertBuffer));

this.bufferMessagesCount = 0;
this.request.send(messages.join('\n'), bytesCount);
sendFn(messages.join('\n'), bytesCount);
}
};
Batch.prototype.flushOnExit = function () {
this.flush(this.request.sendOnExit);
};
Batch.prototype.computeBytesCount = function (candidate) {

@@ -116,3 +120,3 @@ // Accurate bytes count computations can degrade performances when there is a lot of events to process

};
Batch.prototype.flushOnVisibilityHidden = function () {
Batch.prototype.setupFlushOnExit = function () {
var _this = this;

@@ -136,3 +140,3 @@ /**

if (document.visibilityState === 'hidden') {
_this.flush();
_this.flushOnExit();
}

@@ -145,3 +149,3 @@ });

*/
addEventListener(window, "beforeunload" /* BEFORE_UNLOAD */, function () { return _this.flush(); });
addEventListener(window, "beforeunload" /* BEFORE_UNLOAD */, function () { return _this.flushOnExit(); });
}

@@ -148,0 +152,0 @@ };

@@ -10,7 +10,10 @@ import type { EndpointBuilder } from '../domain/configuration';

*/
export declare class HttpRequest {
private endpointBuilder;
private bytesLimit;
constructor(endpointBuilder: EndpointBuilder, bytesLimit: number);
send(data: string | FormData, bytesCount: number): void;
}
export declare type HttpRequest = ReturnType<typeof createHttpRequest>;
export declare function createHttpRequest(endpointBuilder: EndpointBuilder, bytesLimit: number): {
send: (data: string | FormData, bytesCount: number) => void;
/**
* Since fetch keepalive behaves like regular fetch on Firefox,
* keep using sendBeaconStrategy on exit
*/
sendOnExit: (data: string | FormData, bytesCount: number) => void;
};
import { addTelemetryError } from '../domain/telemetry';
/**
* Use POST request without content type to:
* - avoid CORS preflight requests
* - allow usage of sendBeacon
*
* multiple elements are sent separated by \n in order
* to be parsed correctly without content type header
*/
var HttpRequest = /** @class */ (function () {
function HttpRequest(endpointBuilder, bytesLimit) {
this.endpointBuilder = endpointBuilder;
this.bytesLimit = bytesLimit;
}
HttpRequest.prototype.send = function (data, bytesCount) {
var url = this.endpointBuilder.build();
var canUseBeacon = !!navigator.sendBeacon && bytesCount < this.bytesLimit;
import { monitor } from '../tools/monitor';
export function createHttpRequest(endpointBuilder, bytesLimit) {
function sendBeaconStrategy(data, bytesCount) {
var url = endpointBuilder.build();
var canUseBeacon = !!navigator.sendBeacon && bytesCount < bytesLimit;
if (canUseBeacon) {

@@ -29,9 +18,42 @@ try {

}
sendXHR(url, data);
}
function fetchKeepAliveStrategy(data, bytesCount) {
var url = endpointBuilder.build();
var canUseKeepAlive = isKeepAliveSupported() && bytesCount < bytesLimit;
if (canUseKeepAlive) {
fetch(url, { method: 'POST', body: data, keepalive: true }).catch(monitor(function () {
// failed to queue the request
sendXHR(url, data);
}));
}
else {
sendXHR(url, data);
}
}
function isKeepAliveSupported() {
// Request can throw, cf https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#errors
try {
return window.Request && 'keepalive' in new Request('http://a');
}
catch (_a) {
return false;
}
}
function sendXHR(url, data) {
var request = new XMLHttpRequest();
request.open('POST', url, true);
request.send(data);
}
return {
send: function (data, bytesCount) {
fetchKeepAliveStrategy(data, bytesCount);
},
/**
* Since fetch keepalive behaves like regular fetch on Firefox,
* keep using sendBeaconStrategy on exit
*/
sendOnExit: sendBeaconStrategy,
};
return HttpRequest;
}());
export { HttpRequest };
}
var hasReportedBeaconError = false;

@@ -38,0 +60,0 @@ function reportBeaconError(e) {

@@ -1,4 +0,4 @@

export { HttpRequest } from './httpRequest';
export { HttpRequest, createHttpRequest } from './httpRequest';
export { Batch } from './batch';
export { canUseEventBridge, getEventBridge, BrowserWindowWithEventBridge } from './eventBridge';
export { startBatchWithReplica } from './startBatchWithReplica';

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

export { HttpRequest } from './httpRequest';
export { createHttpRequest } from './httpRequest';
export { Batch } from './batch';

@@ -3,0 +3,0 @@ export { canUseEventBridge, getEventBridge } from './eventBridge';

import { Batch } from './batch';
import { HttpRequest } from './httpRequest';
import { createHttpRequest } from './httpRequest';
export function startBatchWithReplica(configuration, endpoint, replicaEndpoint) {

@@ -10,3 +10,3 @@ var primaryBatch = createBatch(endpoint);

function createBatch(endpointBuilder) {
return new Batch(new HttpRequest(endpointBuilder, configuration.batchBytesLimit), configuration.batchMessagesLimit, configuration.batchBytesLimit, configuration.messageBytesLimit, configuration.flushTimeout);
return new Batch(createHttpRequest(endpointBuilder, configuration.batchBytesLimit), configuration.batchMessagesLimit, configuration.batchBytesLimit, configuration.messageBytesLimit, configuration.flushTimeout);
}

@@ -13,0 +13,0 @@ return {

{
"name": "@datadog/browser-core",
"version": "4.17.2",
"version": "4.18.1",
"license": "Apache-2.0",

@@ -24,3 +24,3 @@ "main": "cjs/index.js",

},
"gitHead": "b4a39bcc003ad5f38044dfedbe3bd3b118281183"
"gitHead": "bd833602495172229db1e133b89a9f2b0b8eea9e"
}

@@ -7,2 +7,4 @@ /**

*/
import { includes } from '../../tools/utils'
import { display } from '../../tools/display'

@@ -24,2 +26,5 @@ let enabledExperimentalFeatures: Set<string> | undefined

.forEach((flag: string) => {
if (includes(flag, '-')) {
display.warn(`please use snake case for '${flag}'`)
}
enabledExperimentalFeatures!.add(flag)

@@ -26,0 +31,0 @@ })

@@ -40,3 +40,10 @@ export {

} from './domain/session/sessionConstants'
export { HttpRequest, Batch, canUseEventBridge, getEventBridge, startBatchWithReplica } from './transport'
export {
HttpRequest,
createHttpRequest,
Batch,
canUseEventBridge,
getEventBridge,
startBatchWithReplica,
} from './transport'
export * from './tools/display'

@@ -43,0 +50,0 @@ export * from './tools/urlPolyfill'

@@ -102,8 +102,22 @@ import type { Clock } from '../../test/specHelper'

})
it('should not throw errors if original method was undefined', () => {
const object: { method?: () => number } = {}
const instrumentationStub = () => 2
const { stop } = instrumentMethod(object, 'method', () => instrumentationStub)
thirdPartyInstrumentation(object)
stop()
expect(object.method).not.toThrow()
})
})
})
function thirdPartyInstrumentation(object: { method: () => number }) {
function thirdPartyInstrumentation(object: { method?: () => number }) {
const originalMethod = object.method
object.method = () => originalMethod() + 2
if (typeof originalMethod === 'function') {
object.method = () => originalMethod() + 2
}
}

@@ -110,0 +124,0 @@ })

@@ -15,3 +15,6 @@ import { callMonitored, monitor } from './monitor'

const instrumentationWrapper = function (this: OBJECT): ReturnType<OBJECT[METHOD]> {
const instrumentationWrapper = function (this: OBJECT): ReturnType<OBJECT[METHOD]> | undefined {
if (typeof instrumentation !== 'function') {
return undefined
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return

@@ -18,0 +21,0 @@ return instrumentation.apply(this, arguments as unknown as Parameters<OBJECT[METHOD]>)

@@ -25,3 +25,3 @@ import { display } from '../tools/display'

) {
this.flushOnVisibilityHidden()
this.setupFlushOnExit()
this.flushPeriodically()

@@ -38,3 +38,3 @@ }

flush() {
flush(sendFn = this.request.send) {
if (this.bufferMessagesCount !== 0) {

@@ -49,6 +49,10 @@ const messages = this.pushOnlyBuffer.concat(objectValues(this.upsertBuffer))

this.request.send(messages.join('\n'), bytesCount)
sendFn(messages.join('\n'), bytesCount)
}
}
flushOnExit() {
this.flush(this.request.sendOnExit)
}
computeBytesCount(candidate: string) {

@@ -142,3 +146,3 @@ // Accurate bytes count computations can degrade performances when there is a lot of events to process

private flushOnVisibilityHidden() {
private setupFlushOnExit() {
/**

@@ -162,3 +166,3 @@ * With sendBeacon, requests are guaranteed to be successfully sent during document unload

if (document.visibilityState === 'hidden') {
this.flush()
this.flushOnExit()
}

@@ -171,5 +175,5 @@ })

*/
addEventListener(window, DOM_EVENT.BEFORE_UNLOAD, () => this.flush())
addEventListener(window, DOM_EVENT.BEFORE_UNLOAD, () => this.flushOnExit())
}
}
}
/* eslint-disable @typescript-eslint/unbound-method */
import sinon from 'sinon'
import { stubEndpointBuilder } from '../../test/specHelper'
import { stubEndpointBuilder, interceptRequests } from '../../test/specHelper'
import type { Request } from '../../test/specHelper'
import type { EndpointBuilder } from '../domain/configuration'
import { createEndpointBuilder } from '../domain/configuration'
import { HttpRequest } from './httpRequest'
import { createHttpRequest } from './httpRequest'
import type { HttpRequest } from './httpRequest'
describe('httpRequest', () => {
const BATCH_BYTES_LIMIT = 100
let server: sinon.SinonFakeServer
let interceptor: ReturnType<typeof interceptRequests>
let requests: Request[]
let endpointBuilder: EndpointBuilder

@@ -16,55 +18,120 @@ let request: HttpRequest

beforeEach(() => {
server = sinon.fakeServer.create()
interceptor = interceptRequests()
requests = interceptor.requests
endpointBuilder = stubEndpointBuilder(ENDPOINT_URL)
request = new HttpRequest(endpointBuilder, BATCH_BYTES_LIMIT)
request = createHttpRequest(endpointBuilder, BATCH_BYTES_LIMIT)
})
afterEach(() => {
server.restore()
interceptor.restore()
})
it('should use xhr when sendBeacon is not defined', () => {
request.send('{"foo":"bar1"}\n{"foo":"bar2"}', 10)
describe('send', () => {
it('should use xhr when fetch keepalive is not available', () => {
interceptor.withRequest(false)
expect(server.requests.length).toEqual(1)
expect(server.requests[0].url).toContain(ENDPOINT_URL)
expect(server.requests[0].requestBody).toEqual('{"foo":"bar1"}\n{"foo":"bar2"}')
})
request.send('{"foo":"bar1"}\n{"foo":"bar2"}', 10)
it('should use sendBeacon when the bytes count is correct', () => {
spyOn(navigator, 'sendBeacon').and.callFake(() => true)
expect(requests.length).toEqual(1)
expect(requests[0].type).toBe('xhr')
expect(requests[0].url).toContain(ENDPOINT_URL)
expect(requests[0].body).toEqual('{"foo":"bar1"}\n{"foo":"bar2"}')
})
request.send('{"foo":"bar1"}\n{"foo":"bar2"}', 10)
it('should use fetch keepalive when the bytes count is correct', () => {
if (!interceptor.isFetchKeepAliveSupported()) {
pending('no fetch keepalive support')
}
expect(navigator.sendBeacon).toHaveBeenCalled()
})
request.send('{"foo":"bar1"}\n{"foo":"bar2"}', 10)
it('should use xhr over sendBeacon when the bytes count is too high', () => {
spyOn(navigator, 'sendBeacon').and.callFake(() => true)
expect(requests.length).toEqual(1)
expect(requests[0].type).toBe('fetch')
})
request.send('{"foo":"bar1"}\n{"foo":"bar2"}', BATCH_BYTES_LIMIT)
it('should use xhr over fetch keepalive when the bytes count is too high', () => {
request.send('{"foo":"bar1"}\n{"foo":"bar2"}', BATCH_BYTES_LIMIT)
expect(server.requests.length).toEqual(1)
expect(server.requests[0].url).toContain(ENDPOINT_URL)
expect(server.requests[0].requestBody).toEqual('{"foo":"bar1"}\n{"foo":"bar2"}')
})
expect(requests.length).toEqual(1)
expect(requests[0].type).toBe('xhr')
})
it('should fallback to xhr when sendBeacon is not queued', () => {
spyOn(navigator, 'sendBeacon').and.callFake(() => false)
it('should fallback to xhr when fetch keepalive is not queued', (done) => {
if (!interceptor.isFetchKeepAliveSupported()) {
pending('no fetch keepalive support')
}
let notQueuedFetch: Promise<never>
interceptor.withFetch(() => {
notQueuedFetch = Promise.reject()
return notQueuedFetch
})
request.send('{"foo":"bar1"}\n{"foo":"bar2"}', 10)
request.send('{"foo":"bar1"}\n{"foo":"bar2"}', 10)
expect(navigator.sendBeacon).toHaveBeenCalled()
expect(server.requests.length).toEqual(1)
notQueuedFetch!.catch(() => {
expect(requests.length).toEqual(1)
expect(requests[0].type).toBe('xhr')
done()
})
})
})
it('should fallback to xhr when sendBeacon throws', () => {
spyOn(navigator, 'sendBeacon').and.callFake(() => {
throw new TypeError()
describe('sendOnExit', () => {
it('should use xhr when sendBeacon is not defined', () => {
interceptor.withSendBeacon(false)
request.sendOnExit('{"foo":"bar1"}\n{"foo":"bar2"}', 10)
expect(requests.length).toEqual(1)
expect(requests[0].type).toBe('xhr')
expect(requests[0].url).toContain(ENDPOINT_URL)
expect(requests[0].body).toEqual('{"foo":"bar1"}\n{"foo":"bar2"}')
})
request.send('{"foo":"bar1"}\n{"foo":"bar2"}', 10)
it('should use sendBeacon when the bytes count is correct', () => {
if (!interceptor.isSendBeaconSupported()) {
pending('no sendBeacon support')
}
expect(navigator.sendBeacon).toHaveBeenCalled()
expect(server.requests.length).toEqual(1)
request.sendOnExit('{"foo":"bar1"}\n{"foo":"bar2"}', 10)
expect(requests.length).toEqual(1)
expect(requests[0].type).toBe('sendBeacon')
})
it('should use xhr over sendBeacon when the bytes count is too high', () => {
request.sendOnExit('{"foo":"bar1"}\n{"foo":"bar2"}', BATCH_BYTES_LIMIT)
expect(requests.length).toEqual(1)
expect(requests[0].type).toBe('xhr')
})
it('should fallback to xhr when sendBeacon is not queued', () => {
if (!interceptor.isSendBeaconSupported()) {
pending('no sendBeacon support')
}
interceptor.withSendBeacon(() => false)
request.sendOnExit('{"foo":"bar1"}\n{"foo":"bar2"}', 10)
expect(requests.length).toEqual(1)
expect(requests[0].type).toBe('xhr')
})
it('should fallback to xhr when sendBeacon throws', () => {
if (!interceptor.isSendBeaconSupported()) {
pending('no sendBeacon support')
}
let sendBeaconCalled = false
interceptor.withSendBeacon(() => {
sendBeaconCalled = true
throw new TypeError()
})
request.sendOnExit('{"foo":"bar1"}\n{"foo":"bar2"}', 10)
expect(sendBeaconCalled).toBe(true)
expect(requests.length).toEqual(1)
expect(requests[0].type).toBe('xhr')
})
})

@@ -76,3 +143,4 @@ })

const BATCH_BYTES_LIMIT = 100
let server: sinon.SinonFakeServer
let interceptor: ReturnType<typeof interceptRequests>
let requests: Request[]
let endpointBuilder: EndpointBuilder

@@ -82,9 +150,10 @@ let request: HttpRequest

beforeEach(() => {
server = sinon.fakeServer.create()
interceptor = interceptRequests()
requests = interceptor.requests
endpointBuilder = createEndpointBuilder({ clientToken }, 'logs', [])
request = new HttpRequest(endpointBuilder, BATCH_BYTES_LIMIT)
request = createHttpRequest(endpointBuilder, BATCH_BYTES_LIMIT)
})
afterEach(() => {
server.restore()
interceptor.restore()
})

@@ -97,8 +166,8 @@

const search = /dd-request-id=([^&]*)/
const requestId1 = search.exec(server.requests[0].url)?.[1]
const requestId2 = search.exec(server.requests[1].url)?.[1]
const requestId1 = search.exec(requests[0].url)?.[1]
const requestId2 = search.exec(requests[1].url)?.[1]
expect(requestId1).not.toBe(requestId2)
expect(server.requests.length).toEqual(2)
expect(requests.length).toEqual(2)
})
})
import type { EndpointBuilder } from '../domain/configuration'
import { addTelemetryError } from '../domain/telemetry'
import { monitor } from '../tools/monitor'

@@ -12,8 +13,9 @@ /**

*/
export class HttpRequest {
constructor(private endpointBuilder: EndpointBuilder, private bytesLimit: number) {}
send(data: string | FormData, bytesCount: number) {
const url = this.endpointBuilder.build()
const canUseBeacon = !!navigator.sendBeacon && bytesCount < this.bytesLimit
export type HttpRequest = ReturnType<typeof createHttpRequest>
export function createHttpRequest(endpointBuilder: EndpointBuilder, bytesLimit: number) {
function sendBeaconStrategy(data: string | FormData, bytesCount: number) {
const url = endpointBuilder.build()
const canUseBeacon = !!navigator.sendBeacon && bytesCount < bytesLimit
if (canUseBeacon) {

@@ -31,2 +33,30 @@ try {

sendXHR(url, data)
}
function fetchKeepAliveStrategy(data: string | FormData, bytesCount: number) {
const url = endpointBuilder.build()
const canUseKeepAlive = isKeepAliveSupported() && bytesCount < bytesLimit
if (canUseKeepAlive) {
fetch(url, { method: 'POST', body: data, keepalive: true }).catch(
monitor(() => {
// failed to queue the request
sendXHR(url, data)
})
)
} else {
sendXHR(url, data)
}
}
function isKeepAliveSupported() {
// Request can throw, cf https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#errors
try {
return window.Request && 'keepalive' in new Request('http://a')
} catch {
return false
}
}
function sendXHR(url: string, data: string | FormData) {
const request = new XMLHttpRequest()

@@ -36,5 +66,17 @@ request.open('POST', url, true)

}
return {
send: (data: string | FormData, bytesCount: number) => {
fetchKeepAliveStrategy(data, bytesCount)
},
/**
* Since fetch keepalive behaves like regular fetch on Firefox,
* keep using sendBeaconStrategy on exit
*/
sendOnExit: sendBeaconStrategy,
}
}
let hasReportedBeaconError = false
function reportBeaconError(e: unknown) {

@@ -41,0 +83,0 @@ if (!hasReportedBeaconError) {

@@ -1,4 +0,4 @@

export { HttpRequest } from './httpRequest'
export { HttpRequest, createHttpRequest } from './httpRequest'
export { Batch } from './batch'
export { canUseEventBridge, getEventBridge, BrowserWindowWithEventBridge } from './eventBridge'
export { startBatchWithReplica } from './startBatchWithReplica'
import type { Configuration, EndpointBuilder } from '../domain/configuration'
import type { Context } from '../tools/context'
import { Batch } from './batch'
import { HttpRequest } from './httpRequest'
import { createHttpRequest } from './httpRequest'

@@ -19,3 +19,3 @@ export function startBatchWithReplica<T extends Context>(

return new Batch(
new HttpRequest(endpointBuilder, configuration.batchBytesLimit),
createHttpRequest(endpointBuilder, configuration.batchBytesLimit),
configuration.batchMessagesLimit,

@@ -22,0 +22,0 @@ configuration.batchBytesLimit,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc