@rudderstack/analytics-js 3.19.0 → 3.20.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.
@@ -291,7 +291,11 @@ function _path(pathAr,obj){var val=obj;for(var i=0;i<pathAr.length;i+=1){if(val=
291
291
  * Determines if the input is of type error
292
292
  * @param value input value
293
293
  * @returns true if the input is of type error else false
294
- */const isTypeOfError=value=>{switch(Object.prototype.toString.call(value)){case '[object Error]':case '[object Exception]':case '[object DOMException]':return true;default:return value instanceof Error;}};
294
+ */const isTypeOfError=value=>{switch(Object.prototype.toString.call(value)){case '[object Error]':case '[object Exception]':case '[object DOMException]':return true;default:return value instanceof Error;}};/**
295
+ * A function to check given value is a boolean
296
+ * @param value input value
297
+ * @returns boolean
298
+ */const isBoolean=value=>typeof value==='boolean';
295
299
 
296
300
  const getValueByPath=(obj,keyPath)=>{const pathParts=keyPath.split('.');return path(pathParts,obj);};const hasValueByPath=(obj,path)=>Boolean(getValueByPath(obj,path));const isObject=value=>typeof value==='object';/**
297
301
  * Checks if the input is an object literal or built-in object type and not null
@@ -414,10 +418,12 @@ payload.groupId=tryStringify(payload.groupId);if(isObjectLiteralAndNotNull(paylo
414
418
  *//**
415
419
  * Represents the destinations queue options parameter in loadOptions type
416
420
  */let PageLifecycleEvents=/*#__PURE__*/function(PageLifecycleEvents){PageLifecycleEvents["UNLOADED"]="Page Unloaded";return PageLifecycleEvents;}({});/**
421
+ * Represents the source configuration override options for destinations
422
+ *//**
417
423
  * Represents the options parameter in the load API
418
424
  */
419
425
 
420
- const API_SUFFIX='API';const CAPABILITIES_MANAGER='CapabilitiesManager';const CONFIG_MANAGER='ConfigManager';const EVENT_MANAGER='EventManager';const PLUGINS_MANAGER='PluginsManager';const USER_SESSION_MANAGER='UserSessionManager';const ERROR_HANDLER='ErrorHandler';const PLUGIN_ENGINE='PluginEngine';const STORE_MANAGER='StoreManager';const READY_API=`Ready${API_SUFFIX}`;const LOAD_API=`Load${API_SUFFIX}`;const EXTERNAL_SRC_LOADER='ExternalSrcLoader';const HTTP_CLIENT='HttpClient';const RSA='RudderStackAnalytics';const ANALYTICS_CORE='AnalyticsCore';
426
+ const API_SUFFIX='API';const CAPABILITIES_MANAGER='CapabilitiesManager';const CONFIG_MANAGER='ConfigManager';const EVENT_MANAGER='EventManager';const PLUGINS_MANAGER='PluginsManager';const USER_SESSION_MANAGER='UserSessionManager';const ERROR_HANDLER='ErrorHandler';const PLUGIN_ENGINE='PluginEngine';const STORE_MANAGER='StoreManager';const READY_API=`Ready${API_SUFFIX}`;const LOAD_API=`Load${API_SUFFIX}`;const HTTP_CLIENT='HttpClient';const RSA='RudderStackAnalytics';const ANALYTICS_CORE='AnalyticsCore';
421
427
 
422
428
  function random(len){return crypto.getRandomValues(new Uint8Array(len));}
423
429
 
@@ -448,7 +454,7 @@ const getFormattedTimestamp=date=>date.toISOString();/**
448
454
  * @returns ISO formatted timestamp string
449
455
  */const getCurrentTimeFormatted=()=>getFormattedTimestamp(new Date());
450
456
 
451
- const LOG_CONTEXT_SEPARATOR=':: ';const SCRIPT_ALREADY_EXISTS_ERROR=id=>`A script with the id "${id}" is already loaded. Skipping the loading of this script to prevent conflicts.`;const SCRIPT_LOAD_ERROR=(id,url)=>`Failed to load the script with the id "${id}" from URL "${url}".`;const SCRIPT_LOAD_TIMEOUT_ERROR=(id,url,timeout)=>`A timeout of ${timeout} ms occurred while trying to load the script with id "${id}" from URL "${url}".`;const CIRCULAR_REFERENCE_WARNING=(context,key)=>`${context}${LOG_CONTEXT_SEPARATOR}A circular reference has been detected in the object and the property "${key}" has been dropped from the output.`;const JSON_STRINGIFY_WARNING=`Failed to convert the value to a JSON string.`;const COOKIE_DATA_ENCODING_ERROR=`Failed to encode the cookie data.`;
457
+ const LOG_CONTEXT_SEPARATOR=':: ';const SCRIPT_ALREADY_EXISTS_ERROR=id=>`A script with the id "${id}" is already loaded. Skipping the loading of this script to prevent conflicts`;const SCRIPT_LOAD_ERROR=(id,url,ev)=>`Unable to load (${isString(ev)?ev:ev.type}) the script with the id "${id}" from URL "${url}"`;const SCRIPT_LOAD_TIMEOUT_ERROR=(id,url,timeout)=>`A timeout of ${timeout} ms occurred while trying to load the script with id "${id}" from URL "${url}"`;const CIRCULAR_REFERENCE_WARNING=(context,key)=>`${context}${LOG_CONTEXT_SEPARATOR}A circular reference has been detected in the object and the property "${key}" has been dropped from the output.`;const JSON_STRINGIFY_WARNING=`Failed to convert the value to a JSON string.`;const COOKIE_DATA_ENCODING_ERROR=`Failed to encode the cookie data.`;
452
458
 
453
459
  const JSON_STRINGIFY='JSONStringify';const BIG_INT_PLACEHOLDER='[BigInt]';const CIRCULAR_REFERENCE_PLACEHOLDER='[Circular Reference]';const getCircularReplacer=(excludeNull,excludeKeys,logger)=>{const ancestors=[];// Here we do not want to use arrow function to use "this" in function context
454
460
  // eslint-disable-next-line func-names
@@ -495,7 +501,7 @@ error.stack=`${stack}\n${MANUAL_ERROR_IDENTIFIER}`;break;case stacktrace:// esli
495
501
  error.stacktrace=`${stacktrace}\n${MANUAL_ERROR_IDENTIFIER}`;break;case operaSourceloc:default:// eslint-disable-next-line no-param-reassign
496
502
  error['opera#sourceloc']=`${operaSourceloc}\n${MANUAL_ERROR_IDENTIFIER}`;break;}}}globalThis.dispatchEvent(new ErrorEvent('error',{error,bubbles:true,cancelable:true,composed:true}));};
497
503
 
498
- const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.19.0';const APP_NAMESPACE='com.rudderlabs.javascript';const MODULE_TYPE='npm';const ADBLOCK_PAGE_CATEGORY='RudderJS-Initiated';const ADBLOCK_PAGE_NAME='ad-block page request';const ADBLOCK_PAGE_PATH='/ad-blocked';const GLOBAL_PRELOAD_BUFFER='preloadedEventsBuffer';const CONSENT_TRACK_EVENT_NAME='Consent Management Interaction';
504
+ const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.20.0';const APP_NAMESPACE='com.rudderlabs.javascript';const MODULE_TYPE='npm';const ADBLOCK_PAGE_CATEGORY='RudderJS-Initiated';const ADBLOCK_PAGE_NAME='ad-block page request';const ADBLOCK_PAGE_PATH='/ad-blocked';const GLOBAL_PRELOAD_BUFFER='preloadedEventsBuffer';const CONSENT_TRACK_EVENT_NAME='Consent Management Interaction';
499
505
 
500
506
  const QUERY_PARAM_TRAIT_PREFIX='ajs_trait_';const QUERY_PARAM_PROPERTY_PREFIX='ajs_prop_';const QUERY_PARAM_ANONYMOUS_ID_KEY='ajs_aid';const QUERY_PARAM_USER_ID_KEY='ajs_uid';const QUERY_PARAM_TRACK_EVENT_NAME_KEY='ajs_event';
501
507
 
@@ -575,19 +581,17 @@ const headElement=document.createElement('head');headElement.appendChild(newScri
575
581
  * @param {*} extraAttributes key/value pair with html attributes to add in html tag [optional]
576
582
  *
577
583
  * @returns
578
- */const jsFileLoader=(url,id,timeout,async=true,extraAttributes)=>new Promise((resolve,reject)=>{const scriptExists=document.getElementById(id);if(scriptExists){reject(new Error(SCRIPT_ALREADY_EXISTS_ERROR(id)));}try{let timeoutID;const onload=()=>{globalThis.clearTimeout(timeoutID);resolve(id);};const onerror=()=>{globalThis.clearTimeout(timeoutID);reject(new Error(SCRIPT_LOAD_ERROR(id,url)));};// Create the DOM element to load the script and add it to the DOM
584
+ */const jsFileLoader=(url,id,timeout,async=true,extraAttributes)=>new Promise((resolve,reject)=>{const scriptExists=document.getElementById(id);if(scriptExists){reject(new Error(SCRIPT_ALREADY_EXISTS_ERROR(id)));}try{let timeoutID;const onload=()=>{globalThis.clearTimeout(timeoutID);resolve(id);};const onerror=ev=>{globalThis.clearTimeout(timeoutID);reject(new Error(SCRIPT_LOAD_ERROR(id,url,ev)));};// Create the DOM element to load the script and add it to the DOM
579
585
  insertScript(createScriptElement(url,id,async,onload,onerror,extraAttributes));// Reject on timeout
580
- timeoutID=globalThis.setTimeout(()=>{reject(new Error(SCRIPT_LOAD_TIMEOUT_ERROR(id,url,timeout)));},timeout);}catch(err){reject(getMutatedError(err,SCRIPT_LOAD_ERROR(id,url)));}});
586
+ timeoutID=globalThis.setTimeout(()=>{reject(new Error(SCRIPT_LOAD_TIMEOUT_ERROR(id,url,timeout)));},timeout);}catch(err){reject(getMutatedError(err,SCRIPT_LOAD_ERROR(id,url,'unknown')));}});
581
587
 
582
588
  /**
583
589
  * Service to load external resources/files
584
- */class ExternalSrcLoader{constructor(errorHandler,logger,timeout=DEFAULT_EXT_SRC_LOAD_TIMEOUT_MS){this.errorHandler=errorHandler;this.logger=logger;this.timeout=timeout;this.onError=this.onError.bind(this);}/**
590
+ */class ExternalSrcLoader{constructor(logger,timeout=DEFAULT_EXT_SRC_LOAD_TIMEOUT_MS){this.logger=logger;this.timeout=timeout;}/**
585
591
  * Load external resource of type javascript
586
- */loadJSFile(config){const{url,id,timeout,async,callback,extraAttributes}=config;const isFireAndForget=!isFunction(callback);jsFileLoader(url,id,timeout||this.timeout,async,extraAttributes).then(id=>{if(!isFireAndForget){callback(id);}}).catch(err=>{this.onError(err);if(!isFireAndForget){callback();}});}/**
587
- * Handle errors
588
- */onError(error){this.errorHandler.onError(error,EXTERNAL_SRC_LOADER);}}
592
+ */loadJSFile(config){const{url,id,timeout,async,callback,extraAttributes}=config;const isFireAndForget=!isFunction(callback);jsFileLoader(url,id,timeout||this.timeout,async,extraAttributes).then(id=>{if(!isFireAndForget){callback(id);}}).catch(err=>{if(!isFireAndForget){callback(id,err);}});}}
589
593
 
590
- var i=Symbol.for("preact-signals");function t(){if(!(s>1)){var i,t=false;while(void 0!==h){var r=h;h=void 0;f++;while(void 0!==r){var o=r.o;r.o=void 0;r.f&=-3;if(!(8&r.f)&&c(r))try{r.c();}catch(r){if(!t){i=r;t=true;}}r=o;}}f=0;s--;if(t)throw i;}else s--;}function r(i){if(s>0)return i();s++;try{return i();}finally{t();}}var o=void 0;var h=void 0,s=0,f=0,v=0;function e(i){if(void 0!==o){var t=i.n;if(void 0===t||t.t!==o){t={i:0,S:i,p:o.s,n:void 0,t:o,e:void 0,x:void 0,r:t};if(void 0!==o.s)o.s.n=t;o.s=t;i.n=t;if(32&o.f)i.S(t);return t;}else if(-1===t.i){t.i=0;if(void 0!==t.n){t.n.p=t.p;if(void 0!==t.p)t.p.n=t.n;t.p=o.s;t.n=void 0;o.s.n=t;o.s=t;}return t;}}}function u(i){this.v=i;this.i=0;this.n=void 0;this.t=void 0;}u.prototype.brand=i;u.prototype.h=function(){return true;};u.prototype.S=function(i){if(this.t!==i&&void 0===i.e){i.x=this.t;if(void 0!==this.t)this.t.e=i;this.t=i;}};u.prototype.U=function(i){if(void 0!==this.t){var t=i.e,r=i.x;if(void 0!==t){t.x=r;i.e=void 0;}if(void 0!==r){r.e=t;i.x=void 0;}if(i===this.t)this.t=r;}};u.prototype.subscribe=function(i){var t=this;return E(function(){var r=t.value,n=o;o=void 0;try{i(r);}finally{o=n;}});};u.prototype.valueOf=function(){return this.value;};u.prototype.toString=function(){return this.value+"";};u.prototype.toJSON=function(){return this.value;};u.prototype.peek=function(){var i=o;o=void 0;try{return this.value;}finally{o=i;}};Object.defineProperty(u.prototype,"value",{get:function(){var i=e(this);if(void 0!==i)i.i=this.i;return this.v;},set:function(i){if(i!==this.v){if(f>100)throw new Error("Cycle detected");this.v=i;this.i++;v++;s++;try{for(var r=this.t;void 0!==r;r=r.x)r.t.N();}finally{t();}}}});function d$1(i){return new u(i);}function c(i){for(var t=i.s;void 0!==t;t=t.n)if(t.S.i!==t.i||!t.S.h()||t.S.i!==t.i)return true;return false;}function a(i){for(var t=i.s;void 0!==t;t=t.n){var r=t.S.n;if(void 0!==r)t.r=r;t.S.n=t;t.i=-1;if(void 0===t.n){i.s=t;break;}}}function l(i){var t=i.s,r=void 0;while(void 0!==t){var o=t.p;if(-1===t.i){t.S.U(t);if(void 0!==o)o.n=t.n;if(void 0!==t.n)t.n.p=o;}else r=t;t.S.n=t.r;if(void 0!==t.r)t.r=void 0;t=o;}i.s=r;}function y(i){u.call(this,void 0);this.x=i;this.s=void 0;this.g=v-1;this.f=4;}(y.prototype=new u()).h=function(){this.f&=-3;if(1&this.f)return false;if(32==(36&this.f))return true;this.f&=-5;if(this.g===v)return true;this.g=v;this.f|=1;if(this.i>0&&!c(this)){this.f&=-2;return true;}var i=o;try{a(this);o=this;var t=this.x();if(16&this.f||this.v!==t||0===this.i){this.v=t;this.f&=-17;this.i++;}}catch(i){this.v=i;this.f|=16;this.i++;}o=i;l(this);this.f&=-2;return true;};y.prototype.S=function(i){if(void 0===this.t){this.f|=36;for(var t=this.s;void 0!==t;t=t.n)t.S.S(t);}u.prototype.S.call(this,i);};y.prototype.U=function(i){if(void 0!==this.t){u.prototype.U.call(this,i);if(void 0===this.t){this.f&=-33;for(var t=this.s;void 0!==t;t=t.n)t.S.U(t);}}};y.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var i=this.t;void 0!==i;i=i.x)i.t.N();}};Object.defineProperty(y.prototype,"value",{get:function(){if(1&this.f)throw new Error("Cycle detected");var i=e(this);this.h();if(void 0!==i)i.i=this.i;if(16&this.f)throw this.v;return this.v;}});function _(i){var r=i.u;i.u=void 0;if("function"==typeof r){s++;var n=o;o=void 0;try{r();}catch(t){i.f&=-2;i.f|=8;g(i);throw t;}finally{o=n;t();}}}function g(i){for(var t=i.s;void 0!==t;t=t.n)t.S.U(t);i.x=void 0;i.s=void 0;_(i);}function p(i){if(o!==this)throw new Error("Out-of-order effect");l(this);o=i;this.f&=-2;if(8&this.f)g(this);t();}function b(i){this.x=i;this.u=void 0;this.s=void 0;this.o=void 0;this.f=32;}b.prototype.c=function(){var i=this.S();try{if(8&this.f)return;if(void 0===this.x)return;var t=this.x();if("function"==typeof t)this.u=t;}finally{i();}};b.prototype.S=function(){if(1&this.f)throw new Error("Cycle detected");this.f|=1;this.f&=-9;_(this);a(this);s++;var i=o;o=this;return p.bind(this,i);};b.prototype.N=function(){if(!(2&this.f)){this.f|=2;this.o=h;h=this;}};b.prototype.d=function(){this.f|=8;if(!(1&this.f))g(this);};function E(i){var t=new b(i);try{t.c();}catch(i){t.d();throw i;}return t.d.bind(t);}
594
+ var i=Symbol.for("preact-signals");function t(){if(!(s>1)){var i,t=false;while(void 0!==h){var r=h;h=void 0;f++;while(void 0!==r){var o=r.o;r.o=void 0;r.f&=-3;if(!(8&r.f)&&c(r))try{r.c();}catch(r){if(!t){i=r;t=true;}}r=o;}}f=0;s--;if(t)throw i;}else s--;}function r(i){if(s>0)return i();s++;try{return i();}finally{t();}}var o=void 0;function n(i){var t=o;o=void 0;try{return i();}finally{o=t;}}var h=void 0,s=0,f=0,v=0;function e(i){if(void 0!==o){var t=i.n;if(void 0===t||t.t!==o){t={i:0,S:i,p:o.s,n:void 0,t:o,e:void 0,x:void 0,r:t};if(void 0!==o.s)o.s.n=t;o.s=t;i.n=t;if(32&o.f)i.S(t);return t;}else if(-1===t.i){t.i=0;if(void 0!==t.n){t.n.p=t.p;if(void 0!==t.p)t.p.n=t.n;t.p=o.s;t.n=void 0;o.s.n=t;o.s=t;}return t;}}}function u(i,t){this.v=i;this.i=0;this.n=void 0;this.t=void 0;this.W=null==t?void 0:t.watched;this.Z=null==t?void 0:t.unwatched;}u.prototype.brand=i;u.prototype.h=function(){return true;};u.prototype.S=function(i){var t=this,r=this.t;if(r!==i&&void 0===i.e){i.x=r;this.t=i;if(void 0!==r)r.e=i;else n(function(){var i;null==(i=t.W)||i.call(t);});}};u.prototype.U=function(i){var t=this;if(void 0!==this.t){var r=i.e,o=i.x;if(void 0!==r){r.x=o;i.e=void 0;}if(void 0!==o){o.e=r;i.x=void 0;}if(i===this.t){this.t=o;if(void 0===o)n(function(){var i;null==(i=t.Z)||i.call(t);});}}};u.prototype.subscribe=function(i){var t=this;return E(function(){var r=t.value,n=o;o=void 0;try{i(r);}finally{o=n;}});};u.prototype.valueOf=function(){return this.value;};u.prototype.toString=function(){return this.value+"";};u.prototype.toJSON=function(){return this.value;};u.prototype.peek=function(){var i=o;o=void 0;try{return this.value;}finally{o=i;}};Object.defineProperty(u.prototype,"value",{get:function(){var i=e(this);if(void 0!==i)i.i=this.i;return this.v;},set:function(i){if(i!==this.v){if(f>100)throw new Error("Cycle detected");this.v=i;this.i++;v++;s++;try{for(var r=this.t;void 0!==r;r=r.x)r.t.N();}finally{t();}}}});function d$1(i,t){return new u(i,t);}function c(i){for(var t=i.s;void 0!==t;t=t.n)if(t.S.i!==t.i||!t.S.h()||t.S.i!==t.i)return true;return false;}function a(i){for(var t=i.s;void 0!==t;t=t.n){var r=t.S.n;if(void 0!==r)t.r=r;t.S.n=t;t.i=-1;if(void 0===t.n){i.s=t;break;}}}function l(i){var t=i.s,r=void 0;while(void 0!==t){var o=t.p;if(-1===t.i){t.S.U(t);if(void 0!==o)o.n=t.n;if(void 0!==t.n)t.n.p=o;}else r=t;t.S.n=t.r;if(void 0!==t.r)t.r=void 0;t=o;}i.s=r;}function y(i,t){u.call(this,void 0);this.x=i;this.s=void 0;this.g=v-1;this.f=4;this.W=null==t?void 0:t.watched;this.Z=null==t?void 0:t.unwatched;}y.prototype=new u();y.prototype.h=function(){this.f&=-3;if(1&this.f)return false;if(32==(36&this.f))return true;this.f&=-5;if(this.g===v)return true;this.g=v;this.f|=1;if(this.i>0&&!c(this)){this.f&=-2;return true;}var i=o;try{a(this);o=this;var t=this.x();if(16&this.f||this.v!==t||0===this.i){this.v=t;this.f&=-17;this.i++;}}catch(i){this.v=i;this.f|=16;this.i++;}o=i;l(this);this.f&=-2;return true;};y.prototype.S=function(i){if(void 0===this.t){this.f|=36;for(var t=this.s;void 0!==t;t=t.n)t.S.S(t);}u.prototype.S.call(this,i);};y.prototype.U=function(i){if(void 0!==this.t){u.prototype.U.call(this,i);if(void 0===this.t){this.f&=-33;for(var t=this.s;void 0!==t;t=t.n)t.S.U(t);}}};y.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var i=this.t;void 0!==i;i=i.x)i.t.N();}};Object.defineProperty(y.prototype,"value",{get:function(){if(1&this.f)throw new Error("Cycle detected");var i=e(this);this.h();if(void 0!==i)i.i=this.i;if(16&this.f)throw this.v;return this.v;}});function _(i){var r=i.u;i.u=void 0;if("function"==typeof r){s++;var n=o;o=void 0;try{r();}catch(t){i.f&=-2;i.f|=8;g(i);throw t;}finally{o=n;t();}}}function g(i){for(var t=i.s;void 0!==t;t=t.n)t.S.U(t);i.x=void 0;i.s=void 0;_(i);}function p(i){if(o!==this)throw new Error("Out-of-order effect");l(this);o=i;this.f&=-2;if(8&this.f)g(this);t();}function b(i){this.x=i;this.u=void 0;this.s=void 0;this.o=void 0;this.f=32;}b.prototype.c=function(){var i=this.S();try{if(8&this.f)return;if(void 0===this.x)return;var t=this.x();if("function"==typeof t)this.u=t;}finally{i();}};b.prototype.S=function(){if(1&this.f)throw new Error("Cycle detected");this.f|=1;this.f&=-9;_(this);a(this);s++;var i=o;o=this;return p.bind(this,i);};b.prototype.N=function(){if(!(2&this.f)){this.f|=2;this.o=h;h=this;}};b.prototype.d=function(){this.f|=8;if(!(1&this.f))g(this);};function E(i){var t=new b(i);try{t.c();}catch(i){t.d();throw i;}return t.d.bind(t);}
591
595
 
592
596
  /**
593
597
  * A buffer queue to serve as a store for any type of data
@@ -615,7 +619,7 @@ let ErrorType=/*#__PURE__*/function(ErrorType){ErrorType["HANDLEDEXCEPTION"]="ha
615
619
  const SUPPORTED_STORAGE_TYPES=['localStorage','memoryStorage','cookieStorage','sessionStorage','none'];const DEFAULT_STORAGE_TYPE='cookieStorage';
616
620
 
617
621
  const SOURCE_CONFIG_RESOLUTION_ERROR=`Unable to process/parse source configuration response`;const SOURCE_DISABLED_ERROR=`The source is disabled. Please enable the source in the dashboard to send events.`;const XHR_PAYLOAD_PREP_ERROR=`Failed to prepare data for the request.`;const PLUGIN_EXT_POINT_MISSING_ERROR=`Failed to invoke plugin because the extension point name is missing.`;const PLUGIN_EXT_POINT_INVALID_ERROR=`Failed to invoke plugin because the extension point name is invalid.`;const SOURCE_CONFIG_OPTION_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}The "getSourceConfig" load API option must be a function that returns valid source configuration data.`;const COMPONENT_BASE_URL_ERROR=(context,component,url)=>`${context}${LOG_CONTEXT_SEPARATOR}The base URL "${url}" for ${component} is not valid.`;// ERROR
618
- const UNSUPPORTED_CONSENT_MANAGER_ERROR=(context,selectedConsentManager,consentManagersToPluginNameMap)=>`${context}${LOG_CONTEXT_SEPARATOR}The consent manager "${selectedConsentManager}" is not supported. Please choose one of the following supported consent managers: "${Object.keys(consentManagersToPluginNameMap)}".`;const NON_ERROR_WARNING=(context,errStr)=>`${context}${LOG_CONTEXT_SEPARATOR}Ignoring a non-error: ${errStr}.`;const BREADCRUMB_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to log breadcrumb.`;const HANDLE_ERROR_FAILURE=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to handle the error.`;const PLUGIN_NAME_MISSING_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin name is missing.`;const PLUGIN_ALREADY_EXISTS_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" already exists.`;const PLUGIN_NOT_FOUND_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" not found.`;const PLUGIN_ENGINE_BUG_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" not found in plugins but found in byName. This indicates a bug in the plugin engine. Please report this issue to the development team.`;const PLUGIN_DEPS_ERROR=(context,pluginName,notExistDeps)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" could not be loaded because some of its dependencies "${notExistDeps}" do not exist.`;const PLUGIN_INVOCATION_ERROR=(context,extPoint,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to invoke the "${extPoint}" extension point of plugin "${pluginName}".`;const STORAGE_UNAVAILABILITY_ERROR_PREFIX=(context,storageType)=>`${context}${LOG_CONTEXT_SEPARATOR}The "${storageType}" storage type is `;const SOURCE_CONFIG_FETCH_ERROR='Failed to fetch the source config';const WRITE_KEY_VALIDATION_ERROR=(context,writeKey)=>`${context}${LOG_CONTEXT_SEPARATOR}The write key "${writeKey}" is invalid. It must be a non-empty string. Please check that the write key is correct and try again.`;const DATA_PLANE_URL_VALIDATION_ERROR=(context,dataPlaneUrl)=>`${context}${LOG_CONTEXT_SEPARATOR}The data plane URL "${dataPlaneUrl}" is invalid. It must be a valid URL string. Please check that the data plane URL is correct and try again.`;const INVALID_CALLBACK_FN_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}The provided callback parameter is not a function.`;const XHR_DELIVERY_ERROR=(prefix,status,statusText,url,response)=>`${prefix} with status ${status} (${statusText}) for URL: ${url}. Response: ${response.trim()}`;const XHR_REQUEST_ERROR=(prefix,e,url)=>`${prefix} due to timeout or no connection (${e?e.type:''}) at the client side for URL: ${url}`;const XHR_SEND_ERROR=(prefix,url)=>`${prefix} for URL: ${url}`;const STORE_DATA_SAVE_ERROR=key=>`Failed to save the value for "${key}" to storage`;const STORE_DATA_FETCH_ERROR=key=>`Failed to retrieve or parse data for "${key}" from storage`;const DATA_SERVER_REQUEST_FAIL_ERROR=status=>`The server responded with status ${status} while setting the cookies. As a fallback, the cookies will be set client side.`;const FAILED_SETTING_COOKIE_FROM_SERVER_ERROR=key=>`The server failed to set the ${key} cookie. As a fallback, the cookies will be set client side.`;const FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR=`Failed to set/remove cookies via server. As a fallback, the cookies will be managed client side.`;// WARNING
622
+ const UNSUPPORTED_CONSENT_MANAGER_ERROR=(context,selectedConsentManager,consentManagersToPluginNameMap)=>`${context}${LOG_CONTEXT_SEPARATOR}The consent manager "${selectedConsentManager}" is not supported. Please choose one of the following supported consent managers: "${Object.keys(consentManagersToPluginNameMap)}".`;const NON_ERROR_WARNING=(context,errStr)=>`${context}${LOG_CONTEXT_SEPARATOR}Ignoring a non-error: ${errStr}.`;const BREADCRUMB_ERROR=`Failed to log breadcrumb`;const HANDLE_ERROR_FAILURE=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to handle the error.`;const PLUGIN_NAME_MISSING_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin name is missing.`;const PLUGIN_ALREADY_EXISTS_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" already exists.`;const PLUGIN_NOT_FOUND_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" not found.`;const PLUGIN_ENGINE_BUG_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" not found in plugins but found in byName. This indicates a bug in the plugin engine. Please report this issue to the development team.`;const PLUGIN_DEPS_ERROR=(context,pluginName,notExistDeps)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" could not be loaded because some of its dependencies "${notExistDeps}" do not exist.`;const PLUGIN_INVOCATION_ERROR=(context,extPoint,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to invoke the "${extPoint}" extension point of plugin "${pluginName}".`;const STORAGE_UNAVAILABILITY_ERROR_PREFIX=(context,storageType)=>`${context}${LOG_CONTEXT_SEPARATOR}The "${storageType}" storage type is `;const SOURCE_CONFIG_FETCH_ERROR='Failed to fetch the source config';const WRITE_KEY_VALIDATION_ERROR=(context,writeKey)=>`${context}${LOG_CONTEXT_SEPARATOR}The write key "${writeKey}" is invalid. It must be a non-empty string. Please check that the write key is correct and try again.`;const DATA_PLANE_URL_VALIDATION_ERROR=(context,dataPlaneUrl)=>`${context}${LOG_CONTEXT_SEPARATOR}The data plane URL "${dataPlaneUrl}" is invalid. It must be a valid URL string. Please check that the data plane URL is correct and try again.`;const INVALID_CALLBACK_FN_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}The provided callback parameter is not a function.`;const XHR_DELIVERY_ERROR=(prefix,status,statusText,url,response)=>`${prefix} with status ${status} (${statusText}) for URL: ${url}. Response: ${response.trim()}`;const XHR_REQUEST_ERROR=(prefix,e,url)=>`${prefix} due to timeout or no connection (${e?e.type:''}) at the client side for URL: ${url}`;const XHR_SEND_ERROR=(prefix,url)=>`${prefix} for URL: ${url}`;const STORE_DATA_SAVE_ERROR=key=>`Failed to save the value for "${key}" to storage`;const STORE_DATA_FETCH_ERROR=key=>`Failed to retrieve or parse data for "${key}" from storage`;const DATA_SERVER_REQUEST_FAIL_ERROR=status=>`The server responded with status ${status} while setting the cookies. As a fallback, the cookies will be set client side.`;const FAILED_SETTING_COOKIE_FROM_SERVER_ERROR=key=>`The server failed to set the ${key} cookie. As a fallback, the cookies will be set client side.`;const FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR=`Failed to set/remove cookies via server. As a fallback, the cookies will be managed client side.`;// WARNING
619
623
  const STORAGE_TYPE_VALIDATION_WARNING=(context,storageType,defaultStorageType)=>`${context}${LOG_CONTEXT_SEPARATOR}The storage type "${storageType}" is not supported. Please choose one of the following supported types: "${SUPPORTED_STORAGE_TYPES}". The default type "${defaultStorageType}" will be used instead.`;const UNSUPPORTED_STORAGE_ENCRYPTION_VERSION_WARNING=(context,selectedStorageEncryptionVersion,storageEncryptionVersionsToPluginNameMap,defaultVersion)=>`${context}${LOG_CONTEXT_SEPARATOR}The storage encryption version "${selectedStorageEncryptionVersion}" is not supported. Please choose one of the following supported versions: "${Object.keys(storageEncryptionVersionsToPluginNameMap)}". The default version "${defaultVersion}" will be used instead.`;const STORAGE_DATA_MIGRATION_OVERRIDE_WARNING=(context,storageEncryptionVersion,defaultVersion)=>`${context}${LOG_CONTEXT_SEPARATOR}The storage data migration has been disabled because the configured storage encryption version (${storageEncryptionVersion}) is not the latest (${defaultVersion}). To enable storage data migration, please update the storage encryption version to the latest version.`;const SERVER_SIDE_COOKIE_FEATURE_OVERRIDE_WARNING=(context,providedCookieDomain,currentCookieDomain)=>`${context}${LOG_CONTEXT_SEPARATOR}The provided cookie domain (${providedCookieDomain}) does not match the current webpage's domain (${currentCookieDomain}). Hence, the cookies will be set client-side.`;const RESERVED_KEYWORD_WARNING=(context,property,parentKeyPath,reservedElements)=>`${context}${LOG_CONTEXT_SEPARATOR}The "${property}" property defined under "${parentKeyPath}" is a reserved keyword. Please choose a different property name to avoid conflicts with reserved keywords (${reservedElements}).`;const INVALID_CONTEXT_OBJECT_WARNING=logContext=>`${logContext}${LOG_CONTEXT_SEPARATOR}Please make sure that the "context" property in the event API's "options" argument is a valid object literal with key-value pairs.`;const UNSUPPORTED_BEACON_API_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}The Beacon API is not supported by your browser. The events will be sent using XHR instead.`;const TIMEOUT_NOT_NUMBER_WARNING=(context,timeout,defaultValue)=>`${context}${LOG_CONTEXT_SEPARATOR}The session timeout value "${timeout}" is not a number. The default timeout of ${defaultValue} ms will be used instead.`;const CUT_OFF_DURATION_NOT_NUMBER_WARNING=(context,cutOffDuration,defaultValue)=>`${context}${LOG_CONTEXT_SEPARATOR}The session cut off duration value "${cutOffDuration}" is not a number. The default cut off duration of ${defaultValue} ms will be used instead.`;const CUT_OFF_DURATION_LESS_THAN_TIMEOUT_WARNING=(context,cutOffDuration,timeout)=>`${context}${LOG_CONTEXT_SEPARATOR}The session cut off duration value "${cutOffDuration}" ms is less than the session timeout value "${timeout}" ms. The cut off functionality will be disabled.`;const TIMEOUT_ZERO_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}The session timeout value is 0, which disables the automatic session tracking feature. If you want to enable session tracking, please provide a positive integer value for the timeout.`;const TIMEOUT_NOT_RECOMMENDED_WARNING=(context,timeout,minTimeout)=>`${context}${LOG_CONTEXT_SEPARATOR}The session timeout value ${timeout} ms is less than the recommended minimum of ${minTimeout} ms. Please consider increasing the timeout value to ensure optimal performance and reliability.`;const INVALID_SESSION_ID_WARNING=(context,sessionId,minSessionIdLength)=>`${context}${LOG_CONTEXT_SEPARATOR}The provided session ID (${sessionId}) is either invalid, not a positive integer, or not at least "${minSessionIdLength}" digits long. A new session ID will be auto-generated instead.`;const STORAGE_QUOTA_EXCEEDED_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}The storage is either full or unavailable, so the data will not be persisted. Switching to in-memory storage.`;const STORAGE_UNAVAILABLE_WARNING=(context,entry,selectedStorageType,finalStorageType)=>`${context}${LOG_CONTEXT_SEPARATOR}The storage type "${selectedStorageType}" is not available for entry "${entry}". The SDK will initialize the entry with "${finalStorageType}" storage type instead.`;const CALLBACK_INVOKE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}The callback threw an exception`;const INVALID_CONFIG_URL_WARNING=(context,configUrl)=>`${context}${LOG_CONTEXT_SEPARATOR}The provided source config URL "${configUrl}" is invalid. Using the default source config URL instead.`;const POLYFILL_SCRIPT_LOAD_ERROR=(scriptId,url)=>`Failed to load the polyfill script with ID "${scriptId}" from URL ${url}.`;const UNSUPPORTED_PRE_CONSENT_STORAGE_STRATEGY=(context,selectedStrategy,defaultStrategy)=>`${context}${LOG_CONTEXT_SEPARATOR}The pre-consent storage strategy "${selectedStrategy}" is not supported. Please choose one of the following supported strategies: "none, session, anonymousId". The default strategy "${defaultStrategy}" will be used instead.`;const UNSUPPORTED_PRE_CONSENT_EVENTS_DELIVERY_TYPE=(context,selectedDeliveryType,defaultDeliveryType)=>`${context}${LOG_CONTEXT_SEPARATOR}The pre-consent events delivery type "${selectedDeliveryType}" is not supported. Please choose one of the following supported types: "immediate, buffer". The default type "${defaultDeliveryType}" will be used instead.`;const DEPRECATED_PLUGIN_WARNING=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}${pluginName} plugin is deprecated. Please exclude it from the load API options.`;const generateMisconfiguredPluginsWarning=(context,configurationStatus,missingPlugins,shouldAddMissingPlugins)=>{const isSinglePlugin=missingPlugins.length===1;const pluginsString=isSinglePlugin?` '${missingPlugins[0]}' plugin was`:` ['${missingPlugins.join("', '")}'] plugins were`;const baseWarning=`${context}${LOG_CONTEXT_SEPARATOR}${configurationStatus}, but${pluginsString} not configured to load.`;if(shouldAddMissingPlugins){return `${baseWarning} So, ${isSinglePlugin?'the plugin':'those plugins'} will be loaded automatically.`;}return `${baseWarning} Ignore if this was intentional. Otherwise, consider adding ${isSinglePlugin?'it':'them'} to the 'plugins' load API option.`;};const INVALID_POLYFILL_URL_WARNING=(context,customPolyfillUrl)=>`${context}${LOG_CONTEXT_SEPARATOR}The provided polyfill URL "${customPolyfillUrl}" is invalid. The default polyfill URL will be used instead.`;const PAGE_UNLOAD_ON_BEACON_DISABLED_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}Page Unloaded event can only be tracked when the Beacon transport is active. Please enable "useBeacon" load API option.`;const UNKNOWN_PLUGINS_WARNING=(context,unknownPlugins)=>`${context}${LOG_CONTEXT_SEPARATOR}Ignoring unknown plugins: ${unknownPlugins.join(', ')}.`;
620
624
 
621
625
  const DEFAULT_INTEGRATIONS_CONFIG={All:true};
@@ -728,7 +732,7 @@ const DEFAULT_XHR_REQUEST_OPTIONS={headers:{Accept:'application/json','Content-T
728
732
  * this is not supported by our sourceConfig API
729
733
  */const xhrRequest=(options,timeout=DEFAULT_XHR_TIMEOUT_MS,logger)=>new Promise((resolve,reject)=>{let payload;if(options.sendRawData===true){payload=options.data;}else {payload=stringifyWithoutCircular(options.data,false,[],logger);if(isNull(payload)){reject({error:new Error(XHR_PAYLOAD_PREP_ERROR),undefined,options});// return and don't process further if the payload could not be stringified
730
734
  return;}}const xhr=new XMLHttpRequest();// eslint-disable-next-line @typescript-eslint/no-unused-vars
731
- const xhrReject=e=>{reject({error:new Error(XHR_DELIVERY_ERROR(FAILED_REQUEST_ERR_MSG_PREFIX,xhr.status,xhr.statusText,options.url,xhr.responseText)),xhr,options});};const xhrError=e=>{reject({error:new Error(XHR_REQUEST_ERROR(FAILED_REQUEST_ERR_MSG_PREFIX,e,options.url)),xhr,options});};xhr.ontimeout=xhrError;xhr.onerror=xhrError;xhr.onload=()=>{if(xhr.status>=200&&xhr.status<400){resolve({response:xhr.responseText,xhr,options});}else {xhrReject();}};xhr.open(options.method,options.url,true);if(options.withCredentials===true){xhr.withCredentials=true;}// The timeout property may be set only in the time interval between a call to the open method
735
+ const xhrReject=e=>{reject({error:new Error(XHR_DELIVERY_ERROR(FAILED_REQUEST_ERR_MSG_PREFIX,xhr.status,xhr.statusText,options.url,xhr.responseText)),xhr,options});};const xhrError=e=>{reject({error:new Error(XHR_REQUEST_ERROR(FAILED_REQUEST_ERR_MSG_PREFIX,e,options.url)),xhr,options,...(e?.type==='timeout'?{timedOut:true}:{})});};xhr.ontimeout=xhrError;xhr.onerror=xhrError;xhr.onload=()=>{if(xhr.status>=200&&xhr.status<400){resolve({response:xhr.responseText,xhr,options});}else {xhrReject();}};xhr.open(options.method,options.url,true);if(options.withCredentials===true){xhr.withCredentials=true;}// The timeout property may be set only in the time interval between a call to the open method
732
736
  // and the first call to the send method in legacy browsers
733
737
  xhr.timeout=timeout;Object.keys(options.headers).forEach(headerName=>{if(options.headers[headerName]){xhr.setRequestHeader(headerName,options.headers[headerName]);}});try{xhr.send(payload);}catch(err){reject({error:getMutatedError(err,XHR_SEND_ERROR(FAILED_REQUEST_ERR_MSG_PREFIX,options.url)),xhr,options});}});
734
738
 
@@ -740,7 +744,7 @@ xhr.timeout=timeout;Object.keys(options.headers).forEach(headerName=>{if(options
740
744
  * Implement requests in a non-blocking way
741
745
  */getAsyncData(config){const{callback,url,options,timeout,isRawResponse}=config;const isFireAndForget=!isFunction(callback);xhrRequest(createXhrRequestOptions(url,options,this.basicAuthHeader),timeout,this.logger).then(data=>{if(!isFireAndForget){callback(isRawResponse?data.response:responseTextToJson(data.response,this.onError),data);}}).catch(data=>{if(!isFireAndForget){callback(undefined,data);}});}/**
742
746
  * Handle errors
743
- */onError(error){this.errorHandler?.onError(error,HTTP_CLIENT);}/**
747
+ */onError(error,groupingHash){this.errorHandler?.onError({error,context:HTTP_CLIENT,groupingHash});}/**
744
748
  * Set basic authentication header (eg writekey)
745
749
  */setAuthHeader(value,noBtoa=false){const authVal=noBtoa?value:toBase64(`${value}:`);this.basicAuthHeader=`Basic ${authVal}`;}/**
746
750
  * Clear basic authentication header
@@ -773,7 +777,18 @@ if(INTEGRATIONS_LOAD_FAILURE_MESSAGES.some(regex=>regex.test(errMsg))){return er
773
777
  * @returns
774
778
  */const isSDKError=exception=>{const errorOrigin=exception.stacktrace[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return false;}const srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);const paths=errorOrigin.split('/');// extract the parent folder name from the error origin file path
775
779
  // Ex: parentFolderName will be 'sample' for url: https://example.com/sample/file.min.js
776
- const parentFolderName=paths[paths.length-2];return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(prefix=>srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js'));};const getErrorDeliveryPayload=(payload,state)=>{const data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType},errors:payload};return stringifyWithoutCircular(data);};
780
+ const parentFolderName=paths[paths.length-2];return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(prefix=>srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js'));};const getErrorDeliveryPayload=(payload,state)=>{const data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType},errors:payload};return stringifyWithoutCircular(data);};/**
781
+ * A function to get the grouping hash value to be used for the error event.
782
+ * Grouping hash is suppressed for non-cdn installs.
783
+ * If the grouping hash is an error instance, the normalized error message is used as the grouping hash.
784
+ * If the grouping hash is an empty string or not specified, the default grouping hash is used.
785
+ * If the grouping hash is a string, it is used as is.
786
+ * @param curErrGroupingHash The grouping hash value part of the error event
787
+ * @param defaultGroupingHash The default grouping hash value. It is the error message.
788
+ * @param state The application state
789
+ * @param logger The logger instance
790
+ * @returns The final grouping hash value to be used for the error event
791
+ */const getErrorGroupingHash=(curErrGroupingHash,defaultGroupingHash,state,logger)=>{let normalizedGroupingHash;if(state.context.app.value.installType!=='cdn'){return normalizedGroupingHash;}if(!isDefined(curErrGroupingHash)){normalizedGroupingHash=defaultGroupingHash;}else if(isString(curErrGroupingHash)){normalizedGroupingHash=curErrGroupingHash;}else {const normalizedErrorInstance=normalizeError(curErrGroupingHash,logger);if(isDefined(normalizedErrorInstance)){normalizedGroupingHash=normalizedErrorInstance.message;}else {normalizedGroupingHash=defaultGroupingHash;}}return normalizedGroupingHash;};
777
792
 
778
793
  /**
779
794
  * A service to handle errors
@@ -783,13 +798,15 @@ constructor(httpClient,logger){this.httpClient=httpClient;this.logger=logger;}/*
783
798
  * This method should be called once after construction.
784
799
  */init(){if(this.initialized){return;}this.attachErrorListeners();this.initialized=true;}/**
785
800
  * Attach error listeners to the global window object
786
- */attachErrorListeners(){globalThis.addEventListener('error',event=>{this.onError(event,ERROR_HANDLER,undefined,ErrorType.UNHANDLEDEXCEPTION);});globalThis.addEventListener('unhandledrejection',event=>{this.onError(event,ERROR_HANDLER,undefined,ErrorType.UNHANDLEDREJECTION);});}/**
801
+ */attachErrorListeners(){globalThis.addEventListener('error',event=>{this.onError({error:event,context:ERROR_HANDLER,errorType:ErrorType.UNHANDLEDEXCEPTION});});globalThis.addEventListener('unhandledrejection',event=>{this.onError({error:event,context:ERROR_HANDLER,errorType:ErrorType.UNHANDLEDREJECTION});});}/**
787
802
  * Handle errors
788
- * @param error - The error to handle
789
- * @param context - The context of where the error occurred
790
- * @param customMessage - The custom message of the error
791
- * @param errorType - The type of the error (handled or unhandled)
792
- */onError(error,context='',customMessage='',errorType=ErrorType.HANDLEDEXCEPTION){try{const errInstance=getErrInstance(error,errorType);const normalizedError=normalizeError(errInstance,this.logger);if(isUndefined(normalizedError)){return;}const customMsgVal=customMessage?`${customMessage} - `:'';const errorMsgPrefix=`${context}${LOG_CONTEXT_SEPARATOR}${customMsgVal}`;const bsException=createBugsnagException(normalizedError,errorMsgPrefix);const stacktrace=getStacktrace(normalizedError);const isSdkDispatched=stacktrace.includes(MANUAL_ERROR_IDENTIFIER);// Filter errors that are not originated in the SDK.
803
+ * @param errorInfo - The error information
804
+ * @param errorInfo.error - The error to handle
805
+ * @param errorInfo.context - The context of where the error occurred
806
+ * @param errorInfo.customMessage - The custom message of the error
807
+ * @param errorInfo.errorType - The type of the error (handled or unhandled)
808
+ * @param errorInfo.groupingHash - The grouping hash of the error
809
+ */onError(errorInfo){try{const{error,context,customMessage,groupingHash}=errorInfo;const errorType=errorInfo.errorType??ErrorType.HANDLEDEXCEPTION;const errInstance=getErrInstance(error,errorType);const normalizedError=normalizeError(errInstance,this.logger);if(isUndefined(normalizedError)){return;}const customMsgVal=customMessage?`${customMessage} - `:'';const errorMsgPrefix=`${context}${LOG_CONTEXT_SEPARATOR}${customMsgVal}`;const bsException=createBugsnagException(normalizedError,errorMsgPrefix);const stacktrace=getStacktrace(normalizedError);const isSdkDispatched=stacktrace.includes(MANUAL_ERROR_IDENTIFIER);// Filter errors that are not originated in the SDK.
793
810
  // In case of NPM installations, the unhandled errors from the SDK cannot be identified
794
811
  // and will NOT be reported unless they occur in plugins or integrations.
795
812
  if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCEPTION){return;}if(state.reporting.isErrorReportingEnabled.value&&isAllowedToBeNotified(bsException)){const errorState={severity:'error',unhandled:errorType!==ErrorType.HANDLEDEXCEPTION,severityReason:{type:errorType}};// Set grouping hash only for CDN installations (as an experiment)
@@ -798,10 +815,8 @@ if(!isSdkDispatched&&!isSDKError(bsException)&&errorType!==ErrorType.HANDLEDEXCE
798
815
  // References:
799
816
  // https://docs.bugsnag.com/platforms/javascript/customizing-error-reports/#groupinghash
800
817
  // https://docs.bugsnag.com/product/error-grouping/#user_defined
801
- // const groupingHash =
802
- // state.context.app.value.installType === 'cdn' ? bsException.message : undefined;
803
- // Get the final payload to be sent to the metrics service
804
- const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state);// send it to metrics service
818
+ const normalizedGroupingHash=getErrorGroupingHash(groupingHash,bsException.message,state,this.logger);// Get the final payload to be sent to the metrics service
819
+ const bugsnagPayload=getBugsnagErrorEvent(bsException,errorState,state,normalizedGroupingHash);// send it to metrics service
805
820
  this.httpClient.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state),sendRawData:true},isRawResponse:true});}// Log handled errors and errors dispatched by the SDK
806
821
  if(errorType===ErrorType.HANDLEDEXCEPTION||isSdkDispatched){this.logger.error(bsException.message);}}catch(err){// If an error occurs while handling an error, log it
807
822
  this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**
@@ -809,7 +824,7 @@ this.logger.error(HANDLE_ERROR_FAILURE(ERROR_HANDLER),err);}}/**
809
824
  * occurred and send to external error monitoring service via a plugin
810
825
  *
811
826
  * @param {string} breadcrumb breadcrumbs message
812
- */leaveBreadcrumb(breadcrumb){try{state.reporting.breadcrumbs.value=[...state.reporting.breadcrumbs.value,createNewBreadcrumb(breadcrumb)];}catch(err){this.onError(err,BREADCRUMB_ERROR(ERROR_HANDLER));}}}// Note: Remember to call defaultErrorHandler.init() before using it
827
+ */leaveBreadcrumb(breadcrumb){try{state.reporting.breadcrumbs.value=[...state.reporting.breadcrumbs.value,createNewBreadcrumb(breadcrumb)];}catch(err){this.onError({error:err,context:ERROR_HANDLER,customMessage:BREADCRUMB_ERROR,groupingHash:BREADCRUMB_ERROR});}}}// Note: Remember to call defaultErrorHandler.init() before using it
813
828
  const defaultErrorHandler=new ErrorHandler(defaultHttpClient,defaultLogger);
814
829
 
815
830
  // to next or return the value if it is the last one instead of an array per
@@ -880,6 +895,7 @@ const userIdKey='rl_user_id';const userTraitsKey='rl_trait';const anonymousUserI
880
895
  const encryptBrowser=value=>`${ENCRYPTION_PREFIX_V3}${toBase64(value)}`;const decryptBrowser=value=>{if(value?.startsWith(ENCRYPTION_PREFIX_V3)){return fromBase64(value.substring(ENCRYPTION_PREFIX_V3.length));}return value;};
881
896
 
882
897
  const EVENT_PAYLOAD_SIZE_BYTES_LIMIT=32*1024;// 32 KB
898
+ const RETRY_REASON_CLIENT_NETWORK='client-network';const RETRY_REASON_CLIENT_TIMEOUT='client-timeout';const DEFAULT_RETRY_REASON=RETRY_REASON_CLIENT_NETWORK;
883
899
 
884
900
  const EVENT_PAYLOAD_SIZE_CHECK_FAIL_WARNING=(context,payloadSize,sizeLimit)=>`${context}${LOG_CONTEXT_SEPARATOR}The size of the event payload (${payloadSize} bytes) exceeds the maximum limit of ${sizeLimit} bytes. Events with large payloads may be dropped in the future. Please review your instrumentation to ensure that event payloads are within the size limit.`;const EVENT_PAYLOAD_SIZE_VALIDATION_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to validate event payload size. Please make sure that the event payload is within the size limit and is a valid JSON object.`;const QUEUE_UTILITIES='QueueUtilities';/**
885
901
  * Utility to get the stringified event payload
@@ -900,7 +916,7 @@ finalEvent.sentAt=currentTime;return finalEvent;};
900
916
 
901
917
  const QueueStatuses={IN_PROGRESS:'inProgress',QUEUE:'queue',RECLAIM_START:'reclaimStart',RECLAIM_END:'reclaimEnd',ACK:'ack',BATCH_QUEUE:'batchQueue'};
902
918
 
903
- const BEACON_PLUGIN_EVENTS_QUEUE_DEBUG=context=>`${context}${LOG_CONTEXT_SEPARATOR}Sending events to data plane.`;const BEACON_QUEUE_STRING_CONVERSION_FAILURE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to convert events batch object to string.`;const BEACON_QUEUE_BLOB_CONVERSION_FAILURE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to convert events batch object to Blob.`;const BEACON_QUEUE_SEND_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to send events batch data to the browser's beacon queue.`;const BEACON_QUEUE_DELIVERY_ERROR=url=>`Failed to send events batch data to the browser's beacon queue for URL ${url}.`;
919
+ const BEACON_PLUGIN_EVENTS_QUEUE_DEBUG=context=>`${context}${LOG_CONTEXT_SEPARATOR}Sending events to data plane.`;const BEACON_QUEUE_STRING_CONVERSION_FAILURE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to convert events batch object to string.`;const BEACON_QUEUE_BLOB_CONVERSION_FAILURE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to convert events batch object to Blob.`;const BEACON_QUEUE_SEND_ERROR=(context,url)=>`${context}${LOG_CONTEXT_SEPARATOR}${BEACON_QUEUE_DELIVERY_ERROR(url)}`;const BEACON_QUEUE_DELIVERY_ERROR=url=>`Failed to send events batch data to the browser's beacon queue for URL ${url}.`;
904
920
 
905
921
  const DEFAULT_BEACON_QUEUE_MAX_SIZE=10;const DEFAULT_BEACON_QUEUE_FLUSH_INTERVAL_MS=10*60*1000;// 10 minutes
906
922
  // Limit of the Beacon transfer mechanism on the browsers
@@ -981,23 +997,23 @@ this.setStorageEntry(QueueStatuses.BATCH_QUEUE,batchQueue);return curEntry;}push
981
997
  * Adds an item to the retry queue
982
998
  *
983
999
  * @param {Object} qItem The item to process
984
- */requeue(qItem){const{attemptNumber,item,type,id,firstAttemptedAt,lastAttemptedAt,reclaimed}=qItem;// Increment the attempt number as we're about to retry
985
- const attemptNumberToUse=attemptNumber+1;if(this.shouldRetry(item,attemptNumberToUse)){this.enqueue({item,attemptNumber:attemptNumberToUse,time:this.schedule.now()+this.getDelay(attemptNumberToUse),id:id??generateUUID(),type,firstAttemptedAt,lastAttemptedAt,reclaimed});}}/**
1000
+ */requeue(qItem){const{attemptNumber,item,type,id,firstAttemptedAt,lastAttemptedAt,reclaimed,retryReason}=qItem;// Increment the attempt number as we're about to retry
1001
+ const attemptNumberToUse=attemptNumber+1;if(this.shouldRetry(item,attemptNumberToUse)){this.enqueue({item,attemptNumber:attemptNumberToUse,time:this.schedule.now()+this.getDelay(attemptNumberToUse),id:id??generateUUID(),type,firstAttemptedAt,lastAttemptedAt,reclaimed,retryReason});}}/**
986
1002
  * Returns the information about whether the batch criteria is met or exceeded
987
1003
  * @param batchItems Prospective batch items
988
1004
  * @returns Batch dispatch info
989
1005
  */getBatchDispatchInfo(batchItems){let lengthCriteriaMet=false;let lengthCriteriaExceeded=false;const configuredBatchMaxItems=this.batch?.maxItems;if(isDefined(configuredBatchMaxItems)){lengthCriteriaMet=batchItems.length===configuredBatchMaxItems;lengthCriteriaExceeded=batchItems.length>configuredBatchMaxItems;}if(lengthCriteriaMet||lengthCriteriaExceeded){return {criteriaMet:lengthCriteriaMet,criteriaExceeded:lengthCriteriaExceeded};}let sizeCriteriaMet=false;let sizeCriteriaExceeded=false;const configuredBatchMaxSize=this.batch?.maxSize;if(isDefined(configuredBatchMaxSize)&&isDefined(this.batchSizeCalcCb)){const curBatchSize=this.batchSizeCalcCb(batchItems.map(queueItem=>queueItem.item));sizeCriteriaMet=curBatchSize===configuredBatchMaxSize;sizeCriteriaExceeded=curBatchSize>configuredBatchMaxSize;}return {criteriaMet:sizeCriteriaMet,criteriaExceeded:sizeCriteriaExceeded};}processHead(){// cancel the scheduled task if it exists
990
1006
  this.schedule.cancel(this.processId);// Pop the head off the queue
991
1007
  let queue=this.getStorageEntry(QueueStatuses.QUEUE)??[];const now=this.schedule.now();const toRun=[];// eslint-disable-next-line @typescript-eslint/no-unused-vars
992
- const processItemCallback=(el,id)=>(err,res)=>{const inProgress=this.getStorageEntry(QueueStatuses.IN_PROGRESS)??{};const inProgressItem=inProgress[id];const firstAttemptedAt=inProgressItem?.firstAttemptedAt;const lastAttemptedAt=inProgressItem?.lastAttemptedAt;delete inProgress[id];this.setStorageEntry(QueueStatuses.IN_PROGRESS,inProgress);if(err){this.requeue({...el,firstAttemptedAt,lastAttemptedAt});}};const enqueueItem=(el,id)=>{toRun.push({id,item:el.item,done:processItemCallback(el,id),attemptNumber:el.attemptNumber});};const inProgress=this.getStorageEntry(QueueStatuses.IN_PROGRESS)??{};let inProgressSize=Object.keys(inProgress).length;// eslint-disable-next-line no-plusplus
1008
+ const processItemCallback=(el,id)=>(err,res)=>{const inProgress=this.getStorageEntry(QueueStatuses.IN_PROGRESS)??{};const inProgressItem=inProgress[id];const firstAttemptedAt=inProgressItem?.firstAttemptedAt;const lastAttemptedAt=inProgressItem?.lastAttemptedAt;delete inProgress[id];this.setStorageEntry(QueueStatuses.IN_PROGRESS,inProgress);if(err){this.requeue({...el,firstAttemptedAt,lastAttemptedAt,retryReason:res?.retryReason??DEFAULT_RETRY_REASON});}};const enqueueItem=(el,id)=>{toRun.push({id,item:el.item,done:processItemCallback(el,id),attemptNumber:el.attemptNumber});};const inProgress=this.getStorageEntry(QueueStatuses.IN_PROGRESS)??{};let inProgressSize=Object.keys(inProgress).length;// eslint-disable-next-line no-plusplus
993
1009
  while(queue.length>0&&queue[0].time<=now&&inProgressSize++<this.maxItems){const el=queue.shift();if(el){const id=generateUUID();// Save this to the in progress map
994
1010
  inProgress[id]={item:el.item,attemptNumber:el.attemptNumber,time:this.schedule.now(),type:el.type,firstAttemptedAt:el.firstAttemptedAt,lastAttemptedAt:el.lastAttemptedAt,reclaimed:el.reclaimed};enqueueItem(el,id);}}this.setStorageEntry(QueueStatuses.QUEUE,queue);this.setStorageEntry(QueueStatuses.IN_PROGRESS,inProgress);toRun.forEach(el=>{// TODO: handle processQueueCb timeout
995
- try{const now=this.schedule.now();const inProgress=this.getStorageEntry(QueueStatuses.IN_PROGRESS)??{};const inProgressItem=inProgress[el.id];let firstAttemptedAt=now;let lastAttemptedAt=now;let reclaimed=false;if(inProgressItem){firstAttemptedAt=inProgressItem.firstAttemptedAt??firstAttemptedAt;lastAttemptedAt=inProgressItem.lastAttemptedAt??lastAttemptedAt;// Indicates if the item has been reclaimed from local storage
1011
+ try{const now=this.schedule.now();const inProgress=this.getStorageEntry(QueueStatuses.IN_PROGRESS)??{};const inProgressItem=inProgress[el.id];let firstAttemptedAt=now;let lastAttemptedAt=now;let reclaimed=false;let retryReason=DEFAULT_RETRY_REASON;if(inProgressItem){retryReason=inProgressItem.retryReason??retryReason;firstAttemptedAt=inProgressItem.firstAttemptedAt??firstAttemptedAt;lastAttemptedAt=inProgressItem.lastAttemptedAt??lastAttemptedAt;// Indicates if the item has been reclaimed from local storage
996
1012
  reclaimed=inProgressItem.reclaimed??reclaimed;// Update the first attempted at timestamp for the in progress item
997
1013
  inProgressItem.firstAttemptedAt=firstAttemptedAt;// Update the last attempted at to current timestamp for the in progress item
998
- inProgressItem.lastAttemptedAt=now;inProgress[el.id]=inProgressItem;this.setStorageEntry(QueueStatuses.IN_PROGRESS,inProgress);}// A decimal integer representing the seconds since the first attempt
999
- const timeSinceFirstAttempt=Math.round((now-firstAttemptedAt)/1000);// A decimal integer representing the seconds since the last attempt
1000
- const timeSinceLastAttempt=Math.round((now-lastAttemptedAt)/1000);const willBeRetried=this.shouldRetry(el.item,el.attemptNumber+1);this.processQueueCb(el.item,el.done,{retryAttemptNumber:el.attemptNumber,maxRetryAttempts:this.maxAttempts,willBeRetried,timeSinceFirstAttempt,timeSinceLastAttempt,reclaimed,isPageAccessible:this.isPageAccessible});}catch(err){let errMsg='';if(el.attemptNumber<this.maxAttempts){errMsg='The item will be requeued.';if(el.attemptNumber>0){errMsg=`${errMsg} Retry attempt ${el.attemptNumber} of ${this.maxAttempts}.`;}// requeue the item to be retried
1014
+ inProgressItem.lastAttemptedAt=now;inProgress[el.id]=inProgressItem;this.setStorageEntry(QueueStatuses.IN_PROGRESS,inProgress);}// A decimal integer representing the milliseconds since the first attempt
1015
+ const timeSinceFirstAttempt=now-firstAttemptedAt;// A decimal integer representing the milliseconds since the last attempt
1016
+ const timeSinceLastAttempt=now-lastAttemptedAt;const willBeRetried=this.shouldRetry(el.item,el.attemptNumber+1);this.processQueueCb(el.item,el.done,{retryAttemptNumber:el.attemptNumber,maxRetryAttempts:this.maxAttempts,willBeRetried,timeSinceFirstAttempt,timeSinceLastAttempt,reclaimed,isPageAccessible:this.isPageAccessible,retryReason});}catch(err){let errMsg='';if(el.attemptNumber<this.maxAttempts){errMsg='The item will be requeued.';if(el.attemptNumber>0){errMsg=`${errMsg} Retry attempt ${el.attemptNumber} of ${this.maxAttempts}.`;}// requeue the item to be retried
1001
1017
  el.done(err);}else {errMsg=`Retries exhausted (${this.maxAttempts}). The item will be dropped.`;// drop the event as we're unable to process it
1002
1018
  // after the max attempts are exhausted
1003
1019
  el.done();}this.logger?.error(RETRY_QUEUE_PROCESS_ERROR(RETRY_QUEUE,errMsg),err);}});// re-read the queue in case the process function finished immediately or added another item
@@ -1005,10 +1021,10 @@ queue=this.getStorageEntry(QueueStatuses.QUEUE)??[];this.schedule.cancel(this.pr
1005
1021
  ack(){this.setStorageEntry(QueueStatuses.ACK,this.schedule.now());if(this.reclaimStartVal!=null){this.reclaimStartVal=null;this.setStorageEntry(QueueStatuses.RECLAIM_START,null);}if(this.reclaimEndVal!=null){this.reclaimEndVal=null;this.setStorageEntry(QueueStatuses.RECLAIM_END,null);}this.schedule.run(this.ack,this.timeouts.ackTimer,ScheduleModes.ASAP);}reclaim(id){const other=this.storeManager.setStore({id,name:this.name,validKeys:QueueStatuses,type:LOCAL_STORAGE,errorHandler:this.storeManager.errorHandler,logger:this.storeManager.logger});const our={queue:this.getStorageEntry(QueueStatuses.QUEUE)??[]};const their={inProgress:other.get(QueueStatuses.IN_PROGRESS)??{},batchQueue:other.get(QueueStatuses.BATCH_QUEUE)??[],queue:other.get(QueueStatuses.QUEUE)??[]};const trackMessageIds=[];const addConcatQueue=(queue,incrementAttemptNumberBy)=>{const concatIterator=el=>{const id=el.id??generateUUID();if(trackMessageIds.includes(id));else {// Hack to determine the item type by the contents of the entry
1006
1022
  // After some point, we can remove this hack as most of the stale data will have been processed
1007
1023
  // and the new entries will have the type field set
1008
- const type=Array.isArray(el.item)?BATCH_QUEUE_ITEM_TYPE:SINGLE_QUEUE_ITEM_TYPE;our.queue.push({item:el.item,attemptNumber:el.attemptNumber+incrementAttemptNumberBy,time:this.schedule.now(),id,type:el.type??type,firstAttemptedAt:el.firstAttemptedAt,lastAttemptedAt:el.lastAttemptedAt,// Mark the item as reclaimed from local storage
1024
+ const type=Array.isArray(el.item)?BATCH_QUEUE_ITEM_TYPE:SINGLE_QUEUE_ITEM_TYPE;our.queue.push({item:el.item,attemptNumber:el.attemptNumber+incrementAttemptNumberBy,time:this.schedule.now(),id,type:el.type??type,firstAttemptedAt:el.firstAttemptedAt,lastAttemptedAt:el.lastAttemptedAt,retryReason:el.retryReason,// Mark the item as reclaimed from local storage
1009
1025
  reclaimed:true});trackMessageIds.push(id);}};if(Array.isArray(queue)){queue.forEach(concatIterator);}else if(queue){Object.values(queue).forEach(concatIterator);}};// add their queue to ours, resetting run-time to immediate and copying the attempt#
1010
1026
  addConcatQueue(their.queue,0);// Process batch queue items
1011
- if(this.batch.enabled){their.batchQueue.forEach(el=>{const id=el.id??generateUUID();if(trackMessageIds.includes(id));else {this.enqueue({...el,id,// Mark the item as reclaimed from local storage
1027
+ if(this.batch.enabled){their.batchQueue.forEach(el=>{const id=el.id??generateUUID();if(trackMessageIds.includes(id));else {this.enqueue({...el,id,retryReason:el.retryReason,// Mark the item as reclaimed from local storage
1012
1028
  reclaimed:true,type:el.type??SINGLE_QUEUE_ITEM_TYPE,time:this.schedule.now()});trackMessageIds.push(id);}});}else {// if batching is not enabled in the current instance, add those items to the main queue directly
1013
1029
  addConcatQueue(their.batchQueue,0);}// if the queue is abandoned, all the in-progress are failed. retry them immediately and increment the attempt#
1014
1030
  addConcatQueue(their.inProgress,1);our.queue.sort(sortByTime);this.setStorageEntry(QueueStatuses.QUEUE,our.queue);// remove all keys one by on next tick to avoid NS_ERROR_STORAGE_BUSY error
@@ -1029,10 +1045,10 @@ const pluginName$d='BeaconQueue';const BeaconQueue=()=>({name:pluginName$d,deps:
1029
1045
  * @param logger Logger instance
1030
1046
  * @returns BeaconItemsQueue instance
1031
1047
  */init(state,httpClient,storeManager,errorHandler,logger){const writeKey=state.lifecycle.writeKey.value;const dataplaneUrl=state.lifecycle.activeDataplaneUrl.value;const url=getDeliveryUrl$1(dataplaneUrl,writeKey);const finalQOpts=getNormalizedBeaconQueueOptions(state.loadOptions.value.beaconQueueOptions??{});const queueProcessCallback=(itemData,done,info)=>{const{isPageAccessible}=info;logger?.debug(BEACON_PLUGIN_EVENTS_QUEUE_DEBUG(BEACON_QUEUE_PLUGIN));const currentTime=getCurrentTimeFormatted();const finalEvents=itemData.map(queueItemData=>getFinalEventForDeliveryMutator(queueItemData.event,currentTime));const data=getBatchDeliveryPayload$1(finalEvents,currentTime,logger);if(!data){// Mark the item as done so that it can be removed from the queue
1032
- done(null);return;}try{if(!navigator.sendBeacon(url,data)){if(isPageAccessible){logger?.error(`${BEACON_QUEUE_SEND_ERROR(BEACON_QUEUE_PLUGIN)} The event(s) will be dropped.`);// Remove the item from queue
1048
+ done(null);return;}try{if(!navigator.sendBeacon(url,data)){if(isPageAccessible){logger?.error(`${BEACON_QUEUE_SEND_ERROR(BEACON_QUEUE_PLUGIN,url)} The event(s) will be dropped.`);// Remove the item from queue
1033
1049
  done(null);}else {// Note: We're not removing the item from the queue as we want to retry the request
1034
- logger?.warn(`${BEACON_QUEUE_SEND_ERROR(BEACON_QUEUE_PLUGIN)} The event(s) will be retried as the current page is being unloaded.`);}}else {// Remove the item from queue as the request was successful
1035
- done(null);}}catch(err){errorHandler?.onError(err,BEACON_QUEUE_PLUGIN,BEACON_QUEUE_DELIVERY_ERROR(url));// Remove the item from queue
1050
+ logger?.warn(`${BEACON_QUEUE_SEND_ERROR(BEACON_QUEUE_PLUGIN,url)} The event(s) will be retried as the current page is being unloaded.`);}}else {// Remove the item from queue as the request was successful
1051
+ done(null);}}catch(err){errorHandler?.onError({error:err,context:BEACON_QUEUE_PLUGIN,customMessage:BEACON_QUEUE_DELIVERY_ERROR(url)});// Remove the item from queue
1036
1052
  done(null);}};const eventsQueue=new RetryQueue(`${QUEUE_NAME$3}_${writeKey}`,{batch:{enabled:true,flushInterval:finalQOpts.flushQueueInterval,maxSize:MAX_BATCH_PAYLOAD_SIZE_BYTES,// set the hard limit
1037
1053
  maxItems:finalQOpts.maxItems}},queueProcessCallback,storeManager,LOCAL_STORAGE,logger,itemData=>{const currentTime=getCurrentTimeFormatted();const events=itemData.map(queueItemData=>queueItemData.event);// type casting to Blob as we know that the event has already been validated prior to enqueue
1038
1054
  return getBatchDeliveryPayload$1(events,currentTime,logger).size;});return eventsQueue;},/**
@@ -1058,14 +1074,14 @@ if(!consentManagement){return true;}// Get the corresponding consents for the de
1058
1074
  const cmpConfig=consentManagement.find(c=>c.provider===state.consents.provider.value);// If there are no consents configured for the destination for the current provider, events should be sent.
1059
1075
  if(!cmpConfig?.consents){return true;}const configuredConsents=cmpConfig.consents.map(c=>c.consent.trim()).filter(n=>n);const resolutionStrategy=cmpConfig.resolutionStrategy??state.consents.resolutionStrategy.value;// match the configured consents with user provided consents as per
1060
1076
  // the configured resolution strategy
1061
- const matchPredicate=consent=>allowedConsentIds.includes(consent);switch(resolutionStrategy){case 'or':return configuredConsents.some(matchPredicate)||configuredConsents.length===0;case 'and':default:return configuredConsents.every(matchPredicate);}}catch(err){errorHandler?.onError(err,CUSTOM_CONSENT_MANAGER_PLUGIN,DESTINATION_CONSENT_STATUS_ERROR$3);return true;}}}});
1077
+ const matchPredicate=consent=>allowedConsentIds.includes(consent);switch(resolutionStrategy){case 'or':return configuredConsents.some(matchPredicate)||configuredConsents.length===0;case 'and':default:return configuredConsents.every(matchPredicate);}}catch(err){errorHandler?.onError({error:err,context:CUSTOM_CONSENT_MANAGER_PLUGIN,customMessage:DESTINATION_CONSENT_STATUS_ERROR$3});return true;}}}});
1062
1078
 
1063
1079
  const READY_CHECK_TIMEOUT_MS=11*1000;// 11 seconds
1064
1080
  const SCRIPT_LOAD_TIMEOUT_MS=10*1000;// 10 seconds
1065
1081
  const READY_CHECK_INTERVAL_MS=100;// 100 milliseconds
1066
1082
  const DEVICE_MODE_DESTINATIONS_PLUGIN='DeviceModeDestinationsPlugin';
1067
1083
 
1068
- const DESTINATION_NOT_SUPPORTED_ERROR=destUserFriendlyId=>`Destination ${destUserFriendlyId} is not supported.`;const DESTINATION_SDK_LOAD_ERROR=(context,destUserFriendlyId)=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to load script for destination ${destUserFriendlyId}.`;const DESTINATION_INIT_ERROR=destUserFriendlyId=>`Failed to initialize destination ${destUserFriendlyId}.`;const DESTINATION_INTEGRATIONS_DATA_ERROR=destUserFriendlyId=>`Failed to get integrations data for destination ${destUserFriendlyId}.`;const DESTINATION_READY_TIMEOUT_ERROR=(timeout,destUserFriendlyId)=>`A timeout of ${timeout} ms occurred while trying to check the ready status for "${destUserFriendlyId}" destination.`;
1084
+ const INTEGRATION_NOT_SUPPORTED_ERROR=destDisplayName=>`Integration for destination "${destDisplayName}" is not supported.`;const INTEGRATION_SDK_LOAD_ERROR=destDisplayName=>`Failed to load integration SDK for destination "${destDisplayName}"`;const INTEGRATION_INIT_ERROR=destUserFriendlyId=>`Failed to initialize integration for destination "${destUserFriendlyId}".`;const INTEGRATIONS_DATA_ERROR=destUserFriendlyId=>`Failed to get integrations data for destination "${destUserFriendlyId}".`;const INTEGRATION_READY_TIMEOUT_ERROR=timeout=>`A timeout of ${timeout} ms occurred`;const INTEGRATION_READY_CHECK_ERROR=id=>`Failed to get the ready status from integration for destination "${id}"`;
1069
1085
 
1070
1086
  const isDestIntgConfigTruthy=destIntgConfig=>!isUndefined(destIntgConfig)&&Boolean(destIntgConfig)===true;const isDestIntgConfigFalsy=destIntgConfig=>!isUndefined(destIntgConfig)&&Boolean(destIntgConfig)===false;/**
1071
1087
  * Filters the destinations that should not be loaded or forwarded events to based on the integration options (load or events API)
@@ -1247,34 +1263,67 @@ const destDisplayNamesToFileNamesMap={[HS_DISPLAY_NAME]:DIR_NAME$X,[GA_DISPLAY_N
1247
1263
  * @param sdkTypeName The name of the destination SDK type
1248
1264
  * @param logger Logger instance
1249
1265
  * @returns true if the destination SDK code is evaluated, false otherwise
1250
- */const isDestinationSDKMounted=(destSDKIdentifier,sdkTypeName,logger)=>Boolean(globalThis[destSDKIdentifier]?.[sdkTypeName]?.prototype&&typeof globalThis[destSDKIdentifier][sdkTypeName].prototype.constructor!=='undefined');const wait=time=>new Promise(resolve=>{globalThis.setTimeout(resolve,time);});const createDestinationInstance=(destSDKIdentifier,sdkTypeName,dest,state)=>{const rAnalytics=globalThis.rudderanalytics;const analytics=rAnalytics.getAnalyticsInstance(state.lifecycle.writeKey.value);const analyticsInstance={loadIntegration:state.nativeDestinations.loadIntegration.value,logLevel:state.lifecycle.logLevel.value,loadOnlyIntegrations:state.consents.postConsent.value?.integrations??state.nativeDestinations.loadOnlyIntegrations.value,page:(category,name,properties,options,callback)=>analytics.page(pageArgumentsToCallOptions(getSanitizedValue(category),getSanitizedValue(name),getSanitizedValue(properties),getSanitizedValue(options),getSanitizedValue(callback))),track:(event,properties,options,callback)=>analytics.track(trackArgumentsToCallOptions(getSanitizedValue(event),getSanitizedValue(properties),getSanitizedValue(options),getSanitizedValue(callback))),identify:(userId,traits,options,callback)=>analytics.identify(identifyArgumentsToCallOptions(getSanitizedValue(userId),getSanitizedValue(traits),getSanitizedValue(options),getSanitizedValue(callback))),alias:(to,from,options,callback)=>analytics.alias(aliasArgumentsToCallOptions(getSanitizedValue(to),getSanitizedValue(from),getSanitizedValue(options),getSanitizedValue(callback))),group:(groupId,traits,options,callback)=>analytics.group(groupArgumentsToCallOptions(getSanitizedValue(groupId),getSanitizedValue(traits),getSanitizedValue(options),getSanitizedValue(callback))),getAnonymousId:options=>analytics.getAnonymousId(getSanitizedValue(options)),getUserId:()=>analytics.getUserId(),getUserTraits:()=>analytics.getUserTraits(),getGroupId:()=>analytics.getGroupId(),getGroupTraits:()=>analytics.getGroupTraits(),getSessionId:()=>analytics.getSessionId()};const deviceModeDestination=new globalThis[destSDKIdentifier][sdkTypeName](clone(dest.config),analyticsInstance,{shouldApplyDeviceModeTransformation:dest.shouldApplyDeviceModeTransformation,propagateEventsUntransformedOnError:dest.propagateEventsUntransformedOnError,destinationId:dest.id});return deviceModeDestination;};const isDestinationReady=(dest,time=0)=>new Promise((resolve,reject)=>{const instance=dest.instance;if(instance.isLoaded()&&(!instance.isReady||instance.isReady())){resolve(true);}else if(time>=READY_CHECK_TIMEOUT_MS){reject(new Error(DESTINATION_READY_TIMEOUT_ERROR(READY_CHECK_TIMEOUT_MS,dest.userFriendlyId)));}else {const curTime=Date.now();wait(READY_CHECK_INTERVAL_MS).then(()=>{const elapsedTime=Date.now()-curTime;isDestinationReady(dest,time+elapsedTime).then(resolve).catch(err=>reject(err));});}});/**
1266
+ */const isDestinationSDKMounted=(destSDKIdentifier,sdkTypeName,logger)=>Boolean(globalThis[destSDKIdentifier]?.[sdkTypeName]?.prototype&&typeof globalThis[destSDKIdentifier][sdkTypeName].prototype.constructor!=='undefined');const wait=time=>new Promise(resolve=>{globalThis.setTimeout(resolve,time);});const createDestinationInstance=(destSDKIdentifier,sdkTypeName,dest,state)=>{const rAnalytics=globalThis.rudderanalytics;const analytics=rAnalytics.getAnalyticsInstance(state.lifecycle.writeKey.value);const analyticsInstance={loadIntegration:state.nativeDestinations.loadIntegration.value,logLevel:state.lifecycle.logLevel.value,loadOnlyIntegrations:state.consents.postConsent.value?.integrations??state.nativeDestinations.loadOnlyIntegrations.value,page:(category,name,properties,options,callback)=>analytics.page(pageArgumentsToCallOptions(getSanitizedValue(category),getSanitizedValue(name),getSanitizedValue(properties),getSanitizedValue(options),getSanitizedValue(callback))),track:(event,properties,options,callback)=>analytics.track(trackArgumentsToCallOptions(getSanitizedValue(event),getSanitizedValue(properties),getSanitizedValue(options),getSanitizedValue(callback))),identify:(userId,traits,options,callback)=>analytics.identify(identifyArgumentsToCallOptions(getSanitizedValue(userId),getSanitizedValue(traits),getSanitizedValue(options),getSanitizedValue(callback))),alias:(to,from,options,callback)=>analytics.alias(aliasArgumentsToCallOptions(getSanitizedValue(to),getSanitizedValue(from),getSanitizedValue(options),getSanitizedValue(callback))),group:(groupId,traits,options,callback)=>analytics.group(groupArgumentsToCallOptions(getSanitizedValue(groupId),getSanitizedValue(traits),getSanitizedValue(options),getSanitizedValue(callback))),getAnonymousId:options=>analytics.getAnonymousId(getSanitizedValue(options)),getUserId:()=>analytics.getUserId(),getUserTraits:()=>analytics.getUserTraits(),getGroupId:()=>analytics.getGroupId(),getGroupTraits:()=>analytics.getGroupTraits(),getSessionId:()=>analytics.getSessionId()};const deviceModeDestination=new globalThis[destSDKIdentifier][sdkTypeName](clone(dest.config),analyticsInstance,{shouldApplyDeviceModeTransformation:dest.shouldApplyDeviceModeTransformation,propagateEventsUntransformedOnError:dest.propagateEventsUntransformedOnError,destinationId:dest.id});return deviceModeDestination;};const isDestinationReady=(dest,time=0)=>new Promise((resolve,reject)=>{const instance=dest.instance;if(instance.isLoaded()&&(!instance.isReady||instance.isReady())){resolve(true);}else if(time>=READY_CHECK_TIMEOUT_MS){reject(new Error(INTEGRATION_READY_TIMEOUT_ERROR(READY_CHECK_TIMEOUT_MS)));}else {const curTime=Date.now();wait(READY_CHECK_INTERVAL_MS).then(()=>{const elapsedTime=Date.now()-curTime;isDestinationReady(dest,time+elapsedTime).then(resolve).catch(err=>reject(err));});}});/**
1251
1267
  * Extracts the integration config, if any, from the given destination
1252
1268
  * and merges it with the current integrations config
1253
1269
  * @param dest Destination object
1254
1270
  * @param curDestIntgConfig Current destinations integration config
1255
1271
  * @param logger Logger object
1256
1272
  * @returns Combined destinations integrations config
1257
- */const getCumulativeIntegrationsConfig=(dest,curDestIntgConfig,errorHandler)=>{let integrationsConfig=curDestIntgConfig;if(isFunction(dest.instance?.getDataForIntegrationsObject)){try{integrationsConfig=mergeDeepRight(curDestIntgConfig,getSanitizedValue(dest.instance?.getDataForIntegrationsObject()));}catch(err){errorHandler?.onError(err,DEVICE_MODE_DESTINATIONS_PLUGIN,DESTINATION_INTEGRATIONS_DATA_ERROR(dest.userFriendlyId));}}return integrationsConfig;};const initializeDestination=(dest,state,destSDKIdentifier,sdkTypeName,errorHandler,logger)=>{try{const initializedDestination=clone(dest);const destInstance=createDestinationInstance(destSDKIdentifier,sdkTypeName,dest,state);initializedDestination.instance=destInstance;destInstance.init();isDestinationReady(initializedDestination).then(()=>{// Collect the integrations data for the hybrid mode destinations
1258
- if(isHybridModeDestination(initializedDestination)){state.nativeDestinations.integrationsConfig.value=getCumulativeIntegrationsConfig(initializedDestination,state.nativeDestinations.integrationsConfig.value,errorHandler);}state.nativeDestinations.initializedDestinations.value=[...state.nativeDestinations.initializedDestinations.value,initializedDestination];}).catch(err=>{state.nativeDestinations.failedDestinations.value=[...state.nativeDestinations.failedDestinations.value,dest];// The error message is already formatted in the isDestinationReady function
1259
- logger?.error(err);});}catch(err){state.nativeDestinations.failedDestinations.value=[...state.nativeDestinations.failedDestinations.value,dest];errorHandler?.onError(err,DEVICE_MODE_DESTINATIONS_PLUGIN,DESTINATION_INIT_ERROR(dest.userFriendlyId));}};
1273
+ */const getCumulativeIntegrationsConfig=(dest,curDestIntgConfig,errorHandler)=>{let integrationsConfig=curDestIntgConfig;if(isFunction(dest.instance?.getDataForIntegrationsObject)){try{integrationsConfig={...curDestIntgConfig,...getSanitizedValue(dest.instance.getDataForIntegrationsObject())};}catch(err){errorHandler?.onError({error:err,context:DEVICE_MODE_DESTINATIONS_PLUGIN,customMessage:INTEGRATIONS_DATA_ERROR(dest.userFriendlyId),groupingHash:INTEGRATIONS_DATA_ERROR(dest.displayName)});}}return integrationsConfig;};const initializeDestination=(dest,state,destSDKIdentifier,sdkTypeName,errorHandler,logger)=>{try{const initializedDestination=clone(dest);const destInstance=createDestinationInstance(destSDKIdentifier,sdkTypeName,dest,state);initializedDestination.instance=destInstance;destInstance.init();isDestinationReady(initializedDestination).then(()=>{// Collect the integrations data for the hybrid mode destinations
1274
+ if(isHybridModeDestination(initializedDestination)){state.nativeDestinations.integrationsConfig.value=getCumulativeIntegrationsConfig(initializedDestination,state.nativeDestinations.integrationsConfig.value,errorHandler);}state.nativeDestinations.initializedDestinations.value=[...state.nativeDestinations.initializedDestinations.value,initializedDestination];}).catch(err=>{state.nativeDestinations.failedDestinations.value=[...state.nativeDestinations.failedDestinations.value,dest];errorHandler?.onError({error:err,context:DEVICE_MODE_DESTINATIONS_PLUGIN,customMessage:INTEGRATION_READY_CHECK_ERROR(dest.userFriendlyId),groupingHash:INTEGRATION_READY_CHECK_ERROR(dest.displayName)});});}catch(err){state.nativeDestinations.failedDestinations.value=[...state.nativeDestinations.failedDestinations.value,dest];errorHandler?.onError({error:err,context:DEVICE_MODE_DESTINATIONS_PLUGIN,customMessage:INTEGRATION_INIT_ERROR(dest.userFriendlyId),groupingHash:INTEGRATION_INIT_ERROR(dest.displayName)});}};/**
1275
+ * Applies source configuration overrides to destinations
1276
+ * @param destinations Array of destinations to process
1277
+ * @param sourceConfigOverride Source configuration override options
1278
+ * @param logger Logger instance for warnings
1279
+ * @returns Array of destinations with overrides applied
1280
+ */const applySourceConfigurationOverrides=(destinations,sourceConfigOverride,logger)=>{if(!sourceConfigOverride?.destinations?.length){return filterDisabledDestination(destinations);}const destIds=destinations.map(dest=>dest.id);// Group overrides by destination ID to support future cloning
1281
+ // When cloning is implemented, multiple overrides with same ID will create multiple destination instances
1282
+ const overridesByDestId={};sourceConfigOverride.destinations.forEach(override=>{const existing=overridesByDestId[override.id]||[];existing.push(override);overridesByDestId[override.id]=existing;});// Find unmatched destination IDs and log warning
1283
+ const unmatchedIds=Object.keys(overridesByDestId).filter(id=>!destIds.includes(id));if(unmatchedIds.length>0){logger?.warn(`${DEVICE_MODE_DESTINATIONS_PLUGIN}:: Source configuration override - Unable to identify the destinations with the following IDs: "${unmatchedIds.join(', ')}"`);}// Process overrides and apply them to destinations
1284
+ const processedDestinations=[];destinations.forEach(dest=>{const overrides=overridesByDestId[dest.id];if(!overrides||overrides.length===0){// No override for this destination, keep original
1285
+ processedDestinations.push(dest);return;}if(overrides.length>1){// Multiple overrides for the same destination, create clones
1286
+ overrides.forEach((override,index)=>{const overriddenDestination=applyOverrideToDestination(dest,override,`${index+1}`);overriddenDestination.cloned=true;processedDestinations.push(overriddenDestination);});}else {const overriddenDestination=applyOverrideToDestination(dest,overrides[0]);processedDestinations.push(overriddenDestination);}});return filterDisabledDestination(processedDestinations);};/**
1287
+ * This function filters out disabled destinations from the provided array.
1288
+ * @param destinations Array of destinations to filter
1289
+ * @returns Filtered destinations to only include enabled ones
1290
+ */const filterDisabledDestination=destinations=>destinations.filter(dest=>dest.enabled);/**
1291
+ * Applies a single override configuration to a destination
1292
+ * @param destination Original destination
1293
+ * @param override Override configuration
1294
+ * @param cloneId Unique identifier for the clone,
1295
+ * if provided, the value is appended to the id and userFriendlyId of the destination
1296
+ * @returns Modified destination with override applied
1297
+ */const applyOverrideToDestination=(destination,override,cloneId)=>{// Check if any changes are needed
1298
+ const isEnabledStatusChanged=isBoolean(override.enabled)&&override.enabled!==destination.enabled;// Check if config is provided
1299
+ const isConfigChanged=isNonEmptyObject(override.config);// Determine the final enabled status after applying overrides
1300
+ const finalEnabledStatus=isBoolean(override.enabled)?override.enabled:destination.enabled;// Check if config will actually be applied (only for enabled destinations)
1301
+ const willApplyConfig=isConfigChanged&&finalEnabledStatus;// If no changes needed and no cloneId, return original destination
1302
+ if(!isEnabledStatusChanged&&!willApplyConfig&&!cloneId){return destination;}// Clone destination and apply overrides
1303
+ const clonedDest=clone(destination);if(cloneId){clonedDest.id=`${destination.id}_${cloneId}`;clonedDest.userFriendlyId=`${destination.userFriendlyId}_${cloneId}`;}// Apply enabled status override if provided and different
1304
+ if(isEnabledStatusChanged){clonedDest.enabled=override.enabled;// Mark as overridden
1305
+ clonedDest.overridden=true;}// Apply config overrides if provided for enabled destination
1306
+ if(willApplyConfig){// Override the config with the new config and remove undefined and null values
1307
+ clonedDest.config=removeUndefinedAndNullValues({...clonedDest.config,...override.config});clonedDest.overridden=true;}return clonedDest;};
1260
1308
 
1261
1309
  const pluginName$b='DeviceModeDestinations';const DeviceModeDestinations=()=>({name:pluginName$b,initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$b];},nativeDestinations:{setActiveDestinations(state,pluginsManager,errorHandler,logger){state.nativeDestinations.loadIntegration.value=state.loadOptions.value.loadIntegration;// Filter destination that doesn't have mapping config-->Integration names
1262
- const configSupportedDestinations=state.nativeDestinations.configuredDestinations.value.filter(configDest=>{if(destDisplayNamesToFileNamesMap[configDest.displayName]){return true;}errorHandler?.onError(new Error(DESTINATION_NOT_SUPPORTED_ERROR(configDest.userFriendlyId)),DEVICE_MODE_DESTINATIONS_PLUGIN);return false;});// Filter destinations that are disabled through load or consent API options
1263
- const destinationsToLoad=filterDestinations(state.consents.postConsent.value?.integrations??state.nativeDestinations.loadOnlyIntegrations.value,configSupportedDestinations);const consentedDestinations=destinationsToLoad.filter(dest=>// if consent manager is not configured, then default to load the destination
1310
+ const configSupportedDestinations=state.nativeDestinations.configuredDestinations.value.filter(configDest=>{if(destDisplayNamesToFileNamesMap[configDest.displayName]){return true;}const errMessage=INTEGRATION_NOT_SUPPORTED_ERROR(configDest.displayName);errorHandler?.onError({error:new Error(errMessage),context:DEVICE_MODE_DESTINATIONS_PLUGIN});return false;});// Apply source configuration overrides if provided
1311
+ const destinationsWithOverrides=state.loadOptions.value.sourceConfigurationOverride?applySourceConfigurationOverrides(configSupportedDestinations,state.loadOptions.value.sourceConfigurationOverride,logger):configSupportedDestinations;// Filter destinations that are disabled through load or consent API options
1312
+ const destinationsToLoad=filterDestinations(state.consents.postConsent.value?.integrations??state.nativeDestinations.loadOnlyIntegrations.value,destinationsWithOverrides);const consentedDestinations=destinationsToLoad.filter(dest=>// if consent manager is not configured, then default to load the destination
1264
1313
  pluginsManager.invokeSingle(`consentManager.isDestinationConsented`,state,dest.config,errorHandler,logger)??true);state.nativeDestinations.activeDestinations.value=consentedDestinations;},load(state,externalSrcLoader,errorHandler,logger,externalScriptOnLoad){const integrationsCDNPath=state.lifecycle.integrationsCDNPath.value;const activeDestinations=state.nativeDestinations.activeDestinations.value;activeDestinations.forEach(dest=>{const sdkName=destDisplayNamesToFileNamesMap[dest.displayName];const destSDKIdentifier=`${sdkName}_RS`;// this is the name of the object loaded on the window
1265
- const sdkTypeName=sdkName;if(sdkTypeName&&!isDestinationSDKMounted(destSDKIdentifier,sdkTypeName)){const destSdkURL=`${integrationsCDNPath}/${sdkName}.min.js`;externalSrcLoader.loadJSFile({url:destSdkURL,id:dest.userFriendlyId,callback:externalScriptOnLoad??(id=>{if(!id){logger?.error(DESTINATION_SDK_LOAD_ERROR(DEVICE_MODE_DESTINATIONS_PLUGIN,dest.userFriendlyId));state.nativeDestinations.failedDestinations.value=[...state.nativeDestinations.failedDestinations.value,dest];}else {initializeDestination(dest,state,destSDKIdentifier,sdkTypeName,errorHandler,logger);}}),timeout:SCRIPT_LOAD_TIMEOUT_MS});}else if(sdkTypeName){initializeDestination(dest,state,destSDKIdentifier,sdkTypeName,errorHandler,logger);}else {logger?.error(DESTINATION_SDK_LOAD_ERROR(DEVICE_MODE_DESTINATIONS_PLUGIN,dest.displayName));}});}}});
1314
+ const sdkTypeName=sdkName;if(sdkTypeName&&!isDestinationSDKMounted(destSDKIdentifier,sdkTypeName)){const destSdkURL=`${integrationsCDNPath}/${sdkName}.min.js`;externalSrcLoader.loadJSFile({url:destSdkURL,id:dest.userFriendlyId,callback:externalScriptOnLoad??((id,err)=>{if(err){const customMessage=INTEGRATION_SDK_LOAD_ERROR(dest.displayName);errorHandler?.onError({error:err,context:DEVICE_MODE_DESTINATIONS_PLUGIN,customMessage,groupingHash:customMessage});state.nativeDestinations.failedDestinations.value=[...state.nativeDestinations.failedDestinations.value,dest];}else {initializeDestination(dest,state,destSDKIdentifier,sdkTypeName,errorHandler);}}),timeout:SCRIPT_LOAD_TIMEOUT_MS});}else {initializeDestination(dest,state,destSDKIdentifier,sdkTypeName,errorHandler);}});}}});
1266
1315
 
1267
1316
  const DEFAULT_TRANSFORMATION_QUEUE_OPTIONS={minRetryDelay:500,backoffFactor:2,maxAttempts:3};const REQUEST_TIMEOUT_MS$1=10*1000;// 10 seconds
1268
1317
  const QUEUE_NAME$2='rudder';const DMT_PLUGIN='DeviceModeTransformationPlugin';
1269
1318
 
1270
- const DMT_TRANSFORMATION_UNSUCCESSFUL_ERROR=(context,displayName,reason,action)=>`${context}${LOG_CONTEXT_SEPARATOR}Event transformation unsuccessful for destination "${displayName}". Reason: ${reason}. ${action}.`;const DMT_REQUEST_FAILED_ERROR=(context,displayName,status,action)=>`${context}${LOG_CONTEXT_SEPARATOR}[Destination: ${displayName}].Transformation request failed with status: ${status}. Retries exhausted. ${action}.`;const DMT_EXCEPTION=displayName=>`[Destination:${displayName}].`;const DMT_SERVER_ACCESS_DENIED_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}Transformation server access is denied. The configuration data seems to be out of sync. Sending untransformed event to the destination.`;
1319
+ const DMT_TRANSFORMATION_UNSUCCESSFUL_ERROR=(context,displayName,reason,action)=>`${context}${LOG_CONTEXT_SEPARATOR}Event transformation unsuccessful for destination "${displayName}". Reason: ${reason}. ${action}.`;const DMT_REQUEST_FAILED_ERROR=(context,displayName,status,action)=>`${context}${LOG_CONTEXT_SEPARATOR}[Destination: ${displayName}].Transformation request failed with status: ${status}. Retries exhausted. ${action}.`;const DMT_EXCEPTION=displayName=>`Transformation failed for destination "${displayName}"`;const DMT_SERVER_ACCESS_DENIED_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}Transformation server access is denied. The configuration data seems to be out of sync. Sending untransformed event to the destination.`;
1271
1320
 
1272
1321
  /**
1273
1322
  * A helper function that will take rudderEvent and generate
1274
1323
  * a batch payload that will be sent to transformation server
1275
1324
  *
1276
1325
  */const createPayload=(event,destinationIds,token)=>{const orderNo=Date.now();const payload={metadata:{'Custom-Authorization':token},batch:[{orderNo,destinationIds,event}]};return payload;};const sendTransformedEventToDestinations=(state,pluginsManager,destinationIds,result,status,event,errorHandler,logger)=>{const NATIVE_DEST_EXT_POINT='destinationsEventsQueue.enqueueEventToDestination';const ACTION_TO_SEND_UNTRANSFORMED_EVENT='Sending untransformed event';const ACTION_TO_DROP_EVENT='Dropping the event';const destinations=state.nativeDestinations.initializedDestinations.value.filter(d=>d&&destinationIds.includes(d.id));destinations.forEach(dest=>{try{const eventsToSend=[];switch(status){case 200:{const response=JSON.parse(result);const destTransformedResult=response.transformedBatch.find(e=>e.id===dest.id);destTransformedResult?.payload.forEach(tEvent=>{if(tEvent.status==='200'){eventsToSend.push(tEvent.event);}else {let reason='Unknown';if(tEvent.status==='410'){reason='Transformation is not available';}let action=ACTION_TO_DROP_EVENT;if(dest.propagateEventsUntransformedOnError===true){action=ACTION_TO_SEND_UNTRANSFORMED_EVENT;eventsToSend.push(event);logger?.warn(DMT_TRANSFORMATION_UNSUCCESSFUL_ERROR(DMT_PLUGIN,dest.displayName,reason,action));}else {logger?.error(DMT_TRANSFORMATION_UNSUCCESSFUL_ERROR(DMT_PLUGIN,dest.displayName,reason,action));}}});break;}// Transformation server access denied
1277
- case 404:{logger?.warn(DMT_SERVER_ACCESS_DENIED_WARNING(DMT_PLUGIN));eventsToSend.push(event);break;}default:{if(dest.propagateEventsUntransformedOnError===true){logger?.warn(DMT_REQUEST_FAILED_ERROR(DMT_PLUGIN,dest.displayName,status,ACTION_TO_SEND_UNTRANSFORMED_EVENT));eventsToSend.push(event);}else {logger?.error(DMT_REQUEST_FAILED_ERROR(DMT_PLUGIN,dest.displayName,status,ACTION_TO_DROP_EVENT));}break;}}eventsToSend?.forEach(tEvent=>{if(isNonEmptyObject(tEvent)){pluginsManager.invokeSingle(NATIVE_DEST_EXT_POINT,state,tEvent,dest,errorHandler,logger);}});}catch(e){errorHandler?.onError(e,DMT_PLUGIN,DMT_EXCEPTION(dest.displayName));}});};
1326
+ case 404:{logger?.warn(DMT_SERVER_ACCESS_DENIED_WARNING(DMT_PLUGIN));eventsToSend.push(event);break;}default:{if(dest.propagateEventsUntransformedOnError===true){logger?.warn(DMT_REQUEST_FAILED_ERROR(DMT_PLUGIN,dest.displayName,status,ACTION_TO_SEND_UNTRANSFORMED_EVENT));eventsToSend.push(event);}else {logger?.error(DMT_REQUEST_FAILED_ERROR(DMT_PLUGIN,dest.displayName,status,ACTION_TO_DROP_EVENT));}break;}}eventsToSend?.forEach(tEvent=>{if(isNonEmptyObject(tEvent)){pluginsManager.invokeSingle(NATIVE_DEST_EXT_POINT,state,tEvent,dest,errorHandler,logger);}});}catch(err){errorHandler?.onError({error:err,context:DMT_PLUGIN,customMessage:DMT_EXCEPTION(dest.displayName)});}});};
1278
1327
 
1279
1328
  const pluginName$a='DeviceModeTransformation';const DeviceModeTransformation=()=>({name:pluginName$a,deps:[],initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$a];},transformEvent:{init(state,pluginsManager,httpClient,storeManager,errorHandler,logger){const writeKey=state.lifecycle.writeKey.value;httpClient.setAuthHeader(writeKey);const eventsQueue=new RetryQueue(// adding write key to the queue name to avoid conflicts
1280
1329
  `${QUEUE_NAME$2}_${writeKey}`,DEFAULT_TRANSFORMATION_QUEUE_OPTIONS,(item,done,qItemProcessInfo)=>{const payload=createPayload(item.event,item.destinationIds,item.token);httpClient.getAsyncData({url:`${state.lifecycle.activeDataplaneUrl.value}/transform`,options:{method:'POST',data:getDMTDeliveryPayload(payload),sendRawData:true},isRawResponse:true,timeout:REQUEST_TIMEOUT_MS$1,callback:(result,details)=>{const isRetryable=isErrRetryable(details?.xhr?.status??0);// If there is no error, or the error is not retryable, or the attempt number is the max retry attempts, then attempt send the event to the destinations
@@ -1415,7 +1464,7 @@ if(consentManagement){// Get the corresponding consents for the destination
1415
1464
  const cmpConfig=consentManagement.find(c=>c.provider===state.consents.provider.value);// If there are no consents configured for the destination for the current provider, events should be sent.
1416
1465
  if(!cmpConfig?.consents){return true;}const configuredConsents=cmpConfig.consents.map(c=>c.consent.trim()).filter(n=>n);const resolutionStrategy=cmpConfig.resolutionStrategy??state.consents.resolutionStrategy.value;// match the configured consents with user provided consents as per
1417
1466
  // the configured resolution strategy
1418
- switch(resolutionStrategy){case 'or':return configuredConsents.some(matchPredicate)||configuredConsents.length===0;case 'and':default:return configuredConsents.every(matchPredicate);}}return true;}catch(err){errorHandler?.onError(err,IUBENDA_CONSENT_MANAGER_PLUGIN,DESTINATION_CONSENT_STATUS_ERROR$2);return true;}}}});
1467
+ switch(resolutionStrategy){case 'or':return configuredConsents.some(matchPredicate)||configuredConsents.length===0;case 'and':default:return configuredConsents.every(matchPredicate);}}return true;}catch(err){errorHandler?.onError({error:err,context:IUBENDA_CONSENT_MANAGER_PLUGIN,customMessage:DESTINATION_CONSENT_STATUS_ERROR$2});return true;}}}});
1419
1468
 
1420
1469
  const KETCH_CONSENT_COOKIE_READ_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to read the consent cookie.`;const KETCH_CONSENT_COOKIE_PARSE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to parse the consent cookie.`;const DESTINATION_CONSENT_STATUS_ERROR$1=`Failed to determine the consent status for the destination. Please check the destination configuration and try again.`;
1421
1470
 
@@ -1451,17 +1500,21 @@ switch(state.consents.resolutionStrategy.value){case 'or':return configuredConse
1451
1500
  // TODO: To be removed once the source config API is updated to support generic consent management
1452
1501
  }else if(ketchConsentPurposes){const configuredConsents=ketchConsentPurposes.map(p=>p.purpose.trim()).filter(n=>n);// Check if any of the destination's mapped ketch purposes are consented by the user in the browser.
1453
1502
  return configuredConsents.some(matchPredicate)||configuredConsents.length===0;}// If there are no consents configured for the destination for the current provider, events should be sent.
1454
- return true;}catch(err){errorHandler?.onError(err,KETCH_CONSENT_MANAGER_PLUGIN,DESTINATION_CONSENT_STATUS_ERROR$1);return true;}}}});
1503
+ return true;}catch(err){errorHandler?.onError({error:err,context:KETCH_CONSENT_MANAGER_PLUGIN,customMessage:DESTINATION_CONSENT_STATUS_ERROR$1});return true;}}}});
1455
1504
 
1456
1505
  const DEFAULT_QUEUE_OPTIONS={maxItems:100};const QUEUE_NAME$1='rudder_destinations_events';const NATIVE_DESTINATION_QUEUE_PLUGIN='NativeDestinationQueuePlugin';
1457
1506
 
1458
- const DESTINATION_EVENT_FILTERING_WARNING=(context,eventName,destUserFriendlyId)=>`${context}${LOG_CONTEXT_SEPARATOR}The "${eventName}" track event has been filtered for the "${destUserFriendlyId}" destination.`;const DESTINATION_EVENT_FORWARDING_ERROR=destUserFriendlyId=>`Failed to forward event to destination "${destUserFriendlyId}".`;
1507
+ const DESTINATION_EVENT_FILTERING_WARNING=(context,eventName,destUserFriendlyId)=>`${context}${LOG_CONTEXT_SEPARATOR}The "${eventName}" track event has been filtered for the "${destUserFriendlyId}" destination.`;const INTEGRATION_EVENT_FORWARDING_ERROR=id=>`Failed to forward event to integration for destination "${id}".`;
1459
1508
 
1460
1509
  const getNormalizedQueueOptions$1=queueOpts=>mergeDeepRight(DEFAULT_QUEUE_OPTIONS,queueOpts);const isValidEventName=eventName=>eventName&&typeof eventName==='string';const isEventDenyListed=(eventType,eventName,dest)=>{if(eventType!=='track'){return false;}const{blacklistedEvents,whitelistedEvents,eventFilteringOption}=dest.config;switch(eventFilteringOption){// Blacklist is chosen for filtering events
1461
1510
  case 'blacklistedEvents':{if(!isValidEventName(eventName)){return false;}const trimmedEventName=eventName.trim();if(Array.isArray(blacklistedEvents)){return blacklistedEvents.some(eventObj=>eventObj.eventName.trim()===trimmedEventName);}return false;}// Whitelist is chosen for filtering events
1462
1511
  case 'whitelistedEvents':{if(!isValidEventName(eventName)){return true;}const trimmedEventName=eventName.trim();if(Array.isArray(whitelistedEvents)){return !whitelistedEvents.some(eventObj=>eventObj.eventName.trim()===trimmedEventName);}return true;}case 'disable':default:return false;}};const sendEventToDestination=(item,dest,errorHandler,logger)=>{const methodName=item.type.toString();try{// Destinations expect the event to be wrapped under the `message` key
1463
1512
  // This will remain until we update the destinations to accept the event directly
1464
- dest.instance?.[methodName]?.({message:item});}catch(err){errorHandler?.onError(err,NATIVE_DESTINATION_QUEUE_PLUGIN,DESTINATION_EVENT_FORWARDING_ERROR(dest.userFriendlyId));}};
1513
+ dest.instance?.[methodName]?.({message:item});}catch(err){errorHandler?.onError({error:err,context:NATIVE_DESTINATION_QUEUE_PLUGIN,customMessage:INTEGRATION_EVENT_FORWARDING_ERROR(dest.userFriendlyId),groupingHash:INTEGRATION_EVENT_FORWARDING_ERROR(dest.displayName)});}};/**
1514
+ * A function to check if device mode transformation should be applied for a destination.
1515
+ * @param dest Destination object
1516
+ * @returns Boolean indicating whether the transformation should be applied
1517
+ */const shouldApplyTransformation=dest=>{return dest.shouldApplyDeviceModeTransformation&&!dest.cloned;};
1465
1518
 
1466
1519
  const pluginName$5='NativeDestinationQueue';const NativeDestinationQueue=()=>({name:pluginName$5,deps:[],initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$5];},destinationsEventsQueue:{/**
1467
1520
  * Initialize the queue for delivery to destinations
@@ -1473,7 +1526,7 @@ const pluginName$5='NativeDestinationQueue';const NativeDestinationQueue=()=>({n
1473
1526
  * @returns IQueue instance
1474
1527
  */init(state,pluginsManager,storeManager,dmtQueue,errorHandler,logger){const finalQOpts=getNormalizedQueueOptions$1(state.loadOptions.value.destinationsQueueOptions);const writeKey=state.lifecycle.writeKey.value;const eventsQueue=new RetryQueue(// adding write key to the queue name to avoid conflicts
1475
1528
  `${QUEUE_NAME$1}_${writeKey}`,finalQOpts,(rudderEvent,done)=>{const destinationsToSend=filterDestinations(rudderEvent.integrations,state.nativeDestinations.initializedDestinations.value);// list of destinations which are enable for DMT
1476
- const destWithTransformationEnabled=[];const clonedRudderEvent=clone(rudderEvent);destinationsToSend.forEach(dest=>{try{const sendEvent=!isEventDenyListed(clonedRudderEvent.type,clonedRudderEvent.event,dest);if(!sendEvent){logger?.warn(DESTINATION_EVENT_FILTERING_WARNING(NATIVE_DESTINATION_QUEUE_PLUGIN,clonedRudderEvent.event,dest.userFriendlyId));return;}if(dest.shouldApplyDeviceModeTransformation){destWithTransformationEnabled.push(dest);}else {sendEventToDestination(clonedRudderEvent,dest,errorHandler,logger);}}catch(e){errorHandler?.onError(e,NATIVE_DESTINATION_QUEUE_PLUGIN);}});if(destWithTransformationEnabled.length>0){pluginsManager.invokeSingle('transformEvent.enqueue',state,dmtQueue,clonedRudderEvent,destWithTransformationEnabled,errorHandler,logger);}// Mark success always
1529
+ const destWithTransformationEnabled=[];const clonedRudderEvent=clone(rudderEvent);destinationsToSend.forEach(dest=>{try{const sendEvent=!isEventDenyListed(clonedRudderEvent.type,clonedRudderEvent.event,dest);if(!sendEvent){logger?.warn(DESTINATION_EVENT_FILTERING_WARNING(NATIVE_DESTINATION_QUEUE_PLUGIN,clonedRudderEvent.event,dest.userFriendlyId));return;}if(shouldApplyTransformation(dest)){destWithTransformationEnabled.push(dest);}else {sendEventToDestination(clonedRudderEvent,dest,errorHandler,logger);}}catch(e){errorHandler?.onError({error:e,context:NATIVE_DESTINATION_QUEUE_PLUGIN});}});if(destWithTransformationEnabled.length>0){pluginsManager.invokeSingle('transformEvent.enqueue',state,dmtQueue,clonedRudderEvent,destWithTransformationEnabled,errorHandler,logger);}// Mark success always
1477
1530
  done(null);},storeManager,MEMORY_STORAGE);// TODO: This seems to not work as expected. Need to investigate
1478
1531
  // effect(() => {
1479
1532
  // if (state.nativeDestinations.clientDestinationsReady.value === true) {
@@ -1520,7 +1573,7 @@ switch(state.consents.resolutionStrategy.value){case 'or':return configuredConse
1520
1573
  // ["Performance Cookies", "Functional Cookies"]
1521
1574
  const configuredConsents=oneTrustCookieCategories.map(c=>c.oneTrustCookieCategory.trim()).filter(n=>n);// Check if all the destination's mapped cookie categories are consented by the user in the browser.
1522
1575
  return configuredConsents.every(matchPredicate);}// If there are no consents configured for the destination for the current provider, events should be sent.
1523
- return true;}catch(err){errorHandler?.onError(err,ONETRUST_CONSENT_MANAGER_PLUGIN,DESTINATION_CONSENT_STATUS_ERROR);return true;}}}});
1576
+ return true;}catch(err){errorHandler?.onError({error:err,context:ONETRUST_CONSENT_MANAGER_PLUGIN,customMessage:DESTINATION_CONSENT_STATUS_ERROR});return true;}}}});
1524
1577
 
1525
1578
  const pluginName$3='StorageEncryption';const StorageEncryption=()=>({name:pluginName$3,initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$3];},storage:{encrypt(value){return encryptBrowser(value);},decrypt(value){return decryptBrowser(value);}}});
1526
1579
 
@@ -2495,7 +2548,7 @@ const encrypt=value=>`${ENCRYPTION_PREFIX_V1}${AES.encrypt(value,ENCRYPTION_KEY_
2495
2548
 
2496
2549
  const pluginName$2='StorageEncryptionLegacy';const StorageEncryptionLegacy=()=>({name:pluginName$2,initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$2];},storage:{encrypt(value){return encrypt(value);},decrypt(value){return decrypt(value);}}});
2497
2550
 
2498
- const STORAGE_MIGRATION_ERROR=key=>`Failed to retrieve or parse data for ${key} from storage.`;
2551
+ const STORAGE_MIGRATION_ERROR=key=>`Failed to retrieve or parse data for "${key}" from storage.`;
2499
2552
 
2500
2553
  const STORAGE_MIGRATOR_PLUGIN='StorageMigratorPlugin';
2501
2554
 
@@ -2507,7 +2560,7 @@ while(isString(currentVal)){decryptedVal=decrypt(currentVal);// Decrypt using th
2507
2560
  decryptedVal=decryptBrowser(decryptedVal);// If the decrypted value is the same as the current value,
2508
2561
  // then it's not encrypted anymore
2509
2562
  if(decryptedVal===currentVal){break;}// storejs that is used in localstorage engine already deserializes json strings but swallows errors
2510
- currentVal=JSON.parse(decryptedVal);}return currentVal;}catch(err){errorHandler?.onError(err,STORAGE_MIGRATOR_PLUGIN,STORAGE_MIGRATION_ERROR(key));return null;}}}});
2563
+ currentVal=JSON.parse(decryptedVal);}return currentVal;}catch(err){const customMessage=STORAGE_MIGRATION_ERROR(key);errorHandler?.onError({error:err,context:STORAGE_MIGRATOR_PLUGIN,customMessage,groupingHash:customMessage});return null;}}}});
2511
2564
 
2512
2565
  const DEFAULT_RETRY_QUEUE_OPTIONS={maxRetryDelay:360000,minRetryDelay:1000,backoffFactor:2,maxAttempts:10,maxItems:100};const REQUEST_TIMEOUT_MS=30*1000;// 30 seconds
2513
2566
  const DATA_PLANE_API_VERSION='v1';const QUEUE_NAME='rudder';const XHR_QUEUE_PLUGIN='XhrQueuePlugin';
@@ -2520,11 +2573,12 @@ logger.error(`${logMsg} ${dropMsg}`);}};const getRequestInfo=(itemData,state,qIt
2520
2573
  // The same value is added in the event payload as well
2521
2574
  headers.SentAt=currentTime;// Add a header to indicate if the item has been reclaimed from
2522
2575
  // local storage
2523
- if(qItemProcessInfo.reclaimed){headers.Reclaimed='true';}// Add retry headers if the item is being retried for delivery
2576
+ if(qItemProcessInfo.reclaimed){headers['Rsa-Recovered']='true';}// Add retry headers if the item is being retried for delivery
2524
2577
  if(qItemProcessInfo.retryAttemptNumber>0){// The number of times this item has been attempted to retry
2525
- headers['Retry-Attempt']=qItemProcessInfo.retryAttemptNumber.toString();// The number of seconds since the last attempt
2526
- headers['Retried-After']=qItemProcessInfo.timeSinceLastAttempt.toString();// The number of seconds since the first attempt
2527
- headers['Retried-After-First']=qItemProcessInfo.timeSinceFirstAttempt.toString();}return {data,headers,url};};
2578
+ headers['Rsa-Retry-Attempt']=qItemProcessInfo.retryAttemptNumber.toString();// The number of milliseconds since the last attempt
2579
+ headers['Rsa-Since-Last-Attempt']=qItemProcessInfo.timeSinceLastAttempt.toString();// The number of milliseconds since the first attempt
2580
+ headers['Rsa-Since-First-Attempt']=qItemProcessInfo.timeSinceFirstAttempt.toString();// The reason for the retry
2581
+ headers['Rsa-Retry-Reason']=qItemProcessInfo.retryReason;}return {data,headers,url};};
2528
2582
 
2529
2583
  const pluginName='XhrQueue';const XhrQueue=()=>({name:pluginName,deps:[],initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName];},dataplaneEventsQueue:{/**
2530
2584
  * Initialize the queue for delivery
@@ -2537,8 +2591,8 @@ const pluginName='XhrQueue';const XhrQueue=()=>({name:pluginName,deps:[],initial
2537
2591
  */init(state,httpClient,storeManager,errorHandler,logger){const writeKey=state.lifecycle.writeKey.value;httpClient.setAuthHeader(writeKey);const finalQOpts=getNormalizedQueueOptions(state.loadOptions.value.queueOptions);const eventsQueue=new RetryQueue(// adding write key to the queue name to avoid conflicts
2538
2592
  `${QUEUE_NAME}_${writeKey}`,finalQOpts,(itemData,done,qItemProcessInfo)=>{const{data,url,headers}=getRequestInfo(itemData,state,qItemProcessInfo,logger);httpClient.getAsyncData({url,options:{method:'POST',headers,data:data,sendRawData:true},isRawResponse:true,timeout:REQUEST_TIMEOUT_MS,callback:(result,details)=>{// If there is no error, we can consider the item as delivered
2539
2593
  if(isUndefined(details?.error)){// null means item will not be processed further and will be removed from the queue (even from the storage)
2540
- done(null);return;}const isRetryable=isErrRetryable(details?.xhr?.status??0);logMessageOnFailure(details,isRetryable,qItemProcessInfo,logger);// null means item will not be processed further and will be removed from the queue (even from the storage)
2541
- const queueErrResp=isRetryable?details:null;done(queueErrResp);}});},storeManager,LOCAL_STORAGE,logger,itemData=>{const currentTime=getCurrentTimeFormatted();const events=itemData.map(queueItemData=>queueItemData.event);// type casting to string as we know that the event has already been validated prior to enqueue
2594
+ done(null);return;}const isRetryable=isErrRetryable(details?.xhr?.status??0);logMessageOnFailure(details,isRetryable,qItemProcessInfo,logger);if(isRetryable){let retryReason=DEFAULT_RETRY_REASON;if(details?.timedOut){retryReason=RETRY_REASON_CLIENT_TIMEOUT;}else if(isDefined(details?.xhr?.status)){retryReason=`server-${details.xhr.status}`;}done(details,{retryReason});}else {// null means item will not be processed further and will be removed from the queue (even from the storage)
2595
+ done(null);}}});},storeManager,LOCAL_STORAGE,logger,itemData=>{const currentTime=getCurrentTimeFormatted();const events=itemData.map(queueItemData=>queueItemData.event);// type casting to string as we know that the event has already been validated prior to enqueue
2542
2596
  return getBatchDeliveryPayload(events,currentTime,logger)?.length;});return eventsQueue;},/**
2543
2597
  * Add event to the queue for delivery
2544
2598
  * @param state Application state
@@ -2591,16 +2645,16 @@ const availablePlugins=[...Object.keys(pluginsInventory),...pluginNamesList];con
2591
2645
  */registerLocalPlugins(){Object.values(pluginsInventory).forEach(localPlugin=>{if(isFunction(localPlugin)&&state.plugins.activePlugins.value.includes(localPlugin().name)){this.register([localPlugin()]);}});}/**
2592
2646
  * Register plugins that are dynamic imports to PluginEngine
2593
2647
  */registerRemotePlugins(){const remotePluginsList=remotePluginsInventory(state.plugins.activePlugins.value);Promise.all(Object.keys(remotePluginsList).map(async remotePluginKey=>{await remotePluginsList[remotePluginKey]().then(remotePluginModule=>this.register([remotePluginModule.default()])).catch(err=>{// TODO: add retry here if dynamic import fails
2594
- state.plugins.failedPlugins.value=[...state.plugins.failedPlugins.value,remotePluginKey];this.onError(err,remotePluginKey);});})).catch(err=>{this.onError(err);});}/**
2648
+ state.plugins.failedPlugins.value=[...state.plugins.failedPlugins.value,remotePluginKey];this.onError(err,`Failed to load plugin "${remotePluginKey}"`,err);});})).catch(err=>{this.onError(err);});}/**
2595
2649
  * Extension point invoke that allows multiple plugins to be registered to it with error handling
2596
2650
  */invokeMultiple(extPoint,...args){try{return this.engine.invokeMultiple(extPoint,...args);}catch(e){this.onError(e,extPoint);return [];}}/**
2597
2651
  * Extension point invoke that allows a single plugin to be registered to it with error handling
2598
2652
  */invokeSingle(extPoint,...args){try{return this.engine.invokeSingle(extPoint,...args);}catch(e){this.onError(e,extPoint);return null;}}/**
2599
2653
  * Plugin engine register with error handling
2600
- */register(plugins){plugins.forEach(plugin=>{try{this.engine.register(plugin,state);}catch(e){state.plugins.failedPlugins.value=[...state.plugins.failedPlugins.value,plugin.name];this.onError(e);}});}// TODO: Implement reset API instead
2601
- unregisterLocalPlugins(){Object.values(pluginsInventory).forEach(localPlugin=>{try{this.engine.unregister(localPlugin().name);}catch(e){this.onError(e);}});}/**
2654
+ */register(plugins){plugins.forEach(plugin=>{try{this.engine.register(plugin,state);}catch(e){state.plugins.failedPlugins.value=[...state.plugins.failedPlugins.value,plugin.name];this.onError(e,`Failed to register plugin "${plugin.name}"`);}});}// TODO: Implement reset API instead
2655
+ unregisterLocalPlugins(){Object.values(pluginsInventory).forEach(localPlugin=>{try{this.engine.unregister(localPlugin().name);}catch(e){this.onError(e,`Failed to unregister plugin "${localPlugin().name}"`);}});}/**
2602
2656
  * Handle errors
2603
- */onError(error,customMessage){this.errorHandler.onError(error,PLUGINS_MANAGER,customMessage);}}
2657
+ */onError(error,customMessage,groupingHash){this.errorHandler.onError({error,context:PLUGINS_MANAGER,customMessage,groupingHash});}}
2604
2658
 
2605
2659
  const STORAGE_TEST_COOKIE='test_rudder_cookie';const STORAGE_TEST_LOCAL_STORAGE='test_rudder_ls';const STORAGE_TEST_SESSION_STORAGE='test_rudder_ss';const STORAGE_TEST_TOP_LEVEL_DOMAIN='__tld__';const CLIENT_DATA_STORE_COOKIE='clientDataInCookie';const CLIENT_DATA_STORE_LS='clientDataInLocalStorage';const CLIENT_DATA_STORE_MEMORY='clientDataInMemory';const CLIENT_DATA_STORE_SESSION='clientDataInSessionStorage';const USER_SESSION_KEYS=['userId','userTraits','anonymousId','groupId','groupTraits','initialReferrer','initialReferringDomain','sessionInfo','authToken'];
2606
2660
 
@@ -2736,10 +2790,10 @@ this.remove(key);});this.engine=inMemoryStorage;}/**
2736
2790
  */set(key,value){const validKey=this.createValidKey(key);if(!validKey){return;}try{// storejs that is used in localstorage engine already stringifies json
2737
2791
  this.engine.setItem(validKey,this.encrypt(stringifyWithoutCircular(value,false,[],this.logger)));}catch(err){if(isStorageQuotaExceeded(err)){this.logger.warn(STORAGE_QUOTA_EXCEEDED_WARNING(`Store ${this.id}`));// switch to inMemory engine
2738
2792
  this.swapQueueStoreToInMemoryEngine();// and save it there
2739
- this.set(key,value);}else {this.onError(getMutatedError(err,STORE_DATA_SAVE_ERROR(key)));}}}/**
2793
+ this.set(key,value);}else {const customMessage=STORE_DATA_SAVE_ERROR(key);this.onError(err,customMessage,customMessage);}}}/**
2740
2794
  * Get by Key.
2741
- */get(key){const validKey=this.createValidKey(key);let decryptedValue;try{if(!validKey){return null;}decryptedValue=this.decrypt(this.engine.getItem(validKey));if(isNullOrUndefined(decryptedValue)){return null;}// storejs that is used in localstorage engine already deserializes json strings but swallows errors
2742
- return JSON.parse(decryptedValue);}catch(err){this.onError(new Error(`${STORE_DATA_FETCH_ERROR(key)}: ${err.message}`));return null;}}/**
2795
+ */get(key){const validKey=this.createValidKey(key);let decryptedValue;try{if(!validKey){return null;}decryptedValue=this.decrypt(this.engine.getItem(validKey));if(isNullOrUndefined(decryptedValue)||decryptedValue===''){return null;}// storejs that is used in localstorage engine already deserializes json strings but swallows errors
2796
+ return JSON.parse(decryptedValue);}catch(err){const customMessage=STORE_DATA_FETCH_ERROR(key);this.onError(err,customMessage,customMessage);return null;}}/**
2743
2797
  * Remove by Key.
2744
2798
  */remove(key){const validKey=this.createValidKey(key);if(validKey){this.engine.removeItem(validKey);}}/**
2745
2799
  * Get original engine
@@ -2751,7 +2805,7 @@ return JSON.parse(decryptedValue);}catch(err){this.onError(new Error(`${STORE_DA
2751
2805
  * Extension point to use with encryption plugins
2752
2806
  */crypto(value,mode){const noEncryption=!this.isEncrypted||!value||typeof value!=='string'||trim(value)==='';if(noEncryption){return value;}const extensionPointName=`storage.${mode}`;const formattedValue=this.pluginsManager?this.pluginsManager.invokeSingle(extensionPointName,value):value;return typeof formattedValue==='undefined'?value:formattedValue??'';}/**
2753
2807
  * Handle errors
2754
- */onError(error){this.errorHandler.onError(error,`Store ${this.id}`);}}
2808
+ */onError(error,customMessage,groupingHash){this.errorHandler.onError({error,context:`Store ${this.id}`,customMessage,groupingHash});}}
2755
2809
 
2756
2810
  const getStorageTypeFromPreConsentIfApplicable=(state,sessionKey)=>{let overriddenStorageType;if(state.consents.preConsent.value.enabled){switch(state.consents.preConsent.value.storage?.strategy){case 'none':overriddenStorageType=NO_STORAGE;break;case 'session':if(sessionKey!=='sessionInfo'){overriddenStorageType=NO_STORAGE;}break;case 'anonymousId':if(sessionKey!=='anonymousId'){overriddenStorageType=NO_STORAGE;}break;}}return overriddenStorageType;};
2757
2811
 
@@ -2782,13 +2836,6 @@ if(parts.length>2){// Join the last two parts for the top-level domain
2782
2836
  topDomain=`${parts[parts.length-2]}.${parts[parts.length-1]}`;}else {// If only two parts or less, return as it is
2783
2837
  topDomain=host;}return {topDomain,protocol};};const getTopDomainUrl=url=>{const{topDomain,protocol}=getTopDomain(url);return `${protocol}//${topDomain}`;};const getDataServiceUrl=(endpoint,useExactDomain)=>{const url=useExactDomain?window.location.origin:getTopDomainUrl(window.location.href);const formattedEndpoint=endpoint.startsWith('/')?endpoint.substring(1):endpoint;return `${url}/${formattedEndpoint}`;};const isWebpageTopLevelDomain=providedDomain=>{const{topDomain}=getTopDomain(window.location.href);return topDomain===providedDomain;};
2784
2838
 
2785
- /**
2786
- * A function to filter enabled destinations and map to required properties only
2787
- * @param destinations
2788
- *
2789
- * @returns Destination[]
2790
- */const filterEnabledDestination=destinations=>{const nativeDestinations=[];destinations.forEach(destination=>{if(destination.enabled&&!destination.deleted){nativeDestinations.push({id:destination.id,displayName:destination.destinationDefinition.displayName,config:destination.config,shouldApplyDeviceModeTransformation:destination.shouldApplyDeviceModeTransformation||false,propagateEventsUntransformedOnError:destination.propagateEventsUntransformedOnError||false,userFriendlyId:`${destination.destinationDefinition.displayName.replaceAll(' ','-')}___${destination.id}`});}});return nativeDestinations;};
2791
-
2792
2839
  /**
2793
2840
  * Removes trailing slash from url
2794
2841
  * @param url
@@ -2880,7 +2927,11 @@ enabled:state.loadOptions.value.preConsent?.enabled===true&&initialized===false&
2880
2927
  * @param resp Source config response
2881
2928
  * @param logger Logger instance
2882
2929
  */const updateConsentsState=resp=>{let resolutionStrategy=state.consents.resolutionStrategy.value;let cmpMetadata;if(isObjectLiteralAndNotNull(resp.consentManagementMetadata)){if(state.consents.provider.value){resolutionStrategy=resp.consentManagementMetadata.providers.find(p=>p.provider===state.consents.provider.value)?.resolutionStrategy??state.consents.resolutionStrategy.value;}cmpMetadata=resp.consentManagementMetadata;}// If the provider is custom, then the resolution strategy is not applicable
2883
- if(state.consents.provider.value==='custom'){resolutionStrategy=undefined;}r(()=>{state.consents.metadata.value=clone(cmpMetadata);state.consents.resolutionStrategy.value=resolutionStrategy;});};const updateDataPlaneEventsStateFromLoadOptions=logger=>{if(state.dataPlaneEvents.deliveryEnabled.value){const defaultEventsQueuePluginName='XhrQueue';let eventsQueuePluginName=defaultEventsQueuePluginName;if(state.loadOptions.value.useBeacon){if(state.capabilities.isBeaconAvailable.value){eventsQueuePluginName='BeaconQueue';}else {eventsQueuePluginName=defaultEventsQueuePluginName;logger.warn(UNSUPPORTED_BEACON_API_WARNING(CONFIG_MANAGER));}}r(()=>{state.dataPlaneEvents.eventsQueuePluginName.value=eventsQueuePluginName;});}};const getSourceConfigURL=(configUrl,writeKey,lockIntegrationsVersion,lockPluginsVersion,logger)=>{const defSearchParams=new URLSearchParams({p:MODULE_TYPE,v:APP_VERSION,build:BUILD_TYPE,writeKey,lockIntegrationsVersion:lockIntegrationsVersion.toString(),lockPluginsVersion:lockPluginsVersion.toString()});let origin=DEFAULT_CONFIG_BE_URL;let searchParams=defSearchParams;let pathname='/sourceConfig/';let hash='';if(isValidURL(configUrl)){const configUrlInstance=new URL(configUrl);if(!removeTrailingSlashes(configUrlInstance.pathname).endsWith('/sourceConfig')){configUrlInstance.pathname=`${removeTrailingSlashes(configUrlInstance.pathname)}/sourceConfig/`;}configUrlInstance.pathname=removeDuplicateSlashes(configUrlInstance.pathname);defSearchParams.forEach((value,key)=>{if(configUrlInstance.searchParams.get(key)===null){configUrlInstance.searchParams.set(key,value);}});origin=configUrlInstance.origin;pathname=configUrlInstance.pathname;searchParams=configUrlInstance.searchParams;hash=configUrlInstance.hash;}else {logger.warn(INVALID_CONFIG_URL_WARNING(CONFIG_MANAGER,configUrl));}return `${origin}${pathname}?${searchParams}${hash}`;};
2930
+ if(state.consents.provider.value==='custom'){resolutionStrategy=undefined;}r(()=>{state.consents.metadata.value=clone(cmpMetadata);state.consents.resolutionStrategy.value=resolutionStrategy;});};const updateDataPlaneEventsStateFromLoadOptions=logger=>{if(state.dataPlaneEvents.deliveryEnabled.value){const defaultEventsQueuePluginName='XhrQueue';let eventsQueuePluginName=defaultEventsQueuePluginName;if(state.loadOptions.value.useBeacon){if(state.capabilities.isBeaconAvailable.value){eventsQueuePluginName='BeaconQueue';}else {eventsQueuePluginName=defaultEventsQueuePluginName;logger.warn(UNSUPPORTED_BEACON_API_WARNING(CONFIG_MANAGER));}}r(()=>{state.dataPlaneEvents.eventsQueuePluginName.value=eventsQueuePluginName;});}};const getSourceConfigURL=(configUrl,writeKey,lockIntegrationsVersion,lockPluginsVersion,logger)=>{const defSearchParams=new URLSearchParams({p:MODULE_TYPE,v:APP_VERSION,build:BUILD_TYPE,writeKey,lockIntegrationsVersion:lockIntegrationsVersion.toString(),lockPluginsVersion:lockPluginsVersion.toString()});let origin=DEFAULT_CONFIG_BE_URL;let searchParams=defSearchParams;let pathname='/sourceConfig/';let hash='';if(isValidURL(configUrl)){const configUrlInstance=new URL(configUrl);if(!removeTrailingSlashes(configUrlInstance.pathname).endsWith('/sourceConfig')){configUrlInstance.pathname=`${removeTrailingSlashes(configUrlInstance.pathname)}/sourceConfig/`;}configUrlInstance.pathname=removeDuplicateSlashes(configUrlInstance.pathname);defSearchParams.forEach((value,key)=>{if(configUrlInstance.searchParams.get(key)===null){configUrlInstance.searchParams.set(key,value);}});origin=configUrlInstance.origin;pathname=configUrlInstance.pathname;searchParams=configUrlInstance.searchParams;hash=configUrlInstance.hash;}else {logger.warn(INVALID_CONFIG_URL_WARNING(CONFIG_MANAGER,configUrl));}return `${origin}${pathname}?${searchParams}${hash}`;};/**
2931
+ * Transforms destinations config from source config response to Destination format
2932
+ * @param destinations Array of destination items from config response
2933
+ * @returns Array of transformed Destination objects
2934
+ */const getDestinationsFromConfig=destinations=>destinations.map(destination=>({id:destination.id,displayName:destination.destinationDefinition.displayName,enabled:destination.enabled,config:destination.config,shouldApplyDeviceModeTransformation:destination.shouldApplyDeviceModeTransformation??false,propagateEventsUntransformedOnError:destination.propagateEventsUntransformedOnError??false,userFriendlyId:`${destination.destinationDefinition.displayName.replaceAll(' ','-')}___${destination.id}`}));
2884
2935
 
2885
2936
  /**
2886
2937
  * A function that determines the base URL for the integrations or plugins SDK
@@ -2915,14 +2966,14 @@ const intgCdnUrl=getIntegrationsCDNPath(APP_VERSION,lockIntegrationsVersion,dest
2915
2966
  r(()=>{state.lifecycle.integrationsCDNPath.value=intgCdnUrl;state.lifecycle.pluginsCDNPath.value=pluginsCDNPath;if(logLevel){state.lifecycle.logLevel.value=logLevel;}state.lifecycle.sourceConfigUrl.value=getSourceConfigURL(configUrl,state.lifecycle.writeKey.value,lockIntegrationsVersion,lockPluginsVersion,this.logger);state.metrics.metricsServiceUrl.value=`${state.lifecycle.activeDataplaneUrl.value}/${METRICS_SERVICE_ENDPOINT}`;// Data in the loadOptions state is already normalized
2916
2967
  state.nativeDestinations.loadOnlyIntegrations.value=integrations;});this.getConfig();}/**
2917
2968
  * Handle errors
2918
- */onError(error,customMessage){this.errorHandler.onError(error,CONFIG_MANAGER,customMessage);}/**
2969
+ */onError(error,customMessage,groupingHash){this.errorHandler.onError({error,context:CONFIG_MANAGER,customMessage,groupingHash});}/**
2919
2970
  * A callback function that is executed once we fetch the source config response.
2920
2971
  * Use to construct and store information that are dependent on the sourceConfig.
2921
2972
  */processConfig(response,details){// TODO: add retry logic with backoff based on rejectionDetails.xhr.status
2922
2973
  // We can use isErrRetryable utility method
2923
2974
  if(!isDefined(response)){if(isDefined(details)){this.onError(details.error,SOURCE_CONFIG_FETCH_ERROR);}else {this.onError(new Error(SOURCE_CONFIG_FETCH_ERROR));}return;}let res;try{if(isString(response)){res=JSON.parse(response);}else {res=response;}}catch(err){this.onError(err,SOURCE_CONFIG_RESOLUTION_ERROR);return;}if(!isValidSourceConfig(res)){this.onError(new Error(SOURCE_CONFIG_RESOLUTION_ERROR));return;}// Log error and abort if source is disabled
2924
2975
  if(res.source.enabled===false){this.logger.error(SOURCE_DISABLED_ERROR);return;}// set the values in state for reporting slice
2925
- updateReportingState(res);const nativeDestinations=res.source.destinations.length>0?filterEnabledDestination(res.source.destinations):[];// set in the state --> source, destination, lifecycle, reporting
2976
+ updateReportingState(res);const nativeDestinations=res.source.destinations.length>0?getDestinationsFromConfig(res.source.destinations):[];// set in the state --> source, destination, lifecycle, reporting
2926
2977
  r(()=>{// set source related information in state
2927
2978
  state.source.value={config:res.source.config,name:res.source.name,id:res.source.id,workspaceId:res.source.workspaceId};// set device mode destination related information in state
2928
2979
  state.nativeDestinations.configuredDestinations.value=nativeDestinations;// set the desired optional plugins
@@ -2966,7 +3017,7 @@ if(urlObj.search===''){pageUrl=canonicalUrl+search;}else {pageUrl=canonicalUrl;}
2966
3017
  const POLYFILL_URL=`https://polyfill-fastly.io/v3/polyfill.min.js?version=3.111.0&features=${Object.keys(legacyJSEngineRequiredPolyfills).join('%2C')}`;const POLYFILL_LOAD_TIMEOUT=10*1000;// 10 seconds
2967
3018
  const POLYFILL_SCRIPT_ID='rudderstackPolyfill';
2968
3019
 
2969
- class CapabilitiesManager{constructor(httpClient,errorHandler,logger){this.httpClient=httpClient;this.errorHandler=errorHandler;this.logger=logger;this.externalSrcLoader=new ExternalSrcLoader(this.errorHandler,this.logger);this.onError=this.onError.bind(this);this.onReady=this.onReady.bind(this);}init(){this.prepareBrowserCapabilities();this.attachWindowListeners();}/**
3020
+ class CapabilitiesManager{constructor(httpClient,errorHandler,logger){this.httpClient=httpClient;this.errorHandler=errorHandler;this.logger=logger;this.externalSrcLoader=new ExternalSrcLoader(this.logger);this.onError=this.onError.bind(this);this.onReady=this.onReady.bind(this);}init(){this.prepareBrowserCapabilities();this.attachWindowListeners();}/**
2970
3021
  * Detect supported capabilities and set values in state
2971
3022
  */// eslint-disable-next-line class-methods-use-this
2972
3023
  detectBrowserCapabilities(){r(()=>{// Storage related details
@@ -2986,7 +3037,7 @@ delete globalThis[polyfillCallbackName];};globalThis[polyfillCallbackName]=polyf
2986
3037
  onReady(){this.detectBrowserCapabilities();state.lifecycle.status.value='browserCapabilitiesReady';}/**
2987
3038
  * Handles error
2988
3039
  * @param error The error object
2989
- */onError(error){this.errorHandler.onError(error,CAPABILITIES_MANAGER);}}
3040
+ */onError(error,groupingHash){this.errorHandler.onError({error,context:CAPABILITIES_MANAGER,groupingHash});}}
2990
3041
 
2991
3042
  const CHANNEL='web';// These are the top-level elements in the standard RudderStack event spec
2992
3043
  const TOP_LEVEL_ELEMENTS=['integrations','anonymousId','originalTimestamp'];// Reserved elements in the context of standard RudderStack event spec
@@ -3155,7 +3206,7 @@ sessionInfo={// If manualTrack is set to true in the storage, then do not enable
3155
3206
  // Once manual tracking ends (endSession is called), auto tracking will be enabled in the next SDK run.
3156
3207
  autoTrack:configuredSessionTrackingInfo.autoTrack&&initialSessionInfo.manualTrack!==true,timeout:configuredSessionTrackingInfo.timeout,manualTrack:initialSessionInfo.manualTrack,expiresAt:initialSessionInfo.expiresAt,id:initialSessionInfo.id,sessionStart:initialSessionInfo.sessionStart};// If both autoTrack and manualTrack are disabled, reset the session info to default values
3157
3208
  if(!sessionInfo.autoTrack&&sessionInfo.manualTrack!==true){sessionInfo=DEFAULT_USER_SESSION_VALUES.sessionInfo;}else if(configuredSessionTrackingInfo.cutOff?.enabled===true){sessionInfo.cutOff={enabled:true,duration:configuredSessionTrackingInfo.cutOff.duration,expiresAt:initialSessionInfo.cutOff?.expiresAt};}}else {sessionInfo=DEFAULT_USER_SESSION_VALUES.sessionInfo;}state.session.sessionInfo.value=sessionInfo;// If auto session tracking is enabled start the session tracking
3158
- if(state.session.sessionInfo.value.autoTrack){this.startOrRenewAutoTracking(state.session.sessionInfo.value);}}setInitialReferrerInfo(){const persistedInitialReferrer=this.getInitialReferrer();const persistedInitialReferringDomain=this.getInitialReferringDomain();if(persistedInitialReferrer&&persistedInitialReferringDomain){this.setInitialReferrer(persistedInitialReferrer);this.setInitialReferringDomain(persistedInitialReferringDomain);}else {const initialReferrer=persistedInitialReferrer||getReferrer();this.setInitialReferrer(initialReferrer);this.setInitialReferringDomain(getReferringDomain(initialReferrer));}}isPersistenceEnabledForStorageEntry(entryName){return isStorageTypeValidForStoringData(state.storage.entries.value[entryName]?.type);}migrateDataFromPreviousStorage(){const entries=state.storage.entries.value;const storageTypesForMigration=[COOKIE_STORAGE,LOCAL_STORAGE,SESSION_STORAGE];Object.keys(entries).forEach(entry=>{const key=entry;const currentStorage=entries[key]?.type;const curStore=this.storeManager?.getStore(storageClientDataStoreNameMap[currentStorage]);if(curStore){storageTypesForMigration.forEach(storage=>{const store=this.storeManager?.getStore(storageClientDataStoreNameMap[storage]);if(store&&storage!==currentStorage){const value=store.get(COOKIE_KEYS[key]);if(isDefinedNotNullAndNotEmptyString(value)){curStore.set(COOKIE_KEYS[key],value);}store.remove(COOKIE_KEYS[key]);}});}});}migrateStorageIfNeeded(stores){if(!state.storage.migrate.value){return;}let storesToMigrate=stores??[];if(storesToMigrate.length===0){const persistentStoreNames=[CLIENT_DATA_STORE_COOKIE,CLIENT_DATA_STORE_LS,CLIENT_DATA_STORE_SESSION];persistentStoreNames.forEach(storeName=>{const store=this.storeManager?.getStore(storeName);if(store){storesToMigrate.push(store);}});}Object.keys(COOKIE_KEYS).forEach(storageKey=>{const storageEntry=COOKIE_KEYS[storageKey];storesToMigrate.forEach(store=>{const migratedVal=this.pluginsManager?.invokeSingle('storage.migrate',storageEntry,store.engine,this.errorHandler,this.logger);// Skip setting the value if it is null or undefined
3209
+ if(state.session.sessionInfo.value.autoTrack){this.startOrRenewAutoTracking(state.session.sessionInfo.value);}}setInitialReferrerInfo(){const persistedInitialReferrer=this.getInitialReferrer();const persistedInitialReferringDomain=this.getInitialReferringDomain();if(persistedInitialReferrer&&persistedInitialReferringDomain){this.setInitialReferrer(persistedInitialReferrer);this.setInitialReferringDomain(persistedInitialReferringDomain);}else {const initialReferrer=persistedInitialReferrer||getReferrer();this.setInitialReferrer(initialReferrer);this.setInitialReferringDomain(getReferringDomain(initialReferrer));}}isPersistenceEnabledForStorageEntry(entryName){return isStorageTypeValidForStoringData(state.storage.entries.value[entryName]?.type);}migrateDataFromPreviousStorage(){const entries=state.storage.entries.value;const storageTypesForMigration=[COOKIE_STORAGE,LOCAL_STORAGE,SESSION_STORAGE];Object.keys(entries).forEach(entry=>{const key=entry;const currentStorage=entries[key]?.type;const curStore=this.storeManager?.getStore(storageClientDataStoreNameMap[currentStorage]);if(curStore){storageTypesForMigration.forEach(storage=>{const store=this.storeManager?.getStore(storageClientDataStoreNameMap[storage]);if(store&&storage!==currentStorage){const value=store.get(COOKIE_KEYS[key]);if(isDefinedNotNullAndNotEmptyString(value)){curStore.set(COOKIE_KEYS[key],value);}store.remove(COOKIE_KEYS[key]);}});}});}migrateStorageIfNeeded(stores,keys){if(!state.storage.migrate.value){return;}let storesToMigrate=stores??[];if(storesToMigrate.length===0){const persistentStoreNames=[CLIENT_DATA_STORE_COOKIE,CLIENT_DATA_STORE_LS,CLIENT_DATA_STORE_SESSION];persistentStoreNames.forEach(storeName=>{const store=this.storeManager?.getStore(storeName);if(store){storesToMigrate.push(store);}});}let keysToMigrate=keys??Object.keys(COOKIE_KEYS);keysToMigrate.forEach(storageKey=>{const storageEntry=COOKIE_KEYS[storageKey];storesToMigrate.forEach(store=>{const migratedVal=this.pluginsManager?.invokeSingle('storage.migrate',storageEntry,store.engine,this.errorHandler,this.logger);// Skip setting the value if it is null or undefined
3159
3210
  // as those values indicate there is no need for migration or
3160
3211
  // migration failed
3161
3212
  if(!isNullOrUndefined(migratedVal)){store.set(storageEntry,migratedVal);}});});}getConfiguredSessionTrackingInfo(){let autoTrack=state.loadOptions.value.sessions.autoTrack!==false;// Do not validate any further if autoTrack is disabled
@@ -3165,7 +3216,7 @@ if(timeout>0&&timeout<MIN_SESSION_TIMEOUT_MS){this.logger.warn(TIMEOUT_NOT_RECOM
3165
3216
  cutOffDuration=DEFAULT_SESSION_CUT_OFF_DURATION_MS;}else if(cutOffDuration<sessionTimeout){this.logger.warn(CUT_OFF_DURATION_LESS_THAN_TIMEOUT_WARNING(USER_SESSION_MANAGER,cutOffDuration,sessionTimeout));cutOffEnabled=false;}}return {enabled:cutOffEnabled,duration:cutOffDuration};}/**
3166
3217
  * Handles error
3167
3218
  * @param error The error object
3168
- */onError(error,customMessage){this.errorHandler.onError(error,USER_SESSION_MANAGER,customMessage);}/**
3219
+ */onError(error,customMessage,groupingHash){this.errorHandler.onError({error,context:USER_SESSION_MANAGER,customMessage,groupingHash});}/**
3169
3220
  * A function to encrypt the cookie value and return the encrypted data
3170
3221
  * @param cookiesData
3171
3222
  * @param store
@@ -3180,7 +3231,7 @@ cutOffDuration=DEFAULT_SESSION_CUT_OFF_DURATION_MS;}else if(cutOffDuration<sessi
3180
3231
  * @param value encrypted cookie value
3181
3232
  */setServerSideCookies(cookiesData,cb,store){try{// encrypt cookies values
3182
3233
  const encryptedCookieData=this.getEncryptedCookieData(cookiesData,store);if(encryptedCookieData.length>0){// make request to data service to set the cookie from server side
3183
- this.makeRequestToSetCookie(encryptedCookieData,(res,details)=>{if(details?.xhr?.status===200){cookiesData.forEach(cData=>{const cookieValue=store?.get(cData.name);const before=stringifyWithoutCircular(cData.value,false,[]);const after=stringifyWithoutCircular(cookieValue,false,[]);if(after!==before){this.logger.error(FAILED_SETTING_COOKIE_FROM_SERVER_ERROR(cData.name));if(cb){cb(cData.name,cData.value);}}});}else {this.logger.error(DATA_SERVER_REQUEST_FAIL_ERROR(details?.xhr?.status));cookiesData.forEach(each=>{if(cb){cb(each.name,each.value);}});}});}}catch(e){this.onError(e,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR);cookiesData.forEach(each=>{if(cb){cb(each.name,each.value);}});}}/**
3234
+ this.makeRequestToSetCookie(encryptedCookieData,(res,details)=>{if(details?.xhr?.status===200){cookiesData.forEach(cData=>{const cookieValue=store?.get(cData.name);const before=stringifyWithoutCircular(cData.value,false,[]);const after=stringifyWithoutCircular(cookieValue,false,[]);if(after!==before){this.logger.error(FAILED_SETTING_COOKIE_FROM_SERVER_ERROR(cData.name));if(cb){cb(cData.name,cData.value);}}});}else {this.logger.error(DATA_SERVER_REQUEST_FAIL_ERROR(details?.xhr?.status));cookiesData.forEach(each=>{if(cb){cb(each.name,each.value);}});}});}}catch(e){this.onError(e,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR);cookiesData.forEach(each=>{if(cb){cb(each.name,each.value);}});}}/**
3184
3235
  * A function to sync values in storage
3185
3236
  * @param sessionKey
3186
3237
  * @param value
@@ -3205,7 +3256,7 @@ if(!persistedAnonymousId||persistedAnonymousId===DEFAULT_USER_SESSION_VALUES.ano
3205
3256
  const autoCapturedAnonymousId=this.pluginsManager?.invokeSingle('storage.getAnonymousId',getStorageEngine,options);persistedAnonymousId=autoCapturedAnonymousId;}state.session.anonymousId.value=persistedAnonymousId||generateAnonymousId();}return state.session.anonymousId.value;}getEntryValue(sessionKey){const entries=state.storage.entries.value;const storageType=entries[sessionKey]?.type;if(isStorageTypeValidForStoringData(storageType)){const store=this.storeManager?.getStore(storageClientDataStoreNameMap[storageType]);// Migrate the storage data before fetching the value
3206
3257
  // This is needed for entries that are fetched from the storage
3207
3258
  // during the current session (for example, session info)
3208
- this.migrateStorageIfNeeded([store]);const storageKey=entries[sessionKey]?.key;return store?.get(storageKey)??null;}return null;}getExternalAnonymousIdByCookieName(key){const storageEngine=getStorageEngine(COOKIE_STORAGE);if(storageEngine?.isEnabled){return storageEngine.getItem(key)??null;}return null;}/**
3259
+ this.migrateStorageIfNeeded([store],[sessionKey]);const storageKey=entries[sessionKey]?.key;return store?.get(storageKey)??null;}return null;}getExternalAnonymousIdByCookieName(key){const storageEngine=getStorageEngine(COOKIE_STORAGE);if(storageEngine?.isEnabled){return storageEngine.getItem(key)??null;}return null;}/**
3209
3260
  * Fetches User Id
3210
3261
  * @returns
3211
3262
  */getUserId(){return this.getEntryValue('userId');}/**
@@ -3293,7 +3344,7 @@ state.session.sessionInfo.value=finalSessionInfo;}/**
3293
3344
  */const defaultOptionalPluginsList=['BeaconQueue','CustomConsentManager','DeviceModeDestinations','DeviceModeTransformation','ExternalAnonymousId','GoogleLinker','IubendaConsentManager','KetchConsentManager','NativeDestinationQueue','OneTrustConsentManager','StorageEncryption','StorageEncryptionLegacy','StorageMigrator','XhrQueue'];
3294
3345
 
3295
3346
  const normalizeLoadOptions=(loadOptionsFromState,loadOptions)=>{// TODO: Maybe add warnings for invalid values
3296
- const normalizedLoadOpts=clone(loadOptions);if(!isString(normalizedLoadOpts.setCookieDomain)){normalizedLoadOpts.setCookieDomain=undefined;}const cookieSameSiteValues=['Strict','Lax','None'];if(!cookieSameSiteValues.includes(normalizedLoadOpts.sameSiteCookie)){normalizedLoadOpts.sameSiteCookie=undefined;}normalizedLoadOpts.secureCookie=getNormalizedBooleanValue(normalizedLoadOpts.secureCookie,loadOptionsFromState.secureCookie);normalizedLoadOpts.sameDomainCookiesOnly=getNormalizedBooleanValue(normalizedLoadOpts.sameDomainCookiesOnly,loadOptionsFromState.sameDomainCookiesOnly);const uaChTrackLevels=['none','default','full'];if(!uaChTrackLevels.includes(normalizedLoadOpts.uaChTrackLevel)){normalizedLoadOpts.uaChTrackLevel=undefined;}normalizedLoadOpts.integrations=getNormalizedObjectValue(normalizedLoadOpts.integrations);if(!Array.isArray(normalizedLoadOpts.plugins)){normalizedLoadOpts.plugins=defaultOptionalPluginsList;}normalizedLoadOpts.useGlobalIntegrationsConfigInEvents=getNormalizedBooleanValue(normalizedLoadOpts.useGlobalIntegrationsConfigInEvents,loadOptionsFromState.useGlobalIntegrationsConfigInEvents);normalizedLoadOpts.bufferDataPlaneEventsUntilReady=getNormalizedBooleanValue(normalizedLoadOpts.bufferDataPlaneEventsUntilReady,loadOptionsFromState.bufferDataPlaneEventsUntilReady);normalizedLoadOpts.sendAdblockPage=getNormalizedBooleanValue(normalizedLoadOpts.sendAdblockPage,loadOptionsFromState.sendAdblockPage);normalizedLoadOpts.useServerSideCookies=getNormalizedBooleanValue(normalizedLoadOpts.useServerSideCookies,loadOptionsFromState.useServerSideCookies);if(!isString(normalizedLoadOpts.dataServiceEndpoint)){normalizedLoadOpts.dataServiceEndpoint=undefined;}normalizedLoadOpts.sendAdblockPageOptions=getNormalizedObjectValue(normalizedLoadOpts.sendAdblockPageOptions);normalizedLoadOpts.loadIntegration=getNormalizedBooleanValue(normalizedLoadOpts.loadIntegration,loadOptionsFromState.loadIntegration);if(!isNonEmptyObject(normalizedLoadOpts.storage)){normalizedLoadOpts.storage=undefined;}else {normalizedLoadOpts.storage.migrate=getNormalizedBooleanValue(normalizedLoadOpts.storage.migrate,loadOptionsFromState.storage?.migrate);normalizedLoadOpts.storage.cookie=getNormalizedObjectValue(normalizedLoadOpts.storage.cookie);normalizedLoadOpts.storage.encryption=getNormalizedObjectValue(normalizedLoadOpts.storage.encryption);normalizedLoadOpts.storage=removeUndefinedAndNullValues(normalizedLoadOpts.storage);}normalizedLoadOpts.destinationsQueueOptions=getNormalizedObjectValue(normalizedLoadOpts.destinationsQueueOptions);normalizedLoadOpts.queueOptions=getNormalizedObjectValue(normalizedLoadOpts.queueOptions);normalizedLoadOpts.lockIntegrationsVersion=getNormalizedBooleanValue(normalizedLoadOpts.lockIntegrationsVersion,loadOptionsFromState.lockIntegrationsVersion);normalizedLoadOpts.lockPluginsVersion=getNormalizedBooleanValue(normalizedLoadOpts.lockPluginsVersion,loadOptionsFromState.lockPluginsVersion);if(!isNumber(normalizedLoadOpts.dataPlaneEventsBufferTimeout)){normalizedLoadOpts.dataPlaneEventsBufferTimeout=undefined;}normalizedLoadOpts.beaconQueueOptions=getNormalizedObjectValue(normalizedLoadOpts.beaconQueueOptions);normalizedLoadOpts.preConsent=getNormalizedObjectValue(normalizedLoadOpts.preConsent);const mergedLoadOptions=mergeDeepRight(loadOptionsFromState,removeUndefinedAndNullValues(normalizedLoadOpts));return mergedLoadOptions;};
3347
+ const normalizedLoadOpts=clone(loadOptions);if(!isString(normalizedLoadOpts.setCookieDomain)){normalizedLoadOpts.setCookieDomain=undefined;}const cookieSameSiteValues=['Strict','Lax','None'];if(!cookieSameSiteValues.includes(normalizedLoadOpts.sameSiteCookie)){normalizedLoadOpts.sameSiteCookie=undefined;}normalizedLoadOpts.secureCookie=getNormalizedBooleanValue(normalizedLoadOpts.secureCookie,loadOptionsFromState.secureCookie);normalizedLoadOpts.sameDomainCookiesOnly=getNormalizedBooleanValue(normalizedLoadOpts.sameDomainCookiesOnly,loadOptionsFromState.sameDomainCookiesOnly);const uaChTrackLevels=['none','default','full'];if(!uaChTrackLevels.includes(normalizedLoadOpts.uaChTrackLevel)){normalizedLoadOpts.uaChTrackLevel=undefined;}normalizedLoadOpts.integrations=getNormalizedObjectValue(normalizedLoadOpts.integrations);if(!Array.isArray(normalizedLoadOpts.plugins)){normalizedLoadOpts.plugins=defaultOptionalPluginsList;}normalizedLoadOpts.useGlobalIntegrationsConfigInEvents=getNormalizedBooleanValue(normalizedLoadOpts.useGlobalIntegrationsConfigInEvents,loadOptionsFromState.useGlobalIntegrationsConfigInEvents);normalizedLoadOpts.bufferDataPlaneEventsUntilReady=getNormalizedBooleanValue(normalizedLoadOpts.bufferDataPlaneEventsUntilReady,loadOptionsFromState.bufferDataPlaneEventsUntilReady);normalizedLoadOpts.sendAdblockPage=getNormalizedBooleanValue(normalizedLoadOpts.sendAdblockPage,loadOptionsFromState.sendAdblockPage);normalizedLoadOpts.useServerSideCookies=getNormalizedBooleanValue(normalizedLoadOpts.useServerSideCookies,loadOptionsFromState.useServerSideCookies);if(!isString(normalizedLoadOpts.dataServiceEndpoint)){normalizedLoadOpts.dataServiceEndpoint=undefined;}normalizedLoadOpts.sendAdblockPageOptions=getNormalizedObjectValue(normalizedLoadOpts.sendAdblockPageOptions);normalizedLoadOpts.loadIntegration=getNormalizedBooleanValue(normalizedLoadOpts.loadIntegration,loadOptionsFromState.loadIntegration);if(!isNonEmptyObject(normalizedLoadOpts.storage)){normalizedLoadOpts.storage=undefined;}else {normalizedLoadOpts.storage.migrate=getNormalizedBooleanValue(normalizedLoadOpts.storage.migrate,loadOptionsFromState.storage?.migrate);normalizedLoadOpts.storage.cookie=getNormalizedObjectValue(normalizedLoadOpts.storage.cookie);normalizedLoadOpts.storage.encryption=getNormalizedObjectValue(normalizedLoadOpts.storage.encryption);normalizedLoadOpts.storage=removeUndefinedAndNullValues(normalizedLoadOpts.storage);}normalizedLoadOpts.destinationsQueueOptions=getNormalizedObjectValue(normalizedLoadOpts.destinationsQueueOptions);normalizedLoadOpts.queueOptions=getNormalizedObjectValue(normalizedLoadOpts.queueOptions);normalizedLoadOpts.lockIntegrationsVersion=getNormalizedBooleanValue(normalizedLoadOpts.lockIntegrationsVersion,loadOptionsFromState.lockIntegrationsVersion);normalizedLoadOpts.lockPluginsVersion=getNormalizedBooleanValue(normalizedLoadOpts.lockPluginsVersion,loadOptionsFromState.lockPluginsVersion);if(!isNumber(normalizedLoadOpts.dataPlaneEventsBufferTimeout)){normalizedLoadOpts.dataPlaneEventsBufferTimeout=undefined;}normalizedLoadOpts.beaconQueueOptions=getNormalizedObjectValue(normalizedLoadOpts.beaconQueueOptions);normalizedLoadOpts.preConsent=getNormalizedObjectValue(normalizedLoadOpts.preConsent);normalizedLoadOpts.sourceConfigurationOverride=getNormalizedObjectValue(normalizedLoadOpts.sourceConfigurationOverride);const mergedLoadOptions=mergeDeepRight(loadOptionsFromState,removeUndefinedAndNullValues(normalizedLoadOpts));return mergedLoadOptions;};
3297
3348
 
3298
3349
  const DATA_PLANE_QUEUE_EXT_POINT_PREFIX='dataplaneEventsQueue';const DESTINATIONS_QUEUE_EXT_POINT_PREFIX='destinationsEventsQueue';const DMT_EXT_POINT_PREFIX='transformEvent';
3299
3350
 
@@ -3342,7 +3393,7 @@ const dispatchSDKEvent=event=>{const customEvent=new CustomEvent(event,{detail:{
3342
3393
  * Analytics class with lifecycle based on state ad user triggered events
3343
3394
  */class Analytics{/**
3344
3395
  * Initialize services and components or use default ones if singletons
3345
- */constructor(){this.preloadBuffer=new BufferQueue();this.initialized=false;this.errorHandler=defaultErrorHandler;this.logger=defaultLogger;this.externalSrcLoader=new ExternalSrcLoader(this.errorHandler,this.logger);this.httpClient=defaultHttpClient;this.httpClient.init(this.errorHandler);this.capabilitiesManager=new CapabilitiesManager(this.httpClient,this.errorHandler,this.logger);}/**
3396
+ */constructor(){this.preloadBuffer=new BufferQueue();this.initialized=false;this.errorHandler=defaultErrorHandler;this.logger=defaultLogger;this.externalSrcLoader=new ExternalSrcLoader(this.logger);this.httpClient=defaultHttpClient;this.httpClient.init(this.errorHandler);this.capabilitiesManager=new CapabilitiesManager(this.httpClient,this.errorHandler,this.logger);}/**
3346
3397
  * Start application lifecycle if not already started
3347
3398
  */load(writeKey,dataPlaneUrl,loadOptions={}){if(state.lifecycle.status.value){return;}if(!isWriteKeyValid(writeKey)){this.logger.error(WRITE_KEY_VALIDATION_ERROR(ANALYTICS_CORE,writeKey));return;}if(!isDataPlaneUrlValid(dataPlaneUrl)){this.logger.error(DATA_PLANE_URL_VALIDATION_ERROR(ANALYTICS_CORE,dataPlaneUrl));return;}// Set initial state values
3348
3399
  r(()=>{state.lifecycle.writeKey.value=clone(writeKey);state.lifecycle.dataPlaneUrl.value=clone(dataPlaneUrl);state.loadOptions.value=normalizeLoadOptions(state.loadOptions.value,loadOptions);state.lifecycle.status.value='mounted';});// set log level as early as possible
@@ -3352,7 +3403,7 @@ setExposedGlobal('state',state,writeKey);// Configure initial config of any serv
3352
3403
  this.startLifecycle();}// Start lifecycle methods
3353
3404
  /**
3354
3405
  * Orchestrate the lifecycle of the application phases/status
3355
- */startLifecycle(){E(()=>{try{switch(state.lifecycle.status.value){case 'mounted':this.onMounted();break;case 'browserCapabilitiesReady':this.onBrowserCapabilitiesReady();break;case 'configured':this.onConfigured();break;case 'pluginsLoading':break;case 'pluginsReady':this.onPluginsReady();break;case 'initialized':this.onInitialized();break;case 'loaded':this.onLoaded();break;case 'destinationsLoading':break;case 'destinationsReady':this.onDestinationsReady();break;case 'ready':this.onReady();break;case 'readyExecuted':default:break;}}catch(err){const issue='Failed to load the SDK';this.errorHandler.onError(getMutatedError(err,issue),ANALYTICS_CORE);}});}onBrowserCapabilitiesReady(){// initialize the preloaded events enqueuing
3406
+ */startLifecycle(){E(()=>{try{switch(state.lifecycle.status.value){case 'mounted':this.onMounted();break;case 'browserCapabilitiesReady':this.onBrowserCapabilitiesReady();break;case 'configured':this.onConfigured();break;case 'pluginsLoading':break;case 'pluginsReady':this.onPluginsReady();break;case 'initialized':this.onInitialized();break;case 'loaded':this.onLoaded();break;case 'destinationsLoading':break;case 'destinationsReady':this.onDestinationsReady();break;case 'ready':this.onReady();break;case 'readyExecuted':default:break;}}catch(err){const issue='Failed to load the SDK';this.errorHandler.onError({error:err,context:ANALYTICS_CORE,customMessage:issue,groupingHash:issue});}});}onBrowserCapabilitiesReady(){// initialize the preloaded events enqueuing
3356
3407
  retrievePreloadBufferEvents(this);this.prepareInternalServices();this.loadConfig();}onLoaded(){this.processBufferedEvents();// Short-circuit the life cycle and move to the ready state if pre-consent behavior is enabled
3357
3408
  if(state.consents.preConsent.value.enabled===true){state.lifecycle.status.value='ready';}else {this.loadDestinations();}}/**
3358
3409
  * Load browser polyfill if required