@rudderstack/analytics-js 3.11.12 → 3.11.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -334,54 +334,10 @@
334
334
  * @returns base64 encoded string
335
335
  */const toBase64=value=>bytesToBase64(new TextEncoder().encode(value));
336
336
 
337
- 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.`;
338
-
339
- 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
340
- // eslint-disable-next-line func-names
341
- return function(key,value){if(excludeKeys?.includes(key)){return undefined;}if(excludeNull&&isNullOrUndefined(value)){return undefined;}if(typeof value!=='object'||isNull(value)){return value;}// `this` is the object that value is contained in, i.e., its direct parent.
342
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
343
- // @ts-ignore-next-line
344
- while(ancestors.length>0&&ancestors[ancestors.length-1]!==this){ancestors.pop();}if(ancestors.includes(value)){logger?.warn(CIRCULAR_REFERENCE_WARNING(JSON_STRINGIFY,key));return CIRCULAR_REFERENCE_PLACEHOLDER;}ancestors.push(value);return value;};};/**
345
- * Utility method for JSON stringify object excluding null values & circular references
346
- *
347
- * @param {*} value input
348
- * @param {boolean} excludeNull if it should exclude nul or not
349
- * @param {function} logger optional logger methods for warning
350
- * @returns string
351
- */const stringifyWithoutCircular=(value,excludeNull,excludeKeys,logger)=>{try{return JSON.stringify(value,getCircularReplacer(excludeNull,excludeKeys,logger));}catch(err){logger?.warn(JSON_STRINGIFY_WARNING,err);return null;}};/**
352
- * Utility method for JSON stringify object excluding null values & circular references
353
- *
354
- * @param {*} value input value
355
- * @param {boolean} excludeNull optional flag to exclude null values
356
- * @param {string[]} excludeKeys optional array of keys to exclude
357
- * @returns string
358
- */const stringifyData=(value,excludeNull=true,excludeKeys=[])=>JSON.stringify(value,(key,value)=>{if(excludeNull&&isNull(value)||excludeKeys.includes(key)){return undefined;}return value;});const getReplacer=logger=>{const ancestors=[];// Array to track ancestor objects
359
- // Using a regular function to use `this` for the parent context
360
- return function replacer(key,value){if(isBigInt(value)){return BIG_INT_PLACEHOLDER;// Replace BigInt values
361
- }// `this` is the object that value is contained in, i.e., its direct parent.
362
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
363
- // @ts-ignore-next-line
364
- while(ancestors.length>0&&ancestors[ancestors.length-1]!==this){ancestors.pop();// Remove ancestors that are no longer part of the chain
365
- }// Check for circular references (if the value is already in the ancestors)
366
- if(ancestors.includes(value)){return CIRCULAR_REFERENCE_PLACEHOLDER;}// Add current value to ancestors
367
- ancestors.push(value);return value;};};const traverseWithThis=(obj,replacer)=>{// Create a new result object or array
368
- const result=Array.isArray(obj)?[]:{};// Traverse object properties or array elements
369
- // eslint-disable-next-line no-restricted-syntax
370
- for(const key in obj){if(Object.hasOwnProperty.call(obj,key)){const value=obj[key];// Recursively apply the replacer and traversal
371
- const sanitizedValue=replacer.call(obj,key,value);// If the value is an object or array, continue traversal
372
- if(isObjectLiteralAndNotNull(sanitizedValue)||Array.isArray(sanitizedValue)){result[key]=traverseWithThis(sanitizedValue,replacer);}else {result[key]=sanitizedValue;}}}return result;};/**
373
- * Recursively traverses an object similar to JSON.stringify,
374
- * sanitizing BigInts and circular references
375
- * @param value Input object
376
- * @param logger Logger instance
377
- * @returns Sanitized value
378
- */const getSanitizedValue=(value,logger)=>{const replacer=getReplacer();// This is needed for registering the first ancestor
379
- const newValue=replacer.call(value,'',value);if(isObjectLiteralAndNotNull(value)||Array.isArray(value)){return traverseWithThis(value,replacer);}return newValue;};const tempUtil=()=>{stringifyData();};
380
-
381
337
  // if yes make them null instead of omitting in overloaded cases
382
338
  /*
383
339
  * Normalise the overloaded arguments of the page call facade
384
- */const pageArgumentsToCallOptions=(category,name,properties,options,callback)=>{tempUtil();const payload={category:category,name:name,properties:properties,options:options,callback:undefined};if(isFunction(callback)){payload.callback=callback;}if(isFunction(options)){payload.category=category;payload.name=name;payload.properties=properties;payload.options=undefined;payload.callback=options;}if(isFunction(properties)){payload.category=category;payload.name=name;payload.properties=undefined;payload.options=undefined;payload.callback=properties;}if(isFunction(name)){payload.category=category;payload.name=undefined;payload.properties=undefined;payload.options=undefined;payload.callback=name;}if(isFunction(category)){payload.category=undefined;payload.name=undefined;payload.properties=undefined;payload.options=undefined;payload.callback=category;}if(isObjectLiteralAndNotNull(category)){payload.name=undefined;payload.category=undefined;payload.properties=category;if(!isFunction(name)){payload.options=name;}else {payload.options=undefined;}}else if(isObjectLiteralAndNotNull(name)){payload.name=undefined;payload.properties=name;if(!isFunction(properties)){payload.options=properties;}else {payload.options=undefined;}}// if the category argument alone is provided b/w category and name,
340
+ */const pageArgumentsToCallOptions=(category,name,properties,options,callback)=>{const payload={category:category,name:name,properties:properties,options:options,callback:undefined};if(isFunction(callback)){payload.callback=callback;}if(isFunction(options)){payload.category=category;payload.name=name;payload.properties=properties;payload.options=undefined;payload.callback=options;}if(isFunction(properties)){payload.category=category;payload.name=name;payload.properties=undefined;payload.options=undefined;payload.callback=properties;}if(isFunction(name)){payload.category=category;payload.name=undefined;payload.properties=undefined;payload.options=undefined;payload.callback=name;}if(isFunction(category)){payload.category=undefined;payload.name=undefined;payload.properties=undefined;payload.options=undefined;payload.callback=category;}if(isObjectLiteralAndNotNull(category)){payload.name=undefined;payload.category=undefined;payload.properties=category;if(!isFunction(name)){payload.options=name;}else {payload.options=undefined;}}else if(isObjectLiteralAndNotNull(name)){payload.name=undefined;payload.properties=name;if(!isFunction(properties)){payload.options=properties;}else {payload.options=undefined;}}// if the category argument alone is provided b/w category and name,
385
341
  // use it as name and set category to undefined
386
342
  if(isString(category)&&!isString(name)){payload.category=undefined;payload.name=category;}// Rest of the code is just to clean up undefined values
387
343
  // and set some proper defaults
@@ -456,6 +412,43 @@
456
412
  * @returns ISO formatted timestamp string
457
413
  */const getCurrentTimeFormatted=()=>getFormattedTimestamp(new Date());
458
414
 
415
+ 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.`;
416
+
417
+ 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
418
+ // eslint-disable-next-line func-names
419
+ return function(key,value){if(excludeKeys?.includes(key)){return undefined;}if(excludeNull&&isNullOrUndefined(value)){return undefined;}if(typeof value!=='object'||isNull(value)){return value;}// `this` is the object that value is contained in, i.e., its direct parent.
420
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
421
+ // @ts-ignore-next-line
422
+ while(ancestors.length>0&&ancestors[ancestors.length-1]!==this){ancestors.pop();}if(ancestors.includes(value)){logger?.warn(CIRCULAR_REFERENCE_WARNING(JSON_STRINGIFY,key));return CIRCULAR_REFERENCE_PLACEHOLDER;}ancestors.push(value);return value;};};/**
423
+ * Utility method for JSON stringify object excluding null values & circular references
424
+ *
425
+ * @param {*} value input
426
+ * @param {boolean} excludeNull if it should exclude nul or not
427
+ * @param {function} logger optional logger methods for warning
428
+ * @returns string
429
+ */const stringifyWithoutCircular=(value,excludeNull,excludeKeys,logger)=>{try{return JSON.stringify(value,getCircularReplacer(excludeNull,excludeKeys,logger));}catch(err){logger?.warn(JSON_STRINGIFY_WARNING,err);return null;}};const getReplacer=logger=>{const ancestors=[];// Array to track ancestor objects
430
+ // Using a regular function to use `this` for the parent context
431
+ return function replacer(key,value){if(isBigInt(value)){return BIG_INT_PLACEHOLDER;// Replace BigInt values
432
+ }// `this` is the object that value is contained in, i.e., its direct parent.
433
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
434
+ // @ts-ignore-next-line
435
+ while(ancestors.length>0&&ancestors[ancestors.length-1]!==this){ancestors.pop();// Remove ancestors that are no longer part of the chain
436
+ }// Check for circular references (if the value is already in the ancestors)
437
+ if(ancestors.includes(value)){return CIRCULAR_REFERENCE_PLACEHOLDER;}// Add current value to ancestors
438
+ ancestors.push(value);return value;};};const traverseWithThis=(obj,replacer)=>{// Create a new result object or array
439
+ const result=Array.isArray(obj)?[]:{};// Traverse object properties or array elements
440
+ // eslint-disable-next-line no-restricted-syntax
441
+ for(const key in obj){if(Object.hasOwnProperty.call(obj,key)){const value=obj[key];// Recursively apply the replacer and traversal
442
+ const sanitizedValue=replacer.call(obj,key,value);// If the value is an object or array, continue traversal
443
+ if(isObjectLiteralAndNotNull(sanitizedValue)||Array.isArray(sanitizedValue)){result[key]=traverseWithThis(sanitizedValue,replacer);}else {result[key]=sanitizedValue;}}}return result;};/**
444
+ * Recursively traverses an object similar to JSON.stringify,
445
+ * sanitizing BigInts and circular references
446
+ * @param value Input object
447
+ * @param logger Logger instance
448
+ * @returns Sanitized value
449
+ */const getSanitizedValue=(value,logger)=>{const replacer=getReplacer();// This is needed for registering the first ancestor
450
+ const newValue=replacer.call(value,'',value);if(isObjectLiteralAndNotNull(value)||Array.isArray(value)){return traverseWithThis(value,replacer);}return newValue;};
451
+
459
452
  const MANUAL_ERROR_IDENTIFIER='[MANUAL ERROR]';/**
460
453
  * Get mutated error with issue prepended to error message
461
454
  * @param err Original error
@@ -463,7 +456,7 @@
463
456
  * @returns Instance of Error with message prepended with issue
464
457
  */const getMutatedError=(err,issue)=>{let finalError=err;if(!isTypeOfError(err)){finalError=new Error(`${issue}: ${stringifyWithoutCircular(err)}`);}else {finalError.message=`${issue}: ${err.message}`;}return finalError;};const dispatchErrorEvent=error=>{if(isTypeOfError(error)){error.stack=`${error.stack??''}\n${MANUAL_ERROR_IDENTIFIER}`;}globalThis.dispatchEvent(new ErrorEvent('error',{error}));};
465
458
 
466
- const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.11.12';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';
459
+ const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.11.14';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';
467
460
 
468
461
  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';
469
462
 
@@ -1750,13 +1743,11 @@
1750
1743
  * @param dataPlaneUrl Data plane URL
1751
1744
  * @param loadOptions Additional options for loading the SDK
1752
1745
  * @returns none
1753
- */load(writeKey,dataPlaneUrl,loadOptions){try{if(this.analyticsInstances[writeKey]){return;}this.setDefaultInstanceKey(writeKey);const preloadedEventsArray=this.getPreloadedEvents();// Track page loaded lifecycle event if enabled
1746
+ */load(writeKey,dataPlaneUrl,loadOptions){try{if(this.analyticsInstances[writeKey]){return;}this.setDefaultInstanceKey(writeKey);// Get the preloaded events array from global buffer instead of window.rudderanalytics
1747
+ // as the constructor must have already pushed the events to the global buffer
1748
+ const preloadedEventsArray=getExposedGlobal(GLOBAL_PRELOAD_BUFFER);// Track page loaded lifecycle event if enabled
1754
1749
  this.trackPageLifecycleEvents(preloadedEventsArray,loadOptions);// The array will be mutated in the below method
1755
1750
  promotePreloadedConsentEventsToTop(preloadedEventsArray);setExposedGlobal(GLOBAL_PRELOAD_BUFFER,clone(preloadedEventsArray));this.analyticsInstances[writeKey]=new Analytics();this.getAnalyticsInstance(writeKey)?.load(writeKey,dataPlaneUrl,getSanitizedValue(loadOptions));}catch(error){dispatchErrorEvent(error);}}/**
1756
- * A function to get preloaded events array from global object
1757
- * @returns preloaded events array
1758
- */// eslint-disable-next-line class-methods-use-this
1759
- getPreloadedEvents(){return Array.isArray(globalThis.rudderanalytics)?globalThis.rudderanalytics:[];}/**
1760
1751
  * A function to track page lifecycle events like page loaded and page unloaded
1761
1752
  * @param preloadedEventsArray
1762
1753
  * @param loadOptions
@@ -1779,11 +1770,11 @@
1779
1770
  this.logger.warn(PAGE_UNLOAD_ON_BEACON_DISABLED_WARNING(RSA));}}}/**
1780
1771
  * Trigger load event in buffer queue if exists and stores the
1781
1772
  * remaining preloaded events array in global object
1782
- */triggerBufferedLoadEvent(){const preloadedEventsArray=this.getPreloadedEvents();// Get any load method call that is buffered if any
1773
+ */triggerBufferedLoadEvent(){const preloadedEventsArray=Array.isArray(globalThis.rudderanalytics)?globalThis.rudderanalytics:[];// Get any load method call that is buffered if any
1783
1774
  // BTW, load method is also removed from the array
1784
1775
  // So, the Analytics object can directly consume the remaining events
1785
1776
  const loadEvent=getPreloadedLoadEvent(preloadedEventsArray);// Set the final preloaded events array in global object
1786
- setExposedGlobal(GLOBAL_PRELOAD_BUFFER,clone(preloadedEventsArray));// Process load method if present in the buffered requests
1777
+ setExposedGlobal(GLOBAL_PRELOAD_BUFFER,clone([...preloadedEventsArray]));// Process load method if present in the buffered requests
1787
1778
  if(loadEvent.length>0){// Remove the event name from the Buffered Event array and keep only arguments
1788
1779
  loadEvent.shift();// eslint-disable-next-line @typescript-eslint/ban-ts-comment
1789
1780
  // @ts-ignore
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rudderstack/analytics-js",
3
- "version": "3.11.12",
3
+ "version": "3.11.14",
4
4
  "description": "RudderStack JavaScript SDK",
5
5
  "main": "dist/npm/modern/cjs/index.cjs",
6
6
  "module": "dist/npm/modern/esm/index.mjs",