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

@splitsoftware/browser-rum-agent

Package Overview
Dependencies
Maintainers
8
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@splitsoftware/browser-rum-agent - npm Package Compare versions

Comparing version 0.3.2 to 0.3.3-rc.0

5

CHANGES.txt

@@ -0,1 +1,6 @@

0.4.0 (December 22, 2023)
- Updated `SplitRumAgent.track` and `SplitRumAgent.trackError` methods to return a boolean value. This value indicates whether the event was successfully queued or not (i.e., it was dropped).
An event is dropped if it has an invalid eventTypeId, value or properties, if the queue is full, or if user consent is declined.
- Updated internal implementation to avoid throwing errors in non-browser environments (i.e. environments where `window` and `document` objects are not available), enhancing support for testing frameworks like Jest.
0.3.2 (October 19, 2023)

@@ -2,0 +7,0 @@ - Added user consent feature to allow delaying or disabling the event tracking until user consent is explicitly granted or declined. Read more in our docs.

8

cjs/metrics/errors.js

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

var errorData = (0, getErrorData_1.getErrorData)(error);
if (errorData) {
return errorData ?
ctx.track({

@@ -20,4 +20,4 @@ eventTypeId: 'error',

}
});
}
}) :
false;
}

@@ -29,3 +29,3 @@ /**

function handleCustomErrors(e, ctx) {
trackError(e ? e : constants_1.UNAVAILABLE, ctx);
return trackError(e ? e : constants_1.UNAVAILABLE, ctx);
}

@@ -32,0 +32,0 @@ exports.handleCustomErrors = handleCustomErrors;

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

// - feature detection of Promise, History and Performance APIs is done by event collector modules. These features are required for some modules to collect data, but not for the RUM Agent to work.
(function (w) {
// In Browser, we pollute the global `window` object with the agent.
// In NodeJS, we only export it and no event collectors are registered.
var isBrowser = typeof window === 'object' && typeof document === 'object';
var global = isBrowser ? window : {};
(function (w, isBrowser) {
if (w.SplitRumAgent)
return;
var _config = {

@@ -37,3 +43,3 @@ i: [],

function calculateAndFlush() {
if (!_isConfigured && _config.a && _config.i.length) {
if (isBrowser && !_isConfigured && _config.a && _config.i.length) {
_isConfigured = true;

@@ -45,108 +51,110 @@ // always async never inasync ;)

var context = { track: queue_1.track };
var collectors = [
(0, navigation_1.onNavigationTimingMetrics)(context),
(0, errors_1.onError)(context),
];
// Post events periodically
(0, whenLoaded_1.whenLoaded)(queue_1.setSchedule);
// If there's a pagehide or visibilitychange event, calculate what's possible and send events using beacon by default
(0, whenLoaded_1.onPageHideOrVisibilityChange)(function () {
collectors.forEach(function (collector) {
if (collector && typeof collector.flush === 'function')
collector.flush();
});
(0, queue_1.flush)(true);
});
var collectors = [];
// SplitRumAgent would be our namespace
if (!w.SplitRumAgent)
w.SplitRumAgent = {
// Initialization params
setup: function (sdkKey, config) {
if ((0, isObject_1.isObject)(config)) {
(0, assign_1.objectAssign)(_config, config);
}
if ((0, isString_1.isString)(sdkKey)) {
_config.a = sdkKey;
calculateAndFlush();
}
else {
_config.log.error('SDK key must be a string.');
}
// allow for chaining.
return w.SplitRumAgent;
},
// Configure identities
addIdentities: function (identities) {
if ((0, isArray_1.isArray)(identities)) {
identities.forEach(function (identity) { return w.SplitRumAgent.addIdentity(identity); });
}
else {
_config.log.error('Identities must be an array of objects with key and trafficType.');
}
},
addIdentity: function (identity) {
var validatedIdentity = (0, validateIdentity_1.validateIdentity)(identity, _config.log);
if (validatedIdentity && !_config.i.some(function (i) { return (0, validateIdentity_1.areEqual)(i, validatedIdentity); })) {
_config.i.push(validatedIdentity);
calculateAndFlush();
}
},
removeIdentities: function () {
_config.i = [];
},
removeIdentity: function (identity) {
var validatedIdentity = (0, validateIdentity_1.validateIdentity)(identity, _config.log);
if (validatedIdentity) {
_config.i = _config.i.filter(function (i) { return !(0, validateIdentity_1.areEqual)(i, validatedIdentity); });
}
},
getIdentities: function () {
return _config.i;
},
// Custom error handler.
trackError: function (e) {
(0, errors_1.handleCustomErrors)(e, context);
},
// Track custom events.
track: queue_1.track,
// For internal use.
// @TODO review how to expose config
__getConfig: function () {
return _config;
},
// register event collector
register: function (eventCollector) {
if (typeof eventCollector !== 'function') {
_config.log.error('register method must be called with an event collector function.');
}
else {
collectors.push(eventCollector(context));
}
// allow for chaining.
return w.SplitRumAgent;
},
// Custom properties
setProperties: function (properties) {
(0, assign_1.objectAssign)(_config.p, (0, validateEvent_1.validateProperties)(properties, _config.log));
},
getProperties: function () {
return _config.p;
},
removeProperties: function () {
_config.p = {};
},
// User consent
setUserConsent: function (userConsent) {
if (!(0, isBoolean_1.isBoolean)(userConsent)) {
_config.log.warn('setUserConsent: provided param must be a boolean value');
return false;
}
_config.userConsent = userConsent ? constants_1.CONSENT_GRANTED : constants_1.CONSENT_DECLINED;
return true;
},
getUserConsent: function () {
return _config.userConsent;
var SplitRumAgent = {
// Initialization params
setup: function (sdkKey, config) {
if ((0, isObject_1.isObject)(config)) {
(0, assign_1.objectAssign)(_config, config);
}
};
})(window);
exports.SplitRumAgent = window.SplitRumAgent;
if ((0, isString_1.isString)(sdkKey)) {
_config.a = sdkKey;
calculateAndFlush();
}
else {
_config.log.error('SDK key must be a string.');
}
// allow for chaining.
return SplitRumAgent;
},
// Configure identities
addIdentities: function (identities) {
if ((0, isArray_1.isArray)(identities)) {
identities.forEach(function (identity) { return SplitRumAgent.addIdentity(identity); });
}
else {
_config.log.error('Identities must be an array of objects with key and trafficType.');
}
},
addIdentity: function (identity) {
var validatedIdentity = (0, validateIdentity_1.validateIdentity)(identity, _config.log);
if (validatedIdentity && !_config.i.some(function (i) { return (0, validateIdentity_1.areEqual)(i, validatedIdentity); })) {
_config.i.push(validatedIdentity);
calculateAndFlush();
}
},
removeIdentities: function () {
_config.i = [];
},
removeIdentity: function (identity) {
var validatedIdentity = (0, validateIdentity_1.validateIdentity)(identity, _config.log);
if (validatedIdentity) {
_config.i = _config.i.filter(function (i) { return !(0, validateIdentity_1.areEqual)(i, validatedIdentity); });
}
},
getIdentities: function () {
return _config.i;
},
// Custom error handler.
trackError: function (e) {
return (0, errors_1.handleCustomErrors)(e, context);
},
// Track custom events.
track: queue_1.track,
// For internal use.
// @TODO review how to expose config
__getConfig: function () {
return _config;
},
// register event collector
register: function (eventCollector) {
if (typeof eventCollector !== 'function') {
_config.log.error('register method must be called with an event collector function.');
}
else {
collectors.push(eventCollector(context));
}
// allow for chaining.
return SplitRumAgent;
},
// Custom properties
setProperties: function (properties) {
(0, assign_1.objectAssign)(_config.p, (0, validateEvent_1.validateProperties)(properties, _config.log));
},
getProperties: function () {
return _config.p;
},
removeProperties: function () {
_config.p = {};
},
// User consent
setUserConsent: function (userConsent) {
if (!(0, isBoolean_1.isBoolean)(userConsent)) {
_config.log.warn('setUserConsent: provided param must be a boolean value');
return false;
}
_config.userConsent = userConsent ? constants_1.CONSENT_GRANTED : constants_1.CONSENT_DECLINED;
return true;
},
getUserConsent: function () {
return _config.userConsent;
}
};
if (isBrowser) {
// Built-in collectors
SplitRumAgent.register(navigation_1.onNavigationTimingMetrics);
SplitRumAgent.register(errors_1.onError);
// Post events periodically
(0, whenLoaded_1.whenLoaded)(queue_1.setSchedule);
// If there's a pagehide or visibilitychange event, calculate what's possible and send events using beacon by default
(0, whenLoaded_1.onPageHideOrVisibilityChange)(function () {
collectors.forEach(function (collector) {
if (collector && typeof collector.flush === 'function')
collector.flush();
});
(0, queue_1.flush)(true);
});
}
w.SplitRumAgent = SplitRumAgent;
})(global, isBrowser);
exports.SplitRumAgent = global.SplitRumAgent;

@@ -38,2 +38,2 @@ "use strict";

exports.userAgent = getUserAgent();
exports.languageVersion = 'jsrum-' + '0.3.2';
exports.languageVersion = 'jsrum-' + '0.3.3-rc.0';

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

if (!eventData || conf.userConsent === constants_1.CONSENT_DECLINED)
return;
return false;
// If people configures the agent at a really late time, prevent having a giant queue and attempt to send them or drop. First events will be the most important ones anyways.

@@ -53,3 +53,3 @@ if (exports.queue.length >= conf.queueSize) {

conf.log.warn('Dropping event due to queue size limit.');
return;
return false;
}

@@ -74,3 +74,4 @@ }

(0, assign_1.assignIdentities)(eventData, window.SplitRumAgent.__getConfig().i, exports.queue);
return true;
}
exports.track = track;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.onPageHideOrVisibilityChange = exports.whenLoaded = void 0;
var callbacks = [];
window.addEventListener('load', function () {
// Defer, because we should wait until the handlers finish to allow customer logic run first.
setTimeout(function () {
callbacks.forEach(function (cb) { return cb(); });
}, 0);
});
/**

@@ -20,9 +13,12 @@ * Calls the callback function when the document is loaded or if it is already loaded.

else {
callbacks.push(callback);
window.addEventListener('load', function () {
// Defer, because we should wait until the handlers finish to allow customer logic run first.
setTimeout(callback, 0);
});
}
}
exports.whenLoaded = whenLoaded;
// `unload` is not reliable, so we use `pagehide` if available: https://developer.chrome.com/articles/page-lifecycle-api/#the-unload-event
var PAGE_TERMINATION_EVENT = typeof window.onpagehide !== 'undefined' ? 'pagehide' : 'unload';
function onPageHideOrVisibilityChange(callback) {
// `unload` is not reliable, so we use `pagehide` if available: https://developer.chrome.com/articles/page-lifecycle-api/#the-unload-event
var PAGE_TERMINATION_EVENT = typeof window.onpagehide !== 'undefined' ? 'pagehide' : 'unload';
// Flush data whenever the page is hidden or unloaded

@@ -29,0 +25,0 @@ if (typeof document !== 'undefined' && document.addEventListener) {

@@ -8,3 +8,3 @@ import { getErrorData } from '../utils/getErrorData';

var errorData = getErrorData(error);
if (errorData) {
return errorData ?
ctx.track({

@@ -17,4 +17,4 @@ eventTypeId: 'error',

}
});
}
}) :
false;
}

@@ -26,3 +26,3 @@ /**

export function handleCustomErrors(e, ctx) {
trackError(e ? e : UNAVAILABLE, ctx);
return trackError(e ? e : UNAVAILABLE, ctx);
}

@@ -29,0 +29,0 @@ /**

@@ -19,3 +19,9 @@ import { setSchedule, flush, track } from './queue';

// - feature detection of Promise, History and Performance APIs is done by event collector modules. These features are required for some modules to collect data, but not for the RUM Agent to work.
(function (w) {
// In Browser, we pollute the global `window` object with the agent.
// In NodeJS, we only export it and no event collectors are registered.
var isBrowser = typeof window === 'object' && typeof document === 'object';
var global = isBrowser ? window : {};
(function (w, isBrowser) {
if (w.SplitRumAgent)
return;
var _config = {

@@ -34,3 +40,3 @@ i: [],

function calculateAndFlush() {
if (!_isConfigured && _config.a && _config.i.length) {
if (isBrowser && !_isConfigured && _config.a && _config.i.length) {
_isConfigured = true;

@@ -42,108 +48,110 @@ // always async never inasync ;)

var context = { track: track };
var collectors = [
onNavigationTimingMetrics(context),
onError(context),
];
// Post events periodically
whenLoaded(setSchedule);
// If there's a pagehide or visibilitychange event, calculate what's possible and send events using beacon by default
onPageHideOrVisibilityChange(function () {
collectors.forEach(function (collector) {
if (collector && typeof collector.flush === 'function')
collector.flush();
});
flush(true);
});
var collectors = [];
// SplitRumAgent would be our namespace
if (!w.SplitRumAgent)
w.SplitRumAgent = {
// Initialization params
setup: function (sdkKey, config) {
if (isObject(config)) {
objectAssign(_config, config);
}
if (isString(sdkKey)) {
_config.a = sdkKey;
calculateAndFlush();
}
else {
_config.log.error('SDK key must be a string.');
}
// allow for chaining.
return w.SplitRumAgent;
},
// Configure identities
addIdentities: function (identities) {
if (isArray(identities)) {
identities.forEach(function (identity) { return w.SplitRumAgent.addIdentity(identity); });
}
else {
_config.log.error('Identities must be an array of objects with key and trafficType.');
}
},
addIdentity: function (identity) {
var validatedIdentity = validateIdentity(identity, _config.log);
if (validatedIdentity && !_config.i.some(function (i) { return areEqual(i, validatedIdentity); })) {
_config.i.push(validatedIdentity);
calculateAndFlush();
}
},
removeIdentities: function () {
_config.i = [];
},
removeIdentity: function (identity) {
var validatedIdentity = validateIdentity(identity, _config.log);
if (validatedIdentity) {
_config.i = _config.i.filter(function (i) { return !areEqual(i, validatedIdentity); });
}
},
getIdentities: function () {
return _config.i;
},
// Custom error handler.
trackError: function (e) {
handleCustomErrors(e, context);
},
// Track custom events.
track: track,
// For internal use.
// @TODO review how to expose config
__getConfig: function () {
return _config;
},
// register event collector
register: function (eventCollector) {
if (typeof eventCollector !== 'function') {
_config.log.error('register method must be called with an event collector function.');
}
else {
collectors.push(eventCollector(context));
}
// allow for chaining.
return w.SplitRumAgent;
},
// Custom properties
setProperties: function (properties) {
objectAssign(_config.p, validateProperties(properties, _config.log));
},
getProperties: function () {
return _config.p;
},
removeProperties: function () {
_config.p = {};
},
// User consent
setUserConsent: function (userConsent) {
if (!isBoolean(userConsent)) {
_config.log.warn('setUserConsent: provided param must be a boolean value');
return false;
}
_config.userConsent = userConsent ? CONSENT_GRANTED : CONSENT_DECLINED;
return true;
},
getUserConsent: function () {
return _config.userConsent;
var SplitRumAgent = {
// Initialization params
setup: function (sdkKey, config) {
if (isObject(config)) {
objectAssign(_config, config);
}
};
})(window);
export var SplitRumAgent = window.SplitRumAgent;
if (isString(sdkKey)) {
_config.a = sdkKey;
calculateAndFlush();
}
else {
_config.log.error('SDK key must be a string.');
}
// allow for chaining.
return SplitRumAgent;
},
// Configure identities
addIdentities: function (identities) {
if (isArray(identities)) {
identities.forEach(function (identity) { return SplitRumAgent.addIdentity(identity); });
}
else {
_config.log.error('Identities must be an array of objects with key and trafficType.');
}
},
addIdentity: function (identity) {
var validatedIdentity = validateIdentity(identity, _config.log);
if (validatedIdentity && !_config.i.some(function (i) { return areEqual(i, validatedIdentity); })) {
_config.i.push(validatedIdentity);
calculateAndFlush();
}
},
removeIdentities: function () {
_config.i = [];
},
removeIdentity: function (identity) {
var validatedIdentity = validateIdentity(identity, _config.log);
if (validatedIdentity) {
_config.i = _config.i.filter(function (i) { return !areEqual(i, validatedIdentity); });
}
},
getIdentities: function () {
return _config.i;
},
// Custom error handler.
trackError: function (e) {
return handleCustomErrors(e, context);
},
// Track custom events.
track: track,
// For internal use.
// @TODO review how to expose config
__getConfig: function () {
return _config;
},
// register event collector
register: function (eventCollector) {
if (typeof eventCollector !== 'function') {
_config.log.error('register method must be called with an event collector function.');
}
else {
collectors.push(eventCollector(context));
}
// allow for chaining.
return SplitRumAgent;
},
// Custom properties
setProperties: function (properties) {
objectAssign(_config.p, validateProperties(properties, _config.log));
},
getProperties: function () {
return _config.p;
},
removeProperties: function () {
_config.p = {};
},
// User consent
setUserConsent: function (userConsent) {
if (!isBoolean(userConsent)) {
_config.log.warn('setUserConsent: provided param must be a boolean value');
return false;
}
_config.userConsent = userConsent ? CONSENT_GRANTED : CONSENT_DECLINED;
return true;
},
getUserConsent: function () {
return _config.userConsent;
}
};
if (isBrowser) {
// Built-in collectors
SplitRumAgent.register(onNavigationTimingMetrics);
SplitRumAgent.register(onError);
// Post events periodically
whenLoaded(setSchedule);
// If there's a pagehide or visibilitychange event, calculate what's possible and send events using beacon by default
onPageHideOrVisibilityChange(function () {
collectors.forEach(function (collector) {
if (collector && typeof collector.flush === 'function')
collector.flush();
});
flush(true);
});
}
w.SplitRumAgent = SplitRumAgent;
})(global, isBrowser);
export var SplitRumAgent = global.SplitRumAgent;

@@ -31,2 +31,2 @@ /* eslint-disable compat/compat */

export var userAgent = getUserAgent();
export var languageVersion = 'jsrum-' + '0.3.2';
export var languageVersion = 'jsrum-' + '0.3.3-rc.0';

@@ -42,3 +42,3 @@ import { getConnectionType, getUrl, userAgent } from './context';

if (!eventData || conf.userConsent === CONSENT_DECLINED)
return;
return false;
// If people configures the agent at a really late time, prevent having a giant queue and attempt to send them or drop. First events will be the most important ones anyways.

@@ -48,3 +48,3 @@ if (queue.length >= conf.queueSize) {

conf.log.warn('Dropping event due to queue size limit.');
return;
return false;
}

@@ -69,2 +69,3 @@ }

assignIdentities(eventData, window.SplitRumAgent.__getConfig().i, queue);
return true;
}

@@ -1,8 +0,1 @@

var callbacks = [];
window.addEventListener('load', function () {
// Defer, because we should wait until the handlers finish to allow customer logic run first.
setTimeout(function () {
callbacks.forEach(function (cb) { return cb(); });
}, 0);
});
/**

@@ -17,8 +10,11 @@ * Calls the callback function when the document is loaded or if it is already loaded.

else {
callbacks.push(callback);
window.addEventListener('load', function () {
// Defer, because we should wait until the handlers finish to allow customer logic run first.
setTimeout(callback, 0);
});
}
}
// `unload` is not reliable, so we use `pagehide` if available: https://developer.chrome.com/articles/page-lifecycle-api/#the-unload-event
var PAGE_TERMINATION_EVENT = typeof window.onpagehide !== 'undefined' ? 'pagehide' : 'unload';
export function onPageHideOrVisibilityChange(callback) {
// `unload` is not reliable, so we use `pagehide` if available: https://developer.chrome.com/articles/page-lifecycle-api/#the-unload-event
var PAGE_TERMINATION_EVENT = typeof window.onpagehide !== 'undefined' ? 'pagehide' : 'unload';
// Flush data whenever the page is hidden or unloaded

@@ -25,0 +21,0 @@ if (typeof document !== 'undefined' && document.addEventListener) {

{
"name": "@splitsoftware/browser-rum-agent",
"version": "0.3.2",
"version": "0.3.3-rc.0",
"description": "Split Software RUM Agent for Browsers.",

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

"check:types": "tsc -p ./config/tsconfig.json --noEmit",
"test": "npm run test:karma && npm run test:jest",
"test": "npm run test:ts-decls && npm run test:karma && npm run test:jest",
"test:ts-decls": "tsc ts-tests/index.ts --noEmit",
"test:karma": "karma start config/karma.config.js",

@@ -27,0 +28,0 @@ "test:jest": "jest",

@@ -37,6 +37,2 @@ # Split Browser RUM Agent

## License
Licensed under the Apache License, Version 2.0. See: [Apache License](http://www.apache.org/licenses/).
## About Split

@@ -56,4 +52,4 @@

* Java [Github](https://github.com/splitio/java-client) [Docs](https://help.split.io/hc/en-us/articles/360020405151-Java-SDK)
* Javascript [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK)
* Javascript for Browser [Github](https://github.com/splitio/javascript-browser-client) [Docs](https://help.split.io/hc/en-us/articles/360058730852-Browser-SDK)
* JavaScript [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK)
* JavaScript for Browser [Github](https://github.com/splitio/javascript-browser-client) [Docs](https://help.split.io/hc/en-us/articles/360058730852-Browser-SDK)
* Node [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK)

@@ -60,0 +56,0 @@ * PHP [Github](https://github.com/splitio/php-client) [Docs](https://help.split.io/hc/en-us/articles/360020350372-PHP-SDK)

@@ -49,3 +49,3 @@ import type { ReportOpts } from 'web-vitals'

export type EventCollector = (ctx: {
track(event: EventData): void
track(event: EventData): boolean
}) => void | {

@@ -194,4 +194,5 @@ flush(): void

* @param {string | Error} error - The error message or Error object to track.
* @returns {boolean} Whether the error event was tracked or not. The event will not be tracked if it is an invalid type (e.g., undefined), user consent is 'DECLINED' or the internal events queue is full and couldn't be flushed.
*/
trackError(error: string | Error): void;
trackError(error: string | Error): boolean;
/**

@@ -204,4 +205,5 @@ * Tracks a custom event.

* @param {Properties=} properties - The properties of this event. Values can be string, number, boolean or null.
* @returns {boolean} Whether the event was tracked or not. The event will not be tracked if it has invalid types (e.g., eventTypeId is not a string), user consent is 'DECLINED', or the internal events queue is full and couldn't be flushed.
*/
track(eventTypeId: string, value?: number, properties?: Properties): void;
track(eventTypeId: string, value?: number, properties?: Properties): boolean;
/**

@@ -212,4 +214,5 @@ * Tracks a custom event.

* @param {EventData} event - The event object.
* @returns {boolean} Whether the event was tracked or not. The event will not be tracked if it has invalid types (e.g., eventTypeId property is not a string), user consent is 'DECLINED', or the internal events queue is full and couldn't be flushed.
*/
track(event: EventData): void;
track(event: EventData): boolean;
/**

@@ -216,0 +219,0 @@ * Sets properties to append to events.

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