@rudderstack/analytics-js 3.0.0-beta.9 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +155 -0
- package/README.md +58 -11
- package/dist/npm/index.d.ts +324 -217
- package/dist/npm/legacy/cjs/index.js +1707 -1671
- package/dist/npm/legacy/esm/index.js +1708 -1667
- package/dist/npm/legacy/umd/index.js +1707 -1671
- package/dist/npm/modern/bundled/cjs/index.js +3260 -0
- package/dist/npm/modern/bundled/esm/index.js +3256 -0
- package/dist/npm/modern/bundled/umd/index.js +3266 -0
- package/dist/npm/modern/cjs/index.js +369 -332
- package/dist/npm/modern/content-script/cjs/index.js +3236 -0
- package/dist/npm/modern/content-script/esm/index.js +3232 -0
- package/dist/npm/modern/content-script/umd/index.js +3242 -0
- package/dist/npm/modern/esm/index.js +370 -328
- package/dist/npm/modern/umd/index.js +369 -332
- package/package.json +32 -15
@@ -2,29 +2,6 @@
|
|
2
2
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
4
4
|
|
5
|
-
let UaChTrackLevel=/*#__PURE__*/function(UaChTrackLevel){UaChTrackLevel["None"]="none";UaChTrackLevel["Default"]="default";UaChTrackLevel["Full"]="full";return UaChTrackLevel;}({});/**
|
6
|
-
* Represents the options parameter for anonymousId
|
7
|
-
*/ /**
|
8
|
-
* Represents the beacon queue options parameter in loadOptions type
|
9
|
-
*/ /**
|
10
|
-
* Represents the queue options parameter in loadOptions type
|
11
|
-
*/ /**
|
12
|
-
* Represents the destinations queue options parameter in loadOptions type
|
13
|
-
*/let DeliveryType=/*#__PURE__*/function(DeliveryType){DeliveryType["Immediate"]="immediate";DeliveryType["Buffer"]="buffer";return DeliveryType;}({});let StorageStrategy=/*#__PURE__*/function(StorageStrategy){StorageStrategy["None"]="none";StorageStrategy["Session"]="session";StorageStrategy["AnonymousId"]="anonymousId";return StorageStrategy;}({});/**
|
14
|
-
* Represents the options parameter in the load API
|
15
|
-
*/
|
16
|
-
|
17
|
-
let StorageEncryptionVersion=/*#__PURE__*/function(StorageEncryptionVersion){StorageEncryptionVersion["Legacy"]="legacy";StorageEncryptionVersion["V3"]="v3";return StorageEncryptionVersion;}({});// default
|
18
|
-
const SUPPORTED_STORAGE_TYPES=['localStorage','memoryStorage','cookieStorage','sessionStorage','none'];const DEFAULT_STORAGE_TYPE='cookieStorage';let CookieSameSite=/*#__PURE__*/function(CookieSameSite){CookieSameSite["Strict"]="Strict";CookieSameSite["Lax"]="Lax";CookieSameSite["None"]="None";return CookieSameSite;}({});
|
19
|
-
|
20
|
-
/**
|
21
|
-
* Represents residency server input the options
|
22
|
-
*/let ResidencyServerRegion=/*#__PURE__*/function(ResidencyServerRegion){ResidencyServerRegion["US"]="US";ResidencyServerRegion["EU"]="EU";return ResidencyServerRegion;}({});
|
23
|
-
|
24
|
-
let LogLevel=/*#__PURE__*/function(LogLevel){LogLevel["Log"]="LOG";LogLevel["Info"]="INFO";LogLevel["Debug"]="DEBUG";LogLevel["Warn"]="WARN";LogLevel["Error"]="ERROR";LogLevel["None"]="NONE";return LogLevel;}({});
|
25
|
-
|
26
|
-
let PluginName=/*#__PURE__*/function(PluginName){PluginName["BeaconQueue"]="BeaconQueue";PluginName["Bugsnag"]="Bugsnag";PluginName["DeviceModeDestinations"]="DeviceModeDestinations";PluginName["DeviceModeTransformation"]="DeviceModeTransformation";PluginName["ErrorReporting"]="ErrorReporting";PluginName["ExternalAnonymousId"]="ExternalAnonymousId";PluginName["GoogleLinker"]="GoogleLinker";PluginName["KetchConsentManager"]="KetchConsentManager";PluginName["NativeDestinationQueue"]="NativeDestinationQueue";PluginName["OneTrustConsentManager"]="OneTrustConsentManager";PluginName["StorageEncryption"]="StorageEncryption";PluginName["StorageEncryptionLegacy"]="StorageEncryptionLegacy";PluginName["StorageMigrator"]="StorageMigrator";PluginName["XhrQueue"]="XhrQueue";return PluginName;}({});
|
27
|
-
|
28
5
|
function _isPlaceholder(a){return a!=null&&typeof a==='object'&&a['@@functional/placeholder']===true;}
|
29
6
|
|
30
7
|
/**
|
@@ -79,6 +56,7 @@ function _has(prop,obj){return Object.prototype.hasOwnProperty.call(obj,prop);}
|
|
79
56
|
* R.type([]); //=> "Array"
|
80
57
|
* R.type(/[A-z]/); //=> "RegExp"
|
81
58
|
* R.type(() => {}); //=> "Function"
|
59
|
+
* R.type(async () => {}); //=> "AsyncFunction"
|
82
60
|
* R.type(undefined); //=> "Undefined"
|
83
61
|
*/var type=/*#__PURE__*/_curry1(function type(val){return val===null?'Null':val===undefined?'Undefined':Object.prototype.toString.call(val).slice(8,-1);});
|
84
62
|
|
@@ -164,7 +142,7 @@ var cachedCopy=map.get(value);if(cachedCopy){return cachedCopy;}map.set(value,co
|
|
164
142
|
* const objectsClone = R.clone(objects);
|
165
143
|
* objects === objectsClone; //=> false
|
166
144
|
* objects[0] === objectsClone[0]; //=> false
|
167
|
-
*/var clone=/*#__PURE__*/_curry1(function clone(value){return value!=null&&typeof value.clone==='function'?value.clone():_clone(value,true);});
|
145
|
+
*/var clone=/*#__PURE__*/_curry1(function clone(value){return value!=null&&typeof value.clone==='function'?value.clone():_clone(value,true);});
|
168
146
|
|
169
147
|
/**
|
170
148
|
* Retrieves the values at given paths of an object.
|
@@ -208,7 +186,7 @@ var cachedCopy=map.get(value);if(cachedCopy){return cachedCopy;}map.set(value,co
|
|
208
186
|
* R.path(['a', 'b', -2], {a: {b: [1, 2, 3]}}); //=> 2
|
209
187
|
* R.path([2], {'2': 2}); //=> 2
|
210
188
|
* R.path([-2], {'-2': 'a'}); //=> undefined
|
211
|
-
*/var path=/*#__PURE__*/_curry2(function path(pathAr,obj){return paths([pathAr],obj)[0];});
|
189
|
+
*/var path=/*#__PURE__*/_curry2(function path(pathAr,obj){return paths([pathAr],obj)[0];});
|
212
190
|
|
213
191
|
/**
|
214
192
|
* Creates a new object with the own properties of the two provided objects. If
|
@@ -291,7 +269,7 @@ var cachedCopy=map.get(value);if(cachedCopy){return cachedCopy;}map.set(value,co
|
|
291
269
|
* { a: true, c: { values: [10, 20] }},
|
292
270
|
* { b: true, c: { values: [15, 35] }});
|
293
271
|
* //=> { a: true, b: true, c: { values: [10, 20, 15, 35] }}
|
294
|
-
*/var mergeDeepWith=/*#__PURE__*/_curry3(function mergeDeepWith(fn,lObj,rObj){return mergeDeepWithKey(function(k,lVal,rVal){return fn(lVal,rVal);},lObj,rObj);});
|
272
|
+
*/var mergeDeepWith=/*#__PURE__*/_curry3(function mergeDeepWith(fn,lObj,rObj){return mergeDeepWithKey(function(k,lVal,rVal){return fn(lVal,rVal);},lObj,rObj);});
|
295
273
|
|
296
274
|
/**
|
297
275
|
* Returns a partial copy of an object containing only the keys that satisfy
|
@@ -312,13 +290,14 @@ var cachedCopy=map.get(value);if(cachedCopy){return cachedCopy;}map.set(value,co
|
|
312
290
|
*
|
313
291
|
* const isUpperCase = (val, key) => key.toUpperCase() === key;
|
314
292
|
* R.pickBy(isUpperCase, {a: 1, b: 2, A: 3, B: 4}); //=> {A: 3, B: 4}
|
315
|
-
*/var pickBy=/*#__PURE__*/_curry2(function pickBy(test,obj){var result={};for(var prop in obj){if(test(obj[prop],prop,obj)){result[prop]=obj[prop];}}return result;});
|
293
|
+
*/var pickBy=/*#__PURE__*/_curry2(function pickBy(test,obj){var result={};for(var prop in obj){if(test(obj[prop],prop,obj)){result[prop]=obj[prop];}}return result;});
|
316
294
|
|
317
295
|
/**
|
318
296
|
* A function to check given value is a function
|
319
297
|
* @param value input value
|
320
298
|
* @returns boolean
|
321
|
-
*/
|
299
|
+
*/ // eslint-disable-next-line @typescript-eslint/ban-types
|
300
|
+
const isFunction=value=>typeof value==='function'&&Boolean(value.constructor&&value.call&&value.apply);/**
|
322
301
|
* A function to check given value is a string
|
323
302
|
* @param value input value
|
324
303
|
* @returns boolean
|
@@ -352,7 +331,7 @@ var cachedCopy=map.get(value);if(cachedCopy){return cachedCopy;}map.set(value,co
|
|
352
331
|
* @returns true if the input is an instance of Error and false otherwise
|
353
332
|
*/const isTypeOfError=obj=>obj instanceof Error;
|
354
333
|
|
355
|
-
const getValueByPath=(obj,keyPath)=>{const pathParts=keyPath.split('.');return path
|
334
|
+
const getValueByPath=(obj,keyPath)=>{const pathParts=keyPath.split('.');return path(pathParts,obj);};const hasValueByPath=(obj,path)=>Boolean(getValueByPath(obj,path));/**
|
356
335
|
* Checks if the input is an object literal or built-in object type and not null
|
357
336
|
* @param value Input value
|
358
337
|
* @returns true if the input is an object and not null
|
@@ -360,8 +339,8 @@ const getValueByPath=(obj,keyPath)=>{const pathParts=keyPath.split('.');return p
|
|
360
339
|
* Checks if the input is an object literal and not null
|
361
340
|
* @param value Input value
|
362
341
|
* @returns true if the input is an object and not null
|
363
|
-
*/const isObjectLiteralAndNotNull=value=>!isNull(value)&&Object.prototype.toString.call(value)==='[object Object]';const mergeDeepRightObjectArrays=(leftValue,rightValue)=>{if(!Array.isArray(leftValue)||!Array.isArray(rightValue)){return clone
|
364
|
-
mergeDeepRight(mergedArray[index],value):value;});return mergedArray;};const mergeDeepRight=(leftObject,rightObject)=>mergeDeepWith
|
342
|
+
*/const isObjectLiteralAndNotNull=value=>!isNull(value)&&Object.prototype.toString.call(value)==='[object Object]';const mergeDeepRightObjectArrays=(leftValue,rightValue)=>{if(!Array.isArray(leftValue)||!Array.isArray(rightValue)){return clone(rightValue);}const mergedArray=clone(leftValue);rightValue.forEach((value,index)=>{mergedArray[index]=Array.isArray(value)||isObjectAndNotNull(value)?// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
343
|
+
mergeDeepRight(mergedArray[index],value):value;});return mergedArray;};const mergeDeepRight=(leftObject,rightObject)=>mergeDeepWith(mergeDeepRightObjectArrays,leftObject,rightObject);/**
|
365
344
|
Checks if the input is a non-empty object literal type and not undefined or null
|
366
345
|
* @param value input any
|
367
346
|
* @returns boolean
|
@@ -369,15 +348,11 @@ mergeDeepRight(mergedArray[index],value):value;});return mergedArray;};const mer
|
|
369
348
|
* A utility to recursively remove undefined values from an object
|
370
349
|
* @param obj input object
|
371
350
|
* @returns a new object
|
372
|
-
*/const removeUndefinedValues=obj=>{const result=pickBy
|
351
|
+
*/const removeUndefinedValues=obj=>{const result=pickBy(isDefined,obj);Object.keys(result).forEach(key=>{const value=result[key];if(isObjectLiteralAndNotNull(value)){result[key]=removeUndefinedValues(value);}});return result;};/**
|
373
352
|
* A utility to recursively remove undefined and null values from an object
|
374
353
|
* @param obj input object
|
375
354
|
* @returns a new object
|
376
|
-
*/const removeUndefinedAndNullValues=obj=>{const result=pickBy
|
377
|
-
* A utility to get all the values from an object
|
378
|
-
* @param obj Input object
|
379
|
-
* @returns an array of values from the input object
|
380
|
-
*/const getObjectValues=obj=>{const result=[];Object.keys(obj).forEach(key=>{result.push(obj[key]);});return result;};
|
355
|
+
*/const removeUndefinedAndNullValues=obj=>{const result=pickBy(isDefinedAndNotNull,obj);Object.keys(result).forEach(key=>{const value=result[key];if(isObjectLiteralAndNotNull(value)){result[key]=removeUndefinedAndNullValues(value);}});return result;};
|
381
356
|
|
382
357
|
const trim=value=>value.replace(/^\s+|\s+$/gm,'');const removeDoubleSpaces=value=>value.replace(/ {2,}/g,' ');/**
|
383
358
|
* A function to convert values to string
|
@@ -402,25 +377,25 @@ const trim=value=>value.replace(/^\s+|\s+$/gm,'');const removeDoubleSpaces=value
|
|
402
377
|
if(isString(category)&&!isString(name)){delete payload.category;payload.name=category;}// Rest of the code is just to clean up undefined values
|
403
378
|
// and set some proper defaults
|
404
379
|
// Also, to clone the incoming object type arguments
|
405
|
-
if(!isDefined(payload.category)){delete payload.category;}if(!isDefined(payload.name)){delete payload.name;}payload.properties=payload.properties?clone
|
380
|
+
if(!isDefined(payload.category)){delete payload.category;}if(!isDefined(payload.name)){delete payload.name;}payload.properties=payload.properties?clone(payload.properties):{};if(isDefined(payload.options)){payload.options=clone(payload.options);}else {delete payload.options;}// add name and category to properties
|
406
381
|
payload.properties=mergeDeepRight(isObjectLiteralAndNotNull(payload.properties)?payload.properties:{},{name:isString(payload.name)?payload.name:null,category:isString(payload.category)?payload.category:null});return payload;};/*
|
407
382
|
* Normalise the overloaded arguments of the track call facade
|
408
383
|
*/const trackArgumentsToCallOptions=(event,properties,options,callback)=>{const payload={name:event,properties:properties,options:options};if(isFunction(callback)){payload.callback=callback;}if(isFunction(options)){payload.properties=properties;delete payload.options;payload.callback=options;}if(isFunction(properties)){delete payload.properties;delete payload.options;payload.callback=properties;}// Rest of the code is just to clean up undefined values
|
409
384
|
// and set some proper defaults
|
410
385
|
// Also, to clone the incoming object type arguments
|
411
|
-
payload.properties=isDefinedAndNotNull(payload.properties)?clone
|
386
|
+
payload.properties=isDefinedAndNotNull(payload.properties)?clone(payload.properties):{};if(isDefined(payload.options)){payload.options=clone(payload.options);}else {delete payload.options;}return payload;};/*
|
412
387
|
* Normalise the overloaded arguments of the identify call facade
|
413
388
|
*/const identifyArgumentsToCallOptions=(userId,traits,options,callback)=>{const payload={userId:userId,traits:traits,options:options};if(isFunction(callback)){payload.callback=callback;}if(isFunction(options)){payload.userId=userId;payload.traits=traits;delete payload.options;payload.callback=options;}if(isFunction(traits)){payload.userId=userId;delete payload.traits;delete payload.options;payload.callback=traits;}if(isObjectLiteralAndNotNull(userId)||isNull(userId)){// Explicitly set null to prevent resetting the existing value
|
414
389
|
// in the Analytics class
|
415
390
|
payload.userId=null;payload.traits=userId;payload.options=traits;}// Rest of the code is just to clean up undefined values
|
416
391
|
// and set some proper defaults
|
417
392
|
// Also, to clone the incoming object type arguments
|
418
|
-
if(isDefined(payload.userId)){payload.userId=tryStringify(payload.userId);}else {delete payload.userId;}if(isObjectLiteralAndNotNull(payload.traits)){payload.traits=clone
|
393
|
+
if(isDefined(payload.userId)){payload.userId=tryStringify(payload.userId);}else {delete payload.userId;}if(isObjectLiteralAndNotNull(payload.traits)){payload.traits=clone(payload.traits);}else {delete payload.traits;}if(isDefined(payload.options)){payload.options=clone(payload.options);}else {delete payload.options;}return payload;};/*
|
419
394
|
* Normalise the overloaded arguments of the alias call facade
|
420
395
|
*/const aliasArgumentsToCallOptions=(to,from,options,callback)=>{const payload={to:to,from:from,options:options};if(isFunction(callback)){payload.callback=callback;}if(isFunction(options)){payload.to=to;payload.from=from;delete payload.options;payload.callback=options;}if(isFunction(from)){payload.to=to;delete payload.from;delete payload.options;payload.callback=from;}else if(isObjectLiteralAndNotNull(from)||isNull(from)){payload.to=to;delete payload.from;payload.options=from;}if(isFunction(to)){delete payload.to;delete payload.from;delete payload.options;payload.callback=to;}else if(isObjectLiteralAndNotNull(to)||isNull(to)){delete payload.to;delete payload.from;payload.options=to;}// Rest of the code is just to clean up undefined values
|
421
396
|
// and set some proper defaults
|
422
397
|
// Also, to clone the incoming object type arguments
|
423
|
-
if(isDefined(payload.to)){payload.to=tryStringify(payload.to);}else {delete payload.to;}if(isDefined(payload.from)){payload.from=tryStringify(payload.from);}else {delete payload.from;}if(isDefined(payload.options)){payload.options=clone
|
398
|
+
if(isDefined(payload.to)){payload.to=tryStringify(payload.to);}else {delete payload.to;}if(isDefined(payload.from)){payload.from=tryStringify(payload.from);}else {delete payload.from;}if(isDefined(payload.options)){payload.options=clone(payload.options);}else {delete payload.options;}return payload;};/*
|
424
399
|
* Normalise the overloaded arguments of the group call facade
|
425
400
|
*/const groupArgumentsToCallOptions=(groupId,traits,options,callback)=>{const payload={groupId:groupId,traits:traits,options:options};if(isFunction(callback)){payload.callback=callback;}if(isFunction(options)){payload.groupId=groupId;payload.traits=traits;delete payload.options;payload.callback=options;}if(isFunction(traits)){payload.groupId=groupId;delete payload.traits;delete payload.options;payload.callback=traits;}// TODO: why do we enable overload for group that only passes callback? is there any use case?
|
426
401
|
if(isFunction(groupId)){// Explicitly set null to prevent resetting the existing value
|
@@ -429,11 +404,11 @@ payload.groupId=null;delete payload.traits;delete payload.options;payload.callba
|
|
429
404
|
payload.groupId=null;payload.traits=groupId;payload.options=!isFunction(traits)?traits:null;}// Rest of the code is just to clean up undefined values
|
430
405
|
// and set some proper defaults
|
431
406
|
// Also, to clone the incoming object type arguments
|
432
|
-
if(isDefined(payload.groupId)){payload.groupId=tryStringify(payload.groupId);}else {delete payload.groupId;}payload.traits=isObjectLiteralAndNotNull(payload.traits)?clone
|
407
|
+
if(isDefined(payload.groupId)){payload.groupId=tryStringify(payload.groupId);}else {delete payload.groupId;}payload.traits=isObjectLiteralAndNotNull(payload.traits)?clone(payload.traits):{};if(isDefined(payload.options)){payload.options=clone(payload.options);}else {delete payload.options;}return payload;};
|
433
408
|
|
434
|
-
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='readyApi';const
|
409
|
+
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='readyApi';const EVENT_REPOSITORY='EventRepository';const EXTERNAL_SRC_LOADER='ExternalSrcLoader';const HTTP_CLIENT='HttpClient';const RS_APP='RudderStackApplication';const ANALYTICS_CORE='AnalyticsCore';
|
435
410
|
|
436
|
-
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.0.
|
411
|
+
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.0.1';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';
|
437
412
|
|
438
413
|
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';
|
439
414
|
|
@@ -466,11 +441,17 @@ if(queryObject.get(QUERY_PARAM_ANONYMOUS_ID_KEY)){argumentsArray.unshift(['setAn
|
|
466
441
|
* Retrieve an existing buffered load method call and remove from the existing array
|
467
442
|
*/const getPreloadedLoadEvent=preloadedEventsArray=>{const loadMethodName='load';let loadEvent=[];/**
|
468
443
|
* Iterate the buffered API calls until we find load call and process it separately
|
469
|
-
*/let i=0;while(i<preloadedEventsArray.length){if(preloadedEventsArray[i]&&preloadedEventsArray[i][0]===loadMethodName){loadEvent=preloadedEventsArray[i];preloadedEventsArray.splice(i,1);break;}i+=1;}return loadEvent;};/**
|
444
|
+
*/let i=0;while(i<preloadedEventsArray.length){if(preloadedEventsArray[i]&&preloadedEventsArray[i][0]===loadMethodName){loadEvent=clone(preloadedEventsArray[i]);preloadedEventsArray.splice(i,1);break;}i+=1;}return loadEvent;};/**
|
445
|
+
* Promote consent events to the top of the preloaded events array
|
446
|
+
* @param preloadedEventsArray Preloaded events array
|
447
|
+
* @returns None
|
448
|
+
*/const promotePreloadedConsentEventsToTop=preloadedEventsArray=>{const consentMethodName='consent';const consentEvents=preloadedEventsArray.filter(bufferedEvent=>bufferedEvent[0]===consentMethodName);const nonConsentEvents=preloadedEventsArray.filter(bufferedEvent=>bufferedEvent[0]!==consentMethodName);// Remove all elements and add consent events first followed by non consent events
|
449
|
+
// eslint-disable-next-line unicorn/no-useless-spread
|
450
|
+
preloadedEventsArray.splice(0,preloadedEventsArray.length,...consentEvents,...nonConsentEvents);};/**
|
470
451
|
* Retrieve any existing events that were triggered before SDK load and enqueue in buffer
|
471
452
|
*/const retrievePreloadBufferEvents=instance=>{const preloadedEventsArray=getExposedGlobal(GLOBAL_PRELOAD_BUFFER)||[];// Get events that are pre-populated via query string params
|
472
|
-
retrieveEventsFromQueryString(preloadedEventsArray)
|
473
|
-
if(
|
453
|
+
retrieveEventsFromQueryString(preloadedEventsArray);// Enqueue the non load events in the buffer of the global rudder analytics singleton
|
454
|
+
if(preloadedEventsArray.length>0){instance.enqueuePreloadBufferEvents(preloadedEventsArray);setExposedGlobal(GLOBAL_PRELOAD_BUFFER,[]);}};const consumePreloadBufferedEvent=(event,analyticsInstance)=>{const methodName=event.shift();let callOptions;if(isFunction(analyticsInstance[methodName])){switch(methodName){case'page':callOptions=pageArgumentsToCallOptions(...event);break;case'track':callOptions=trackArgumentsToCallOptions(...event);break;case'identify':callOptions=identifyArgumentsToCallOptions(...event);break;case'alias':callOptions=aliasArgumentsToCallOptions(...event);break;case'group':callOptions=groupArgumentsToCallOptions(...event);break;default:analyticsInstance[methodName](...event);break;}if(callOptions){analyticsInstance[methodName](callOptions);}}};
|
474
455
|
|
475
456
|
const DEFAULT_EXT_SRC_LOAD_TIMEOUT_MS=10*1000;// 10 seconds
|
476
457
|
|
@@ -517,9 +498,9 @@ const EXTERNAL_SOURCE_LOAD_ORIGIN='RS_JS_SDK';
|
|
517
498
|
*
|
518
499
|
* @returns
|
519
500
|
*/const insertScript=newScriptElement=>{// First try to add it to the head
|
520
|
-
const headElements=document.getElementsByTagName('head');if(headElements.length>0){headElements[0]
|
521
|
-
const scriptElements=document.getElementsByTagName('script');if(scriptElements.length>0&&scriptElements[0]
|
522
|
-
const headElement=document.createElement('head');headElement.appendChild(newScriptElement);const htmlElement=document.getElementsByTagName('html')[0];htmlElement
|
501
|
+
const headElements=document.getElementsByTagName('head');if(headElements.length>0){headElements[0]?.insertBefore(newScriptElement,headElements[0]?.firstChild);return;}// Else wise add it before the first script tag
|
502
|
+
const scriptElements=document.getElementsByTagName('script');if(scriptElements.length>0&&scriptElements[0]?.parentNode){scriptElements[0]?.parentNode.insertBefore(newScriptElement,scriptElements[0]);return;}// Create a new head element and add the script as fallback
|
503
|
+
const headElement=document.createElement('head');headElement.appendChild(newScriptElement);const htmlElement=document.getElementsByTagName('html')[0];htmlElement?.insertBefore(headElement,htmlElement.firstChild);};/**
|
523
504
|
* Loads external js file as a script html tag
|
524
505
|
*
|
525
506
|
* @param {*} url The URL of the script to be loaded
|
@@ -537,23 +518,19 @@ timeoutID=globalThis.setTimeout(()=>{reject(new Error(SCRIPT_LOAD_TIMEOUT_ERROR(
|
|
537
518
|
* Service to load external resources/files
|
538
519
|
*/class ExternalSrcLoader{hasErrorHandler=false;constructor(errorHandler,logger,timeout=DEFAULT_EXT_SRC_LOAD_TIMEOUT_MS){this.errorHandler=errorHandler;this.logger=logger;this.timeout=timeout;this.hasErrorHandler=Boolean(this.errorHandler);this.onError=this.onError.bind(this);}/**
|
539
520
|
* Load external resource of type javascript
|
540
|
-
*/loadJSFile(config){const{url,id,timeout,async,callback,extraAttributes}=config;const isFireAndForget=!
|
521
|
+
*/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();}});}/**
|
541
522
|
* Handle errors
|
542
523
|
*/onError(error){if(this.hasErrorHandler){this.errorHandler?.onError(error,EXTERNAL_SRC_LOADER);}else {throw error;}}}
|
543
524
|
|
544
|
-
function i(){throw new Error("Cycle detected");}
|
545
|
-
|
546
|
-
let LifecycleStatus=/*#__PURE__*/function(LifecycleStatus){LifecycleStatus["Mounted"]="mounted";LifecycleStatus["BrowserCapabilitiesReady"]="browserCapabilitiesReady";LifecycleStatus["Configured"]="configured";LifecycleStatus["PluginsLoading"]="pluginsLoading";LifecycleStatus["PluginsReady"]="pluginsReady";LifecycleStatus["Initialized"]="initialized";LifecycleStatus["Loaded"]="loaded";LifecycleStatus["DestinationsLoading"]="destinationsLoading";LifecycleStatus["DestinationsReady"]="destinationsReady";LifecycleStatus["Ready"]="ready";return LifecycleStatus;}({});
|
525
|
+
function i(){throw new Error("Cycle detected");}var t=Symbol.for("preact-signals");function r(){if(!(v>1)){var i,t=!1;while(void 0!==f){var r=f;f=void 0;e++;while(void 0!==r){var n=r.o;r.o=void 0;r.f&=-3;if(!(8&r.f)&&l(r))try{r.c();}catch(r){if(!t){i=r;t=!0;}}r=n;}}e=0;v--;if(t)throw i;}else v--;}function n(i){if(v>0)return i();v++;try{return i();}finally{r();}}var o=void 0;var f=void 0,v=0,e=0,u=0;function c(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 d(i){this.v=i;this.i=0;this.n=void 0;this.t=void 0;}d.prototype.brand=t;d.prototype.h=function(){return !0;};d.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;}};d.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;}};d.prototype.subscribe=function(i){var t=this;return O(function(){var r=t.value,n=32&this.f;this.f&=-33;try{i(r);}finally{this.f|=n;}});};d.prototype.valueOf=function(){return this.value;};d.prototype.toString=function(){return this.value+"";};d.prototype.toJSON=function(){return this.value;};d.prototype.peek=function(){return this.v;};Object.defineProperty(d.prototype,"value",{get:function(){var i=c(this);if(void 0!==i)i.i=this.i;return this.v;},set:function(t){if(o instanceof _)!function(){throw new Error("Computed cannot have side-effects");}();if(t!==this.v){if(e>100)i();this.v=t;this.i++;u++;v++;try{for(var n=this.t;void 0!==n;n=n.x)n.t.N();}finally{r();}}}});function a(i){return new d(i);}function l(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 !0;return !1;}function y(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 w(i){var t=i.s,r=void 0;while(void 0!==t){var n=t.p;if(-1===t.i){t.S.U(t);if(void 0!==n)n.n=t.n;if(void 0!==t.n)t.n.p=n;}else r=t;t.S.n=t.r;if(void 0!==t.r)t.r=void 0;t=n;}i.s=r;}function _(i){d.call(this,void 0);this.x=i;this.s=void 0;this.g=u-1;this.f=4;}(_.prototype=new d()).h=function(){this.f&=-3;if(1&this.f)return !1;if(32==(36&this.f))return !0;this.f&=-5;if(this.g===u)return !0;this.g=u;this.f|=1;if(this.i>0&&!l(this)){this.f&=-2;return !0;}var i=o;try{y(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;w(this);this.f&=-2;return !0;};_.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);}d.prototype.S.call(this,i);};_.prototype.U=function(i){if(void 0!==this.t){d.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);}}};_.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var i=this.t;void 0!==i;i=i.x)i.t.N();}};_.prototype.peek=function(){if(!this.h())i();if(16&this.f)throw this.v;return this.v;};Object.defineProperty(_.prototype,"value",{get:function(){if(1&this.f)i();var t=c(this);this.h();if(void 0!==t)t.i=this.i;if(16&this.f)throw this.v;return this.v;}});function g(i){var t=i.u;i.u=void 0;if("function"==typeof t){v++;var n=o;o=void 0;try{t();}catch(t){i.f&=-2;i.f|=8;b(i);throw t;}finally{o=n;r();}}}function b(i){for(var t=i.s;void 0!==t;t=t.n)t.S.U(t);i.x=void 0;i.s=void 0;g(i);}function x(i){if(o!==this)throw new Error("Out-of-order effect");w(this);o=i;this.f&=-2;if(8&this.f)b(this);r();}function E(i){this.x=i;this.u=void 0;this.s=void 0;this.o=void 0;this.f=32;}E.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();}};E.prototype.S=function(){if(1&this.f)i();this.f|=1;this.f&=-9;g(this);y(this);v++;var t=o;o=this;return x.bind(this,t);};E.prototype.N=function(){if(!(2&this.f)){this.f|=2;this.o=f;f=this;}};E.prototype.d=function(){this.f|=8;if(!(1&this.f))b(this);};function O(i){var t=new E(i);try{t.c();}catch(i){t.d();throw i;}return t.d.bind(t);}
|
547
526
|
|
548
|
-
// TODO: should we take the types from IdentifyTrait instead of any string key?
|
549
|
-
// https://www.rudderstack.com/docs/event-spec/standard-events/identify/#identify-traits
|
550
527
|
/**
|
551
|
-
*
|
552
|
-
*/
|
528
|
+
* A buffer queue to serve as a store for any type of data
|
529
|
+
*/class BufferQueue{constructor(){this.items=[];}enqueue(item){this.items.push(item);}dequeue(){if(this.items.length===0){return null;}return this.items.shift();}isEmpty(){return this.items.length===0;}size(){return this.items.length;}clear(){this.items=[];}}
|
553
530
|
|
554
|
-
const LOG_LEVEL_MAP={
|
531
|
+
const LOG_LEVEL_MAP={LOG:0,INFO:1,DEBUG:2,WARN:3,ERROR:4,NONE:5};const DEFAULT_LOG_LEVEL='ERROR';const LOG_MSG_PREFIX='RS SDK';const LOG_MSG_PREFIX_STYLE='font-weight: bold; background: black; color: white;';const LOG_MSG_STYLE='font-weight: normal;';/**
|
555
532
|
* Service to log messages/data to output provider, default is console
|
556
|
-
*/class Logger{constructor(minLogLevel=DEFAULT_LOG_LEVEL,scope='',logProvider=console){this.minLogLevel=LOG_LEVEL_MAP[minLogLevel];this.scope=scope;this.logProvider=logProvider;}log(...data){this.outputLog(
|
533
|
+
*/class Logger{constructor(minLogLevel=DEFAULT_LOG_LEVEL,scope='',logProvider=console){this.minLogLevel=LOG_LEVEL_MAP[minLogLevel];this.scope=scope;this.logProvider=logProvider;}log(...data){this.outputLog('LOG',data);}info(...data){this.outputLog('INFO',data);}debug(...data){this.outputLog('DEBUG',data);}warn(...data){this.outputLog('WARN',data);}error(...data){this.outputLog('ERROR',data);}outputLog(logMethod,data){if(this.minLogLevel<=LOG_LEVEL_MAP[logMethod]){this.logProvider[logMethod.toLowerCase()]?.(...this.formatLogData(data));}}setScope(scopeVal){this.scope=scopeVal||this.scope;}// TODO: should we allow to change the level via global variable on run time
|
557
534
|
// to assist on the fly debugging?
|
558
535
|
setMinLogLevel(logLevel){this.minLogLevel=LOG_LEVEL_MAP[logLevel];if(isUndefined(this.minLogLevel)){this.minLogLevel=LOG_LEVEL_MAP[DEFAULT_LOG_LEVEL];}}/**
|
559
536
|
* Formats the console message using `scope` and styles
|
@@ -567,53 +544,53 @@ LOG_MSG_STYLE// reset the style for the actual message
|
|
567
544
|
if(!isString(data[0])){styledLogArgs.push(data[0]);}// append rest of the original arguments
|
568
545
|
styledLogArgs.push(...data.slice(1));return styledLogArgs;}return data;}}const defaultLogger=new Logger();
|
569
546
|
|
570
|
-
|
547
|
+
// default is v3
|
548
|
+
const SUPPORTED_STORAGE_TYPES=['localStorage','memoryStorage','cookieStorage','sessionStorage','none'];const DEFAULT_STORAGE_TYPE='cookieStorage';
|
549
|
+
|
550
|
+
const SOURCE_CONFIG_OPTION_ERROR=`"getSourceConfig" must be a function. Please make sure that it is defined and returns a valid source configuration object.`;const INTG_CDN_BASE_URL_ERROR=`Failed to load the SDK as the CDN base URL for integrations is not valid.`;const PLUGINS_CDN_BASE_URL_ERROR=`Failed to load the SDK as the CDN base URL for plugins is not valid.`;const DATA_PLANE_URL_ERROR=`Failed to load the SDK as the data plane URL could not be determined. Please check that the data plane URL is set correctly and try again.`;const SOURCE_CONFIG_RESOLUTION_ERROR=`Unable to process/parse source configuration response.`;const XHR_PAYLOAD_PREP_ERROR=`Failed to prepare data for the request.`;const EVENT_OBJECT_GENERATION_ERROR=`Failed to generate the event object.`;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.`;// ERROR
|
571
551
|
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 REPORTING_PLUGIN_INIT_FAILURE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to initialize the error reporting plugin.`;const NOTIFY_FAILURE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to notify 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=reason=>`Failed to fetch the source config. Reason: ${reason}`;const WRITE_KEY_VALIDATION_ERROR=writeKey=>`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=dataPlaneUrl=>`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 READY_API_CALLBACK_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}The callback is not a function.`;const XHR_DELIVERY_ERROR=(prefix,status,statusText,url)=>`${prefix} with status: ${status}, ${statusText} for URL: ${url}.`;const XHR_REQUEST_ERROR=(prefix,e,url)=>`${prefix} due to timeout or no connection (${e?e.type:''}) 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`;// WARNING
|
572
|
-
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_ERROR_REPORTING_PROVIDER_WARNING=(context,selectedErrorReportingProvider,errorReportingProvidersToPluginNameMap,defaultProvider)=>`${context}${LOG_CONTEXT_SEPARATOR}The error reporting provider "${selectedErrorReportingProvider}" is not supported. Please choose one of the following supported providers: "${Object.keys(errorReportingProvidersToPluginNameMap)}". The default provider "${defaultProvider}" 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 UNSUPPORTED_RESIDENCY_SERVER_REGION_WARNING=(context,selectedResidencyServerRegion,defaultRegion)=>`${context}${LOG_CONTEXT_SEPARATOR}The residency server region "${selectedResidencyServerRegion}" is not supported. Please choose one of the following supported regions: "
|
552
|
+
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_ERROR_REPORTING_PROVIDER_WARNING=(context,selectedErrorReportingProvider,errorReportingProvidersToPluginNameMap,defaultProvider)=>`${context}${LOG_CONTEXT_SEPARATOR}The error reporting provider "${selectedErrorReportingProvider}" is not supported. Please choose one of the following supported providers: "${Object.keys(errorReportingProvidersToPluginNameMap)}". The default provider "${defaultProvider}" 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 UNSUPPORTED_RESIDENCY_SERVER_REGION_WARNING=(context,selectedResidencyServerRegion,defaultRegion)=>`${context}${LOG_CONTEXT_SEPARATOR}The residency server region "${selectedResidencyServerRegion}" is not supported. Please choose one of the following supported regions: "US, EU". The default region "${defaultRegion}" will be used instead.`;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 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 WRITE_KEY_NOT_A_STRING_ERROR=(context,writeKey)=>`${context}${LOG_CONTEXT_SEPARATOR}The write key "${writeKey}" is not a string. Please check that the write key is correct and try again.`;const EMPTY_GROUP_CALL_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}The group() method must be called with at least one argument.`;const READY_CALLBACK_INVOKE_ERROR=`Failed to invoke the ready callback`;const API_CALLBACK_INVOKE_ERROR=`API Callback Invocation Failed`;const NATIVE_DEST_PLUGIN_INITIALIZE_ERROR=`NativeDestinationQueuePlugin initialization failed`;const DATAPLANE_PLUGIN_INITIALIZE_ERROR=`XhrQueuePlugin initialization failed`;const DMT_PLUGIN_INITIALIZE_ERROR=`DeviceModeTransformationPlugin initialization failed`;const NATIVE_DEST_PLUGIN_ENQUEUE_ERROR=`NativeDestinationQueuePlugin event enqueue failed`;const DATAPLANE_PLUGIN_ENQUEUE_ERROR=`XhrQueuePlugin event enqueue failed`;const INVALID_CONFIG_URL_WARNING=(context,configUrl)=>`${context}${LOG_CONTEXT_SEPARATOR}The provided config URL "${configUrl}" is invalid. Using the default value instead.`;const POLYFILL_SCRIPT_LOAD_ERROR=(scriptId,url)=>`Failed to load the polyfill script with ID "${scriptId}" from URL ${url}.`;const COOKIE_DATA_ENCODING_ERROR=`Failed to encode the cookie data.`;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.`;// DEBUG
|
573
553
|
|
574
554
|
const CDN_INT_DIR='js-integrations';const CDN_PLUGINS_DIR='plugins';
|
575
555
|
|
576
|
-
const BUILD_TYPE='modern';const SDK_CDN_BASE_URL='https://cdn.rudderlabs.com';const CDN_ARCH_VERSION_DIR='v3';const DEST_SDK_BASE_URL=`${SDK_CDN_BASE_URL}
|
577
|
-
// const DEST_SDK_BASE_URL = `${SDK_CDN_BASE_URL}/latest/${CDN_ARCH_VERSION_DIR}/${BUILD_TYPE}/${CDN_INT_DIR}`;
|
578
|
-
// const PLUGINS_BASE_URL = `${SDK_CDN_BASE_URL}/latest/${CDN_ARCH_VERSION_DIR}/${BUILD_TYPE}/${CDN_PLUGINS_DIR}`;
|
579
|
-
const DEFAULT_CONFIG_BE_URL='https://api.rudderstack.com';
|
556
|
+
const BUILD_TYPE='modern';const SDK_CDN_BASE_URL='https://cdn.rudderlabs.com';const CDN_ARCH_VERSION_DIR='v3';const DEST_SDK_BASE_URL=`${SDK_CDN_BASE_URL}/${CDN_ARCH_VERSION_DIR}/${BUILD_TYPE}/${CDN_INT_DIR}`;const PLUGINS_BASE_URL=`${SDK_CDN_BASE_URL}/${CDN_ARCH_VERSION_DIR}/${BUILD_TYPE}/${CDN_PLUGINS_DIR}`;const DEFAULT_CONFIG_BE_URL='https://api.rudderstack.com';
|
580
557
|
|
581
|
-
const DEFAULT_ERROR_REPORTING_PROVIDER='bugsnag';const DEFAULT_STORAGE_ENCRYPTION_VERSION=
|
558
|
+
const DEFAULT_ERROR_REPORTING_PROVIDER='bugsnag';const DEFAULT_STORAGE_ENCRYPTION_VERSION='v3';const ConsentManagersToPluginNameMap={oneTrust:'OneTrustConsentManager',ketch:'KetchConsentManager',custom:'CustomConsentManager'};const ErrorReportingProvidersToPluginNameMap={[DEFAULT_ERROR_REPORTING_PROVIDER]:'Bugsnag'};const StorageEncryptionVersionsToPluginNameMap={[DEFAULT_STORAGE_ENCRYPTION_VERSION]:'StorageEncryption',legacy:'StorageEncryptionLegacy'};
|
582
559
|
|
583
|
-
const defaultLoadOptions={logLevel:
|
560
|
+
const defaultLoadOptions={logLevel:'ERROR',configUrl:DEFAULT_CONFIG_BE_URL,loadIntegration:true,sessions:{autoTrack:true,timeout:DEFAULT_SESSION_TIMEOUT_MS},sameSiteCookie:'Lax',polyfillIfRequired:true,integrations:{All:true},useBeacon:false,beaconQueueOptions:{},destinationsQueueOptions:{},queueOptions:{},lockIntegrationsVersion:false,uaChTrackLevel:'none',plugins:[],useGlobalIntegrationsConfigInEvents:false,bufferDataPlaneEventsUntilReady:false,dataPlaneEventsBufferTimeout:DEFAULT_DATA_PLANE_EVENTS_BUFFER_TIMEOUT_MS,storage:{encryption:{version:DEFAULT_STORAGE_ENCRYPTION_VERSION},migrate:true},sendAdblockPageOptions:{}};const loadOptionsState=a(clone(defaultLoadOptions));
|
584
561
|
|
585
|
-
const
|
562
|
+
const USER_SESSION_STORAGE_KEYS={userId:'rl_user_id',userTraits:'rl_trait',anonymousId:'rl_anonymous_id',groupId:'rl_group_id',groupTraits:'rl_group_trait',initialReferrer:'rl_page_init_referrer',initialReferringDomain:'rl_page_init_referring_domain',sessionInfo:'rl_session',authToken:'rl_auth_token'};const DEFAULT_USER_SESSION_VALUES={userId:'',userTraits:{},anonymousId:'',groupId:'',groupTraits:{},initialReferrer:'',initialReferringDomain:'',sessionInfo:{},authToken:null};
|
586
563
|
|
587
|
-
const defaultSessionInfo={autoTrack:true,timeout:DEFAULT_SESSION_TIMEOUT_MS};const sessionState={userId:
|
564
|
+
const defaultSessionInfo={autoTrack:true,timeout:DEFAULT_SESSION_TIMEOUT_MS};const sessionState={userId:a(DEFAULT_USER_SESSION_VALUES.userId),userTraits:a(DEFAULT_USER_SESSION_VALUES.userTraits),anonymousId:a(DEFAULT_USER_SESSION_VALUES.anonymousId),groupId:a(DEFAULT_USER_SESSION_VALUES.groupId),groupTraits:a(DEFAULT_USER_SESSION_VALUES.groupTraits),initialReferrer:a(DEFAULT_USER_SESSION_VALUES.initialReferrer),initialReferringDomain:a(DEFAULT_USER_SESSION_VALUES.initialReferringDomain),sessionInfo:a(DEFAULT_USER_SESSION_VALUES.sessionInfo),authToken:a(DEFAULT_USER_SESSION_VALUES.authToken)};
|
588
565
|
|
589
|
-
const capabilitiesState={isOnline:
|
566
|
+
const capabilitiesState={isOnline:a(true),storage:{isLocalStorageAvailable:a(false),isCookieStorageAvailable:a(false),isSessionStorageAvailable:a(false)},isBeaconAvailable:a(false),isLegacyDOM:a(false),isUaCHAvailable:a(false),isCryptoAvailable:a(false),isIE11:a(false),isAdBlocked:a(false)};
|
590
567
|
|
591
|
-
const reportingState={isErrorReportingEnabled:
|
568
|
+
const reportingState={isErrorReportingEnabled:a(false),isMetricsReportingEnabled:a(false),errorReportingProviderPluginName:a(undefined),isErrorReportingPluginLoaded:a(false)};
|
592
569
|
|
593
|
-
const sourceConfigState=
|
570
|
+
const sourceConfigState=a(undefined);
|
594
571
|
|
595
|
-
const lifecycleState={activeDataplaneUrl:
|
572
|
+
const lifecycleState={activeDataplaneUrl:a(undefined),integrationsCDNPath:a(DEST_SDK_BASE_URL),pluginsCDNPath:a(PLUGINS_BASE_URL),sourceConfigUrl:a(undefined),status:a(undefined),initialized:a(false),logLevel:a('ERROR'),loaded:a(false),readyCallbacks:a([]),writeKey:a(undefined),dataPlaneUrl:a(undefined)};
|
596
573
|
|
597
|
-
const consentsState={
|
574
|
+
const consentsState={enabled:a(false),initialized:a(false),data:a({}),activeConsentManagerPluginName:a(undefined),preConsent:a({enabled:false}),postConsent:a({}),resolutionStrategy:a('and'),provider:a(undefined),metadata:a(undefined)};
|
598
575
|
|
599
|
-
const metricsState={retries:
|
576
|
+
const metricsState={retries:a(0),dropped:a(0),sent:a(0),queued:a(0),triggered:a(0)};
|
600
577
|
|
601
|
-
const contextState={app:
|
578
|
+
const contextState={app:a({name:APP_NAME,namespace:APP_NAMESPACE,version:APP_VERSION}),traits:a(null),library:a({name:APP_NAME,version:APP_VERSION,snippetVersion:globalThis.RudderSnippetVersion}),userAgent:a(''),device:a(null),network:a(null),os:a({name:'',version:''}),locale:a(null),screen:a({density:0,width:0,height:0,innerWidth:0,innerHeight:0}),'ua-ch':a(undefined),timezone:a(undefined)};
|
602
579
|
|
603
|
-
const nativeDestinationsState={configuredDestinations:
|
580
|
+
const nativeDestinationsState={configuredDestinations:a([]),activeDestinations:a([]),loadOnlyIntegrations:a({}),failedDestinations:a([]),loadIntegration:a(true),initializedDestinations:a([]),clientDestinationsReady:a(false),integrationsConfig:a({})};
|
604
581
|
|
605
|
-
const eventBufferState={toBeProcessedArray:
|
582
|
+
const eventBufferState={toBeProcessedArray:a([]),readyCallbacksArray:a([])};
|
606
583
|
|
607
|
-
const pluginsState={ready:
|
584
|
+
const pluginsState={ready:a(false),loadedPlugins:a([]),failedPlugins:a([]),pluginsToLoadFromConfig:a([]),activePlugins:a([]),totalPluginsToLoad:a(0)};
|
608
585
|
|
609
|
-
const storageState={encryptionPluginName:
|
586
|
+
const storageState={encryptionPluginName:a(undefined),migrate:a(false),type:a(undefined),cookie:a(undefined),entries:a({}),trulyAnonymousTracking:a(false)};
|
610
587
|
|
611
|
-
const defaultStateValues={capabilities:capabilitiesState,consents:consentsState,context:contextState,eventBuffer:eventBufferState,lifecycle:lifecycleState,loadOptions:loadOptionsState,metrics:metricsState,nativeDestinations:nativeDestinationsState,plugins:pluginsState,reporting:reportingState,session:sessionState,source:sourceConfigState,storage:storageState};const state={...clone
|
588
|
+
const defaultStateValues={capabilities:capabilitiesState,consents:consentsState,context:contextState,eventBuffer:eventBufferState,lifecycle:lifecycleState,loadOptions:loadOptionsState,metrics:metricsState,nativeDestinations:nativeDestinationsState,plugins:pluginsState,reporting:reportingState,session:sessionState,source:sourceConfigState,storage:storageState};const state={...clone(defaultStateValues)};
|
612
589
|
|
613
590
|
// to next or return the value if it is the last one instead of an array per
|
614
591
|
// plugin that is the normal invoke
|
615
592
|
// TODO: add invoke method for extension point that we know only one plugin can be used. add invokeMultiple and invokeSingle methods
|
616
|
-
class PluginEngine{plugins=[];byName={};cache={};config={throws:true};constructor(options={},logger){this.config={throws:true,...options};this.logger=logger;}register(plugin,state){if(!plugin.name){const errorMessage=PLUGIN_NAME_MISSING_ERROR(PLUGIN_ENGINE);if(this.config.throws){throw new Error(errorMessage);}else {this.logger?.error(errorMessage,plugin);}}if(this.byName[plugin.name]){const errorMessage=PLUGIN_ALREADY_EXISTS_ERROR(PLUGIN_ENGINE,plugin.name);if(this.config.throws){throw new Error(errorMessage);}else {this.logger?.error(errorMessage);}}this.cache={};this.plugins=this.plugins.slice();let pos=this.plugins.length;this.plugins.forEach((pluginItem,index)=>{if(pluginItem.deps?.includes(plugin.name)){pos=Math.min(pos,index);}});this.plugins.splice(pos,0,plugin);this.byName[plugin.name]=plugin;if(
|
593
|
+
class PluginEngine{plugins=[];byName={};cache={};config={throws:true};constructor(options={},logger){this.config={throws:true,...options};this.logger=logger;}register(plugin,state){if(!plugin.name){const errorMessage=PLUGIN_NAME_MISSING_ERROR(PLUGIN_ENGINE);if(this.config.throws){throw new Error(errorMessage);}else {this.logger?.error(errorMessage,plugin);}}if(this.byName[plugin.name]){const errorMessage=PLUGIN_ALREADY_EXISTS_ERROR(PLUGIN_ENGINE,plugin.name);if(this.config.throws){throw new Error(errorMessage);}else {this.logger?.error(errorMessage);}}this.cache={};this.plugins=this.plugins.slice();let pos=this.plugins.length;this.plugins.forEach((pluginItem,index)=>{if(pluginItem.deps?.includes(plugin.name)){pos=Math.min(pos,index);}});this.plugins.splice(pos,0,plugin);this.byName[plugin.name]=plugin;if(isFunction(plugin.initialize)){plugin.initialize(state);}}unregister(name){const plugin=this.byName[name];if(!plugin){const errorMessage=PLUGIN_NOT_FOUND_ERROR(PLUGIN_ENGINE,name);if(this.config.throws){throw new Error(errorMessage);}else {this.logger?.error(errorMessage);}}const index=this.plugins.indexOf(plugin);if(index===-1){const errorMessage=PLUGIN_ENGINE_BUG_ERROR(PLUGIN_ENGINE,name);if(this.config.throws){throw new Error(errorMessage);}else {this.logger?.error(errorMessage);}}this.cache={};delete this.byName[name];this.plugins=this.plugins.slice();this.plugins.splice(index,1);}getPlugin(name){return this.byName[name];}getPlugins(extPoint){const lifeCycleName=extPoint??'.';if(!this.cache[lifeCycleName]){this.cache[lifeCycleName]=this.plugins.filter(plugin=>{if(plugin.deps?.some(dependency=>!this.byName[dependency])){// If deps not exist, then not load it.
|
617
594
|
const notExistDeps=plugin.deps.filter(dependency=>!this.byName[dependency]);this.logger?.error(PLUGIN_DEPS_ERROR(PLUGIN_ENGINE,plugin.name,notExistDeps));return false;}return lifeCycleName==='.'?true:hasValueByPath(plugin,lifeCycleName);});}return this.cache[lifeCycleName];}// This method allows to process this.plugins so that it could
|
618
595
|
// do some unified pre-process before application starts.
|
619
596
|
processRawPlugins(callback){callback(this.plugins);this.cache={};}invoke(extPoint,allowMultiple=true,...args){let extensionPointName=extPoint;if(!extensionPointName){throw new Error(PLUGIN_EXT_POINT_MISSING_ERROR);}const noCall=extensionPointName.startsWith('!');const throws=this.config.throws??extensionPointName.endsWith('!');// eslint-disable-next-line unicorn/better-regex
|
@@ -622,9 +599,14 @@ if(throws){throw err;}else {this.logger?.error(PLUGIN_INVOCATION_ERROR(PLUGIN_EN
|
|
622
599
|
|
623
600
|
const FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';const ERROR_MESSAGES_TO_BE_FILTERED=[FAILED_REQUEST_ERR_MSG_PREFIX];
|
624
601
|
|
602
|
+
const LOAD_ORIGIN='RS_JS_SDK';
|
603
|
+
|
625
604
|
/**
|
626
605
|
* Utility method to normalise errors
|
627
|
-
*/const processError=error=>{let errorMessage;try{if(isString(error)){errorMessage=error;}else if(error instanceof Error){errorMessage=error.message;}else {errorMessage=error.message
|
606
|
+
*/const processError=error=>{let errorMessage;try{if(isString(error)){errorMessage=error;}else if(error instanceof Error){errorMessage=error.message;}else if(error instanceof ErrorEvent){errorMessage=error.message;}// TODO: remove this block once all device mode integrations start using the v3 script loader module (TS)
|
607
|
+
else if(error instanceof Event){const eventTarget=error.target;// Discard all the non-script loading errors
|
608
|
+
if(eventTarget&&eventTarget.localName!=='script'){return '';}// Discard script errors that are not originated at SDK or from native SDKs
|
609
|
+
if(eventTarget?.dataset&&(eventTarget.dataset.loader!==LOAD_ORIGIN||eventTarget.dataset.isnonnativesdk!=='true')){return '';}errorMessage=`Error in loading a third-party script from URL ${eventTarget?.src} with ID ${eventTarget?.id}.`;}else {errorMessage=error.message?error.message:stringifyWithoutCircular(error);}}catch(e){errorMessage=`Unknown error: ${e.message}`;}return errorMessage;};/**
|
628
610
|
* A function to determine whether the error should be promoted to notify or not
|
629
611
|
* @param {Error} error
|
630
612
|
* @returns
|
@@ -633,10 +615,12 @@ const FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';const ERROR_MESSAGES_TO
|
|
633
615
|
/**
|
634
616
|
* A service to handle errors
|
635
617
|
*/class ErrorHandler{// If no logger is passed errors will be thrown as unhandled error
|
636
|
-
constructor(logger,pluginEngine){this.logger=logger;this.pluginEngine=pluginEngine;}init(externalSrcLoader){if(!this.pluginEngine){return;}try{const extPoint='errorReporting.init';const errReportingInitVal=this.pluginEngine.invokeSingle(extPoint,state,this.pluginEngine,externalSrcLoader,this.logger);if(errReportingInitVal instanceof Promise){errReportingInitVal.then(client=>{this.errReportingClient=client;}).catch(err=>{this.logger?.error(REPORTING_PLUGIN_INIT_FAILURE_ERROR(ERROR_HANDLER),err);});}}catch(err){this.onError(err,ERROR_HANDLER);}}onError(error,context='',customMessage='',shouldAlwaysThrow=false){// Error handling is already implemented in processError method
|
618
|
+
constructor(logger,pluginEngine){this.logger=logger;this.pluginEngine=pluginEngine;this.errorBuffer=new BufferQueue();this.attachEffect();}attachEffect(){if(state.reporting.isErrorReportingPluginLoaded.value===true){while(this.errorBuffer.size()>0){this.errorBuffer.dequeue();}}}attachErrorListeners(){if('addEventListener'in globalThis){globalThis.addEventListener('error',event=>{this.onError(event,undefined,undefined,undefined,'unhandledException');});globalThis.addEventListener('unhandledrejection',event=>{this.onError(event,undefined,undefined,undefined,'unhandledPromiseRejection');});}else {this.logger?.debug(`Failed to attach global error listeners.`);}}init(externalSrcLoader){if(!this.pluginEngine){return;}try{const extPoint='errorReporting.init';const errReportingInitVal=this.pluginEngine.invokeSingle(extPoint,state,this.pluginEngine,externalSrcLoader,this.logger);if(errReportingInitVal instanceof Promise){errReportingInitVal.then(client=>{this.errReportingClient=client;}).catch(err=>{this.logger?.error(REPORTING_PLUGIN_INIT_FAILURE_ERROR(ERROR_HANDLER),err);});}}catch(err){this.onError(err,ERROR_HANDLER);}}onError(error,context='',customMessage='',shouldAlwaysThrow=false,errorType='handled'){// Error handling is already implemented in processError method
|
637
619
|
let errorMessage=processError(error);// If no error message after we normalize, then we swallow/ignore the errors
|
638
|
-
if(!errorMessage){return;}
|
639
|
-
|
620
|
+
if(!errorMessage){return;}// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
621
|
+
errorMessage=removeDoubleSpaces(`${context}${LOG_CONTEXT_SEPARATOR}${customMessage} ${errorMessage}`);let normalizedError=new Error(errorMessage);if(isTypeOfError(error)){normalizedError=Object.create(error,{message:{value:errorMessage}});}if(errorType==='handled'){// TODO: Remove the below line once the new Reporting plugin is ready
|
622
|
+
this.notifyError(normalizedError);if(this.logger){this.logger.error(errorMessage);if(shouldAlwaysThrow){throw normalizedError;}}else {throw normalizedError;}}// eslint-disable-next-line sonarjs/no-all-duplicated-branches
|
623
|
+
if(state.reporting.isErrorReportingEnabled.value&&!state.reporting.isErrorReportingPluginLoaded.value);}/**
|
640
624
|
* Add breadcrumbs to add insight of a user's journey before an error
|
641
625
|
* occurred and send to external error monitoring service via a plugin
|
642
626
|
*
|
@@ -648,15 +632,13 @@ if(isTypeOfError(error)){normalizedError.message=errorMessage;}else {normalizedE
|
|
648
632
|
*/notifyError(error){if(this.pluginEngine&&isAllowedToBeNotified(error)){try{this.pluginEngine.invokeSingle('errorReporting.notify',this.pluginEngine,this.errReportingClient,error,state,this.logger);}catch(err){// Not calling onError here as we don't want to go into infinite loop
|
649
633
|
this.logger?.error(NOTIFY_FAILURE_ERROR(ERROR_HANDLER),err);}}}}const defaultErrorHandler=new ErrorHandler(defaultLogger,defaultPluginEngine);
|
650
634
|
|
651
|
-
let DestinationConnectionMode=/*#__PURE__*/function(DestinationConnectionMode){DestinationConnectionMode["Hybrid"]="hybrid";DestinationConnectionMode["Cloud"]="cloud";DestinationConnectionMode["Device"]="device";return DestinationConnectionMode;}({});
|
652
|
-
|
653
635
|
/**
|
654
636
|
* A function to filter and return non cloud mode destinations
|
655
637
|
* @param destination
|
656
638
|
*
|
657
639
|
* @returns boolean
|
658
|
-
*/const isNonCloudDestination=destination=>Boolean(destination.config.connectionMode!==
|
659
|
-
destination.config.useNativeSDK===true);const isHybridModeDestination=destination=>Boolean(destination.config.connectionMode===
|
640
|
+
*/const isNonCloudDestination=destination=>Boolean(destination.config.connectionMode!=='cloud'||destination.config.useNativeSDKToSend===true||// this is the older flag for hybrid mode destinations
|
641
|
+
destination.config.useNativeSDK===true);const isHybridModeDestination=destination=>Boolean(destination.config.connectionMode==='hybrid'||destination.config.useNativeSDKToSend===true);/**
|
660
642
|
* A function to filter and return non cloud mode destinations
|
661
643
|
* @param destinations
|
662
644
|
*
|
@@ -665,10 +647,10 @@ destination.config.useNativeSDK===true);const isHybridModeDestination=destinatio
|
|
665
647
|
|
666
648
|
/**
|
667
649
|
* List of plugin names that are loaded as dynamic imports in modern builds
|
668
|
-
*/const
|
650
|
+
*/const pluginNamesList=['BeaconQueue','Bugsnag','CustomConsentManager','DeviceModeDestinations','DeviceModeTransformation','ErrorReporting','ExternalAnonymousId','GoogleLinker','KetchConsentManager','NativeDestinationQueue','OneTrustConsentManager','StorageEncryption','StorageEncryptionLegacy','StorageMigrator','XhrQueue'];
|
669
651
|
|
670
652
|
const remotesMap = {
|
671
|
-
'rudderAnalyticsRemotePlugins':{url:()=>Promise.resolve(window.RudderStackGlobals && window.RudderStackGlobals.app && window.RudderStackGlobals.app.pluginsCDNPath ? "" + window.RudderStackGlobals.app.pluginsCDNPath + "/rsa-plugins.js" : "https://cdn.rudderlabs.com/3.0.
|
653
|
+
'rudderAnalyticsRemotePlugins':{url:()=>Promise.resolve(window.RudderStackGlobals && window.RudderStackGlobals.app && window.RudderStackGlobals.app.pluginsCDNPath ? "" + window.RudderStackGlobals.app.pluginsCDNPath + "/rsa-plugins.js" : "https://cdn.rudderlabs.com/3.0.1/modern/plugins/rsa-plugins.js"),format:'esm',from:'vite'}
|
672
654
|
};
|
673
655
|
const loadJS = async (url, fn) => {
|
674
656
|
const resolvedUrl = typeof url === 'function' ? await url() : url;
|
@@ -678,11 +660,21 @@ const remotesMap = {
|
|
678
660
|
script.src = resolvedUrl;
|
679
661
|
document.getElementsByTagName('head')[0].appendChild(script);
|
680
662
|
};
|
663
|
+
|
664
|
+
function merge(obj1, obj2) {
|
665
|
+
const mergedObj = Object.assign(obj1, obj2);
|
666
|
+
for (const key of Object.keys(mergedObj)) {
|
667
|
+
if (typeof mergedObj[key] === 'object' && typeof obj2[key] === 'object') {
|
668
|
+
mergedObj[key] = merge(mergedObj[key], obj2[key]);
|
669
|
+
}
|
670
|
+
}
|
671
|
+
return mergedObj;
|
672
|
+
}
|
681
673
|
|
682
674
|
const wrapShareModule = remoteFrom => {
|
683
|
-
|
684
|
-
|
685
|
-
|
675
|
+
return merge({
|
676
|
+
|
677
|
+
}, (globalThis.__federation_shared__ || {})['default'] || {});
|
686
678
|
};
|
687
679
|
|
688
680
|
async function __federation_method_ensure(remoteId) {
|
@@ -706,7 +698,7 @@ const remotesMap = {
|
|
706
698
|
return new Promise((resolve, reject) => {
|
707
699
|
const getUrl = typeof remote.url === 'function' ? remote.url : () => Promise.resolve(remote.url);
|
708
700
|
getUrl().then(url => {
|
709
|
-
import(/* @vite-ignore */ url).then(lib => {
|
701
|
+
import(/* webpackIgnore: true */ /* @vite-ignore */ url).then(lib => {
|
710
702
|
if (!remote.inited) {
|
711
703
|
const shareScope = wrapShareModule(remote.from);
|
712
704
|
lib.init(shareScope);
|
@@ -740,9 +732,9 @@ const remotesMap = {
|
|
740
732
|
|
741
733
|
/**
|
742
734
|
* Get the lazy loaded dynamic import for a plugin name
|
743
|
-
*/const getFederatedModuleImport=pluginName=>{switch(pluginName){case
|
735
|
+
*/const getFederatedModuleImport=pluginName=>{switch(pluginName){case'BeaconQueue':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./BeaconQueue").then(module=>__federation_method_wrapDefault(module, true));case'Bugsnag':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./Bugsnag").then(module=>__federation_method_wrapDefault(module, true));case'CustomConsentManager':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./CustomConsentManager").then(module=>__federation_method_wrapDefault(module, true));case'DeviceModeDestinations':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./DeviceModeDestinations").then(module=>__federation_method_wrapDefault(module, true));case'DeviceModeTransformation':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./DeviceModeTransformation").then(module=>__federation_method_wrapDefault(module, true));case'ErrorReporting':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./ErrorReporting").then(module=>__federation_method_wrapDefault(module, true));case'ExternalAnonymousId':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./ExternalAnonymousId").then(module=>__federation_method_wrapDefault(module, true));case'GoogleLinker':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./GoogleLinker").then(module=>__federation_method_wrapDefault(module, true));case'KetchConsentManager':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./KetchConsentManager").then(module=>__federation_method_wrapDefault(module, true));case'NativeDestinationQueue':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./NativeDestinationQueue").then(module=>__federation_method_wrapDefault(module, true));case'OneTrustConsentManager':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./OneTrustConsentManager").then(module=>__federation_method_wrapDefault(module, true));case'StorageEncryption':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./StorageEncryption").then(module=>__federation_method_wrapDefault(module, true));case'StorageEncryptionLegacy':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./StorageEncryptionLegacy").then(module=>__federation_method_wrapDefault(module, true));case'StorageMigrator':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./StorageMigrator").then(module=>__federation_method_wrapDefault(module, true));case'XhrQueue':return ()=>__federation_method_getRemote("rudderAnalyticsRemotePlugins" , "./XhrQueue").then(module=>__federation_method_wrapDefault(module, true));default:return undefined;}};/**
|
744
736
|
* Map of active plugin names to their dynamic import
|
745
|
-
*/const
|
737
|
+
*/const federatedModulesBuildPluginImports=activePluginNames=>{const remotePlugins={};activePluginNames.forEach(pluginName=>{if(pluginNamesList.includes(pluginName)){const lazyLoadImport=getFederatedModuleImport(pluginName);if(lazyLoadImport){remotePlugins[pluginName]=lazyLoadImport;}}});return remotePlugins;};
|
746
738
|
|
747
739
|
/**
|
748
740
|
* Map of mandatory plugin names and direct imports
|
@@ -750,35 +742,36 @@ const remotesMap = {
|
|
750
742
|
* Map of optional plugin names and direct imports for legacy builds
|
751
743
|
*/const getOptionalPluginsMap=()=>{{return {};}};/**
|
752
744
|
* Map of optional plugin names and dynamic imports for modern builds
|
753
|
-
*/const getRemotePluginsMap=activePluginNames=>{return
|
745
|
+
*/const getRemotePluginsMap=activePluginNames=>{return federatedModulesBuildPluginImports?.(activePluginNames)||{};};const pluginsInventory={...getMandatoryPluginsMap(),...getOptionalPluginsMap()};const remotePluginsInventory=activePluginNames=>({...getRemotePluginsMap(activePluginNames)});
|
754
746
|
|
755
747
|
// TODO: add retry mechanism for getting remote plugins
|
756
748
|
// TODO: add timeout error mechanism for marking remote plugins that failed to load as failed in state
|
757
749
|
class PluginsManager{constructor(engine,errorHandler,logger){this.engine=engine;this.errorHandler=errorHandler;this.logger=logger;this.onError=this.onError.bind(this);}/**
|
758
750
|
* Orchestrate the plugin loading and registering
|
759
|
-
*/init(){state.lifecycle.status.value=
|
751
|
+
*/init(){state.lifecycle.status.value='pluginsLoading';// Expose pluginsCDNPath to global object, so it can be used in the promise that determines
|
760
752
|
// remote plugin cdn path to support proxied plugin remotes
|
761
753
|
{setExposedGlobal('pluginsCDNPath',state.lifecycle.pluginsCDNPath.value);}this.setActivePlugins();this.registerLocalPlugins();this.registerRemotePlugins();this.attachEffects();}/**
|
762
754
|
* Update state based on plugin loaded status
|
763
755
|
*/ // eslint-disable-next-line class-methods-use-this
|
764
|
-
attachEffects(){
|
756
|
+
attachEffects(){O(()=>{const isAllPluginsReady=state.plugins.activePlugins.value.length===0||state.plugins.loadedPlugins.value.length+state.plugins.failedPlugins.value.length===state.plugins.totalPluginsToLoad.value;if(isAllPluginsReady){n(()=>{state.plugins.ready.value=true;// TODO: decide what to do if a plugin fails to load for any reason.
|
765
757
|
// Should we stop here or should we progress?
|
766
|
-
state.lifecycle.status.value=
|
758
|
+
state.lifecycle.status.value='pluginsReady';});}});}/**
|
767
759
|
* Determine the list of plugins that should be loaded based on sourceConfig & load options
|
768
760
|
*/ // eslint-disable-next-line class-methods-use-this
|
769
761
|
getPluginsToLoadBasedOnConfig(){// This contains the default plugins if load option has been omitted by user
|
770
762
|
let pluginsToLoadFromConfig=state.plugins.pluginsToLoadFromConfig.value;if(!pluginsToLoadFromConfig){return [];}// Error reporting related plugins
|
771
|
-
const supportedErrReportingProviderPluginNames=Object.values(ErrorReportingProvidersToPluginNameMap);if(state.reporting.errorReportingProviderPluginName.value){pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(pluginName=>!(pluginName!==state.reporting.errorReportingProviderPluginName.value&&supportedErrReportingProviderPluginNames.includes(pluginName)));}else {pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(pluginName=>!(pluginName===
|
772
|
-
if(state.loadOptions.value.useBeacon===true&&state.capabilities.isBeaconAvailable.value){pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(pluginName=>pluginName!==
|
773
|
-
if(
|
774
|
-
|
763
|
+
const supportedErrReportingProviderPluginNames=Object.values(ErrorReportingProvidersToPluginNameMap);if(state.reporting.errorReportingProviderPluginName.value){pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(pluginName=>!(pluginName!==state.reporting.errorReportingProviderPluginName.value&&supportedErrReportingProviderPluginNames.includes(pluginName)));}else {pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(pluginName=>!(pluginName==='ErrorReporting'||supportedErrReportingProviderPluginNames.includes(pluginName)));}// Cloud mode (dataplane) events delivery plugins
|
764
|
+
if(state.loadOptions.value.useBeacon===true&&state.capabilities.isBeaconAvailable.value){pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(pluginName=>pluginName!=='XhrQueue');}else {if(state.loadOptions.value.useBeacon===true){this.logger?.warn(UNSUPPORTED_BEACON_API_WARNING(PLUGINS_MANAGER));}pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(pluginName=>pluginName!=='BeaconQueue');}// Enforce default cloud mode event delivery queue plugin is none exists
|
765
|
+
if(!pluginsToLoadFromConfig.includes('XhrQueue')&&!pluginsToLoadFromConfig.includes('BeaconQueue')){pluginsToLoadFromConfig.push('XhrQueue');}// Device mode destinations related plugins
|
766
|
+
if(getNonCloudDestinations(state.nativeDestinations.configuredDestinations.value??[]).length===0){pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(pluginName=>!['DeviceModeDestinations','DeviceModeTransformation','NativeDestinationQueue'].includes(pluginName));}// Consent Management related plugins
|
767
|
+
const supportedConsentManagerPlugins=Object.values(ConsentManagersToPluginNameMap);let filterCondition=pluginName=>!(pluginName!==state.consents.activeConsentManagerPluginName.value&&supportedConsentManagerPlugins.includes(pluginName));if(!state.consents.enabled.value){filterCondition=pluginName=>!supportedConsentManagerPlugins.includes(pluginName);}pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(filterCondition);// Storage encryption related plugins
|
775
768
|
const supportedStorageEncryptionPlugins=Object.values(StorageEncryptionVersionsToPluginNameMap);pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(pluginName=>!(pluginName!==state.storage.encryptionPluginName.value&&supportedStorageEncryptionPlugins.includes(pluginName)));// Storage migrator related plugins
|
776
|
-
if(!state.storage.migrate.value){pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(pluginName=>pluginName!==
|
769
|
+
if(!state.storage.migrate.value){pluginsToLoadFromConfig=pluginsToLoadFromConfig.filter(pluginName=>pluginName!=='StorageMigrator');}return [...Object.keys(getMandatoryPluginsMap()),...pluginsToLoadFromConfig];}/**
|
777
770
|
* Determine the list of plugins that should be activated
|
778
771
|
*/setActivePlugins(){const pluginsToLoad=this.getPluginsToLoadBasedOnConfig();// Merging available mandatory and optional plugin name list
|
779
|
-
const availablePlugins=[...Object.keys(pluginsInventory),...
|
772
|
+
const availablePlugins=[...Object.keys(pluginsInventory),...pluginNamesList];const activePlugins=[];const failedPlugins=[];pluginsToLoad.forEach(pluginName=>{if(availablePlugins.includes(pluginName)){activePlugins.push(pluginName);}else {failedPlugins.push(pluginName);}});if(failedPlugins.length>0){this.onError(new Error(`Ignoring loading of unknown plugins: ${failedPlugins.join(',')}. Mandatory plugins: ${Object.keys(getMandatoryPluginsMap()).join(',')}. Load option plugins: ${state.plugins.pluginsToLoadFromConfig.value.join(',')}`));}n(()=>{state.plugins.totalPluginsToLoad.value=pluginsToLoad.length;state.plugins.activePlugins.value=activePlugins;state.plugins.failedPlugins.value=failedPlugins;});}/**
|
780
773
|
* Register plugins that are direct imports to PluginEngine
|
781
|
-
*/registerLocalPlugins(){Object.values(pluginsInventory).forEach(localPlugin=>{if(state.plugins.activePlugins.value.includes(localPlugin().name)){this.register([localPlugin()]);}});}/**
|
774
|
+
*/registerLocalPlugins(){Object.values(pluginsInventory).forEach(localPlugin=>{if(isFunction(localPlugin)&&state.plugins.activePlugins.value.includes(localPlugin().name)){this.register([localPlugin()]);}});}/**
|
782
775
|
* Register plugins that are dynamic imports to PluginEngine
|
783
776
|
*/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
|
784
777
|
state.plugins.failedPlugins.value=[...state.plugins.failedPlugins.value,remotePluginKey];this.onError(err,remotePluginKey);});})).catch(err=>{this.onError(err);});}/**
|
@@ -794,7 +787,7 @@ unregisterLocalPlugins(){Object.values(pluginsInventory).forEach(localPlugin=>{t
|
|
794
787
|
|
795
788
|
/**
|
796
789
|
* Utility to parse XHR JSON response
|
797
|
-
*/const responseTextToJson=(responseText,onError)=>{try{return JSON.parse(responseText||'');}catch(err){const error=getMutatedError(err,'Failed to parse response data');if(
|
790
|
+
*/const responseTextToJson=(responseText,onError)=>{try{return JSON.parse(responseText||'');}catch(err){const error=getMutatedError(err,'Failed to parse response data');if(isFunction(onError)){onError(error);}else {throw error;}}return undefined;};
|
798
791
|
|
799
792
|
const DEFAULT_XHR_REQUEST_OPTIONS={headers:{Accept:'application/json','Content-Type':'application/json;charset=UTF-8'},method:'GET'};/**
|
800
793
|
* Utility to create request configuration based on default options
|
@@ -814,7 +807,7 @@ xhr.timeout=timeout;Object.keys(options.headers).forEach(headerName=>{if(options
|
|
814
807
|
* Implement requests in a blocking way
|
815
808
|
*/async getData(config){const{url,options,timeout,isRawResponse}=config;try{const data=await xhrRequest(createXhrRequestOptions(url,options,this.basicAuthHeader),timeout,this.logger);return {data:isRawResponse?data.response:responseTextToJson(data.response,this.onError),details:data};}catch(reason){this.onError(reason.error??reason);return {data:undefined,details:reason};}}/**
|
816
809
|
* Implement requests in a non-blocking way
|
817
|
-
*/getAsyncData(config){const{callback,url,options,timeout,isRawResponse}=config;const isFireAndForget=!
|
810
|
+
*/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=>{this.onError(data.error??data);if(!isFireAndForget){callback(undefined,data);}});}/**
|
818
811
|
* Handle errors
|
819
812
|
*/onError(error){if(this.hasErrorHandler){this.errorHandler?.onError(error,HTTP_CLIENT);}else {throw error;}}/**
|
820
813
|
* Set basic authentication header (eg writekey)
|
@@ -824,11 +817,9 @@ xhr.timeout=timeout;Object.keys(options.headers).forEach(headerName=>{if(options
|
|
824
817
|
|
825
818
|
const COOKIE_STORAGE='cookieStorage';const LOCAL_STORAGE='localStorage';const SESSION_STORAGE='sessionStorage';const MEMORY_STORAGE='memoryStorage';const NO_STORAGE='none';
|
826
819
|
|
827
|
-
|
828
|
-
|
829
|
-
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';
|
820
|
+
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'];
|
830
821
|
|
831
|
-
const storageClientDataStoreNameMap={[COOKIE_STORAGE]:CLIENT_DATA_STORE_COOKIE,[LOCAL_STORAGE]:CLIENT_DATA_STORE_LS,[MEMORY_STORAGE]:CLIENT_DATA_STORE_MEMORY};
|
822
|
+
const storageClientDataStoreNameMap={[COOKIE_STORAGE]:CLIENT_DATA_STORE_COOKIE,[LOCAL_STORAGE]:CLIENT_DATA_STORE_LS,[MEMORY_STORAGE]:CLIENT_DATA_STORE_MEMORY,[SESSION_STORAGE]:CLIENT_DATA_STORE_SESSION};
|
832
823
|
|
833
824
|
const detectAdBlockers=(errorHandler,logger)=>{// Apparently, '?view=ad' is a query param that is blocked by majority of adblockers
|
834
825
|
// Use source config URL here as it is very unlikely to be blocked by adblockers
|
@@ -844,7 +835,7 @@ const hasCrypto$1=()=>!isNullOrUndefined(globalThis.crypto)&&isFunction(globalTh
|
|
844
835
|
|
845
836
|
const getUserAgentClientHint=(callback,level='none')=>{if(level==='none'){callback(undefined);}if(level==='default'){callback(navigator.userAgentData);}if(level==='full'){navigator.userAgentData?.getHighEntropyValues(['architecture','bitness','brands','mobile','model','platform','platformVersion','uaFullVersion','fullVersionList','wow64']).then(ua=>{callback(ua);}).catch(()=>{callback();});}};
|
846
837
|
|
847
|
-
const isDatasetAvailable=()=>{const testElement=document.createElement('div');testElement.setAttribute('data-a-b','c');return testElement.dataset?testElement.dataset.aB==='c':false;};const legacyJSEngineRequiredPolyfills={
|
838
|
+
const isDatasetAvailable=()=>{const testElement=document.createElement('div');testElement.setAttribute('data-a-b','c');return testElement.dataset?testElement.dataset.aB==='c':false;};const legacyJSEngineRequiredPolyfills={URL:()=>!isFunction(globalThis.URL)||!globalThis.URLSearchParams,MutationObserver:()=>isUndefined(MutationObserver),Promise:()=>isUndefined(Promise),'Number.isNaN':()=>!Number.isNaN,'Number.isInteger':()=>!Number.isInteger,'Array.from':()=>!Array.from,'Array.prototype.find':()=>!Array.prototype.find,'Array.prototype.includes':()=>!Array.prototype.includes,'String.prototype.endsWith':()=>!String.prototype.endsWith,'String.prototype.startsWith':()=>!String.prototype.startsWith,'String.prototype.includes':()=>!String.prototype.includes,'Object.entries':()=>!Object.entries,'Object.values':()=>!Object.values,'Object.assign':()=>typeof Object.assign!=='function','Element.prototype.dataset':()=>!isDatasetAvailable(),'String.prototype.replaceAll':()=>!String.prototype.replaceAll,TextEncoder:()=>isUndefined(TextEncoder)||isUndefined(TextDecoder),'String.fromCodePoint':()=>!String.fromCodePoint,requestAnimationFrame:()=>!isFunction(globalThis.requestAnimationFrame)||!isFunction(globalThis.cancelAnimationFrame),CustomEvent:()=>!isFunction(globalThis.CustomEvent),/* eslint-disable-next-line */'navigator.sendBeacon':()=>!isFunction(navigator.sendBeacon),ArrayBuffer:()=>!isFunction(Uint8Array)};const isLegacyJSEngine=()=>{const requiredCapabilitiesList=Object.keys(legacyJSEngineRequiredPolyfills);let needsPolyfill=false;/* eslint-disable-next-line unicorn/no-for-loop */for(let i=0;i<requiredCapabilitiesList.length;i++){const isCapabilityMissing=legacyJSEngineRequiredPolyfills[requiredCapabilitiesList[i]];if(isFunction(isCapabilityMissing)&&isCapabilityMissing()){needsPolyfill=true;break;}}return needsPolyfill;};
|
848
839
|
|
849
840
|
const getScreenDetails=()=>{let screenDetails={density:0,width:0,height:0,innerWidth:0,innerHeight:0};screenDetails={width:globalThis.screen.width,height:globalThis.screen.height,density:globalThis.devicePixelRatio,innerWidth:globalThis.innerWidth,innerHeight:globalThis.innerHeight};return screenDetails;};
|
850
841
|
|
@@ -853,7 +844,7 @@ const matchingCodes=[22,1014];// [everything except Firefox, Firefox]
|
|
853
844
|
const isQuotaExceededError=matchingNames.includes(e.name)||matchingCodes.includes(e.code);return e instanceof DOMException&&isQuotaExceededError;};// TODO: also check for SecurityErrors
|
854
845
|
// https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage#exceptions
|
855
846
|
const isStorageAvailable=(type=LOCAL_STORAGE,storageInstance,logger)=>{let storage;let testData;try{switch(type){case MEMORY_STORAGE:return true;case COOKIE_STORAGE:storage=storageInstance;testData=STORAGE_TEST_COOKIE;break;case LOCAL_STORAGE:storage=storageInstance??globalThis.localStorage;testData=STORAGE_TEST_LOCAL_STORAGE;// was STORAGE_TEST_LOCAL_STORAGE in ours and generateUUID() in segment retry one
|
856
|
-
break;case SESSION_STORAGE:storage=storageInstance??globalThis.sessionStorage;testData=STORAGE_TEST_SESSION_STORAGE;break;default:return false;}if(!storage){return false;}storage.setItem(testData,'true');if(storage.getItem(testData)){storage.removeItem(testData);return true;}return false;}catch(err){const msgPrefix=STORAGE_UNAVAILABILITY_ERROR_PREFIX(CAPABILITIES_MANAGER,type);let reason='unavailable';if(isStorageQuotaExceeded(err)){reason='full';}logger?.
|
847
|
+
break;case SESSION_STORAGE:storage=storageInstance??globalThis.sessionStorage;testData=STORAGE_TEST_SESSION_STORAGE;break;default:return false;}if(!storage){return false;}storage.setItem(testData,'true');if(storage.getItem(testData)){storage.removeItem(testData);return true;}return false;}catch(err){const msgPrefix=STORAGE_UNAVAILABILITY_ERROR_PREFIX(CAPABILITIES_MANAGER,type);let reason='unavailable';if(isStorageQuotaExceeded(err)){reason='full';}logger?.warn(`${msgPrefix}${reason}.`,err);return false;}};
|
857
848
|
|
858
849
|
/**
|
859
850
|
* Encode.
|
@@ -863,7 +854,7 @@ break;case SESSION_STORAGE:storage=storageInstance??globalThis.sessionStorage;te
|
|
863
854
|
return undefined;}};/**
|
864
855
|
* Parse cookie `str`
|
865
856
|
*/const parse=str=>{const obj={};const pairs=str.split(/\s*;\s*/);let pair;if(!pairs[0]){return obj;}// TODO: Decode only the cookies that are needed by the SDK
|
866
|
-
pairs.forEach(pairItem=>{pair=pairItem.split('=');const keyName=decode(pair[0]);if(keyName){obj[keyName]=decode(pair[1]);}});return obj;};/**
|
857
|
+
pairs.forEach(pairItem=>{pair=pairItem.split('=');const keyName=pair[0]?decode(pair[0]):undefined;if(keyName){obj[keyName]=pair[1]?decode(pair[1]):undefined;}});return obj;};/**
|
867
858
|
* Set cookie `name` to `value`
|
868
859
|
*/const set=(name,value,optionsConfig,logger)=>{const options={...optionsConfig}||{};let cookieString=`${encode(name,logger)}=${encode(value,logger)}`;if(isNull(value)){options.maxage=-1;}if(options.maxage){options.expires=new Date(+new Date()+options.maxage);}if(options.path){cookieString+=`; path=${options.path}`;}if(options.domain){cookieString+=`; domain=${options.domain}`;}if(options.expires){cookieString+=`; expires=${options.expires.toUTCString()}`;}if(options.samesite){cookieString+=`; samesite=${options.samesite}`;}if(options.secure){cookieString+=`; secure`;}globalThis.document.cookie=cookieString;};/**
|
869
860
|
* Return all cookies
|
@@ -880,9 +871,9 @@ const legacyGetHostname=href=>{const l=document.createElement('a');l.href=href;r
|
|
880
871
|
* The method returns an empty array when the hostname is an ip.
|
881
872
|
*/const levelsFunc=url=>{// This is called before the polyfills load thus new URL cannot be used
|
882
873
|
const host=typeof globalThis.URL!=='function'?legacyGetHostname(url):new URL(url).hostname;const parts=host?.split('.')??[];const last=parts[parts.length-1];const levels=[];// Ip address.
|
883
|
-
if(parts.length===4&&last===parseInt(last,10).toString()){return levels;}// Localhost.
|
874
|
+
if(parts.length===4&&last&&last===parseInt(last,10).toString()){return levels;}// Localhost.
|
884
875
|
if(parts.length<=1){// Fix to support localhost
|
885
|
-
if(parts[0].indexOf('localhost')!==-1){return ['localhost'];}return levels;}// Create levels.
|
876
|
+
if(parts[0]&&parts[0].indexOf('localhost')!==-1){return ['localhost'];}return levels;}// Create levels.
|
886
877
|
for(let i=parts.length-2;i>=0;i-=1){levels.push(parts.slice(i).join('.'));}return levels;};/**
|
887
878
|
* Get the top domain.
|
888
879
|
*
|
@@ -897,12 +888,12 @@ cookie(cname,1,opts);// If successful
|
|
897
888
|
if(cookie(cname)){// Remove cookie from domain
|
898
889
|
cookie(cname,null,opts);return domain;}}return '';};
|
899
890
|
|
900
|
-
const getDefaultCookieOptions=()=>{const topDomain=domain(globalThis.location.href);return {maxage:DEFAULT_COOKIE_MAX_AGE_MS,path:'/',domain:!topDomain||topDomain==='.'?undefined:topDomain,samesite:
|
891
|
+
const getDefaultCookieOptions=()=>{const topDomain=domain(globalThis.location.href);return {maxage:DEFAULT_COOKIE_MAX_AGE_MS,path:'/',domain:!topDomain||topDomain==='.'?undefined:topDomain,samesite:'Lax',enabled:true};};const getDefaultLocalStorageOptions=()=>({enabled:true});const getDefaultSessionStorageOptions=()=>({enabled:true});const getDefaultInMemoryStorageOptions=()=>({enabled:true});
|
901
892
|
|
902
893
|
/**
|
903
894
|
* A storage utility to persist values in cookies via Storage interface
|
904
895
|
*/class CookieStorage{static globalSingleton=null;isSupportAvailable=true;isEnabled=true;length=0;constructor(options={},logger){if(CookieStorage.globalSingleton){// eslint-disable-next-line no-constructor-return
|
905
|
-
return CookieStorage.globalSingleton;}this.options=getDefaultCookieOptions();this.logger=logger;this.configure(options);CookieStorage.globalSingleton=this;}configure(options){this.options=mergeDeepRight(this.options??{},options);this.isSupportAvailable=isStorageAvailable(COOKIE_STORAGE,this,this.logger);this.isEnabled=Boolean(this.options.enabled&&this.isSupportAvailable);return this.options;}setItem(key,value){cookie(key,value,this.options,this.logger);this.length=Object.keys(cookie()).length;return true;}// eslint-disable-next-line class-methods-use-this
|
896
|
+
return CookieStorage.globalSingleton;}this.options=getDefaultCookieOptions();this.logger=logger;this.configure(options);CookieStorage.globalSingleton=this;}configure(options){this.options=mergeDeepRight(this.options??{},options);if(options.sameDomainCookiesOnly){delete this.options.domain;}this.isSupportAvailable=isStorageAvailable(COOKIE_STORAGE,this,this.logger);this.isEnabled=Boolean(this.options.enabled&&this.isSupportAvailable);return this.options;}setItem(key,value){cookie(key,value,this.options,this.logger);this.length=Object.keys(cookie()).length;return true;}// eslint-disable-next-line class-methods-use-this
|
906
897
|
getItem(key){const value=cookie(key);return isUndefined(value)?null:value;}removeItem(key){const result=this.setItem(key,null);this.length=Object.keys(cookie()).length;return result;}// eslint-disable-next-line class-methods-use-this
|
907
898
|
clear(){// Not implemented
|
908
899
|
// getting a list of all cookie storage keys and remove all values
|
@@ -914,7 +905,7 @@ key(index){const cookies=cookie();const cookieNames=Object.keys(cookies);return
|
|
914
905
|
|
915
906
|
/**
|
916
907
|
* A storage utility to retain values in memory via Storage interface
|
917
|
-
*/class InMemoryStorage{isEnabled=true;length=0;data={};constructor(options,logger){this.options=getDefaultInMemoryStorageOptions();this.logger=logger;this.configure(options??{});}configure(options){this.options=mergeDeepRight(this.options,options);this.isEnabled=Boolean(this.options.enabled);return this.options;}setItem(key,value){this.data[key]=value;this.length=Object.keys(this.data).length;return value;}getItem(key){if(key in this.data){return this.data[key];}return null;}removeItem(key){if(key in this.data){delete this.data[key];}this.length=Object.keys(this.data).length;return null;}clear(){this.data={};this.length=0;}key(index){return Object.keys(this.data)[index];}}const defaultInMemoryStorage=new InMemoryStorage({},defaultLogger);
|
908
|
+
*/class InMemoryStorage{isEnabled=true;length=0;data={};constructor(options,logger){this.options=getDefaultInMemoryStorageOptions();this.logger=logger;this.configure(options??{});}configure(options){this.options=mergeDeepRight(this.options,options);this.isEnabled=Boolean(this.options.enabled);return this.options;}setItem(key,value){this.data[key]=value;this.length=Object.keys(this.data).length;return value;}getItem(key){if(key in this.data){return this.data[key];}return null;}removeItem(key){if(key in this.data){delete this.data[key];}this.length=Object.keys(this.data).length;return null;}clear(){this.data={};this.length=0;}key(index){return Object.keys(this.data)[index]?Object.keys(this.data)[index]:null;}}const defaultInMemoryStorage=new InMemoryStorage({},defaultLogger);
|
918
909
|
|
919
910
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
920
911
|
|
@@ -938,19 +929,25 @@ if(key===undefined){var ret={};this.forEach(function(key,val){return ret[key]=va
|
|
938
929
|
* A storage utility to persist values in localstorage via Storage interface
|
939
930
|
*/class LocalStorage{isSupportAvailable=true;isEnabled=true;length=0;constructor(options={},logger){this.options=getDefaultLocalStorageOptions();this.logger=logger;this.configure(options);}configure(options){this.options=mergeDeepRight(this.options,options);this.isSupportAvailable=isStorageAvailable(LOCAL_STORAGE,this,this.logger);this.isEnabled=Boolean(this.options.enabled&&this.isSupportAvailable);return this.options;}setItem(key,value){store.set(key,value);this.length=store.keys().length;}// eslint-disable-next-line class-methods-use-this
|
940
931
|
getItem(key){const value=store.get(key);return isUndefined(value)?null:value;}removeItem(key){store.remove(key);this.length=store.keys().length;}clear(){store.clear();this.length=0;}// eslint-disable-next-line class-methods-use-this
|
941
|
-
key(index){return store.keys()[index];}}const defaultLocalStorage=new LocalStorage({},defaultLogger);
|
932
|
+
key(index){return store.keys()[index]?store.keys()[index]:null;}}const defaultLocalStorage=new LocalStorage({},defaultLogger);
|
933
|
+
|
934
|
+
/**
|
935
|
+
* A storage utility to persist values in SessionStorage via Storage interface
|
936
|
+
*/class SessionStorage{isSupportAvailable=true;isEnabled=true;length=0;store=globalThis.sessionStorage;constructor(options={},logger){this.options=getDefaultSessionStorageOptions();this.logger=logger;this.configure(options);}configure(options){this.options=mergeDeepRight(this.options,options);this.isSupportAvailable=isStorageAvailable(SESSION_STORAGE,this,this.logger);this.isEnabled=Boolean(this.options.enabled&&this.isSupportAvailable);return this.options;}setItem(key,value){this.store.setItem(key,value);this.length=this.store.length;}getItem(key){const value=this.store.getItem(key);return isUndefined(value)?null:value;}removeItem(key){this.store.removeItem(key);this.length=this.store.length;}clear(){this.store.clear();this.length=0;}key(index){return this.store.key(index);}}const defaultSessionStorage=new SessionStorage({},defaultLogger);
|
942
937
|
|
943
938
|
/**
|
944
939
|
* A utility to retrieve the storage singleton instance by type
|
945
|
-
*/const getStorageEngine=type=>{switch(type){case LOCAL_STORAGE:return defaultLocalStorage;case SESSION_STORAGE:return
|
940
|
+
*/const getStorageEngine=type=>{switch(type){case LOCAL_STORAGE:return defaultLocalStorage;case SESSION_STORAGE:return defaultSessionStorage;case MEMORY_STORAGE:return defaultInMemoryStorage;case COOKIE_STORAGE:return new CookieStorage({},defaultLogger);default:return defaultInMemoryStorage;}};/**
|
946
941
|
* Configure cookie storage singleton
|
947
942
|
*/const configureCookieStorageEngine=options=>{new CookieStorage({},defaultLogger).configure(options);};/**
|
948
943
|
* Configure local storage singleton
|
949
944
|
*/const configureLocalStorageEngine=options=>{defaultLocalStorage.configure(options);};/**
|
950
945
|
* Configure in memory storage singleton
|
951
946
|
*/const configureInMemoryStorageEngine=options=>{defaultInMemoryStorage.configure(options);};/**
|
947
|
+
* Configure session storage singleton
|
948
|
+
*/const configureSessionStorageEngine=options=>{defaultSessionStorage.configure(options);};/**
|
952
949
|
* Configure all storage singleton instances
|
953
|
-
*/const configureStorageEngines=(
|
950
|
+
*/const configureStorageEngines=(cookieStorageOptions={},localStorageOptions={},inMemoryStorageOptions={},sessionStorageOptions={})=>{configureCookieStorageEngine(cookieStorageOptions);configureLocalStorageEngine(localStorageOptions);configureInMemoryStorageEngine(inMemoryStorageOptions);configureSessionStorageEngine(sessionStorageOptions);};
|
954
951
|
|
955
952
|
/**
|
956
953
|
* Store Implementation with dedicated storage
|
@@ -986,18 +983,22 @@ return JSON.parse(str);}catch(err){this.onError(new Error(`${STORE_DATA_FETCH_ER
|
|
986
983
|
* Handle errors
|
987
984
|
*/onError(error){if(this.hasErrorHandler){this.errorHandler?.onError(error,`Store ${this.id}`);}else {throw error;}}}
|
988
985
|
|
986
|
+
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;};
|
987
|
+
|
989
988
|
/**
|
990
989
|
* A service to manage stores & available storage client configurations
|
991
990
|
*/class StoreManager{stores={};isInitialized=false;hasErrorHandler=false;constructor(pluginsManager,errorHandler,logger){this.errorHandler=errorHandler;this.logger=logger;this.hasErrorHandler=Boolean(this.errorHandler);this.pluginsManager=pluginsManager;this.onError=this.onError.bind(this);}/**
|
992
991
|
* Configure available storage client instances
|
993
|
-
*/init(){if(this.isInitialized){return;}const config={
|
992
|
+
*/init(){if(this.isInitialized){return;}const loadOptions=state.loadOptions.value;const config={cookieStorageOptions:{samesite:loadOptions.sameSiteCookie,secure:loadOptions.secureCookie,domain:loadOptions.setCookieDomain,sameDomainCookiesOnly:loadOptions.sameDomainCookiesOnly,enabled:true},localStorageOptions:{enabled:true},inMemoryStorageOptions:{enabled:true},sessionStorageOptions:{enabled:true}};configureStorageEngines(removeUndefinedValues(mergeDeepRight(config.cookieStorageOptions??{},state.storage.cookie?.value??{})),removeUndefinedValues(config.localStorageOptions),removeUndefinedValues(config.inMemoryStorageOptions),removeUndefinedValues(config.sessionStorageOptions));this.initClientDataStores();this.isInitialized=true;}/**
|
994
993
|
* Create store to persist data used by the SDK like session, used details etc
|
995
|
-
*/
|
996
|
-
if(getStorageEngine(COOKIE_STORAGE)?.isEnabled){finalStorageType=COOKIE_STORAGE;}else if(getStorageEngine(LOCAL_STORAGE)?.isEnabled){finalStorageType=LOCAL_STORAGE;}else {finalStorageType=MEMORY_STORAGE;}break;}if(finalStorageType!==storageType){this.logger?.warn(STORAGE_UNAVAILABLE_WARNING(STORE_MANAGER,storageType,finalStorageType));}if(finalStorageType!==NO_STORAGE){trulyAnonymousTracking=false;}const storageState=state.storage.entries.value;state.storage.entries.value={...storageState,[sessionKey]:{type:finalStorageType,key:userSessionStorageKeys[storageKey]}};});state.storage.trulyAnonymousTracking.value=trulyAnonymousTracking;// TODO: fill in extra config values and bring them in from StoreManagerOptions if needed
|
994
|
+
*/initClientDataStores(){this.initializeStorageState();// TODO: fill in extra config values and bring them in from StoreManagerOptions if needed
|
997
995
|
// TODO: should we pass the keys for all in order to validate or leave free as v1.1?
|
998
996
|
// Initializing all the enabled store because previous user data might be in different storage
|
999
997
|
// that needs auto migration
|
1000
|
-
const
|
998
|
+
const storageTypes=[MEMORY_STORAGE,LOCAL_STORAGE,COOKIE_STORAGE,SESSION_STORAGE];storageTypes.forEach(storageType=>{if(getStorageEngine(storageType)?.isEnabled){this.setStore({id:storageClientDataStoreNameMap[storageType],name:storageClientDataStoreNameMap[storageType],isEncrypted:true,noCompoundKey:true,type:storageType});}});}initializeStorageState(){let globalStorageType=state.storage.type.value;let entriesOptions=state.loadOptions.value.storage?.entries;// Use the storage options from post consent if anything is defined
|
999
|
+
const postConsentStorageOpts=state.consents.postConsent.value.storage;if(isDefined(postConsentStorageOpts?.type)||isDefined(postConsentStorageOpts?.entries)){globalStorageType=postConsentStorageOpts?.type;entriesOptions=postConsentStorageOpts?.entries;}let trulyAnonymousTracking=true;let storageEntries={};USER_SESSION_KEYS.forEach(sessionKey=>{const key=sessionKey;const storageKey=sessionKey;const configuredStorageType=entriesOptions?.[key]?.type;const preConsentStorageType=getStorageTypeFromPreConsentIfApplicable(state,sessionKey);// Storage type precedence order: pre-consent strategy > entry type > global type > default
|
1000
|
+
const storageType=preConsentStorageType??configuredStorageType??globalStorageType??DEFAULT_STORAGE_TYPE;const finalStorageType=this.getResolvedStorageTypeForEntry(storageType,sessionKey);if(finalStorageType!==NO_STORAGE){trulyAnonymousTracking=false;}storageEntries={...storageEntries,[sessionKey]:{type:finalStorageType,key:USER_SESSION_STORAGE_KEYS[storageKey]}};});n(()=>{state.storage.type.value=globalStorageType;state.storage.entries.value=storageEntries;state.storage.trulyAnonymousTracking.value=trulyAnonymousTracking;});}getResolvedStorageTypeForEntry(storageType,sessionKey){let finalStorageType=storageType;switch(storageType){case LOCAL_STORAGE:if(!getStorageEngine(LOCAL_STORAGE)?.isEnabled){finalStorageType=MEMORY_STORAGE;}break;case SESSION_STORAGE:if(!getStorageEngine(SESSION_STORAGE)?.isEnabled){finalStorageType=MEMORY_STORAGE;}break;case MEMORY_STORAGE:case NO_STORAGE:break;case COOKIE_STORAGE:default:// First try setting the storage to cookie else to local storage
|
1001
|
+
if(getStorageEngine(COOKIE_STORAGE)?.isEnabled){finalStorageType=COOKIE_STORAGE;}else if(getStorageEngine(LOCAL_STORAGE)?.isEnabled){finalStorageType=LOCAL_STORAGE;}else if(getStorageEngine(SESSION_STORAGE)?.isEnabled){finalStorageType=SESSION_STORAGE;}else {finalStorageType=MEMORY_STORAGE;}break;}if(finalStorageType!==storageType){this.logger?.warn(STORAGE_UNAVAILABLE_WARNING(STORE_MANAGER,sessionKey,storageType,finalStorageType));}return finalStorageType;}/**
|
1001
1002
|
* Create a new store
|
1002
1003
|
*/setStore(storeConfig){const storageEngine=getStorageEngine(storeConfig.type);this.stores[storeConfig.id]=new Store(storeConfig,storageEngine,this.pluginsManager);return this.stores[storeConfig.id];}/**
|
1003
1004
|
* Retrieve a store
|
@@ -1035,7 +1036,9 @@ const validateWriteKey=writeKey=>{if(!isString(writeKey)||writeKey.trim().length
|
|
1035
1036
|
|
1036
1037
|
const removeDuplicateSlashes=str=>str.replace(/\/{2,}/g,'/');
|
1037
1038
|
|
1038
|
-
|
1039
|
+
/**
|
1040
|
+
* Plugins to be loaded in the plugins loadOption is not defined
|
1041
|
+
*/const defaultOptionalPluginsList=['BeaconQueue','Bugsnag','CustomConsentManager','DeviceModeDestinations','DeviceModeTransformation','ErrorReporting','ExternalAnonymousId','GoogleLinker','KetchConsentManager','NativeDestinationQueue','OneTrustConsentManager','StorageEncryption','StorageEncryptionLegacy','StorageMigrator','XhrQueue'];
|
1039
1042
|
|
1040
1043
|
/**
|
1041
1044
|
* A function to check given value is a number or not
|
@@ -1053,7 +1056,7 @@ const defaultOptionalPluginsList=[PluginName.Bugsnag,PluginName.DeviceModeDestin
|
|
1053
1056
|
*/const isPositiveInteger=num=>isNumber(num)&&num>=0&&Number.isInteger(num);
|
1054
1057
|
|
1055
1058
|
const normalizeLoadOptions=(loadOptionsFromState,loadOptions)=>{// TODO: Maybe add warnings for invalid values
|
1056
|
-
const normalizedLoadOpts=clone
|
1059
|
+
const normalizedLoadOpts=clone(loadOptions);if(!isString(normalizedLoadOpts.setCookieDomain)){delete normalizedLoadOpts.setCookieDomain;}const cookieSameSiteValues=['Strict','Lax','None'];if(!cookieSameSiteValues.includes(normalizedLoadOpts.sameSiteCookie)){delete normalizedLoadOpts.sameSiteCookie;}normalizedLoadOpts.secureCookie=normalizedLoadOpts.secureCookie===true;const uaChTrackLevels=['none','default','full'];if(!uaChTrackLevels.includes(normalizedLoadOpts.uaChTrackLevel)){delete normalizedLoadOpts.uaChTrackLevel;}if(!isObjectLiteralAndNotNull(normalizedLoadOpts.integrations)){delete normalizedLoadOpts.integrations;}normalizedLoadOpts.plugins=normalizedLoadOpts.plugins??defaultOptionalPluginsList;normalizedLoadOpts.useGlobalIntegrationsConfigInEvents=normalizedLoadOpts.useGlobalIntegrationsConfigInEvents===true;normalizedLoadOpts.bufferDataPlaneEventsUntilReady=normalizedLoadOpts.bufferDataPlaneEventsUntilReady===true;normalizedLoadOpts.sendAdblockPage=normalizedLoadOpts.sendAdblockPage===true;if(!isObjectLiteralAndNotNull(normalizedLoadOpts.sendAdblockPageOptions)){delete normalizedLoadOpts.sendAdblockPageOptions;}if(!isDefined(normalizedLoadOpts.loadIntegration)){delete normalizedLoadOpts.loadIntegration;}else {normalizedLoadOpts.loadIntegration=normalizedLoadOpts.loadIntegration===true;}if(!isObjectLiteralAndNotNull(normalizedLoadOpts.storage)){delete normalizedLoadOpts.storage;}else {normalizedLoadOpts.storage=removeUndefinedAndNullValues(normalizedLoadOpts.storage);normalizedLoadOpts.storage.migrate=normalizedLoadOpts.storage?.migrate===true;}if(!isObjectLiteralAndNotNull(normalizedLoadOpts.beaconQueueOptions)){delete normalizedLoadOpts.beaconQueueOptions;}else {normalizedLoadOpts.beaconQueueOptions=removeUndefinedAndNullValues(normalizedLoadOpts.beaconQueueOptions);}if(!isObjectLiteralAndNotNull(normalizedLoadOpts.destinationsQueueOptions)){delete normalizedLoadOpts.destinationsQueueOptions;}else {normalizedLoadOpts.destinationsQueueOptions=removeUndefinedAndNullValues(normalizedLoadOpts.destinationsQueueOptions);}if(!isObjectLiteralAndNotNull(normalizedLoadOpts.queueOptions)){delete normalizedLoadOpts.queueOptions;}else {normalizedLoadOpts.queueOptions=removeUndefinedAndNullValues(normalizedLoadOpts.queueOptions);}normalizedLoadOpts.lockIntegrationsVersion=normalizedLoadOpts.lockIntegrationsVersion===true;if(!isNumber(normalizedLoadOpts.dataPlaneEventsBufferTimeout)){delete normalizedLoadOpts.dataPlaneEventsBufferTimeout;}if(!isObjectLiteralAndNotNull(normalizedLoadOpts.storage?.cookie)){delete normalizedLoadOpts.storage?.cookie;}else {normalizedLoadOpts.storage.cookie=removeUndefinedAndNullValues(normalizedLoadOpts.storage?.cookie);}if(!isObjectLiteralAndNotNull(normalizedLoadOpts.preConsent)){delete normalizedLoadOpts.preConsent;}else {normalizedLoadOpts.preConsent=removeUndefinedAndNullValues(normalizedLoadOpts.preConsent);}const mergedLoadOptions=mergeDeepRight(loadOptionsFromState,normalizedLoadOpts);return mergedLoadOptions;};const getSourceConfigURL=(configUrl,writeKey,lockIntegrationsVersion,logger)=>{const defSearchParams=new URLSearchParams({p:MODULE_TYPE,v:APP_VERSION,build:BUILD_TYPE,writeKey,lockIntegrationsVersion:lockIntegrationsVersion.toString()});let origin=DEFAULT_CONFIG_BE_URL;let searchParams=defSearchParams;let pathname='/sourceConfig/';let hash='';// Ideally, this check is not required but URL polyfill
|
1057
1060
|
// doesn't seem to throw errors for empty URLs
|
1058
1061
|
// TODO: Need to improve this check to find out if the URL is valid or not
|
1059
1062
|
if(configUrl){try{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;}catch(err){logger?.warn(INVALID_CONFIG_URL_WARNING(CONFIG_MANAGER,configUrl));}}return `${origin}${pathname}?${searchParams}${hash}`;};
|
@@ -1069,7 +1072,7 @@ const DEFAULT_REGION='US';/**
|
|
1069
1072
|
* A function to get url from source config response
|
1070
1073
|
* @param {array} urls An array of objects containing urls
|
1071
1074
|
* @returns
|
1072
|
-
*/const getDefaultUrlOfRegion=urls=>{let url;if(Array.isArray(urls)&&urls.length>0){const obj=urls.find(elem=>elem.default===true);if(obj&&isValidUrl(obj.url)){return obj.url;}}return url;};const validateResidencyServerRegion=(residencyServerRegion,logger)=>{if(residencyServerRegion&&!
|
1075
|
+
*/const getDefaultUrlOfRegion=urls=>{let url;if(Array.isArray(urls)&&urls.length>0){const obj=urls.find(elem=>elem.default===true);if(obj&&isValidUrl(obj.url)){return obj.url;}}return url;};const validateResidencyServerRegion=(residencyServerRegion,logger)=>{const residencyServerRegions=['US','EU'];if(residencyServerRegion&&!residencyServerRegions.includes(residencyServerRegion)){logger?.warn(UNSUPPORTED_RESIDENCY_SERVER_REGION_WARNING(CONFIG_MANAGER,residencyServerRegion,DEFAULT_REGION));return undefined;}return residencyServerRegion;};/**
|
1073
1076
|
* A function to determine the dataPlaneUrl
|
1074
1077
|
* @param {Object} dataplanes An object containing dataPlaneUrl for different region
|
1075
1078
|
* @param {String} serverUrl dataPlaneUrl provided in the load call
|
@@ -1081,23 +1084,40 @@ if(dataplanes&&Object.keys(dataplanes).length>0){const region=validateResidencyS
|
|
1081
1084
|
if(serverUrl){return serverUrl;}// return undefined if data plane url can not be determined
|
1082
1085
|
return undefined;};
|
1083
1086
|
|
1084
|
-
|
1087
|
+
/**
|
1088
|
+
* Determines if the SDK is running inside a chrome extension
|
1089
|
+
* @returns boolean
|
1090
|
+
*/const isSDKRunningInChromeExtension=()=>!!(window.chrome&&window.chrome.runtime&&window.chrome.runtime.id);
|
1091
|
+
|
1092
|
+
const DEFAULT_PRE_CONSENT_STORAGE_STRATEGY='none';const DEFAULT_PRE_CONSENT_EVENTS_DELIVERY_TYPE='immediate';
|
1085
1093
|
|
1086
1094
|
const isErrorReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.errors?.enabled===true;const getErrorReportingProviderNameFromConfig=sourceConfig=>sourceConfig?.statsCollection?.errors?.provider;const isMetricsReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.metrics?.enabled===true;
|
1087
1095
|
|
1096
|
+
const DEFAULT_INTEGRATIONS_CONFIG={All:true};
|
1097
|
+
|
1088
1098
|
/**
|
1089
|
-
*
|
1090
|
-
* @param
|
1091
|
-
* @returns
|
1092
|
-
|
1093
|
-
|
1094
|
-
*
|
1095
|
-
*
|
1096
|
-
*
|
1097
|
-
|
1098
|
-
*
|
1099
|
-
*
|
1100
|
-
|
1099
|
+
* Validates and normalizes the consent options provided by the user
|
1100
|
+
* @param options Consent options provided by the user
|
1101
|
+
* @returns Validated and normalized consent options
|
1102
|
+
*/const getValidPostConsentOptions=options=>{const validOptions={sendPageEvent:false,trackConsent:false,discardPreConsentEvents:false};if(isObjectLiteralAndNotNull(options)){const clonedOptions=clone(options);validOptions.storage=clonedOptions.storage;if(isDefined(clonedOptions.integrations)){validOptions.integrations=isObjectLiteralAndNotNull(clonedOptions.integrations)?clonedOptions.integrations:DEFAULT_INTEGRATIONS_CONFIG;}validOptions.discardPreConsentEvents=clonedOptions.discardPreConsentEvents===true;validOptions.sendPageEvent=clonedOptions.sendPageEvent===true;validOptions.trackConsent=clonedOptions.trackConsent===true;if(isNonEmptyObject(clonedOptions.consentManagement)){// Override enabled value with the current state value
|
1103
|
+
validOptions.consentManagement=mergeDeepRight(clonedOptions.consentManagement,{enabled:state.consents.enabled.value});}}return validOptions;};/**
|
1104
|
+
* Validates if the input is a valid consents data
|
1105
|
+
* @param value Input consents data
|
1106
|
+
* @returns true if the input is a valid consents data else false
|
1107
|
+
*/const isValidConsentsData=value=>isNonEmptyObject(value)||Array.isArray(value);/**
|
1108
|
+
* Retrieves the corresponding provider and plugin name of the selected consent manager from the supported consent managers
|
1109
|
+
* @param consentManagementOpts consent management options
|
1110
|
+
* @param logger logger instance
|
1111
|
+
* @returns Corresponding provider and plugin name of the selected consent manager from the supported consent managers
|
1112
|
+
*/const getConsentManagerInfo=(consentManagementOpts,logger)=>{let{provider}=consentManagementOpts;const consentManagerPluginName=ConsentManagersToPluginNameMap[provider];if(provider&&!consentManagerPluginName){logger?.error(UNSUPPORTED_CONSENT_MANAGER_ERROR(CONFIG_MANAGER,provider,ConsentManagersToPluginNameMap));// Reset the provider value
|
1113
|
+
provider=undefined;}return {provider,consentManagerPluginName};};/**
|
1114
|
+
* Validates and converts the consent management options into a normalized format
|
1115
|
+
* @param consentManagementOpts Consent management options provided by the user
|
1116
|
+
* @param logger logger instance
|
1117
|
+
* @returns An object containing the consent manager plugin name, initialized, enabled and consents data
|
1118
|
+
*/const getConsentManagementData=(consentManagementOpts,logger)=>{let consentManagerPluginName;let allowedConsentIds=[];let deniedConsentIds=[];let initialized=false;let provider;let enabled=consentManagementOpts?.enabled===true;if(isNonEmptyObject(consentManagementOpts)&&enabled){// Get the corresponding plugin name of the selected consent manager from the supported consent managers
|
1119
|
+
({provider,consentManagerPluginName}=getConsentManagerInfo(consentManagementOpts,logger));if(isValidConsentsData(consentManagementOpts.allowedConsentIds)){allowedConsentIds=consentManagementOpts.allowedConsentIds;initialized=true;}if(isValidConsentsData(consentManagementOpts.deniedConsentIds)){deniedConsentIds=consentManagementOpts.deniedConsentIds;initialized=true;}}const consentsData={allowedConsentIds,deniedConsentIds};// Enable consent management only if consent manager is supported
|
1120
|
+
enabled=enabled&&Boolean(consentManagerPluginName);return {provider,consentManagerPluginName,initialized,enabled,consentsData};};
|
1101
1121
|
|
1102
1122
|
/**
|
1103
1123
|
* Determines the SDK url
|
@@ -1106,14 +1126,20 @@ const isErrorReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.error
|
|
1106
1126
|
* Updates the reporting state variables from the source config data
|
1107
1127
|
* @param res Source config
|
1108
1128
|
* @param logger Logger instance
|
1109
|
-
*/const updateReportingState=(res,logger)=>{state.reporting.isErrorReportingEnabled.value=isErrorReportingEnabled(res.source.config);state.reporting.isMetricsReportingEnabled.value=isMetricsReportingEnabled(res.source.config);if(state.reporting.isErrorReportingEnabled.value){const errReportingProvider=getErrorReportingProviderNameFromConfig(res.source.config);// Get the corresponding plugin name of the selected error reporting provider from the supported error reporting providers
|
1129
|
+
*/const updateReportingState=(res,logger)=>{state.reporting.isErrorReportingEnabled.value=isErrorReportingEnabled(res.source.config)&&!isSDKRunningInChromeExtension();state.reporting.isMetricsReportingEnabled.value=isMetricsReportingEnabled(res.source.config);if(state.reporting.isErrorReportingEnabled.value){const errReportingProvider=getErrorReportingProviderNameFromConfig(res.source.config);// Get the corresponding plugin name of the selected error reporting provider from the supported error reporting providers
|
1110
1130
|
const errReportingProviderPlugin=errReportingProvider?ErrorReportingProvidersToPluginNameMap[errReportingProvider]:undefined;if(!isUndefined(errReportingProvider)&&!errReportingProviderPlugin){// set the default error reporting provider
|
1111
|
-
logger?.warn(UNSUPPORTED_ERROR_REPORTING_PROVIDER_WARNING(CONFIG_MANAGER,errReportingProvider,ErrorReportingProvidersToPluginNameMap,DEFAULT_ERROR_REPORTING_PROVIDER));}state.reporting.errorReportingProviderPluginName.value=errReportingProviderPlugin??ErrorReportingProvidersToPluginNameMap[DEFAULT_ERROR_REPORTING_PROVIDER];}};const
|
1131
|
+
logger?.warn(UNSUPPORTED_ERROR_REPORTING_PROVIDER_WARNING(CONFIG_MANAGER,errReportingProvider,ErrorReportingProvidersToPluginNameMap,DEFAULT_ERROR_REPORTING_PROVIDER));}state.reporting.errorReportingProviderPluginName.value=errReportingProviderPlugin??ErrorReportingProvidersToPluginNameMap[DEFAULT_ERROR_REPORTING_PROVIDER];}};const updateStorageStateFromLoadOptions=logger=>{const storageOptsFromLoad=state.loadOptions.value.storage;let storageType=storageOptsFromLoad?.type;if(isDefined(storageType)&&!isValidStorageType(storageType)){logger?.warn(STORAGE_TYPE_VALIDATION_WARNING(CONFIG_MANAGER,storageType,DEFAULT_STORAGE_TYPE));storageType=DEFAULT_STORAGE_TYPE;}let storageEncryptionVersion=storageOptsFromLoad?.encryption?.version;const encryptionPluginName=storageEncryptionVersion&&StorageEncryptionVersionsToPluginNameMap[storageEncryptionVersion];if(!isUndefined(storageEncryptionVersion)&&isUndefined(encryptionPluginName)){// set the default encryption plugin
|
1112
1132
|
logger?.warn(UNSUPPORTED_STORAGE_ENCRYPTION_VERSION_WARNING(CONFIG_MANAGER,storageEncryptionVersion,StorageEncryptionVersionsToPluginNameMap,DEFAULT_STORAGE_ENCRYPTION_VERSION));storageEncryptionVersion=DEFAULT_STORAGE_ENCRYPTION_VERSION;}else if(isUndefined(storageEncryptionVersion)){storageEncryptionVersion=DEFAULT_STORAGE_ENCRYPTION_VERSION;}// Allow migration only if the configured encryption version is the default encryption version
|
1113
|
-
const configuredMigrationValue=storageOptsFromLoad?.migrate;const finalMigrationVal=configuredMigrationValue&&storageEncryptionVersion===DEFAULT_STORAGE_ENCRYPTION_VERSION;if(configuredMigrationValue===true&&
|
1114
|
-
const
|
1115
|
-
|
1116
|
-
|
1133
|
+
const configuredMigrationValue=storageOptsFromLoad?.migrate;const finalMigrationVal=configuredMigrationValue&&storageEncryptionVersion===DEFAULT_STORAGE_ENCRYPTION_VERSION;if(configuredMigrationValue===true&&finalMigrationVal!==configuredMigrationValue){logger?.warn(STORAGE_DATA_MIGRATION_OVERRIDE_WARNING(CONFIG_MANAGER,storageEncryptionVersion,DEFAULT_STORAGE_ENCRYPTION_VERSION));}n(()=>{state.storage.type.value=storageType;state.storage.cookie.value=storageOptsFromLoad?.cookie;state.storage.encryptionPluginName.value=StorageEncryptionVersionsToPluginNameMap[storageEncryptionVersion];state.storage.migrate.value=finalMigrationVal;});};const updateConsentsStateFromLoadOptions=logger=>{const{provider,consentManagerPluginName,initialized,enabled,consentsData}=getConsentManagementData(state.loadOptions.value.consentManagement,logger);// Pre-consent
|
1134
|
+
const preConsentOpts=state.loadOptions.value.preConsent;let storageStrategy=preConsentOpts?.storage?.strategy??DEFAULT_PRE_CONSENT_STORAGE_STRATEGY;const StorageStrategies=['none','session','anonymousId'];if(isDefined(storageStrategy)&&!StorageStrategies.includes(storageStrategy)){storageStrategy=DEFAULT_PRE_CONSENT_STORAGE_STRATEGY;logger?.warn(UNSUPPORTED_PRE_CONSENT_STORAGE_STRATEGY(CONFIG_MANAGER,preConsentOpts?.storage?.strategy,DEFAULT_PRE_CONSENT_STORAGE_STRATEGY));}let eventsDeliveryType=preConsentOpts?.events?.delivery??DEFAULT_PRE_CONSENT_EVENTS_DELIVERY_TYPE;const deliveryTypes=['immediate','buffer'];if(isDefined(eventsDeliveryType)&&!deliveryTypes.includes(eventsDeliveryType)){eventsDeliveryType=DEFAULT_PRE_CONSENT_EVENTS_DELIVERY_TYPE;logger?.warn(UNSUPPORTED_PRE_CONSENT_EVENTS_DELIVERY_TYPE(CONFIG_MANAGER,preConsentOpts?.events?.delivery,DEFAULT_PRE_CONSENT_EVENTS_DELIVERY_TYPE));}n(()=>{state.consents.activeConsentManagerPluginName.value=consentManagerPluginName;state.consents.initialized.value=initialized;state.consents.enabled.value=enabled;state.consents.data.value=consentsData;state.consents.provider.value=provider;state.consents.preConsent.value={// Only enable pre-consent if it is explicitly enabled and
|
1135
|
+
// if it is not already initialized and
|
1136
|
+
// if consent management is enabled
|
1137
|
+
enabled:state.loadOptions.value.preConsent?.enabled===true&&initialized===false&&enabled===true,storage:{strategy:storageStrategy},events:{delivery:eventsDeliveryType}};});};/**
|
1138
|
+
* Determines the consent management state variables from the source config data
|
1139
|
+
* @param resp Source config response
|
1140
|
+
* @param logger Logger instance
|
1141
|
+
*/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
|
1142
|
+
if(state.consents.provider.value==='custom'){resolutionStrategy=undefined;}n(()=>{state.consents.metadata.value=clone(cmpMetadata);state.consents.resolutionStrategy.value=resolutionStrategy;});};
|
1117
1143
|
|
1118
1144
|
/**
|
1119
1145
|
* A function that determines integration SDK loading path
|
@@ -1132,28 +1158,28 @@ if(lockIntegrationsVersion){integrationsCDNPath=integrationsCDNPath.replace(CDN_
|
|
1132
1158
|
if(customPluginsCDNPath){pluginsCDNPath=removeTrailingSlashes(customPluginsCDNPath);if(!pluginsCDNPath||pluginsCDNPath&&!isValidUrl(pluginsCDNPath)){throw new Error(PLUGINS_CDN_BASE_URL_ERROR);}return pluginsCDNPath;}// Get the base path from the SDK script tag src attribute or use the default path
|
1133
1159
|
const sdkURL=getSDKUrl();pluginsCDNPath=sdkURL&&isString(sdkURL)?sdkURL.split('/').slice(0,-1).concat(CDN_PLUGINS_DIR).join('/'):PLUGINS_BASE_URL;return pluginsCDNPath;};
|
1134
1160
|
|
1135
|
-
class ConfigManager{hasErrorHandler=false;constructor(httpClient,errorHandler,logger){this.errorHandler=errorHandler;this.logger=logger;this.httpClient=httpClient;this.hasErrorHandler=Boolean(this.errorHandler);this.onError=this.onError.bind(this);this.processConfig=this.processConfig.bind(this);}attachEffects(){
|
1161
|
+
class ConfigManager{hasErrorHandler=false;constructor(httpClient,errorHandler,logger){this.errorHandler=errorHandler;this.logger=logger;this.httpClient=httpClient;this.hasErrorHandler=Boolean(this.errorHandler);this.onError=this.onError.bind(this);this.processConfig=this.processConfig.bind(this);}attachEffects(){O(()=>{this.logger?.setMinLogLevel(state.lifecycle.logLevel.value);});}/**
|
1136
1162
|
* A function to validate, construct and store loadOption, lifecycle, source and destination
|
1137
1163
|
* config related information in global state
|
1138
|
-
*/init(){this.attachEffects();
|
1164
|
+
*/init(){this.attachEffects();validateLoadArgs(state.lifecycle.writeKey.value,state.lifecycle.dataPlaneUrl.value);const lockIntegrationsVersion=state.loadOptions.value.lockIntegrationsVersion;// determine the path to fetch integration SDK from
|
1139
1165
|
const intgCdnUrl=getIntegrationsCDNPath(APP_VERSION,lockIntegrationsVersion,state.loadOptions.value.destSDKBaseURL);// determine the path to fetch remote plugins from
|
1140
|
-
const pluginsCDNPath=getPluginsCDNPath(state.loadOptions.value.pluginsSDKBaseURL);
|
1141
|
-
|
1166
|
+
const pluginsCDNPath=getPluginsCDNPath(state.loadOptions.value.pluginsSDKBaseURL);updateStorageStateFromLoadOptions(this.logger);updateConsentsStateFromLoadOptions(this.logger);// set application lifecycle state in global state
|
1167
|
+
n(()=>{state.lifecycle.integrationsCDNPath.value=intgCdnUrl;state.lifecycle.pluginsCDNPath.value=pluginsCDNPath;if(state.loadOptions.value.logLevel){state.lifecycle.logLevel.value=state.loadOptions.value.logLevel;}state.lifecycle.sourceConfigUrl.value=getSourceConfigURL(state.loadOptions.value.configUrl,state.lifecycle.writeKey.value,lockIntegrationsVersion,this.logger);});this.getConfig();}/**
|
1142
1168
|
* Handle errors
|
1143
1169
|
*/onError(error,customMessage,shouldAlwaysThrow){if(this.hasErrorHandler){this.errorHandler?.onError(error,CONFIG_MANAGER,customMessage,shouldAlwaysThrow);}else {throw error;}}/**
|
1144
1170
|
* A callback function that is executed once we fetch the source config response.
|
1145
1171
|
* Use to construct and store information that are dependent on the sourceConfig.
|
1146
1172
|
*/processConfig(response,details){// TODO: add retry logic with backoff based on rejectionDetails.xhr.status
|
1147
1173
|
// We can use isErrRetryable utility method
|
1148
|
-
if(!response){this.onError(SOURCE_CONFIG_FETCH_ERROR(details?.error));return;}let res;
|
1174
|
+
if(!response){this.onError(SOURCE_CONFIG_FETCH_ERROR(details?.error));return;}let res;try{if(isString(response)){res=JSON.parse(response);}else {res=response;}}catch(err){this.onError(err,SOURCE_CONFIG_RESOLUTION_ERROR,true);return;}if(!isValidSourceConfig(res)){this.onError(new Error(SOURCE_CONFIG_RESOLUTION_ERROR),undefined,true);return;}// set the values in state for reporting slice
|
1149
1175
|
updateReportingState(res,this.logger);// determine the dataPlane url
|
1150
1176
|
const dataPlaneUrl=resolveDataPlaneUrl(res.source.dataplanes,state.lifecycle.dataPlaneUrl.value,state.loadOptions.value.residencyServer,this.logger);if(!dataPlaneUrl){this.onError(new Error(DATA_PLANE_URL_ERROR),undefined,true);return;}const nativeDestinations=res.source.destinations.length>0?filterEnabledDestination(res.source.destinations):[];// set in the state --> source, destination, lifecycle, reporting
|
1151
|
-
|
1177
|
+
n(()=>{// set source related information in state
|
1152
1178
|
state.source.value={config:res.source.config,id:res.source.id};// set device mode destination related information in state
|
1153
1179
|
state.nativeDestinations.configuredDestinations.value=nativeDestinations;// set the desired optional plugins
|
1154
|
-
state.plugins.pluginsToLoadFromConfig.value=state.loadOptions.value.plugins??[];// set application lifecycle state
|
1180
|
+
state.plugins.pluginsToLoadFromConfig.value=state.loadOptions.value.plugins??[];updateConsentsState(res);// set application lifecycle state
|
1155
1181
|
// Cast to string as we are sure that the value is not undefined
|
1156
|
-
state.lifecycle.activeDataplaneUrl.value=removeTrailingSlashes(dataPlaneUrl);state.lifecycle.status.value=
|
1182
|
+
state.lifecycle.activeDataplaneUrl.value=removeTrailingSlashes(dataPlaneUrl);state.lifecycle.status.value='configured';});}/**
|
1157
1183
|
* A function to fetch source config either from /sourceConfig endpoint
|
1158
1184
|
* or from getSourceConfig load option
|
1159
1185
|
* @returns
|
@@ -1161,10 +1187,16 @@ state.lifecycle.activeDataplaneUrl.value=removeTrailingSlashes(dataPlaneUrl);sta
|
|
1161
1187
|
const res=sourceConfigFunc();if(res instanceof Promise){res.then(pRes=>this.processConfig(pRes)).catch(err=>{this.onError(err,'SourceConfig');});}else {this.processConfig(res);}}else {// fetch source config from config url API
|
1162
1188
|
this.httpClient.getAsyncData({url:state.lifecycle.sourceConfigUrl.value,options:{headers:{'Content-Type':undefined}},callback:this.processConfig});}}}
|
1163
1189
|
|
1190
|
+
/**
|
1191
|
+
* To get the timezone of the user
|
1192
|
+
*
|
1193
|
+
* @returns string
|
1194
|
+
*/const getTimezone=()=>{const timezone=new Date().toString().match(/([A-Z]+[+-]\d+)/);return timezone&&timezone[1]?timezone[1]:'NA';};
|
1195
|
+
|
1164
1196
|
/**
|
1165
1197
|
* Get the referrer URL
|
1166
1198
|
* @returns The referrer URL
|
1167
|
-
*/const getReferrer=()=>document
|
1199
|
+
*/const getReferrer=()=>document?.referrer||'$direct';/**
|
1168
1200
|
* To get the canonical URL of the page
|
1169
1201
|
* @returns canonical URL
|
1170
1202
|
*/const getCanonicalUrl=()=>{const tags=document.getElementsByTagName('link');let canonicalUrl='';for(let i=0;tags[i];i+=1){const tag=tags[i];if(tag.getAttribute('rel')==='canonical'&&!canonicalUrl){canonicalUrl=tag.getAttribute('href')??'';break;}}return canonicalUrl;};const getUserAgent=()=>{if(isUndefined(globalThis.navigator)){return null;}let{userAgent}=globalThis.navigator;const{brave}=globalThis.navigator;// For supporting Brave browser detection,
|
@@ -1179,27 +1211,27 @@ if(canonicalUrl){try{const urlObj=new URL(canonicalUrl);// If existing, query pa
|
|
1179
1211
|
if(urlObj.search===''){pageUrl=canonicalUrl+search;}else {pageUrl=canonicalUrl;}path=urlObj.pathname;}catch(err){// Do nothing
|
1180
1212
|
}}const url=getUrlWithoutHash(pageUrl);const{title}=document;const referrer=getReferrer();return {path,referrer,referring_domain:getReferringDomain(referrer),search,title,url,tab_url:tabUrl};};
|
1181
1213
|
|
1182
|
-
const POLYFILL_URL=`https://polyfill.io/v3/polyfill.min.js?features=${Object.keys(legacyJSEngineRequiredPolyfills).join('%2C')}`;const POLYFILL_LOAD_TIMEOUT=10*1000;// 10 seconds
|
1214
|
+
const POLYFILL_URL=`https://polyfill.io/v3/polyfill.min.js?version=3.111.0&features=${Object.keys(legacyJSEngineRequiredPolyfills).join('%2C')}`;const POLYFILL_LOAD_TIMEOUT=10*1000;// 10 seconds
|
1183
1215
|
const POLYFILL_SCRIPT_ID='rudderstackPolyfill';
|
1184
1216
|
|
1185
1217
|
class CapabilitiesManager{constructor(errorHandler,logger){this.logger=logger;this.errorHandler=errorHandler;this.externalSrcLoader=new ExternalSrcLoader(this.errorHandler,this.logger);this.onError=this.onError.bind(this);this.onReady=this.onReady.bind(this);}init(){try{this.prepareBrowserCapabilities();this.attachWindowListeners();}catch(err){this.onError(err);}}/**
|
1186
1218
|
* Detect supported capabilities and set values in state
|
1187
1219
|
*/ // eslint-disable-next-line class-methods-use-this
|
1188
|
-
detectBrowserCapabilities(){
|
1220
|
+
detectBrowserCapabilities(){n(()=>{// Storage related details
|
1189
1221
|
state.capabilities.storage.isCookieStorageAvailable.value=isStorageAvailable(COOKIE_STORAGE,getStorageEngine(COOKIE_STORAGE),this.logger);state.capabilities.storage.isLocalStorageAvailable.value=isStorageAvailable(LOCAL_STORAGE,undefined,this.logger);state.capabilities.storage.isSessionStorageAvailable.value=isStorageAvailable(SESSION_STORAGE,undefined,this.logger);// Browser feature detection details
|
1190
1222
|
state.capabilities.isBeaconAvailable.value=hasBeacon();state.capabilities.isUaCHAvailable.value=hasUAClientHints();state.capabilities.isCryptoAvailable.value=hasCrypto$1();state.capabilities.isIE11.value=isIE11();state.capabilities.isOnline.value=globalThis.navigator.onLine;// Get page context details
|
1191
|
-
state.context.userAgent.value=getUserAgent();state.context.locale.value=getLanguage();state.context.screen.value=getScreenDetails();if(hasUAClientHints()){getUserAgentClientHint(uach=>{state.context['ua-ch'].value=uach;},state.loadOptions.value.uaChTrackLevel);}});// Ad blocker detection
|
1192
|
-
|
1223
|
+
state.context.userAgent.value=getUserAgent();state.context.locale.value=getLanguage();state.context.screen.value=getScreenDetails();state.context.timezone.value=getTimezone();if(hasUAClientHints()){getUserAgentClientHint(uach=>{state.context['ua-ch'].value=uach;},state.loadOptions.value.uaChTrackLevel);}});// Ad blocker detection
|
1224
|
+
O(()=>{if(state.loadOptions.value.sendAdblockPage===true&&state.lifecycle.sourceConfigUrl.value!==undefined){detectAdBlockers(this.errorHandler,this.logger);}});}/**
|
1193
1225
|
* Detect if polyfills are required and then load script from polyfill URL
|
1194
|
-
*/prepareBrowserCapabilities(){state.capabilities.isLegacyDOM.value=isLegacyJSEngine();let polyfillUrl=state.loadOptions.value.polyfillURL??POLYFILL_URL;const shouldLoadPolyfill=state.loadOptions.value.polyfillIfRequired&&state.capabilities.isLegacyDOM.value&&Boolean(polyfillUrl);if(shouldLoadPolyfill){const isDefaultPolyfillService=polyfillUrl!==state.loadOptions.value.polyfillURL;if(isDefaultPolyfillService){
|
1226
|
+
*/prepareBrowserCapabilities(){state.capabilities.isLegacyDOM.value=isLegacyJSEngine();let polyfillUrl=state.loadOptions.value.polyfillURL??POLYFILL_URL;const shouldLoadPolyfill=state.loadOptions.value.polyfillIfRequired&&state.capabilities.isLegacyDOM.value&&Boolean(polyfillUrl);if(shouldLoadPolyfill){const isDefaultPolyfillService=polyfillUrl!==state.loadOptions.value.polyfillURL;if(isDefaultPolyfillService){// write key specific callback
|
1195
1227
|
// NOTE: we're not putting this into RudderStackGlobals as providing the property path to the callback function in the polyfill URL is not possible
|
1196
|
-
const polyfillCallbackName=`RS_polyfillCallback_${state.lifecycle.writeKey.value}`;
|
1228
|
+
const polyfillCallbackName=`RS_polyfillCallback_${state.lifecycle.writeKey.value}`;const polyfillCallback=()=>{this.onReady();// Remove the entry from window so we don't leave room for calling it again
|
1229
|
+
delete globalThis[polyfillCallbackName];};globalThis[polyfillCallbackName]=polyfillCallback;polyfillUrl=`${polyfillUrl}&callback=${polyfillCallbackName}`;}this.externalSrcLoader?.loadJSFile({url:polyfillUrl,id:POLYFILL_SCRIPT_ID,async:true,timeout:POLYFILL_LOAD_TIMEOUT,callback:scriptId=>{if(!scriptId){this.onError(new Error(POLYFILL_SCRIPT_LOAD_ERROR(POLYFILL_SCRIPT_ID,polyfillUrl)));}else if(!isDefaultPolyfillService){this.onReady();}}});}else {this.onReady();}}/**
|
1197
1230
|
* Attach listeners to window to observe event that update capabilities state values
|
1198
|
-
*/
|
1199
|
-
attachWindowListeners(){globalThis.addEventListener('offline',()=>{state.capabilities.isOnline.value=false;});globalThis.addEventListener('online',()=>{state.capabilities.isOnline.value=true;});globalThis.addEventListener('resize',debounce(()=>{state.context.screen.value=getScreenDetails();},this));}/**
|
1231
|
+
*/attachWindowListeners(){globalThis.addEventListener('offline',()=>{state.capabilities.isOnline.value=false;});globalThis.addEventListener('online',()=>{state.capabilities.isOnline.value=true;});globalThis.addEventListener('resize',debounce(()=>{state.context.screen.value=getScreenDetails();},this));}/**
|
1200
1232
|
* Set the lifecycle status to next phase
|
1201
1233
|
*/ // eslint-disable-next-line class-methods-use-this
|
1202
|
-
onReady(){this.detectBrowserCapabilities();state.lifecycle.status.value=
|
1234
|
+
onReady(){this.detectBrowserCapabilities();state.lifecycle.status.value='browserCapabilitiesReady';}/**
|
1203
1235
|
* Handles error
|
1204
1236
|
* @param error The error object
|
1205
1237
|
*/onError(error){if(this.errorHandler){this.errorHandler.onError(error,CAPABILITIES_MANAGER);}else {throw error;}}}
|
@@ -1219,13 +1251,38 @@ const generateUUID=()=>{if(hasCrypto()){return v4$1();}return v4();};
|
|
1219
1251
|
* @returns ISO formatted timestamp string
|
1220
1252
|
*/const getCurrentTimeFormatted=()=>{const curDateTime=new Date().toISOString();return curDateTime;};
|
1221
1253
|
|
1222
|
-
const DEFAULT_INTEGRATIONS_CONFIG={All:true};
|
1223
|
-
|
1224
1254
|
const CHANNEL='web';// These are the top-level elements in the standard RudderStack event spec
|
1225
1255
|
const TOP_LEVEL_ELEMENTS=['integrations','anonymousId','originalTimestamp'];// Reserved elements in the context of standard RudderStack event spec
|
1226
1256
|
// Typically, these elements are not allowed to be overridden by the user
|
1227
1257
|
const CONTEXT_RESERVED_ELEMENTS=['library','consentManagement','userAgent','ua-ch','screen'];// Reserved elements in the standard RudderStack event spec
|
1228
|
-
const RESERVED_ELEMENTS=['
|
1258
|
+
const RESERVED_ELEMENTS=['id','anonymous_id','user_id','sent_at','timestamp','received_at','original_timestamp','event','event_text','channel','context_ip','context_request_ip','context_passed_ip','group_id','previous_id'];
|
1259
|
+
|
1260
|
+
const MIN_SESSION_ID_LENGTH=10;/**
|
1261
|
+
* A function to validate current session and return true/false depending on that
|
1262
|
+
* @returns boolean
|
1263
|
+
*/const hasSessionExpired=expiresAt=>{const timestamp=Date.now();return Boolean(!expiresAt||timestamp>expiresAt);};/**
|
1264
|
+
* A function to generate session id
|
1265
|
+
* @returns number
|
1266
|
+
*/const generateSessionId=()=>Date.now();/**
|
1267
|
+
* Function to validate user provided sessionId
|
1268
|
+
* @param {number} sessionId
|
1269
|
+
* @param logger logger
|
1270
|
+
* @returns
|
1271
|
+
*/const isManualSessionIdValid=(sessionId,logger)=>{if(!sessionId||!isPositiveInteger(sessionId)||!hasMinLength(MIN_SESSION_ID_LENGTH,sessionId)){logger?.warn(INVALID_SESSION_ID_WARNING(USER_SESSION_MANAGER,sessionId,MIN_SESSION_ID_LENGTH));return false;}return true;};/**
|
1272
|
+
* A function to generate new auto tracking session
|
1273
|
+
* @param sessionTimeout current timestamp
|
1274
|
+
* @returns SessionInfo
|
1275
|
+
*/const generateAutoTrackingSession=sessionTimeout=>{const timestamp=Date.now();const timeout=sessionTimeout||DEFAULT_SESSION_TIMEOUT_MS;return {id:timestamp,// set the current timestamp
|
1276
|
+
expiresAt:timestamp+timeout,// set the expiry time of the session
|
1277
|
+
timeout,sessionStart:undefined,autoTrack:true};};/**
|
1278
|
+
* A function to generate new manual tracking session
|
1279
|
+
* @param id Provided sessionId
|
1280
|
+
* @param logger Logger module
|
1281
|
+
* @returns SessionInfo
|
1282
|
+
*/const generateManualTrackingSession=(id,logger)=>{const sessionId=isManualSessionIdValid(id,logger)?id:generateSessionId();return {id:sessionId,sessionStart:undefined,manualTrack:true};};const isStorageTypeValidForStoringData=storageType=>Boolean(storageType===COOKIE_STORAGE||storageType===LOCAL_STORAGE||storageType===SESSION_STORAGE||storageType===MEMORY_STORAGE);/**
|
1283
|
+
* Generate a new anonymousId
|
1284
|
+
* @returns string anonymousID
|
1285
|
+
*/const generateAnonymousId=()=>generateUUID();
|
1229
1286
|
|
1230
1287
|
/**
|
1231
1288
|
* To get the page properties for context object
|
@@ -1252,7 +1309,7 @@ const{properties,traits,context}=rudderEvent;const{traits:contextualTraits}=cont
|
|
1252
1309
|
* @param rudderEvent Generated rudder event
|
1253
1310
|
* @param options API options
|
1254
1311
|
*/const updateTopLevelEventElements=(rudderEvent,options)=>{if(options.anonymousId&&isString(options.anonymousId)){// eslint-disable-next-line no-param-reassign
|
1255
|
-
rudderEvent.anonymousId=options.anonymousId;}if(
|
1312
|
+
rudderEvent.anonymousId=options.anonymousId;}if(isObjectLiteralAndNotNull(options.integrations)){// eslint-disable-next-line no-param-reassign
|
1256
1313
|
rudderEvent.integrations=options.integrations;}if(options.originalTimestamp&&isString(options.originalTimestamp)){// eslint-disable-next-line no-param-reassign
|
1257
1314
|
rudderEvent.originalTimestamp=options.originalTimestamp;}};/**
|
1258
1315
|
* To merge the contextual information in API options with existing data
|
@@ -1262,30 +1319,30 @@ rudderEvent.originalTimestamp=options.originalTimestamp;}};/**
|
|
1262
1319
|
*/const getMergedContext=(rudderContext,options,logger)=>{let context=rudderContext;Object.keys(options).forEach(key=>{if(!TOP_LEVEL_ELEMENTS.includes(key)&&!CONTEXT_RESERVED_ELEMENTS.includes(key)){if(key!=='context'){context=mergeDeepRight(context,{[key]:options[key]});}else if(!isUndefined(options[key])&&isObjectLiteralAndNotNull(options[key])){const tempContext={};Object.keys(options[key]).forEach(e=>{if(!CONTEXT_RESERVED_ELEMENTS.includes(e)){tempContext[e]=options[key][e];}});context=mergeDeepRight(context,{...tempContext});}else {logger?.warn(INVALID_CONTEXT_OBJECT_WARNING(EVENT_MANAGER));}}});return context;};/**
|
1263
1320
|
* A function to determine whether SDK should use the integration option provided in load call
|
1264
1321
|
* @returns boolean
|
1265
|
-
*/const shouldUseGlobalIntegrationsConfigInEvents=()=>state.loadOptions.value.useGlobalIntegrationsConfigInEvents&&isObjectLiteralAndNotNull(state.nativeDestinations.loadOnlyIntegrations.value);/**
|
1322
|
+
*/const shouldUseGlobalIntegrationsConfigInEvents=()=>state.loadOptions.value.useGlobalIntegrationsConfigInEvents&&(isObjectLiteralAndNotNull(state.consents.postConsent.value?.integrations)||isObjectLiteralAndNotNull(state.nativeDestinations.loadOnlyIntegrations.value));/**
|
1266
1323
|
* Updates rudder event object with data from the API options
|
1267
1324
|
* @param rudderEvent Generated rudder event
|
1268
1325
|
* @param options API options
|
1269
1326
|
*/const processOptions=(rudderEvent,options)=>{// Only allow object type for options
|
1270
|
-
if(
|
1327
|
+
if(isObjectLiteralAndNotNull(options)){updateTopLevelEventElements(rudderEvent,options);// eslint-disable-next-line no-param-reassign
|
1271
1328
|
rudderEvent.context=getMergedContext(rudderEvent.context,options);}};/**
|
1272
1329
|
* Returns the final integrations config for the event based on the global config and event's config
|
1273
1330
|
* @param integrationsConfig Event's integrations config
|
1274
1331
|
* @returns Final integrations config
|
1275
|
-
*/const getEventIntegrationsConfig=integrationsConfig=>{let finalIntgConfig;if(shouldUseGlobalIntegrationsConfigInEvents()){finalIntgConfig=state.nativeDestinations.loadOnlyIntegrations.value;}else if(isObjectLiteralAndNotNull(integrationsConfig)){finalIntgConfig=integrationsConfig;}else {finalIntgConfig=DEFAULT_INTEGRATIONS_CONFIG;}return finalIntgConfig;};/**
|
1332
|
+
*/const getEventIntegrationsConfig=integrationsConfig=>{let finalIntgConfig;if(shouldUseGlobalIntegrationsConfigInEvents()){finalIntgConfig=clone(state.consents.postConsent.value?.integrations??state.nativeDestinations.loadOnlyIntegrations.value);}else if(isObjectLiteralAndNotNull(integrationsConfig)){finalIntgConfig=integrationsConfig;}else {finalIntgConfig=DEFAULT_INTEGRATIONS_CONFIG;}return finalIntgConfig;};/**
|
1276
1333
|
* Enrich the base event object with data from state and the API options
|
1277
1334
|
* @param rudderEvent RudderEvent object
|
1278
1335
|
* @param options API options
|
1279
1336
|
* @param pageProps Page properties
|
1280
1337
|
* @param logger logger
|
1281
1338
|
* @returns Enriched RudderEvent object
|
1282
|
-
*/const getEnrichedEvent=(rudderEvent,options,pageProps,logger)=>{const commonEventData={channel:CHANNEL,context:{traits:clone
|
1283
|
-
|
1339
|
+
*/const getEnrichedEvent=(rudderEvent,options,pageProps,logger)=>{const commonEventData={channel:CHANNEL,context:{traits:clone(state.session.userTraits.value),sessionId:state.session.sessionInfo.value.id||undefined,sessionStart:state.session.sessionInfo.value.sessionStart||undefined,// Add 'consentManagement' only if consent management is enabled
|
1340
|
+
...(state.consents.enabled.value&&{consentManagement:{deniedConsentIds:clone(state.consents.data.value.deniedConsentIds),allowedConsentIds:clone(state.consents.data.value.allowedConsentIds),provider:state.consents.provider.value,resolutionStrategy:state.consents.resolutionStrategy.value}}),'ua-ch':state.context['ua-ch'].value,app:state.context.app.value,library:state.context.library.value,userAgent:state.context.userAgent.value,os:state.context.os.value,locale:state.context.locale.value,screen:state.context.screen.value,campaign:extractUTMParameters(globalThis.location.href),page:getContextPageProperties(pageProps),timezone:state.context.timezone.value},originalTimestamp:getCurrentTimeFormatted(),integrations:DEFAULT_INTEGRATIONS_CONFIG,messageId:generateUUID(),userId:rudderEvent.userId||state.session.userId.value};if(!isStorageTypeValidForStoringData(state.storage.entries.value.anonymousId?.type)){// Generate new anonymous id for each request
|
1341
|
+
commonEventData.anonymousId=generateAnonymousId();}else {// Type casting to string as the user session manager will take care of initializing the value
|
1284
1342
|
commonEventData.anonymousId=state.session.anonymousId.value;}// set truly anonymous tracking flag
|
1285
|
-
if(state.storage.trulyAnonymousTracking.value){commonEventData.context.trulyAnonymousTracking=true;}if(rudderEvent.type===
|
1343
|
+
if(state.storage.trulyAnonymousTracking.value){commonEventData.context.trulyAnonymousTracking=true;}if(rudderEvent.type==='identify'){commonEventData.context.traits=state.storage.entries.value.userTraits?.type!==NO_STORAGE?clone(state.session.userTraits.value):rudderEvent.context.traits;}if(rudderEvent.type==='group'){if(rudderEvent.groupId||state.session.groupId.value){commonEventData.groupId=rudderEvent.groupId||state.session.groupId.value;}if(rudderEvent.traits||state.session.groupTraits.value){commonEventData.traits=state.storage.entries.value.groupTraits?.type!==NO_STORAGE?clone(state.session.groupTraits.value):rudderEvent.traits;}}const processedEvent=mergeDeepRight(rudderEvent,commonEventData);// Set the default values for the event properties
|
1286
1344
|
// matching with v1.1 payload
|
1287
|
-
if(processedEvent.event===undefined){processedEvent.event=null;}if(processedEvent.properties===undefined){processedEvent.properties=null;}processOptions(processedEvent,options);//
|
1288
|
-
checkForReservedElements(processedEvent,logger);// Update the integrations config for the event
|
1345
|
+
if(processedEvent.event===undefined){processedEvent.event=null;}if(processedEvent.properties===undefined){processedEvent.properties=null;}processOptions(processedEvent,options);checkForReservedElements(processedEvent,logger);// Update the integrations config for the event
|
1289
1346
|
processedEvent.integrations=getEventIntegrationsConfig(processedEvent.integrations);return processedEvent;};
|
1290
1347
|
|
1291
1348
|
class RudderEventFactory{constructor(logger){this.logger=logger;}/**
|
@@ -1294,28 +1351,32 @@ class RudderEventFactory{constructor(logger){this.logger=logger;}/**
|
|
1294
1351
|
* @param name Page name
|
1295
1352
|
* @param properties Page properties
|
1296
1353
|
* @param options API options
|
1297
|
-
*/generatePageEvent(category,name,properties,options){let props=properties??{};props.name=name;props.category=category;props=getUpdatedPageProperties(props,options);const pageEvent={properties:props,name,category,type:
|
1354
|
+
*/generatePageEvent(category,name,properties,options){let props=properties??{};props.name=name;props.category=category;props=getUpdatedPageProperties(props,options);const pageEvent={properties:props,name,category,type:'page'};return getEnrichedEvent(pageEvent,options,props,this.logger);}/**
|
1298
1355
|
* Generate a 'track' event based on the user-input fields
|
1299
1356
|
* @param event The event name
|
1300
1357
|
* @param properties Event properties
|
1301
1358
|
* @param options API options
|
1302
|
-
*/generateTrackEvent(event,properties,options){const trackEvent={properties,event,type:
|
1359
|
+
*/generateTrackEvent(event,properties,options){const trackEvent={properties,event,type:'track'};return getEnrichedEvent(trackEvent,options,undefined,this.logger);}/**
|
1303
1360
|
* Generate an 'identify' event based on the user-input fields
|
1361
|
+
* @param userId New user ID
|
1362
|
+
* @param traits new traits
|
1304
1363
|
* @param options API options
|
1305
|
-
*/generateIdentifyEvent(userId,traits,options){const identifyEvent={userId,type:
|
1364
|
+
*/generateIdentifyEvent(userId,traits,options){const identifyEvent={userId,type:'identify',context:{traits}};return getEnrichedEvent(identifyEvent,options,undefined,this.logger);}/**
|
1306
1365
|
* Generate an 'alias' event based on the user-input fields
|
1307
1366
|
* @param to New user ID
|
1308
1367
|
* @param from Old user ID
|
1309
1368
|
* @param options API options
|
1310
|
-
*/generateAliasEvent(to,from,options){const aliasEvent={previousId:from,type:
|
1369
|
+
*/generateAliasEvent(to,from,options){const aliasEvent={previousId:from,type:'alias'};const enrichedEvent=getEnrichedEvent(aliasEvent,options,undefined,this.logger);// override the User ID from the API inputs
|
1311
1370
|
enrichedEvent.userId=to??enrichedEvent.userId;return enrichedEvent;}/**
|
1312
1371
|
* Generate a 'group' event based on the user-input fields
|
1372
|
+
* @param groupId New group ID
|
1373
|
+
* @param traits new group traits
|
1313
1374
|
* @param options API options
|
1314
|
-
*/generateGroupEvent(groupId,traits,options){const groupEvent={type:
|
1375
|
+
*/generateGroupEvent(groupId,traits,options){const groupEvent={type:'group'};if(groupId){groupEvent.groupId=groupId;}if(traits){groupEvent.traits=traits;}return getEnrichedEvent(groupEvent,options,undefined,this.logger);}/**
|
1315
1376
|
* Generates a new RudderEvent object based on the user-input fields
|
1316
1377
|
* @param event API event parameters object
|
1317
1378
|
* @returns A RudderEvent object
|
1318
|
-
*/create(event){let eventObj;switch(event.type){case
|
1379
|
+
*/create(event){let eventObj;switch(event.type){case'page':eventObj=this.generatePageEvent(event.category,event.name,event.properties,event.options);break;case'track':eventObj=this.generateTrackEvent(event.name,event.properties,event.options);break;case'identify':eventObj=this.generateIdentifyEvent(event.userId,event.traits,event.options);break;case'alias':eventObj=this.generateAliasEvent(event.to,event.from,event.options);break;case'group':eventObj=this.generateGroupEvent(event.groupId,event.traits,event.options);break;}return eventObj;}}
|
1319
1380
|
|
1320
1381
|
/**
|
1321
1382
|
* A service to generate valid event payloads and queue them for processing
|
@@ -1327,7 +1388,7 @@ enrichedEvent.userId=to??enrichedEvent.userId;return enrichedEvent;}/**
|
|
1327
1388
|
* @param logger Logger object
|
1328
1389
|
*/constructor(eventRepository,userSessionManager,errorHandler,logger){this.eventRepository=eventRepository;this.userSessionManager=userSessionManager;this.errorHandler=errorHandler;this.logger=logger;this.eventFactory=new RudderEventFactory(this.logger);this.onError=this.onError.bind(this);}/**
|
1329
1390
|
* Initializes the event manager
|
1330
|
-
*/init(){this.eventRepository.init();}/**
|
1391
|
+
*/init(){this.eventRepository.init();}resume(){this.eventRepository.resume();}/**
|
1331
1392
|
* Consumes a new incoming event
|
1332
1393
|
* @param event Incoming event data
|
1333
1394
|
*/addEvent(event){this.userSessionManager.refreshSession();const rudderEvent=this.eventFactory.create(event);if(rudderEvent){this.eventRepository.enqueue(rudderEvent,event.callback);}else {this.onError(new Error(EVENT_OBJECT_GENERATION_ERROR));}}/**
|
@@ -1335,133 +1396,98 @@ enrichedEvent.userId=to??enrichedEvent.userId;return enrichedEvent;}/**
|
|
1335
1396
|
* @param error The error object
|
1336
1397
|
*/onError(error,customMessage,shouldAlwaysThrow){if(this.errorHandler){this.errorHandler.onError(error,EVENT_MANAGER,customMessage,shouldAlwaysThrow);}else {throw error;}}}
|
1337
1398
|
|
1338
|
-
const MIN_SESSION_ID_LENGTH=10;/**
|
1339
|
-
* A function to validate current session and return true/false depending on that
|
1340
|
-
* @returns boolean
|
1341
|
-
*/const hasSessionExpired=expiresAt=>{const timestamp=Date.now();return Boolean(!expiresAt||timestamp>expiresAt);};/**
|
1342
|
-
* A function to generate session id
|
1343
|
-
* @returns number
|
1344
|
-
*/const generateSessionId=()=>Date.now();/**
|
1345
|
-
* Function to validate user provided sessionId
|
1346
|
-
* @param {number} sessionId
|
1347
|
-
* @returns
|
1348
|
-
*/const isManualSessionIdValid=(sessionId,logger)=>{if(!sessionId||!isPositiveInteger(sessionId)||!hasMinLength(MIN_SESSION_ID_LENGTH,sessionId)){logger?.warn(INVALID_SESSION_ID_WARNING(USER_SESSION_MANAGER,sessionId,MIN_SESSION_ID_LENGTH));return false;}return true;};/**
|
1349
|
-
* A function to generate new auto tracking session
|
1350
|
-
* @param sessionTimeout current timestamp
|
1351
|
-
* @returns SessionInfo
|
1352
|
-
*/const generateAutoTrackingSession=sessionTimeout=>{const timestamp=Date.now();const timeout=sessionTimeout||DEFAULT_SESSION_TIMEOUT_MS;return {id:timestamp,// set the current timestamp
|
1353
|
-
expiresAt:timestamp+timeout,// set the expiry time of the session
|
1354
|
-
timeout,sessionStart:undefined,autoTrack:true};};/**
|
1355
|
-
* A function to generate new manual tracking session
|
1356
|
-
* @param id Provided sessionId
|
1357
|
-
* @param logger Logger module
|
1358
|
-
* @returns SessionInfo
|
1359
|
-
*/const generateManualTrackingSession=(id,logger)=>{const sessionId=isManualSessionIdValid(id,logger)?id:generateSessionId();return {id:sessionId,sessionStart:undefined,manualTrack:true};};const isStorageTypeValidForStoringData=storageType=>!!(storageType===COOKIE_STORAGE||storageType===LOCAL_STORAGE||storageType===MEMORY_STORAGE);
|
1360
|
-
|
1361
1399
|
class UserSessionManager{constructor(errorHandler,logger,pluginsManager,storeManager){this.storeManager=storeManager;this.pluginsManager=pluginsManager;this.logger=logger;this.errorHandler=errorHandler;this.onError=this.onError.bind(this);}/**
|
1362
1400
|
* Initialize User session with values from storage
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1401
|
+
*/init(){this.syncStorageDataToState();// Register the effect to sync with storage
|
1402
|
+
this.registerEffects();}syncStorageDataToState(){this.migrateStorageIfNeeded();this.migrateDataFromPreviousStorage();// get the values from storage and set it again
|
1403
|
+
this.setUserId(this.getUserId());this.setUserTraits(this.getUserTraits());this.setGroupId(this.getGroupId());this.setGroupTraits(this.getGroupTraits());const{externalAnonymousIdCookieName,anonymousIdOptions}=state.loadOptions.value;let externalAnonymousId;if(isDefinedAndNotNull(externalAnonymousIdCookieName)&&typeof externalAnonymousIdCookieName==='string'){externalAnonymousId=this.getExternalAnonymousIdByCookieName(externalAnonymousIdCookieName);}this.setAnonymousId(externalAnonymousId??this.getAnonymousId(anonymousIdOptions));this.setAuthToken(this.getAuthToken());this.setInitialReferrerInfo();this.configureSessionTracking();}configureSessionTracking(){let sessionInfo=this.getSessionInfo();if(this.isPersistenceEnabledForStorageEntry('sessionInfo')){const configuredSessionTrackingInfo=this.getConfiguredSessionTrackingInfo();const persistedSessionInfo=this.getSessionInfo()??defaultSessionInfo;sessionInfo={...persistedSessionInfo,...configuredSessionTrackingInfo,autoTrack:configuredSessionTrackingInfo.autoTrack&&persistedSessionInfo.manualTrack!==true};}this.setSessionInfo(sessionInfo);}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(USER_SESSION_STORAGE_KEYS[key]);if(isDefinedNotNullAndNotEmptyString(value)){curStore.set(USER_SESSION_STORAGE_KEYS[key],value);}store.remove(USER_SESSION_STORAGE_KEYS[key]);}});}});}migrateStorageIfNeeded(){if(!state.storage.migrate.value){return;}const persistentStoreNames=[CLIENT_DATA_STORE_COOKIE,CLIENT_DATA_STORE_LS,CLIENT_DATA_STORE_SESSION];const stores=[];persistentStoreNames.forEach(storeName=>{const store=this.storeManager?.getStore(storeName);if(store){stores.push(store);}});Object.keys(USER_SESSION_STORAGE_KEYS).forEach(storageKey=>{const storageEntry=USER_SESSION_STORAGE_KEYS[storageKey];stores.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
|
1404
|
+
// as those values indicate there is no need for migration or
|
1405
|
+
// migration failed
|
1406
|
+
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
|
1407
|
+
if(!autoTrack){return {autoTrack};}let timeout;const configuredSessionTimeout=state.loadOptions.value.sessions?.timeout;if(!isPositiveInteger(configuredSessionTimeout)){this.logger?.warn(TIMEOUT_NOT_NUMBER_WARNING(USER_SESSION_MANAGER,configuredSessionTimeout,DEFAULT_SESSION_TIMEOUT_MS));timeout=DEFAULT_SESSION_TIMEOUT_MS;}else {timeout=configuredSessionTimeout;}if(timeout===0){this.logger?.warn(TIMEOUT_ZERO_WARNING(USER_SESSION_MANAGER));autoTrack=false;}// In case user provides a timeout value greater than 0 but less than 10 seconds SDK will show a warning
|
1370
1408
|
// and will proceed with it
|
1371
|
-
if(
|
1372
|
-
if(state.session.sessionInfo.value.autoTrack){this.startOrRenewAutoTracking();}}/**
|
1409
|
+
if(timeout>0&&timeout<MIN_SESSION_TIMEOUT_MS){this.logger?.warn(TIMEOUT_NOT_RECOMMENDED_WARNING(USER_SESSION_MANAGER,timeout,MIN_SESSION_TIMEOUT_MS));}return {timeout,autoTrack};}/**
|
1373
1410
|
* Handles error
|
1374
1411
|
* @param error The error object
|
1375
1412
|
*/onError(error){if(this.errorHandler){this.errorHandler.onError(error,USER_SESSION_MANAGER);}else {throw error;}}/**
|
1376
1413
|
* A function to sync values in storage
|
1377
|
-
* @param
|
1414
|
+
* @param sessionKey
|
1378
1415
|
* @param value
|
1379
1416
|
*/syncValueToStorage(sessionKey,value){const entries=state.storage.entries.value;const storage=entries[sessionKey]?.type;const key=entries[sessionKey]?.key;if(isStorageTypeValidForStoringData(storage)){const curStore=this.storeManager?.getStore(storageClientDataStoreNameMap[storage]);if(value&&isString(value)||isNonEmptyObject(value)){curStore?.set(key,value);}else {curStore?.remove(key);}}}/**
|
1380
1417
|
* Function to update storage whenever state value changes
|
1381
|
-
*/registerEffects(){
|
1382
|
-
|
1383
|
-
*/E(()=>{this.syncValueToStorage(UserSessionKeys.userId,state.session.userId.value);});/**
|
1384
|
-
* Update user traits in storage automatically when it is updated in state
|
1385
|
-
*/E(()=>{this.syncValueToStorage(UserSessionKeys.userTraits,state.session.userTraits.value);});/**
|
1386
|
-
* Update group id in storage automatically when it is updated in state
|
1387
|
-
*/E(()=>{this.syncValueToStorage(UserSessionKeys.groupId,state.session.groupId.value);});/**
|
1388
|
-
* Update group traits in storage automatically when it is updated in state
|
1389
|
-
*/E(()=>{this.syncValueToStorage(UserSessionKeys.groupTraits,state.session.groupTraits.value);});/**
|
1390
|
-
* Update anonymous user id in storage automatically when it is updated in state
|
1391
|
-
*/E(()=>{this.syncValueToStorage(UserSessionKeys.anonymousId,state.session.anonymousId.value);});/**
|
1392
|
-
* Update initial referrer in storage automatically when it is updated in state
|
1393
|
-
*/E(()=>{this.syncValueToStorage(UserSessionKeys.initialReferrer,state.session.initialReferrer.value);});/**
|
1394
|
-
* Update initial referring domain in storage automatically when it is updated in state
|
1395
|
-
*/E(()=>{this.syncValueToStorage(UserSessionKeys.initialReferringDomain,state.session.initialReferringDomain.value);});/**
|
1396
|
-
* Update session tracking info in storage automatically when it is updated in state
|
1397
|
-
*/E(()=>{this.syncValueToStorage(UserSessionKeys.sessionInfo,state.session.sessionInfo.value);});}/**
|
1418
|
+
*/registerEffects(){// This will work as long as the user session entry key names are same as the state keys
|
1419
|
+
USER_SESSION_KEYS.forEach(sessionKey=>{O(()=>{this.syncValueToStorage(sessionKey,state.session[sessionKey].value);});});}/**
|
1398
1420
|
* Sets anonymous id in the following precedence:
|
1399
1421
|
*
|
1400
1422
|
* 1. anonymousId: Id directly provided to the function.
|
1401
1423
|
* 2. rudderAmpLinkerParam: value generated from linker query parm (rudderstack)
|
1402
1424
|
* using parseLinker util.
|
1403
1425
|
* 3. generateUUID: A new unique id is generated and assigned.
|
1404
|
-
*/setAnonymousId(anonymousId,rudderAmpLinkerParam){let finalAnonymousId=anonymousId;
|
1405
|
-
* Generate a new anonymousId
|
1406
|
-
* @returns string anonymousID
|
1407
|
-
*/generateAnonymousId(){return generateUUID();}/**
|
1426
|
+
*/setAnonymousId(anonymousId,rudderAmpLinkerParam){let finalAnonymousId=anonymousId;if(this.isPersistenceEnabledForStorageEntry('anonymousId')){if(!finalAnonymousId&&rudderAmpLinkerParam){const linkerPluginsResult=this.pluginsManager?.invokeSingle('userSession.anonymousIdGoogleLinker',rudderAmpLinkerParam);finalAnonymousId=linkerPluginsResult;}finalAnonymousId=finalAnonymousId||generateAnonymousId();}else {finalAnonymousId=DEFAULT_USER_SESSION_VALUES.anonymousId;}state.session.anonymousId.value=finalAnonymousId;}/**
|
1408
1427
|
* Fetches anonymousId
|
1409
1428
|
* @param options option to fetch it from external source
|
1410
1429
|
* @returns anonymousId
|
1411
|
-
*/getAnonymousId(options){const storage=state.storage.entries.value.anonymousId?.type
|
1412
|
-
if(isStorageTypeValidForStoringData(storage)){
|
1413
|
-
const autoCapturedAnonymousId=this.pluginsManager?.invokeSingle('storage.getAnonymousId',getStorageEngine,options);persistedAnonymousId=autoCapturedAnonymousId;}state.session.anonymousId.value=persistedAnonymousId||
|
1430
|
+
*/getAnonymousId(options){const storage=state.storage.entries.value.anonymousId?.type;// fetch the anonymousId from storage
|
1431
|
+
if(isStorageTypeValidForStoringData(storage)){let persistedAnonymousId=this.getEntryValue('anonymousId');if(!persistedAnonymousId&&options){// fetch anonymousId from external source
|
1432
|
+
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]);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;}/**
|
1414
1433
|
* Fetches User Id
|
1415
1434
|
* @returns
|
1416
|
-
*/getUserId(){return this.
|
1435
|
+
*/getUserId(){return this.getEntryValue('userId');}/**
|
1417
1436
|
* Fetches User Traits
|
1418
1437
|
* @returns
|
1419
|
-
*/getUserTraits(){return this.
|
1438
|
+
*/getUserTraits(){return this.getEntryValue('userTraits');}/**
|
1420
1439
|
* Fetches Group Id
|
1421
1440
|
* @returns
|
1422
|
-
*/getGroupId(){return this.
|
1441
|
+
*/getGroupId(){return this.getEntryValue('groupId');}/**
|
1423
1442
|
* Fetches Group Traits
|
1424
1443
|
* @returns
|
1425
|
-
*/getGroupTraits(){return this.
|
1444
|
+
*/getGroupTraits(){return this.getEntryValue('groupTraits');}/**
|
1426
1445
|
* Fetches Initial Referrer
|
1427
1446
|
* @returns
|
1428
|
-
*/getInitialReferrer(){return this.
|
1447
|
+
*/getInitialReferrer(){return this.getEntryValue('initialReferrer');}/**
|
1429
1448
|
* Fetches Initial Referring domain
|
1430
1449
|
* @returns
|
1431
|
-
*/getInitialReferringDomain(){return this.
|
1450
|
+
*/getInitialReferringDomain(){return this.getEntryValue('initialReferringDomain');}/**
|
1432
1451
|
* Fetches session tracking information from storage
|
1433
1452
|
* @returns
|
1434
|
-
*/
|
1453
|
+
*/getSessionInfo(){return this.getEntryValue('sessionInfo');}/**
|
1454
|
+
* Fetches auth token from storage
|
1455
|
+
* @returns
|
1456
|
+
*/getAuthToken(){return this.getEntryValue('authToken');}/**
|
1435
1457
|
* If session is active it returns the sessionId
|
1436
1458
|
* @returns
|
1437
|
-
*/getSessionId(){
|
1459
|
+
*/getSessionId(){const sessionInfo=state.session.sessionInfo.value;if(sessionInfo.autoTrack&&!hasSessionExpired(sessionInfo.expiresAt)||sessionInfo.manualTrack){return sessionInfo.id??null;}return null;}/**
|
1438
1460
|
* A function to update current session info after each event call
|
1439
|
-
*/refreshSession(){
|
1461
|
+
*/refreshSession(){let sessionInfo=state.session.sessionInfo.value;if(sessionInfo.autoTrack||sessionInfo.manualTrack){if(sessionInfo.autoTrack){this.startOrRenewAutoTracking();}// Re-assigning the variable with the same value intentionally as
|
1462
|
+
// startOrRenewAutoTracking() will update the sessionInfo value
|
1463
|
+
sessionInfo=state.session.sessionInfo.value;if(sessionInfo.sessionStart===undefined){state.session.sessionInfo.value={...sessionInfo,sessionStart:true};}else if(sessionInfo.sessionStart){state.session.sessionInfo.value={...sessionInfo,sessionStart:false};}}}/**
|
1440
1464
|
* Reset state values
|
1441
1465
|
* @param resetAnonymousId
|
1442
1466
|
* @param noNewSessionStart
|
1443
1467
|
* @returns
|
1444
|
-
*/reset(resetAnonymousId,noNewSessionStart){const{manualTrack,autoTrack}=
|
1468
|
+
*/reset(resetAnonymousId,noNewSessionStart){const{session}=state;const{manualTrack,autoTrack}=session.sessionInfo.value;n(()=>{session.userId.value=DEFAULT_USER_SESSION_VALUES.userId;session.userTraits.value=DEFAULT_USER_SESSION_VALUES.userTraits;session.groupId.value=DEFAULT_USER_SESSION_VALUES.groupId;session.groupTraits.value=DEFAULT_USER_SESSION_VALUES.groupTraits;session.authToken.value=DEFAULT_USER_SESSION_VALUES.authToken;if(resetAnonymousId){// This will generate a new anonymous ID
|
1469
|
+
this.setAnonymousId();}if(noNewSessionStart){return;}if(autoTrack){session.sessionInfo.value=DEFAULT_USER_SESSION_VALUES.sessionInfo;this.startOrRenewAutoTracking();}else if(manualTrack){this.startManualTrackingInternal();}});}setSessionInfo(sessionInfo){state.session.sessionInfo.value=this.isPersistenceEnabledForStorageEntry('sessionInfo')?sessionInfo:DEFAULT_USER_SESSION_VALUES.sessionInfo;// If auto session tracking is enabled start the session tracking
|
1470
|
+
if(state.session.sessionInfo.value.autoTrack){this.startOrRenewAutoTracking();}}/**
|
1445
1471
|
* Set user Id
|
1446
1472
|
* @param userId
|
1447
|
-
*/setUserId(userId){
|
1473
|
+
*/setUserId(userId){state.session.userId.value=this.isPersistenceEnabledForStorageEntry('userId')&&userId?userId:DEFAULT_USER_SESSION_VALUES.userId;}/**
|
1448
1474
|
* Set user traits
|
1449
1475
|
* @param traits
|
1450
|
-
*/setUserTraits(traits){
|
1476
|
+
*/setUserTraits(traits){state.session.userTraits.value=this.isPersistenceEnabledForStorageEntry('userTraits')&&traits?mergeDeepRight(state.session.userTraits.value??{},traits):DEFAULT_USER_SESSION_VALUES.userTraits;}/**
|
1451
1477
|
* Set group Id
|
1452
1478
|
* @param groupId
|
1453
|
-
*/setGroupId(groupId){
|
1479
|
+
*/setGroupId(groupId){state.session.groupId.value=this.isPersistenceEnabledForStorageEntry('groupId')&&groupId?groupId:DEFAULT_USER_SESSION_VALUES.groupId;}/**
|
1454
1480
|
* Set group traits
|
1455
1481
|
* @param traits
|
1456
|
-
*/setGroupTraits(traits){
|
1482
|
+
*/setGroupTraits(traits){state.session.groupTraits.value=this.isPersistenceEnabledForStorageEntry('groupTraits')&&traits?mergeDeepRight(state.session.groupTraits.value??{},traits):DEFAULT_USER_SESSION_VALUES.groupTraits;}/**
|
1457
1483
|
* Set initial referrer
|
1458
1484
|
* @param referrer
|
1459
|
-
*/setInitialReferrer(referrer){
|
1485
|
+
*/setInitialReferrer(referrer){state.session.initialReferrer.value=this.isPersistenceEnabledForStorageEntry('initialReferrer')&&referrer?referrer:DEFAULT_USER_SESSION_VALUES.initialReferrer;}/**
|
1460
1486
|
* Set initial referring domain
|
1461
|
-
* @param
|
1462
|
-
*/setInitialReferringDomain(referringDomain){
|
1463
|
-
* A function to check for existing session details and depending on that create a new session
|
1464
|
-
*/startOrRenewAutoTracking(){
|
1487
|
+
* @param {String} referringDomain
|
1488
|
+
*/setInitialReferringDomain(referringDomain){state.session.initialReferringDomain.value=this.isPersistenceEnabledForStorageEntry('initialReferringDomain')&&referringDomain?referringDomain:DEFAULT_USER_SESSION_VALUES.initialReferringDomain;}/**
|
1489
|
+
* A function to check for existing session details and depending on that create a new session
|
1490
|
+
*/startOrRenewAutoTracking(){const sessionInfo=state.session.sessionInfo.value;if(hasSessionExpired(sessionInfo.expiresAt)){state.session.sessionInfo.value=generateAutoTrackingSession(sessionInfo.timeout);}else {const timestamp=Date.now();const timeout=sessionInfo.timeout;state.session.sessionInfo.value=mergeDeepRight(sessionInfo,{expiresAt:timestamp+timeout// set the expiry time of the session
|
1465
1491
|
});}}/**
|
1466
1492
|
* A function method to start a manual session
|
1467
1493
|
* @param {number} id session identifier
|
@@ -1470,27 +1496,26 @@ const autoCapturedAnonymousId=this.pluginsManager?.invokeSingle('storage.getAnon
|
|
1470
1496
|
* An internal function to start manual session
|
1471
1497
|
*/startManualTrackingInternal(){this.start(Date.now());}/**
|
1472
1498
|
* A public method to end an ongoing session.
|
1473
|
-
*/end(){state.session.sessionInfo.value={};}
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
*/class BufferQueue{constructor(){this.items=[];}enqueue(item){this.items.push(item);}dequeue(){if(this.items.length===0){return null;}return this.items.shift();}isEmpty(){return this.items.length===0;}size(){return this.items.length;}clear(){this.items=[];}}
|
1499
|
+
*/end(){state.session.sessionInfo.value={};}/**
|
1500
|
+
* Set auth token
|
1501
|
+
* @param userId
|
1502
|
+
*/setAuthToken(token){state.session.authToken.value=this.isPersistenceEnabledForStorageEntry('authToken')&&token?token:DEFAULT_USER_SESSION_VALUES.authToken;}}
|
1478
1503
|
|
1479
|
-
const DATA_PLANE_QUEUE_EXT_POINT_PREFIX='dataplaneEventsQueue';const DESTINATIONS_QUEUE_EXT_POINT_PREFIX='destinationsEventsQueue';
|
1504
|
+
const DATA_PLANE_QUEUE_EXT_POINT_PREFIX='dataplaneEventsQueue';const DESTINATIONS_QUEUE_EXT_POINT_PREFIX='destinationsEventsQueue';const DMT_EXT_POINT_PREFIX='transformEvent';
|
1480
1505
|
|
1481
1506
|
/**
|
1482
1507
|
* Filters and returns the user supplied integrations config that should take preference over the destination specific integrations config
|
1483
1508
|
* @param eventIntgConfig User supplied integrations config at event level
|
1484
1509
|
* @param destinationsIntgConfig Cumulative integrations config from all destinations
|
1485
1510
|
* @returns Filtered user supplied integrations config
|
1486
|
-
*/const getOverriddenIntegrationOptions=(eventIntgConfig,destinationsIntgConfig)=>Object.keys(eventIntgConfig).filter(intgName=>eventIntgConfig[intgName]!==true||!destinationsIntgConfig[intgName]).reduce((obj,key)=>{const retVal=clone
|
1511
|
+
*/const getOverriddenIntegrationOptions=(eventIntgConfig,destinationsIntgConfig)=>Object.keys(eventIntgConfig).filter(intgName=>eventIntgConfig[intgName]!==true||!destinationsIntgConfig[intgName]).reduce((obj,key)=>{const retVal=clone(obj);retVal[key]=eventIntgConfig[key];return retVal;},{});/**
|
1487
1512
|
* Returns the event object with final integrations config
|
1488
1513
|
* @param event RudderEvent object
|
1489
1514
|
* @param state Application state
|
1490
1515
|
* @returns Mutated event with final integrations config
|
1491
|
-
*/const getFinalEvent=(event,state)=>{const finalEvent=clone
|
1516
|
+
*/const getFinalEvent=(event,state)=>{const finalEvent=clone(event);// Merge the destination specific integrations config with the event's integrations config
|
1492
1517
|
// In general, the preference is given to the event's integrations config
|
1493
|
-
const eventIntgConfig=event.integrations??DEFAULT_INTEGRATIONS_CONFIG;const destinationsIntgConfig=state.nativeDestinations.integrationsConfig.value;const overriddenIntgOpts=getOverriddenIntegrationOptions(eventIntgConfig,destinationsIntgConfig);finalEvent.integrations=mergeDeepRight(destinationsIntgConfig,overriddenIntgOpts);return finalEvent;};
|
1518
|
+
const eventIntgConfig=event.integrations??DEFAULT_INTEGRATIONS_CONFIG;const destinationsIntgConfig=state.nativeDestinations.integrationsConfig.value;const overriddenIntgOpts=getOverriddenIntegrationOptions(eventIntgConfig,destinationsIntgConfig);finalEvent.integrations=mergeDeepRight(destinationsIntgConfig,overriddenIntgOpts);return finalEvent;};const shouldBufferEventsForPreConsent=state=>state.consents.preConsent.value.enabled&&state.consents.preConsent.value.events?.delivery==='buffer'&&(state.consents.preConsent.value.storage?.strategy==='session'||state.consents.preConsent.value.storage?.strategy==='none');
|
1494
1519
|
|
1495
1520
|
/**
|
1496
1521
|
* Event repository class responsible for queuing events for further processing and delivery
|
@@ -1502,17 +1527,17 @@ const eventIntgConfig=event.integrations??DEFAULT_INTEGRATIONS_CONFIG;const dest
|
|
1502
1527
|
* @param logger Logger object
|
1503
1528
|
*/constructor(pluginsManager,storeManager,errorHandler,logger){this.pluginsManager=pluginsManager;this.errorHandler=errorHandler;this.logger=logger;this.httpClient=new HttpClient(errorHandler,logger);this.storeManager=storeManager;this.onError=this.onError.bind(this);}/**
|
1504
1529
|
* Initializes the event repository
|
1505
|
-
*/init(){this.dataplaneEventsQueue=this.pluginsManager.invokeSingle(`${DATA_PLANE_QUEUE_EXT_POINT_PREFIX}.init`,state,this.httpClient,this.storeManager,this.errorHandler,this.logger);this.destinationsEventsQueue=this.pluginsManager.invokeSingle(`${DESTINATIONS_QUEUE_EXT_POINT_PREFIX}.init`,state,this.pluginsManager,this.storeManager,this.errorHandler,this.logger)
|
1506
|
-
|
1530
|
+
*/init(){try{this.dataplaneEventsQueue=this.pluginsManager.invokeSingle(`${DATA_PLANE_QUEUE_EXT_POINT_PREFIX}.init`,state,this.httpClient,this.storeManager,this.errorHandler,this.logger);}catch(e){this.onError(e,DATAPLANE_PLUGIN_INITIALIZE_ERROR);}try{this.dmtEventsQueue=this.pluginsManager.invokeSingle(`${DMT_EXT_POINT_PREFIX}.init`,state,this.pluginsManager,this.httpClient,this.storeManager,this.errorHandler,this.logger);}catch(e){this.onError(e,DMT_PLUGIN_INITIALIZE_ERROR);}try{this.destinationsEventsQueue=this.pluginsManager.invokeSingle(`${DESTINATIONS_QUEUE_EXT_POINT_PREFIX}.init`,state,this.pluginsManager,this.storeManager,this.dmtEventsQueue,this.errorHandler,this.logger);}catch(e){this.onError(e,NATIVE_DEST_PLUGIN_INITIALIZE_ERROR);}// Start the queue once the client destinations are ready
|
1531
|
+
O(()=>{if(state.nativeDestinations.clientDestinationsReady.value===true){this.destinationsEventsQueue?.start();this.dmtEventsQueue?.start();}});const bufferEventsBeforeConsent=shouldBufferEventsForPreConsent(state);// Start the queue processing only when the destinations are ready or hybrid mode destinations exist
|
1507
1532
|
// However, events will be enqueued for now.
|
1508
1533
|
// At the time of processing the events, the integrations config data from destinations
|
1509
1534
|
// is merged into the event object
|
1510
|
-
let timeoutId;
|
1511
|
-
if(state.loadOptions.value.bufferDataPlaneEventsUntilReady===true){timeoutId=globalThis.setTimeout(()=>{if(this.dataplaneEventsQueue?.scheduleTimeoutActive!==true){this.dataplaneEventsQueue?.start();}},state.loadOptions.value.dataPlaneEventsBufferTimeout);}}/**
|
1535
|
+
let timeoutId;O(()=>{const shouldBufferDpEvents=state.loadOptions.value.bufferDataPlaneEventsUntilReady===true&&state.nativeDestinations.clientDestinationsReady.value===false;const hybridDestExist=state.nativeDestinations.activeDestinations.value.some(dest=>isHybridModeDestination(dest));if((hybridDestExist===false||shouldBufferDpEvents===false)&&!bufferEventsBeforeConsent&&this.dataplaneEventsQueue?.scheduleTimeoutActive!==true){globalThis.clearTimeout(timeoutId);this.dataplaneEventsQueue?.start();}});// Force start the data plane events queue processing after a timeout
|
1536
|
+
if(state.loadOptions.value.bufferDataPlaneEventsUntilReady===true){timeoutId=globalThis.setTimeout(()=>{if(this.dataplaneEventsQueue?.scheduleTimeoutActive!==true){this.dataplaneEventsQueue?.start();}},state.loadOptions.value.dataPlaneEventsBufferTimeout);}}resume(){if(this.dataplaneEventsQueue?.scheduleTimeoutActive!==true){if(state.consents.postConsent.value.discardPreConsentEvents){this.dataplaneEventsQueue?.clear();this.destinationsEventsQueue?.clear();}this.dataplaneEventsQueue?.start();}}/**
|
1512
1537
|
* Enqueues the event for processing
|
1513
1538
|
* @param event RudderEvent object
|
1514
1539
|
* @param callback API callback function
|
1515
|
-
*/enqueue(event,callback){
|
1540
|
+
*/enqueue(event,callback){let dpQEvent;try{dpQEvent=getFinalEvent(event,state);this.pluginsManager.invokeSingle(`${DATA_PLANE_QUEUE_EXT_POINT_PREFIX}.enqueue`,state,this.dataplaneEventsQueue,dpQEvent,this.errorHandler,this.logger);}catch(e){this.onError(e,DATAPLANE_PLUGIN_ENQUEUE_ERROR);}try{const dQEvent=clone(event);this.pluginsManager.invokeSingle(`${DESTINATIONS_QUEUE_EXT_POINT_PREFIX}.enqueue`,state,this.destinationsEventsQueue,dQEvent,this.errorHandler,this.logger);}catch(e){this.onError(e,NATIVE_DEST_PLUGIN_ENQUEUE_ERROR);}// Invoke the callback if it exists
|
1516
1541
|
try{// Using the event sent to the data plane queue here
|
1517
1542
|
// to ensure the mutated (if any) event is sent to the callback
|
1518
1543
|
callback?.(dpQEvent);}catch(error){this.onError(error,API_CALLBACK_INVOKE_ERROR);}}/**
|
@@ -1522,38 +1547,42 @@ callback?.(dpQEvent);}catch(error){this.onError(error,API_CALLBACK_INVOKE_ERROR)
|
|
1522
1547
|
* @param shouldAlwaysThrow if it should throw or use logger
|
1523
1548
|
*/onError(error,customMessage,shouldAlwaysThrow){if(this.errorHandler){this.errorHandler.onError(error,EVENT_REPOSITORY,customMessage,shouldAlwaysThrow);}else {throw error;}}}
|
1524
1549
|
|
1550
|
+
const dispatchSDKEvent=event=>{const customEvent=new CustomEvent(event,{detail:{analyticsInstance:globalThis.rudderanalytics},bubbles:true,cancelable:true,composed:true});globalThis.document.dispatchEvent(customEvent);};
|
1551
|
+
|
1525
1552
|
/*
|
1526
1553
|
* Analytics class with lifecycle based on state ad user triggered events
|
1527
|
-
*/class Analytics{
|
1554
|
+
*/class Analytics{/**
|
1528
1555
|
* Initialize services and components or use default ones if singletons
|
1529
|
-
*/constructor(){this.initialized=false;this.errorHandler=defaultErrorHandler;this.logger=defaultLogger;this.externalSrcLoader=new ExternalSrcLoader(this.errorHandler,this.logger);this.capabilitiesManager=new CapabilitiesManager(this.errorHandler,this.logger);this.httpClient=defaultHttpClient;
|
1556
|
+
*/constructor(){this.preloadBuffer=new BufferQueue();this.initialized=false;this.errorHandler=defaultErrorHandler;this.logger=defaultLogger;this.externalSrcLoader=new ExternalSrcLoader(this.errorHandler,this.logger);this.capabilitiesManager=new CapabilitiesManager(this.errorHandler,this.logger);this.httpClient=defaultHttpClient;}/**
|
1530
1557
|
* Start application lifecycle if not already started
|
1531
|
-
*/load(writeKey,dataPlaneUrl,loadOptions={}){if(state.lifecycle.status.value){return;}let clonedDataPlaneUrl=clone
|
1558
|
+
*/load(writeKey,dataPlaneUrl,loadOptions={}){if(state.lifecycle.status.value){return;}let clonedDataPlaneUrl=clone(dataPlaneUrl);let clonedLoadOptions=clone(loadOptions);// dataPlaneUrl is not provided
|
1532
1559
|
if(isObjectAndNotNull(dataPlaneUrl)){clonedLoadOptions=dataPlaneUrl;clonedDataPlaneUrl=undefined;}// Set initial state values
|
1533
|
-
|
1560
|
+
n(()=>{state.lifecycle.writeKey.value=writeKey;state.lifecycle.dataPlaneUrl.value=clonedDataPlaneUrl;state.loadOptions.value=normalizeLoadOptions(state.loadOptions.value,clonedLoadOptions);state.lifecycle.status.value='mounted';});// set log level as early as possible
|
1561
|
+
if(state.loadOptions.value.logLevel){this.logger?.setMinLogLevel(state.loadOptions.value.logLevel);}// Expose state to global objects
|
1534
1562
|
setExposedGlobal('state',state,writeKey);// Configure initial config of any services or components here
|
1535
1563
|
// State application lifecycle
|
1536
1564
|
this.startLifecycle();}// Start lifecycle methods
|
1537
1565
|
/**
|
1538
1566
|
* Orchestrate the lifecycle of the application phases/status
|
1539
|
-
*/startLifecycle(){
|
1540
|
-
retrievePreloadBufferEvents(this);this.prepareInternalServices();this.loadConfig();
|
1567
|
+
*/startLifecycle(){O(()=>{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
|
1568
|
+
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
|
1569
|
+
if(state.consents.preConsent.value.enabled===true){state.lifecycle.status.value='ready';}else {this.loadDestinations();}}/**
|
1541
1570
|
* Load browser polyfill if required
|
1542
|
-
*/
|
1571
|
+
*/onMounted(){this.capabilitiesManager.init();}/**
|
1543
1572
|
* Enqueue in SDK preload buffer events, used from preloadBuffer component
|
1544
|
-
*/enqueuePreloadBufferEvents(bufferedEvents){if(Array.isArray(bufferedEvents)){bufferedEvents.forEach(bufferedEvent=>this.preloadBuffer.enqueue(clone
|
1573
|
+
*/enqueuePreloadBufferEvents(bufferedEvents){if(Array.isArray(bufferedEvents)){bufferedEvents.forEach(bufferedEvent=>this.preloadBuffer.enqueue(clone(bufferedEvent)));}}/**
|
1545
1574
|
* Process the buffer preloaded events by passing their arguments to the respective facade methods
|
1546
1575
|
*/processDataInPreloadBuffer(){while(this.preloadBuffer.size()>0){const eventToProcess=this.preloadBuffer.dequeue();if(eventToProcess){consumePreloadBufferedEvent([...eventToProcess],this);}}}prepareInternalServices(){this.pluginsManager=new PluginsManager(defaultPluginEngine,this.errorHandler,this.logger);this.storeManager=new StoreManager(this.pluginsManager,this.errorHandler,this.logger);this.configManager=new ConfigManager(this.httpClient,this.errorHandler,this.logger);this.userSessionManager=new UserSessionManager(this.errorHandler,this.logger,this.pluginsManager,this.storeManager);this.eventRepository=new EventRepository(this.pluginsManager,this.storeManager,this.errorHandler,this.logger);this.eventManager=new EventManager(this.eventRepository,this.userSessionManager,this.errorHandler,this.logger);}/**
|
1547
1576
|
* Load configuration
|
1548
|
-
*/loadConfig(){if(
|
1577
|
+
*/loadConfig(){if(state.lifecycle.writeKey.value){this.httpClient.setAuthHeader(state.lifecycle.writeKey.value);}this.configManager?.init();}/**
|
1549
1578
|
* Initialize the storage and event queue
|
1550
|
-
*/
|
1551
|
-
this.storeManager?.init();this.userSessionManager?.init();// Initialize consent manager
|
1552
|
-
if(state.consents.
|
1579
|
+
*/onPluginsReady(){this.errorHandler.init(this.externalSrcLoader);// Initialize storage
|
1580
|
+
this.storeManager?.init();this.userSessionManager?.init();// Initialize the appropriate consent manager plugin
|
1581
|
+
if(state.consents.enabled.value&&!state.consents.initialized.value){this.pluginsManager?.invokeSingle(`consentManager.init`,state,this.logger);if(state.consents.preConsent.value.enabled===false){this.pluginsManager?.invokeSingle(`consentManager.updateConsentsInfo`,state,this.storeManager,this.logger);}}// Initialize event manager
|
1553
1582
|
this.eventManager?.init();// Mark the SDK as initialized
|
1554
|
-
state.lifecycle.status.value=
|
1583
|
+
state.lifecycle.status.value='initialized';}/**
|
1555
1584
|
* Load plugins
|
1556
|
-
*/
|
1585
|
+
*/onConfigured(){this.pluginsManager?.init();// TODO: are we going to enable custom plugins to be passed as load options?
|
1557
1586
|
// registerCustomPlugins(state.loadOptions.value.customPlugins);
|
1558
1587
|
}/**
|
1559
1588
|
* Trigger onLoaded callback if any is provided in config & emit initialised event
|
@@ -1562,42 +1591,53 @@ this.processDataInPreloadBuffer();// TODO: we need to avoid passing the window o
|
|
1562
1591
|
// as this will prevent us from supporting multiple SDK instances in the same page
|
1563
1592
|
// Execute onLoaded callback if provided in load options
|
1564
1593
|
if(isFunction(state.loadOptions.value.onLoaded)){state.loadOptions.value.onLoaded(globalThis.rudderanalytics);}// Set lifecycle state
|
1565
|
-
|
1566
|
-
|
1594
|
+
n(()=>{state.lifecycle.loaded.value=true;state.lifecycle.status.value='loaded';});this.initialized=true;// Emit an event to use as substitute to the onLoaded callback
|
1595
|
+
dispatchSDKEvent('RSA_Initialised');}/**
|
1567
1596
|
* Emit ready event
|
1568
1597
|
*/ // eslint-disable-next-line class-methods-use-this
|
1569
|
-
onReady(){
|
1570
|
-
|
1598
|
+
onReady(){state.lifecycle.status.value='readyExecuted';state.eventBuffer.readyCallbacksArray.value.forEach(callback=>{try{callback();}catch(err){this.errorHandler.onError(err,ANALYTICS_CORE,READY_CALLBACK_INVOKE_ERROR);}});// Emit an event to use as substitute to the ready callback
|
1599
|
+
dispatchSDKEvent('RSA_Ready');}/**
|
1571
1600
|
* Consume preloaded events buffer
|
1572
|
-
*/processBufferedEvents(){//
|
1573
|
-
|
1601
|
+
*/processBufferedEvents(){// This logic has been intentionally implemented without a simple
|
1602
|
+
// for-loop as the individual events that are processed may
|
1603
|
+
// add more events to the buffer (this is needed for the consent API)
|
1604
|
+
let bufferedEvents=state.eventBuffer.toBeProcessedArray.value;while(bufferedEvents.length>0){const bufferedEvent=bufferedEvents.shift();state.eventBuffer.toBeProcessedArray.value=bufferedEvents;if(bufferedEvent){const methodName=bufferedEvent[0];if(isFunction(this[methodName])){// Send additional arg 'true' to indicate that this is a buffered invocation
|
1605
|
+
this[methodName](...bufferedEvent.slice(1),true);}}bufferedEvents=state.eventBuffer.toBeProcessedArray.value;}}/**
|
1574
1606
|
* Load device mode destinations
|
1575
|
-
*/loadDestinations(){// Set in state the desired activeDestinations to inject in DOM
|
1576
|
-
this.pluginsManager?.invokeSingle('nativeDestinations.setActiveDestinations',state,this.pluginsManager,this.errorHandler,this.logger);const totalDestinationsToLoad=state.nativeDestinations.activeDestinations.value.length;if(totalDestinationsToLoad===0){state.lifecycle.status.value=
|
1577
|
-
state.lifecycle.status.value=
|
1578
|
-
|
1579
|
-
*
|
1607
|
+
*/loadDestinations(){if(state.nativeDestinations.clientDestinationsReady.value){return;}// Set in state the desired activeDestinations to inject in DOM
|
1608
|
+
this.pluginsManager?.invokeSingle('nativeDestinations.setActiveDestinations',state,this.pluginsManager,this.errorHandler,this.logger);const totalDestinationsToLoad=state.nativeDestinations.activeDestinations.value.length;if(totalDestinationsToLoad===0){state.lifecycle.status.value='destinationsReady';return;}// Start loading native integration scripts and create instances
|
1609
|
+
state.lifecycle.status.value='destinationsLoading';this.pluginsManager?.invokeSingle('nativeDestinations.load',state,this.externalSrcLoader,this.errorHandler,this.logger);// Progress to next lifecycle phase if all native destinations are initialized or failed
|
1610
|
+
O(()=>{const areAllDestinationsReady=totalDestinationsToLoad===0||state.nativeDestinations.initializedDestinations.value.length+state.nativeDestinations.failedDestinations.value.length===totalDestinationsToLoad;if(areAllDestinationsReady){n(()=>{state.lifecycle.status.value='destinationsReady';state.nativeDestinations.clientDestinationsReady.value=true;});}});}/**
|
1611
|
+
* Move to the ready state
|
1580
1612
|
*/ // eslint-disable-next-line class-methods-use-this
|
1581
|
-
onDestinationsReady(){
|
1613
|
+
onDestinationsReady(){// May be do any destination specific actions here
|
1614
|
+
// Mark the ready status if not already done
|
1615
|
+
if(state.lifecycle.status.value!=='ready'){state.lifecycle.status.value='ready';}}// End lifecycle methods
|
1582
1616
|
// Start consumer exposed methods
|
1583
|
-
ready(callback){const type='ready';
|
1617
|
+
ready(callback,isBufferedInvocation=false){const type='ready';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,callback]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} invocation`);if(!isFunction(callback)){this.logger.error(READY_API_CALLBACK_ERROR(READY_API));return;}/**
|
1584
1618
|
* If destinations are loaded or no integration is available for loading
|
1585
1619
|
* execute the callback immediately else push the callbacks to a queue that
|
1586
1620
|
* will be executed after loading completes
|
1587
|
-
*/if(state.lifecycle.status.value===
|
1588
|
-
// Send automatic ad blocked page event if
|
1621
|
+
*/if(state.lifecycle.status.value==='readyExecuted'){try{callback();}catch(err){this.errorHandler.onError(err,ANALYTICS_CORE,READY_CALLBACK_INVOKE_ERROR);}}else {state.eventBuffer.readyCallbacksArray.value=[...state.eventBuffer.readyCallbacksArray.value,callback];}}page(payload,isBufferedInvocation=false){const type='page';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,payload]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} event`);state.metrics.triggered.value+=1;this.eventManager?.addEvent({type:'page',category:payload.category,name:payload.name,properties:payload.properties,options:payload.options,callback:payload.callback});// TODO: Maybe we should alter the behavior to send the ad-block page event even if the SDK is still loaded. It'll be pushed into the to be processed queue.
|
1622
|
+
// Send automatic ad blocked page event if ad-blockers are detected on the page
|
1589
1623
|
// Check page category to avoid infinite loop
|
1590
|
-
if(state.capabilities.isAdBlocked.value===true&&payload.category!==ADBLOCK_PAGE_CATEGORY){
|
1624
|
+
if(state.capabilities.isAdBlocked.value===true&&payload.category!==ADBLOCK_PAGE_CATEGORY){this.page(pageArgumentsToCallOptions(ADBLOCK_PAGE_CATEGORY,ADBLOCK_PAGE_NAME,{// 'title' is intentionally omitted as it does not make sense
|
1591
1625
|
// in v3 implementation
|
1592
|
-
path:ADBLOCK_PAGE_PATH},
|
1593
|
-
if(!isNull(payload.userId)){this.userSessionManager?.setUserId(payload.userId);}this.userSessionManager?.setUserTraits(payload.traits);this.eventManager?.addEvent({type
|
1594
|
-
if(!isNull(payload.groupId)){this.userSessionManager?.setGroupId(payload.groupId);}this.userSessionManager?.setGroupTraits(payload.traits);this.eventManager?.addEvent({type
|
1595
|
-
if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value.
|
1626
|
+
path:ADBLOCK_PAGE_PATH},state.loadOptions.value.sendAdblockPageOptions));}}track(payload,isBufferedInvocation=false){const type='track';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,payload]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} event`);state.metrics.triggered.value+=1;this.eventManager?.addEvent({type,name:payload.name||undefined,properties:payload.properties,options:payload.options,callback:payload.callback});}identify(payload,isBufferedInvocation=false){const type='identify';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,payload]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} event`);state.metrics.triggered.value+=1;const shouldResetSession=Boolean(payload.userId&&state.session.userId.value&&payload.userId!==state.session.userId.value);if(shouldResetSession){this.reset();}// `null` value indicates that previous user ID needs to be retained
|
1627
|
+
if(!isNull(payload.userId)){this.userSessionManager?.setUserId(payload.userId);}this.userSessionManager?.setUserTraits(payload.traits);this.eventManager?.addEvent({type,userId:payload.userId,traits:payload.traits,options:payload.options,callback:payload.callback});}alias(payload,isBufferedInvocation=false){const type='alias';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,payload]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} event`);state.metrics.triggered.value+=1;const previousId=payload.from??this.userSessionManager?.getUserId()??this.userSessionManager?.getAnonymousId();this.eventManager?.addEvent({type,to:payload.to,from:previousId,options:payload.options,callback:payload.callback});}group(payload,isBufferedInvocation=false){const type='group';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,payload]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} event`);state.metrics.triggered.value+=1;// `null` value indicates that previous group ID needs to be retained
|
1628
|
+
if(!isNull(payload.groupId)){this.userSessionManager?.setGroupId(payload.groupId);}this.userSessionManager?.setGroupTraits(payload.traits);this.eventManager?.addEvent({type,groupId:payload.groupId,traits:payload.traits,options:payload.options,callback:payload.callback});}reset(resetAnonymousId,isBufferedInvocation=false){const type='reset';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,resetAnonymousId]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} invocation, resetAnonymousId: ${resetAnonymousId}`);this.userSessionManager?.reset(resetAnonymousId);}getAnonymousId(options){return this.userSessionManager?.getAnonymousId(options);}setAnonymousId(anonymousId,rudderAmpLinkerParam,isBufferedInvocation=false){const type='setAnonymousId';// Buffering is needed as setting the anonymous ID may require invoking the GoogleLinker plugin
|
1629
|
+
if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,anonymousId,rudderAmpLinkerParam]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} invocation`);this.userSessionManager?.setAnonymousId(anonymousId,rudderAmpLinkerParam);}// eslint-disable-next-line class-methods-use-this
|
1596
1630
|
getUserId(){return state.session.userId.value;}// eslint-disable-next-line class-methods-use-this
|
1597
1631
|
getUserTraits(){return state.session.userTraits.value;}// eslint-disable-next-line class-methods-use-this
|
1598
1632
|
getGroupId(){return state.session.groupId.value;}// eslint-disable-next-line class-methods-use-this
|
1599
|
-
getGroupTraits(){return state.session.groupTraits.value;}startSession(sessionId){const type='startSession';
|
1600
|
-
getSessionId(){const sessionId=this.userSessionManager?.getSessionId();return sessionId??null;}
|
1633
|
+
getGroupTraits(){return state.session.groupTraits.value;}startSession(sessionId,isBufferedInvocation=false){const type='startSession';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,sessionId]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} invocation`);this.userSessionManager?.start(sessionId);}endSession(isBufferedInvocation=false){const type='endSession';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type]];return;}this.errorHandler.leaveBreadcrumb(`New ${type} invocation`);this.userSessionManager?.end();}// eslint-disable-next-line class-methods-use-this
|
1634
|
+
getSessionId(){const sessionId=this.userSessionManager?.getSessionId();return sessionId??null;}consent(options,isBufferedInvocation=false){const type='consent';if(!state.lifecycle.loaded.value){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,[type,options]];return;}this.errorHandler.leaveBreadcrumb(`New consent invocation`);n(()=>{state.consents.preConsent.value={...state.consents.preConsent.value,enabled:false};state.consents.postConsent.value=getValidPostConsentOptions(options);const{initialized,consentsData}=getConsentManagementData(state.consents.postConsent.value.consentManagement,this.logger);state.consents.initialized.value=initialized||state.consents.initialized.value;state.consents.data.value=consentsData;});// Update consents data in state
|
1635
|
+
if(state.consents.enabled.value&&!state.consents.initialized.value){this.pluginsManager?.invokeSingle(`consentManager.updateConsentsInfo`,state,this.storeManager,this.logger);}// Re-init store manager
|
1636
|
+
this.storeManager?.initializeStorageState();// Re-init user session manager
|
1637
|
+
this.userSessionManager?.syncStorageDataToState();// Resume event manager to process the events to destinations
|
1638
|
+
this.eventManager?.resume();this.loadDestinations();this.sendTrackingEvents(isBufferedInvocation);}sendTrackingEvents(isBufferedInvocation){// If isBufferedInvocation is true, then the tracking events will be added to the end of the
|
1639
|
+
// events buffer array so that any other preload events (mainly from query string API) will be processed first.
|
1640
|
+
if(state.consents.postConsent.value.trackConsent){const trackOptions=trackArgumentsToCallOptions(CONSENT_TRACK_EVENT_NAME);if(isBufferedInvocation){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,['track',trackOptions]];}else {this.track(trackOptions);}}if(state.consents.postConsent.value.sendPageEvent){const pageOptions=pageArgumentsToCallOptions();if(isBufferedInvocation){state.eventBuffer.toBeProcessedArray.value=[...state.eventBuffer.toBeProcessedArray.value,['page',pageOptions]];}else {this.page(pageOptions);}}}setAuthToken(token){this.userSessionManager?.setAuthToken(token);}// End consumer exposed methods
|
1601
1641
|
}
|
1602
1642
|
|
1603
1643
|
/*
|
@@ -1609,9 +1649,10 @@ getSessionId(){const sessionId=this.userSessionManager?.getSessionId();return se
|
|
1609
1649
|
constructor(){if(RudderAnalytics.globalSingleton){// START-NO-SONAR-SCAN
|
1610
1650
|
// eslint-disable-next-line no-constructor-return
|
1611
1651
|
return RudderAnalytics.globalSingleton;// END-NO-SONAR-SCAN
|
1612
|
-
}this.setDefaultInstanceKey=this.setDefaultInstanceKey.bind(this);this.getAnalyticsInstance=this.getAnalyticsInstance.bind(this);this.load=this.load.bind(this);this.ready=this.ready.bind(this);this.
|
1613
|
-
this.
|
1614
|
-
this
|
1652
|
+
}defaultErrorHandler.attachErrorListeners();this.setDefaultInstanceKey=this.setDefaultInstanceKey.bind(this);this.getAnalyticsInstance=this.getAnalyticsInstance.bind(this);this.load=this.load.bind(this);this.ready=this.ready.bind(this);this.triggerBufferedLoadEvent=this.triggerBufferedLoadEvent.bind(this);this.page=this.page.bind(this);this.track=this.track.bind(this);this.identify=this.identify.bind(this);this.alias=this.alias.bind(this);this.group=this.group.bind(this);this.reset=this.reset.bind(this);this.getAnonymousId=this.getAnonymousId.bind(this);this.setAnonymousId=this.setAnonymousId.bind(this);this.getUserId=this.getUserId.bind(this);this.getUserTraits=this.getUserTraits.bind(this);this.getGroupId=this.getGroupId.bind(this);this.getGroupTraits=this.getGroupTraits.bind(this);this.startSession=this.startSession.bind(this);this.endSession=this.endSession.bind(this);this.getSessionId=this.getSessionId.bind(this);this.setAuthToken=this.setAuthToken.bind(this);this.consent=this.consent.bind(this);RudderAnalytics.globalSingleton=this;// start loading if a load event was buffered or wait for explicit load call
|
1653
|
+
this.triggerBufferedLoadEvent();// Assign to global "rudderanalytics" object after processing the preload buffer (if any exists)
|
1654
|
+
// for CDN bundling IIFE exports covers this but for npm ESM and CJS bundling has to be done explicitly
|
1655
|
+
globalThis.rudderanalytics=this;}/**
|
1615
1656
|
* Set instance to use if no specific writeKey is provided in methods
|
1616
1657
|
* automatically for the first created instance
|
1617
1658
|
* TODO: to support multiple analytics instances in the near future
|
@@ -1620,13 +1661,14 @@ this.triggerBufferedLoadEvent();}/**
|
|
1620
1661
|
*/getAnalyticsInstance(writeKey){const instanceId=writeKey??this.defaultAnalyticsKey;const analyticsInstanceExists=Boolean(this.analyticsInstances[instanceId]);if(!analyticsInstanceExists){this.analyticsInstances[instanceId]=new Analytics();}return this.analyticsInstances[instanceId];}/**
|
1621
1662
|
* Create new analytics instance and trigger application lifecycle start
|
1622
1663
|
*/load(writeKey,dataPlaneUrl,loadOptions){if(!isString(writeKey)){this.logger.error(WRITE_KEY_NOT_A_STRING_ERROR(RS_APP,writeKey));return;}if(this.analyticsInstances[writeKey]){return;}this.setDefaultInstanceKey(writeKey);this.analyticsInstances[writeKey]=new Analytics();this.getAnalyticsInstance(writeKey).load(writeKey,dataPlaneUrl,loadOptions);}/**
|
1623
|
-
*
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
const loadEvent=getPreloadedLoadEvent(preloadedEventsArray);//
|
1664
|
+
* Trigger load event in buffer queue if exists and stores the
|
1665
|
+
* remaining preloaded events array in global object
|
1666
|
+
*/triggerBufferedLoadEvent(){const preloadedEventsArray=Array.isArray(globalThis.rudderanalytics)?globalThis.rudderanalytics:[];// The array will be mutated in the below method
|
1667
|
+
promotePreloadedConsentEventsToTop(preloadedEventsArray);// Get any load method call that is buffered if any
|
1668
|
+
// BTW, load method is also removed from the array
|
1669
|
+
// So, the Analytics object can directly consume the remaining events
|
1670
|
+
const loadEvent=getPreloadedLoadEvent(preloadedEventsArray);// Set the final preloaded events array in global object
|
1671
|
+
setExposedGlobal(GLOBAL_PRELOAD_BUFFER,clone(preloadedEventsArray));// Process load method if present in the buffered requests
|
1630
1672
|
if(loadEvent.length>0){// Remove the event name from the Buffered Event array and keep only arguments
|
1631
1673
|
loadEvent.shift();// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
1632
1674
|
// @ts-ignore
|
@@ -1642,11 +1684,6 @@ this.load.apply(null,loadEvent);}}/**
|
|
1642
1684
|
* Process alias arguments and forward to page call
|
1643
1685
|
*/alias(to,from,options,callback){this.getAnalyticsInstance().alias(aliasArgumentsToCallOptions(to,from,options,callback));}/**
|
1644
1686
|
* Process group arguments and forward to page call
|
1645
|
-
*/group(groupId,traits,options,callback){if(arguments.length===0){this.logger.error(EMPTY_GROUP_CALL_ERROR(RS_APP));return;}this.getAnalyticsInstance().group(groupArgumentsToCallOptions(groupId,traits,options,callback));}reset(resetAnonymousId){this.getAnalyticsInstance().reset(resetAnonymousId);}getAnonymousId(options){return this.getAnalyticsInstance().getAnonymousId(options);}setAnonymousId(anonymousId,rudderAmpLinkerParam){this.getAnalyticsInstance().setAnonymousId(anonymousId,rudderAmpLinkerParam);}getUserId(){return this.getAnalyticsInstance().getUserId();}getUserTraits(){return this.getAnalyticsInstance().getUserTraits();}getGroupId(){return this.getAnalyticsInstance().getGroupId();}getGroupTraits(){return this.getAnalyticsInstance().getGroupTraits();}startSession(sessionId){return this.getAnalyticsInstance().startSession(sessionId);}endSession(){return this.getAnalyticsInstance().endSession();}getSessionId(){return this.getAnalyticsInstance().getSessionId();}}
|
1687
|
+
*/group(groupId,traits,options,callback){if(arguments.length===0){this.logger.error(EMPTY_GROUP_CALL_ERROR(RS_APP));return;}this.getAnalyticsInstance().group(groupArgumentsToCallOptions(groupId,traits,options,callback));}reset(resetAnonymousId){this.getAnalyticsInstance().reset(resetAnonymousId);}getAnonymousId(options){return this.getAnalyticsInstance().getAnonymousId(options);}setAnonymousId(anonymousId,rudderAmpLinkerParam){this.getAnalyticsInstance().setAnonymousId(anonymousId,rudderAmpLinkerParam);}getUserId(){return this.getAnalyticsInstance().getUserId();}getUserTraits(){return this.getAnalyticsInstance().getUserTraits();}getGroupId(){return this.getAnalyticsInstance().getGroupId();}getGroupTraits(){return this.getAnalyticsInstance().getGroupTraits();}startSession(sessionId){return this.getAnalyticsInstance().startSession(sessionId);}endSession(){return this.getAnalyticsInstance().endSession();}getSessionId(){return this.getAnalyticsInstance().getSessionId();}setAuthToken(token){return this.getAnalyticsInstance().setAuthToken(token);}consent(options){return this.getAnalyticsInstance().consent(options);}}
|
1646
1688
|
|
1647
|
-
exports.CookieSameSite = CookieSameSite;
|
1648
|
-
exports.LogLevel = LogLevel;
|
1649
|
-
exports.PluginName = PluginName;
|
1650
|
-
exports.ResidencyServerRegion = ResidencyServerRegion;
|
1651
1689
|
exports.RudderAnalytics = RudderAnalytics;
|
1652
|
-
exports.UaChTrackLevel = UaChTrackLevel;
|