@rudderstack/analytics-js 3.7.6 → 3.7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/npm/legacy/bundled/cjs/index.cjs +29 -47
- package/dist/npm/legacy/bundled/esm/index.mjs +29 -47
- package/dist/npm/legacy/bundled/umd/index.js +29 -47
- package/dist/npm/legacy/cjs/index.cjs +29 -47
- package/dist/npm/legacy/content-script/cjs/index.cjs +29 -47
- package/dist/npm/legacy/content-script/esm/index.mjs +29 -47
- package/dist/npm/legacy/content-script/umd/index.js +29 -47
- package/dist/npm/legacy/esm/index.mjs +29 -47
- package/dist/npm/legacy/umd/index.js +29 -47
- package/dist/npm/modern/bundled/cjs/index.cjs +29 -47
- package/dist/npm/modern/bundled/esm/index.mjs +29 -47
- package/dist/npm/modern/bundled/umd/index.js +29 -47
- package/dist/npm/modern/cjs/index.cjs +15 -32
- package/dist/npm/modern/content-script/cjs/index.cjs +29 -47
- package/dist/npm/modern/content-script/esm/index.mjs +29 -47
- package/dist/npm/modern/content-script/umd/index.js +29 -47
- package/dist/npm/modern/esm/index.mjs +15 -32
- package/dist/npm/modern/umd/index.js +15 -32
- package/package.json +1 -1
@@ -376,7 +376,7 @@
|
|
376
376
|
|
377
377
|
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';
|
378
378
|
|
379
|
-
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.7.
|
379
|
+
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.7.8';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';
|
380
380
|
|
381
381
|
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';
|
382
382
|
|
@@ -581,35 +581,14 @@
|
|
581
581
|
extensionPointName=extensionPointName.replace(/(^!|!$)/g,'');if(!extensionPointName){throw new Error(PLUGIN_EXT_POINT_INVALID_ERROR);}const extensionPointNameParts=extensionPointName.split('.');extensionPointNameParts.pop();const pluginMethodPath=extensionPointNameParts.join('.');const pluginsToInvoke=allowMultiple?this.getPlugins(extensionPointName):[this.getPlugins(extensionPointName)[0]];return pluginsToInvoke.map(plugin=>{const method=getValueByPath(plugin,extensionPointName);if(!isFunction(method)||noCall){return method;}try{return method.apply(getValueByPath(plugin,pluginMethodPath),args);}catch(err){// When a plugin failed, doesn't break the app
|
582
582
|
if(throws){throw err;}else {this.logger?.error(PLUGIN_INVOCATION_ERROR(PLUGIN_ENGINE,extensionPointName,plugin.name),err);}}return null;});}invokeSingle(extPoint,...args){return this.invoke(extPoint,false,...args)[0];}invokeMultiple(extPoint,...args){return this.invoke(extPoint,true,...args);}}const defaultPluginEngine=new PluginEngine({throws:true},defaultLogger);
|
583
583
|
|
584
|
-
const
|
584
|
+
const LOAD_ORIGIN='RS_JS_SDK';
|
585
585
|
|
586
586
|
/**
|
587
587
|
* Utility method to normalise errors
|
588
588
|
*/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;}else {errorMessage=error.message?error.message:stringifyWithoutCircular(error);}}catch(e){errorMessage=`Unknown error: ${e.message}`;}return errorMessage;};const getNormalizedErrorForUnhandledError=error=>{try{if(error instanceof Error||error instanceof ErrorEvent||error instanceof PromiseRejectionEvent&&error.reason){return error;}// TODO: remove this block once all device mode integrations start using the v3 script loader module (TS)
|
589
|
-
|
590
|
-
//
|
591
|
-
|
592
|
-
// if (eventTarget && eventTarget.localName !== 'script') {
|
593
|
-
// return undefined;
|
594
|
-
// }
|
595
|
-
// // Discard script errors that are not originated at SDK or from native SDKs
|
596
|
-
// if (
|
597
|
-
// eventTarget?.dataset &&
|
598
|
-
// (eventTarget.dataset.loader !== LOAD_ORIGIN ||
|
599
|
-
// eventTarget.dataset.isnonnativesdk !== 'true')
|
600
|
-
// ) {
|
601
|
-
// return undefined;
|
602
|
-
// }
|
603
|
-
// const errorMessage = `Error in loading a third-party script from URL ${eventTarget?.src} with ID ${eventTarget?.id}.`;
|
604
|
-
// return Object.create(error, {
|
605
|
-
// message: { value: errorMessage },
|
606
|
-
// });
|
607
|
-
// }
|
608
|
-
return undefined;}catch(e){return e;}};/**
|
609
|
-
* A function to determine whether the error should be promoted to notify or not
|
610
|
-
* @param {Error} error
|
611
|
-
* @returns
|
612
|
-
*/const isAllowedToBeNotified=error=>{if((error instanceof Error||error instanceof ErrorEvent)&&error.message){return !ERROR_MESSAGES_TO_BE_FILTERED.some(e=>error.message.includes(e));}if(error instanceof PromiseRejectionEvent&&typeof error.reason==='string'){return !ERROR_MESSAGES_TO_BE_FILTERED.some(e=>error.reason.includes(e));}return true;};
|
589
|
+
if(error instanceof Event){const eventTarget=error.target;// Discard all the non-script loading errors
|
590
|
+
if(eventTarget&&eventTarget.localName!=='script'){return undefined;}// Discard script errors that are not originated at SDK or from native SDKs
|
591
|
+
if(eventTarget?.dataset&&(eventTarget.dataset.loader!==LOAD_ORIGIN||eventTarget.dataset.isnonnativesdk!=='true')){return undefined;}const errorMessage=`Error in loading a third-party script from URL ${eventTarget?.src} with ID ${eventTarget?.id}.`;return Object.create(error,{message:{value:errorMessage}});}return error;}catch(e){return e;}};
|
613
592
|
|
614
593
|
/**
|
615
594
|
* A service to handle errors
|
@@ -630,7 +609,7 @@
|
|
630
609
|
* Send handled errors to external error monitoring service via a plugin
|
631
610
|
*
|
632
611
|
* @param {Error} error Error instance from handled error
|
633
|
-
*/notifyError(error,errorState){if(this.pluginEngine&&this.httpClient
|
612
|
+
*/notifyError(error,errorState){if(this.pluginEngine&&this.httpClient){try{this.pluginEngine.invokeSingle('errorReporting.notify',this.pluginEngine,// deprecated parameter
|
634
613
|
this.errReportingClient,// deprecated parameter
|
635
614
|
error,state,this.logger,this.httpClient,errorState);}catch(err){// Not calling onError here as we don't want to go into infinite loop
|
636
615
|
this.logger?.error(NOTIFY_FAILURE_ERROR(ERROR_HANDLER),err);}}}}const defaultErrorHandler=new ErrorHandler(defaultLogger,defaultPluginEngine);
|
@@ -1137,6 +1116,8 @@
|
|
1137
1116
|
|
1138
1117
|
const METRICS_PAYLOAD_VERSION='1';
|
1139
1118
|
|
1119
|
+
const FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';const ERROR_MESSAGES_TO_BE_FILTERED=[FAILED_REQUEST_ERR_MSG_PREFIX];
|
1120
|
+
|
1140
1121
|
// Errors from the below scripts are NOT allowed to reach Bugsnag
|
1141
1122
|
const SDK_FILE_NAME_PREFIXES=()=>['rsa'// Prefix for all the SDK scripts including plugins and module federated chunks
|
1142
1123
|
];const DEV_HOSTS=['www.test-host.com','localhost','127.0.0.1','[::1]'];// List of keys to exclude from the metadata
|
@@ -1144,11 +1125,19 @@
|
|
1144
1125
|
const APP_STATE_EXCLUDE_KEYS=['userId','userTraits','groupId','groupTraits','anonymousId','config','instance',// destination instance objects
|
1145
1126
|
'eventBuffer',// pre-load event buffer (may contain PII)
|
1146
1127
|
'traits'];const REQUEST_TIMEOUT_MS$1=10*1000;// 10 seconds
|
1147
|
-
const NOTIFIER_NAME='RudderStack JavaScript SDK Error Notifier';const SDK_GITHUB_URL='https://github.com/rudderlabs/rudder-sdk-js';const SOURCE_NAME='js';
|
1128
|
+
const NOTIFIER_NAME='RudderStack JavaScript SDK Error Notifier';const SDK_GITHUB_URL='https://github.com/rudderlabs/rudder-sdk-js';const SOURCE_NAME='js';const ERROR_REPORTING_PLUGIN='ErrorReportingPlugin';
|
1148
1129
|
|
1149
1130
|
const getConfigForPayloadCreation=(err,errorType)=>{switch(errorType){case ErrorType.UNHANDLEDEXCEPTION:{const{error}=err;return {component:'unhandledException handler',tolerateNonErrors:true,errorFramesToSkip:1,normalizedError:error||err};}case ErrorType.UNHANDLEDREJECTION:{const error=err;return {component:'unhandledrejection handler',tolerateNonErrors:false,errorFramesToSkip:1,normalizedError:error.reason};}case ErrorType.HANDLEDEXCEPTION:default:return {component:'notify()',tolerateNonErrors:true,errorFramesToSkip:2,normalizedError:err};}};const createNewBreadcrumb=(message,metaData)=>({type:'manual',name:message,timestamp:new Date(),metaData:metaData??{}});const getReleaseStage=()=>{const host=globalThis.location.hostname;return host&&DEV_HOSTS.includes(host)?'development':'production';};const getAppStateForMetadata=state=>{const stateStr=stringifyWithoutCircular(state,false,APP_STATE_EXCLUDE_KEYS);return stateStr!==null?JSON.parse(stateStr):{};};const getURLWithoutQueryString=()=>{const url=globalThis.location.href.split('?');return url[0];};const getErrorContext=event=>{const{message}=event;let context=message;// Hack for easily grouping the script load errors
|
1150
1131
|
// on the dashboard
|
1151
|
-
if(message.includes('Error in loading a third-party script')){context='Script load failures';}return context;};const getBugsnagErrorEvent=(payload,errorState,state)=>({notifier:{name:NOTIFIER_NAME,version:state.context.app.value.version,url:SDK_GITHUB_URL},events:[{payloadVersion:'5',exceptions:clone(payload.errors),severity:errorState.severity,unhandled:errorState.unhandled,severityReason:errorState.severityReason,app:{version:state.context.app.value.version,releaseStage:getReleaseStage()},device:{locale:state.context.locale.value??undefined,userAgent:state.context.userAgent.value??undefined,time:new Date()},request:{url:getURLWithoutQueryString(),clientIp:'[NOT COLLECTED]'},breadcrumbs:clone(state.reporting.breadcrumbs.value),context:getErrorContext(payload.errors[0]),metaData:{sdk:{name:'JS',installType:state.context.app.value.installType},state:getAppStateForMetadata(state)??{},source:{snippetVersion:globalThis.RudderSnippetVersion}},user:{id:state.source.value?.id??state.lifecycle.writeKey.value}}]})
|
1132
|
+
if(message.includes('Error in loading a third-party script')){context='Script load failures';}return context;};const getBugsnagErrorEvent=(payload,errorState,state)=>({notifier:{name:NOTIFIER_NAME,version:state.context.app.value.version,url:SDK_GITHUB_URL},events:[{payloadVersion:'5',exceptions:clone(payload.errors),severity:errorState.severity,unhandled:errorState.unhandled,severityReason:errorState.severityReason,app:{version:state.context.app.value.version,releaseStage:getReleaseStage()},device:{locale:state.context.locale.value??undefined,userAgent:state.context.userAgent.value??undefined,time:new Date()},request:{url:getURLWithoutQueryString(),clientIp:'[NOT COLLECTED]'},breadcrumbs:clone(state.reporting.breadcrumbs.value),context:getErrorContext(payload.errors[0]),metaData:{sdk:{name:'JS',installType:state.context.app.value.installType},state:getAppStateForMetadata(state)??{},source:{snippetVersion:globalThis.RudderSnippetVersion}},user:{id:state.source.value?.id??state.lifecycle.writeKey.value}}]});/**
|
1133
|
+
* A function to determine whether the error should be promoted to notify or not
|
1134
|
+
* @param {Error} error
|
1135
|
+
* @returns
|
1136
|
+
*/const isAllowedToBeNotified=event=>{const errorMessage=event.message;if(errorMessage&&typeof errorMessage==='string'){return !ERROR_MESSAGES_TO_BE_FILTERED.some(e=>errorMessage.includes(e));}return true;};/**
|
1137
|
+
* A function to determine if the error is from Rudder SDK
|
1138
|
+
* @param {Error} event
|
1139
|
+
* @returns
|
1140
|
+
*/const isRudderSDKError=event=>{const errorOrigin=event.stacktrace?.[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return false;}const srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);const paths=errorOrigin.split('/');// extract the parent folder name from the error origin file path
|
1152
1141
|
// Ex: parentFolderName will be 'sample' for url: https://example.com/sample/file.min.js
|
1153
1142
|
const parentFolderName=paths[paths.length-2];return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(prefix=>srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js'));};const getErrorDeliveryPayload=(payload,state)=>{const data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType},errors:payload};return stringifyWithoutCircular(data);};
|
1154
1143
|
|
@@ -1192,19 +1181,10 @@
|
|
1192
1181
|
// This adds one.
|
1193
1182
|
if(f.lineNumber>-1&&!f.file&&!f.method){f.file='global code';}return f;};const ensureString=str=>typeof str==='string'?str:'';function createBugsnagError(errorClass,errorMessage,stacktrace){return {errorClass:ensureString(errorClass),message:ensureString(errorMessage),type:'browserjs',stacktrace:stacktrace.reduce((accum,frame)=>{const f=formatStackframe(frame);// don't include a stackframe if none of its properties are defined
|
1194
1183
|
try{if(JSON.stringify(f)==='{}')return accum;return accum.concat(f);}catch(e){return accum;}},[])};}// Helpers
|
1195
|
-
const getStacktrace=(error,errorFramesToSkip)=>{if(hasStack(error))return ErrorStackParser.parse(error).slice(errorFramesToSkip);return [];};const hasNecessaryFields=error=>(typeof error.name==='string'||typeof error.errorClass==='string')&&(typeof error.message==='string'||typeof error.errorMessage==='string');const normaliseError=(maybeError,
|
1196
|
-
//
|
1197
|
-
// - the promise rejection handler (both in the browser and node)
|
1198
|
-
// - the node uncaughtException handler
|
1199
|
-
//
|
1200
|
-
// We are really limited in what we can do to get a stacktrace. So we use the
|
1201
|
-
// tolerateNonErrors option to ensure that the resulting error communicates as
|
1202
|
-
// such.
|
1203
|
-
if(!tolerateNonErrors){if(isError(maybeError)){error=maybeError;}else {error=createAndLogInputError(typeof maybeError);internalFrames+=2;}}else {switch(typeof maybeError){case'string':case'number':case'boolean':error=new Error(String(maybeError));internalFrames+=1;break;case'function':error=createAndLogInputError('function');internalFrames+=2;break;case'object':if(maybeError!==null&&isError(maybeError)){error=maybeError;}else if(maybeError!==null&&hasNecessaryFields(maybeError)){error=new Error(maybeError.message||maybeError.errorMessage);error.name=maybeError.name||maybeError.errorClass;internalFrames+=1;}else {error=createAndLogInputError(maybeError===null?'null':'unsupported object');internalFrames+=2;}break;default:error=createAndLogInputError('nothing');internalFrames+=2;}}if(!hasStack(error)){// in IE10/11 a new Error() doesn't have a stacktrace until you throw it, so try that here
|
1184
|
+
const getStacktrace=(error,errorFramesToSkip)=>{if(hasStack(error))return ErrorStackParser.parse(error).slice(errorFramesToSkip);return [];};const hasNecessaryFields=error=>(typeof error.name==='string'||typeof error.errorClass==='string')&&(typeof error.message==='string'||typeof error.errorMessage==='string');const normaliseError=(maybeError,component,logger)=>{let error;let internalFrames=0;if(isError(maybeError)){error=maybeError;}else if(typeof maybeError==='object'&&hasNecessaryFields(maybeError)){error=new Error(maybeError.message||maybeError.errorMessage);error.name=maybeError.name||maybeError.errorClass;internalFrames+=1;}else {logger?.warn(`${ERROR_REPORTING_PLUGIN}:: ${component} received a non-error: ${stringifyWithoutCircular(error)}`);error=undefined;}if(error&&!hasStack(error)){// in IE10/11 a new Error() doesn't have a stacktrace until you throw it, so try that here
|
1204
1185
|
try{throw error;}catch(e){if(hasStack(e)){error=e;// if the error only got a stacktrace after we threw it here, we know it
|
1205
|
-
// will only have one extra internal frame from this function
|
1206
|
-
|
1207
|
-
internalFrames=1;}}}return [error,internalFrames];};class ErrorFormat{constructor(errorClass,errorMessage,stacktrace){this.errors=[createBugsnagError(errorClass,errorMessage,stacktrace)];}static create(maybeError,tolerateNonErrors,handledState,component,errorFramesToSkip=0,logger){const[error,internalFrames]=normaliseError(maybeError,tolerateNonErrors,component,logger);let event;try{const stacktrace=getStacktrace(error,// if an error was created/throw in the normaliseError() function, we need to
|
1186
|
+
// will only have one extra internal frame from this function
|
1187
|
+
internalFrames=1;}}}return [error,internalFrames];};class ErrorFormat{constructor(errorClass,errorMessage,stacktrace){this.errors=[createBugsnagError(errorClass,errorMessage,stacktrace)];}static create(maybeError,tolerateNonErrors,handledState,component,errorFramesToSkip=0,logger){const[error,internalFrames]=normaliseError(maybeError,component,logger);if(!error){return undefined;}let event;try{const stacktrace=getStacktrace(error,// if an error was created/throw in the normaliseError() function, we need to
|
1208
1188
|
// tell the getStacktrace() function to skip the number of frames we know will
|
1209
1189
|
// be from our own functions. This is added to the number of frames deep we
|
1210
1190
|
// were told about
|
@@ -1215,7 +1195,7 @@
|
|
1215
1195
|
const pluginName$9='ErrorReporting';const ErrorReporting=()=>({name:pluginName$9,deps:[],initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$9];state.reporting.isErrorReportingPluginLoaded.value=true;if(state.reporting.breadcrumbs?.value){state.reporting.breadcrumbs.value=[createNewBreadcrumb('Error Reporting Plugin Loaded')];}},errorReporting:{// This extension point is deprecated
|
1216
1196
|
// TODO: Remove this in the next major release
|
1217
1197
|
init:(state,pluginEngine,externalSrcLoader,logger,isInvokedFromLatestCore)=>{if(isInvokedFromLatestCore){return undefined;}if(!state.source.value?.config||!state.source.value?.id){return Promise.reject(new Error(INVALID_SOURCE_CONFIG_ERROR));}return pluginEngine.invokeSingle('errorReportingProvider.init',state,externalSrcLoader,logger);},notify:(pluginEngine,client,error,state,logger,httpClient,errorState)=>{if(httpClient){const{component,tolerateNonErrors,errorFramesToSkip,normalizedError}=getConfigForPayloadCreation(error,errorState?.severityReason.type);// Generate the error payload
|
1218
|
-
const errorPayload=ErrorFormat.create(normalizedError,tolerateNonErrors,errorState,component,errorFramesToSkip,logger)
|
1198
|
+
const errorPayload=ErrorFormat.create(normalizedError,tolerateNonErrors,errorState,component,errorFramesToSkip,logger);if(!errorPayload||!isAllowedToBeNotified(errorPayload.errors[0])){return;}// filter errors
|
1219
1199
|
if(!isRudderSDKError(errorPayload.errors[0])){return;}// enrich error payload
|
1220
1200
|
const bugsnagPayload=getBugsnagErrorEvent(errorPayload,errorState,state);// send it to metrics service
|
1221
1201
|
httpClient?.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state),sendRawData:true},isRawResponse:true,timeout:REQUEST_TIMEOUT_MS$1,callback:(result,details)=>{// do nothing
|
@@ -2734,9 +2714,14 @@
|
|
2734
2714
|
*/const getUrlWithoutHash=url=>{let urlWithoutHash=url;try{const urlObj=new URL(url);urlWithoutHash=urlObj.origin+urlObj.pathname+urlObj.search;}catch(error){// Do nothing
|
2735
2715
|
}return urlWithoutHash;};
|
2736
2716
|
|
2717
|
+
/**
|
2718
|
+
* Determines if the SDK is running inside a chrome extension
|
2719
|
+
* @returns boolean
|
2720
|
+
*/const isSDKRunningInChromeExtension=()=>!!(window.chrome&&window.chrome.runtime&&window.chrome.runtime.id);
|
2721
|
+
|
2737
2722
|
const DEFAULT_PRE_CONSENT_STORAGE_STRATEGY='none';const DEFAULT_PRE_CONSENT_EVENTS_DELIVERY_TYPE='immediate';
|
2738
2723
|
|
2739
|
-
const isMetricsReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.metrics?.enabled===true;
|
2724
|
+
const isErrorReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.errors?.enabled===true;const isMetricsReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.metrics?.enabled===true;
|
2740
2725
|
|
2741
2726
|
/**
|
2742
2727
|
* Validates and normalizes the consent options provided by the user
|
@@ -2770,10 +2755,7 @@
|
|
2770
2755
|
* Updates the reporting state variables from the source config data
|
2771
2756
|
* @param res Source config
|
2772
2757
|
* @param logger Logger instance
|
2773
|
-
*/const updateReportingState=res=>{state.reporting.isErrorReportingEnabled.value=
|
2774
|
-
// state.reporting.isErrorReportingEnabled.value =
|
2775
|
-
// isErrorReportingEnabled(res.source.config) && !isSDKRunningInChromeExtension();
|
2776
|
-
state.reporting.isMetricsReportingEnabled.value=isMetricsReportingEnabled(res.source.config);};const updateStorageStateFromLoadOptions=logger=>{const{useServerSideCookies,dataServiceEndpoint,storage:storageOptsFromLoad,setCookieDomain,sameDomainCookiesOnly}=state.loadOptions.value;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
|
2758
|
+
*/const updateReportingState=res=>{state.reporting.isErrorReportingEnabled.value=isErrorReportingEnabled(res.source.config)&&!isSDKRunningInChromeExtension();state.reporting.isMetricsReportingEnabled.value=isMetricsReportingEnabled(res.source.config);};const updateStorageStateFromLoadOptions=logger=>{const{useServerSideCookies,dataServiceEndpoint,storage:storageOptsFromLoad,setCookieDomain,sameDomainCookiesOnly}=state.loadOptions.value;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
|
2777
2759
|
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
|
2778
2760
|
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));}r(()=>{state.storage.type.value=storageType;let cookieOptions=storageOptsFromLoad?.cookie??{};if(useServerSideCookies){state.serverCookies.isEnabledServerSideCookies.value=useServerSideCookies;const providedCookieDomain=cookieOptions.domain??setCookieDomain;/**
|
2779
2761
|
* Based on the following conditions, we decide whether to use the exact domain or not to determine the data service URL:
|
@@ -365,7 +365,7 @@ payload.groupId=tryStringify(payload.groupId);if(isObjectLiteralAndNotNull(paylo
|
|
365
365
|
|
366
366
|
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';
|
367
367
|
|
368
|
-
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.7.
|
368
|
+
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.7.8';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';
|
369
369
|
|
370
370
|
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';
|
371
371
|
|
@@ -570,35 +570,14 @@ processRawPlugins(callback){callback(this.plugins);this.cache={};}invoke(extPoin
|
|
570
570
|
extensionPointName=extensionPointName.replace(/(^!|!$)/g,'');if(!extensionPointName){throw new Error(PLUGIN_EXT_POINT_INVALID_ERROR);}const extensionPointNameParts=extensionPointName.split('.');extensionPointNameParts.pop();const pluginMethodPath=extensionPointNameParts.join('.');const pluginsToInvoke=allowMultiple?this.getPlugins(extensionPointName):[this.getPlugins(extensionPointName)[0]];return pluginsToInvoke.map(plugin=>{const method=getValueByPath(plugin,extensionPointName);if(!isFunction(method)||noCall){return method;}try{return method.apply(getValueByPath(plugin,pluginMethodPath),args);}catch(err){// When a plugin failed, doesn't break the app
|
571
571
|
if(throws){throw err;}else {this.logger?.error(PLUGIN_INVOCATION_ERROR(PLUGIN_ENGINE,extensionPointName,plugin.name),err);}}return null;});}invokeSingle(extPoint,...args){return this.invoke(extPoint,false,...args)[0];}invokeMultiple(extPoint,...args){return this.invoke(extPoint,true,...args);}}const defaultPluginEngine=new PluginEngine({throws:true},defaultLogger);
|
572
572
|
|
573
|
-
const
|
573
|
+
const LOAD_ORIGIN='RS_JS_SDK';
|
574
574
|
|
575
575
|
/**
|
576
576
|
* Utility method to normalise errors
|
577
577
|
*/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;}else {errorMessage=error.message?error.message:stringifyWithoutCircular(error);}}catch(e){errorMessage=`Unknown error: ${e.message}`;}return errorMessage;};const getNormalizedErrorForUnhandledError=error=>{try{if(error instanceof Error||error instanceof ErrorEvent||error instanceof PromiseRejectionEvent&&error.reason){return error;}// TODO: remove this block once all device mode integrations start using the v3 script loader module (TS)
|
578
|
-
|
579
|
-
//
|
580
|
-
|
581
|
-
// if (eventTarget && eventTarget.localName !== 'script') {
|
582
|
-
// return undefined;
|
583
|
-
// }
|
584
|
-
// // Discard script errors that are not originated at SDK or from native SDKs
|
585
|
-
// if (
|
586
|
-
// eventTarget?.dataset &&
|
587
|
-
// (eventTarget.dataset.loader !== LOAD_ORIGIN ||
|
588
|
-
// eventTarget.dataset.isnonnativesdk !== 'true')
|
589
|
-
// ) {
|
590
|
-
// return undefined;
|
591
|
-
// }
|
592
|
-
// const errorMessage = `Error in loading a third-party script from URL ${eventTarget?.src} with ID ${eventTarget?.id}.`;
|
593
|
-
// return Object.create(error, {
|
594
|
-
// message: { value: errorMessage },
|
595
|
-
// });
|
596
|
-
// }
|
597
|
-
return undefined;}catch(e){return e;}};/**
|
598
|
-
* A function to determine whether the error should be promoted to notify or not
|
599
|
-
* @param {Error} error
|
600
|
-
* @returns
|
601
|
-
*/const isAllowedToBeNotified=error=>{if((error instanceof Error||error instanceof ErrorEvent)&&error.message){return !ERROR_MESSAGES_TO_BE_FILTERED.some(e=>error.message.includes(e));}if(error instanceof PromiseRejectionEvent&&typeof error.reason==='string'){return !ERROR_MESSAGES_TO_BE_FILTERED.some(e=>error.reason.includes(e));}return true;};
|
578
|
+
if(error instanceof Event){const eventTarget=error.target;// Discard all the non-script loading errors
|
579
|
+
if(eventTarget&&eventTarget.localName!=='script'){return undefined;}// Discard script errors that are not originated at SDK or from native SDKs
|
580
|
+
if(eventTarget?.dataset&&(eventTarget.dataset.loader!==LOAD_ORIGIN||eventTarget.dataset.isnonnativesdk!=='true')){return undefined;}const errorMessage=`Error in loading a third-party script from URL ${eventTarget?.src} with ID ${eventTarget?.id}.`;return Object.create(error,{message:{value:errorMessage}});}return error;}catch(e){return e;}};
|
602
581
|
|
603
582
|
/**
|
604
583
|
* A service to handle errors
|
@@ -619,7 +598,7 @@ breadcrumb,this.logger,state);}catch(err){this.onError(err,ERROR_HANDLER,'errorR
|
|
619
598
|
* Send handled errors to external error monitoring service via a plugin
|
620
599
|
*
|
621
600
|
* @param {Error} error Error instance from handled error
|
622
|
-
*/notifyError(error,errorState){if(this.pluginEngine&&this.httpClient
|
601
|
+
*/notifyError(error,errorState){if(this.pluginEngine&&this.httpClient){try{this.pluginEngine.invokeSingle('errorReporting.notify',this.pluginEngine,// deprecated parameter
|
623
602
|
this.errReportingClient,// deprecated parameter
|
624
603
|
error,state,this.logger,this.httpClient,errorState);}catch(err){// Not calling onError here as we don't want to go into infinite loop
|
625
604
|
this.logger?.error(NOTIFY_FAILURE_ERROR(ERROR_HANDLER),err);}}}}const defaultErrorHandler=new ErrorHandler(defaultLogger,defaultPluginEngine);
|
@@ -786,6 +765,8 @@ unregisterLocalPlugins(){Object.values(pluginsInventory).forEach(localPlugin=>{t
|
|
786
765
|
* Utility to parse XHR JSON response
|
787
766
|
*/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;};
|
788
767
|
|
768
|
+
const FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';
|
769
|
+
|
789
770
|
const DEFAULT_XHR_REQUEST_OPTIONS={headers:{Accept:'application/json','Content-Type':'application/json;charset=UTF-8'},method:'GET'};/**
|
790
771
|
* Utility to create request configuration based on default options
|
791
772
|
*/const createXhrRequestOptions=(url,options,basicAuthHeader)=>{const requestOptions=mergeDeepRight(DEFAULT_XHR_REQUEST_OPTIONS,options||{});if(basicAuthHeader){requestOptions.headers=mergeDeepRight(requestOptions.headers,{Authorization:basicAuthHeader});}requestOptions.url=url;return requestOptions;};/**
|
@@ -1057,9 +1038,14 @@ if(utmParam==='campaign'){utmParam='name';}result[utmParam]=value;}});}catch(err
|
|
1057
1038
|
*/const getUrlWithoutHash=url=>{let urlWithoutHash=url;try{const urlObj=new URL(url);urlWithoutHash=urlObj.origin+urlObj.pathname+urlObj.search;}catch(error){// Do nothing
|
1058
1039
|
}return urlWithoutHash;};
|
1059
1040
|
|
1041
|
+
/**
|
1042
|
+
* Determines if the SDK is running inside a chrome extension
|
1043
|
+
* @returns boolean
|
1044
|
+
*/const isSDKRunningInChromeExtension=()=>!!(window.chrome&&window.chrome.runtime&&window.chrome.runtime.id);
|
1045
|
+
|
1060
1046
|
const DEFAULT_PRE_CONSENT_STORAGE_STRATEGY='none';const DEFAULT_PRE_CONSENT_EVENTS_DELIVERY_TYPE='immediate';
|
1061
1047
|
|
1062
|
-
const isMetricsReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.metrics?.enabled===true;
|
1048
|
+
const isErrorReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.errors?.enabled===true;const isMetricsReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.metrics?.enabled===true;
|
1063
1049
|
|
1064
1050
|
const DEFAULT_INTEGRATIONS_CONFIG={All:true};
|
1065
1051
|
|
@@ -1095,10 +1081,7 @@ for(const script of scripts){const src=script.getAttribute('src');if(src&&sdkFil
|
|
1095
1081
|
* Updates the reporting state variables from the source config data
|
1096
1082
|
* @param res Source config
|
1097
1083
|
* @param logger Logger instance
|
1098
|
-
*/const updateReportingState=res=>{state.reporting.isErrorReportingEnabled.value=
|
1099
|
-
// state.reporting.isErrorReportingEnabled.value =
|
1100
|
-
// isErrorReportingEnabled(res.source.config) && !isSDKRunningInChromeExtension();
|
1101
|
-
state.reporting.isMetricsReportingEnabled.value=isMetricsReportingEnabled(res.source.config);};const updateStorageStateFromLoadOptions=logger=>{const{useServerSideCookies,dataServiceEndpoint,storage:storageOptsFromLoad,setCookieDomain,sameDomainCookiesOnly}=state.loadOptions.value;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
|
1084
|
+
*/const updateReportingState=res=>{state.reporting.isErrorReportingEnabled.value=isErrorReportingEnabled(res.source.config)&&!isSDKRunningInChromeExtension();state.reporting.isMetricsReportingEnabled.value=isMetricsReportingEnabled(res.source.config);};const updateStorageStateFromLoadOptions=logger=>{const{useServerSideCookies,dataServiceEndpoint,storage:storageOptsFromLoad,setCookieDomain,sameDomainCookiesOnly}=state.loadOptions.value;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
|
1102
1085
|
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
|
1103
1086
|
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));}r(()=>{state.storage.type.value=storageType;let cookieOptions=storageOptsFromLoad?.cookie??{};if(useServerSideCookies){state.serverCookies.isEnabledServerSideCookies.value=useServerSideCookies;const providedCookieDomain=cookieOptions.domain??setCookieDomain;/**
|
1104
1087
|
* Based on the following conditions, we decide whether to use the exact domain or not to determine the data service URL:
|
@@ -374,7 +374,7 @@ payload.groupId=tryStringify(payload.groupId);if(isObjectLiteralAndNotNull(paylo
|
|
374
374
|
|
375
375
|
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';
|
376
376
|
|
377
|
-
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.7.
|
377
|
+
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.7.8';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';
|
378
378
|
|
379
379
|
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';
|
380
380
|
|
@@ -579,35 +579,14 @@ processRawPlugins(callback){callback(this.plugins);this.cache={};}invoke(extPoin
|
|
579
579
|
extensionPointName=extensionPointName.replace(/(^!|!$)/g,'');if(!extensionPointName){throw new Error(PLUGIN_EXT_POINT_INVALID_ERROR);}const extensionPointNameParts=extensionPointName.split('.');extensionPointNameParts.pop();const pluginMethodPath=extensionPointNameParts.join('.');const pluginsToInvoke=allowMultiple?this.getPlugins(extensionPointName):[this.getPlugins(extensionPointName)[0]];return pluginsToInvoke.map(plugin=>{const method=getValueByPath(plugin,extensionPointName);if(!isFunction(method)||noCall){return method;}try{return method.apply(getValueByPath(plugin,pluginMethodPath),args);}catch(err){// When a plugin failed, doesn't break the app
|
580
580
|
if(throws){throw err;}else {this.logger?.error(PLUGIN_INVOCATION_ERROR(PLUGIN_ENGINE,extensionPointName,plugin.name),err);}}return null;});}invokeSingle(extPoint,...args){return this.invoke(extPoint,false,...args)[0];}invokeMultiple(extPoint,...args){return this.invoke(extPoint,true,...args);}}const defaultPluginEngine=new PluginEngine({throws:true},defaultLogger);
|
581
581
|
|
582
|
-
const
|
582
|
+
const LOAD_ORIGIN='RS_JS_SDK';
|
583
583
|
|
584
584
|
/**
|
585
585
|
* Utility method to normalise errors
|
586
586
|
*/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;}else {errorMessage=error.message?error.message:stringifyWithoutCircular(error);}}catch(e){errorMessage=`Unknown error: ${e.message}`;}return errorMessage;};const getNormalizedErrorForUnhandledError=error=>{try{if(error instanceof Error||error instanceof ErrorEvent||error instanceof PromiseRejectionEvent&&error.reason){return error;}// TODO: remove this block once all device mode integrations start using the v3 script loader module (TS)
|
587
|
-
|
588
|
-
//
|
589
|
-
|
590
|
-
// if (eventTarget && eventTarget.localName !== 'script') {
|
591
|
-
// return undefined;
|
592
|
-
// }
|
593
|
-
// // Discard script errors that are not originated at SDK or from native SDKs
|
594
|
-
// if (
|
595
|
-
// eventTarget?.dataset &&
|
596
|
-
// (eventTarget.dataset.loader !== LOAD_ORIGIN ||
|
597
|
-
// eventTarget.dataset.isnonnativesdk !== 'true')
|
598
|
-
// ) {
|
599
|
-
// return undefined;
|
600
|
-
// }
|
601
|
-
// const errorMessage = `Error in loading a third-party script from URL ${eventTarget?.src} with ID ${eventTarget?.id}.`;
|
602
|
-
// return Object.create(error, {
|
603
|
-
// message: { value: errorMessage },
|
604
|
-
// });
|
605
|
-
// }
|
606
|
-
return undefined;}catch(e){return e;}};/**
|
607
|
-
* A function to determine whether the error should be promoted to notify or not
|
608
|
-
* @param {Error} error
|
609
|
-
* @returns
|
610
|
-
*/const isAllowedToBeNotified=error=>{if((error instanceof Error||error instanceof ErrorEvent)&&error.message){return !ERROR_MESSAGES_TO_BE_FILTERED.some(e=>error.message.includes(e));}if(error instanceof PromiseRejectionEvent&&typeof error.reason==='string'){return !ERROR_MESSAGES_TO_BE_FILTERED.some(e=>error.reason.includes(e));}return true;};
|
587
|
+
if(error instanceof Event){const eventTarget=error.target;// Discard all the non-script loading errors
|
588
|
+
if(eventTarget&&eventTarget.localName!=='script'){return undefined;}// Discard script errors that are not originated at SDK or from native SDKs
|
589
|
+
if(eventTarget?.dataset&&(eventTarget.dataset.loader!==LOAD_ORIGIN||eventTarget.dataset.isnonnativesdk!=='true')){return undefined;}const errorMessage=`Error in loading a third-party script from URL ${eventTarget?.src} with ID ${eventTarget?.id}.`;return Object.create(error,{message:{value:errorMessage}});}return error;}catch(e){return e;}};
|
611
590
|
|
612
591
|
/**
|
613
592
|
* A service to handle errors
|
@@ -628,7 +607,7 @@ breadcrumb,this.logger,state);}catch(err){this.onError(err,ERROR_HANDLER,'errorR
|
|
628
607
|
* Send handled errors to external error monitoring service via a plugin
|
629
608
|
*
|
630
609
|
* @param {Error} error Error instance from handled error
|
631
|
-
*/notifyError(error,errorState){if(this.pluginEngine&&this.httpClient
|
610
|
+
*/notifyError(error,errorState){if(this.pluginEngine&&this.httpClient){try{this.pluginEngine.invokeSingle('errorReporting.notify',this.pluginEngine,// deprecated parameter
|
632
611
|
this.errReportingClient,// deprecated parameter
|
633
612
|
error,state,this.logger,this.httpClient,errorState);}catch(err){// Not calling onError here as we don't want to go into infinite loop
|
634
613
|
this.logger?.error(NOTIFY_FAILURE_ERROR(ERROR_HANDLER),err);}}}}const defaultErrorHandler=new ErrorHandler(defaultLogger,defaultPluginEngine);
|
@@ -1109,6 +1088,8 @@ const queueErrResp=isErrRetryable(details)?details:null;if(!queueErrResp||attemp
|
|
1109
1088
|
|
1110
1089
|
const METRICS_PAYLOAD_VERSION='1';
|
1111
1090
|
|
1091
|
+
const FAILED_REQUEST_ERR_MSG_PREFIX='The request failed';const ERROR_MESSAGES_TO_BE_FILTERED=[FAILED_REQUEST_ERR_MSG_PREFIX];
|
1092
|
+
|
1112
1093
|
// Errors from the below scripts are NOT allowed to reach Bugsnag
|
1113
1094
|
const SDK_FILE_NAME_PREFIXES=()=>['rsa'// Prefix for all the SDK scripts including plugins and module federated chunks
|
1114
1095
|
];const DEV_HOSTS=['www.test-host.com','localhost','127.0.0.1','[::1]'];// List of keys to exclude from the metadata
|
@@ -1116,11 +1097,19 @@ const SDK_FILE_NAME_PREFIXES=()=>['rsa'// Prefix for all the SDK scripts includi
|
|
1116
1097
|
const APP_STATE_EXCLUDE_KEYS=['userId','userTraits','groupId','groupTraits','anonymousId','config','instance',// destination instance objects
|
1117
1098
|
'eventBuffer',// pre-load event buffer (may contain PII)
|
1118
1099
|
'traits'];const REQUEST_TIMEOUT_MS$1=10*1000;// 10 seconds
|
1119
|
-
const NOTIFIER_NAME='RudderStack JavaScript SDK Error Notifier';const SDK_GITHUB_URL='https://github.com/rudderlabs/rudder-sdk-js';const SOURCE_NAME='js';
|
1100
|
+
const NOTIFIER_NAME='RudderStack JavaScript SDK Error Notifier';const SDK_GITHUB_URL='https://github.com/rudderlabs/rudder-sdk-js';const SOURCE_NAME='js';const ERROR_REPORTING_PLUGIN='ErrorReportingPlugin';
|
1120
1101
|
|
1121
1102
|
const getConfigForPayloadCreation=(err,errorType)=>{switch(errorType){case ErrorType.UNHANDLEDEXCEPTION:{const{error}=err;return {component:'unhandledException handler',tolerateNonErrors:true,errorFramesToSkip:1,normalizedError:error||err};}case ErrorType.UNHANDLEDREJECTION:{const error=err;return {component:'unhandledrejection handler',tolerateNonErrors:false,errorFramesToSkip:1,normalizedError:error.reason};}case ErrorType.HANDLEDEXCEPTION:default:return {component:'notify()',tolerateNonErrors:true,errorFramesToSkip:2,normalizedError:err};}};const createNewBreadcrumb=(message,metaData)=>({type:'manual',name:message,timestamp:new Date(),metaData:metaData??{}});const getReleaseStage=()=>{const host=globalThis.location.hostname;return host&&DEV_HOSTS.includes(host)?'development':'production';};const getAppStateForMetadata=state=>{const stateStr=stringifyWithoutCircular(state,false,APP_STATE_EXCLUDE_KEYS);return stateStr!==null?JSON.parse(stateStr):{};};const getURLWithoutQueryString=()=>{const url=globalThis.location.href.split('?');return url[0];};const getErrorContext=event=>{const{message}=event;let context=message;// Hack for easily grouping the script load errors
|
1122
1103
|
// on the dashboard
|
1123
|
-
if(message.includes('Error in loading a third-party script')){context='Script load failures';}return context;};const getBugsnagErrorEvent=(payload,errorState,state)=>({notifier:{name:NOTIFIER_NAME,version:state.context.app.value.version,url:SDK_GITHUB_URL},events:[{payloadVersion:'5',exceptions:clone(payload.errors),severity:errorState.severity,unhandled:errorState.unhandled,severityReason:errorState.severityReason,app:{version:state.context.app.value.version,releaseStage:getReleaseStage()},device:{locale:state.context.locale.value??undefined,userAgent:state.context.userAgent.value??undefined,time:new Date()},request:{url:getURLWithoutQueryString(),clientIp:'[NOT COLLECTED]'},breadcrumbs:clone(state.reporting.breadcrumbs.value),context:getErrorContext(payload.errors[0]),metaData:{sdk:{name:'JS',installType:state.context.app.value.installType},state:getAppStateForMetadata(state)??{},source:{snippetVersion:globalThis.RudderSnippetVersion}},user:{id:state.source.value?.id??state.lifecycle.writeKey.value}}]})
|
1104
|
+
if(message.includes('Error in loading a third-party script')){context='Script load failures';}return context;};const getBugsnagErrorEvent=(payload,errorState,state)=>({notifier:{name:NOTIFIER_NAME,version:state.context.app.value.version,url:SDK_GITHUB_URL},events:[{payloadVersion:'5',exceptions:clone(payload.errors),severity:errorState.severity,unhandled:errorState.unhandled,severityReason:errorState.severityReason,app:{version:state.context.app.value.version,releaseStage:getReleaseStage()},device:{locale:state.context.locale.value??undefined,userAgent:state.context.userAgent.value??undefined,time:new Date()},request:{url:getURLWithoutQueryString(),clientIp:'[NOT COLLECTED]'},breadcrumbs:clone(state.reporting.breadcrumbs.value),context:getErrorContext(payload.errors[0]),metaData:{sdk:{name:'JS',installType:state.context.app.value.installType},state:getAppStateForMetadata(state)??{},source:{snippetVersion:globalThis.RudderSnippetVersion}},user:{id:state.source.value?.id??state.lifecycle.writeKey.value}}]});/**
|
1105
|
+
* A function to determine whether the error should be promoted to notify or not
|
1106
|
+
* @param {Error} error
|
1107
|
+
* @returns
|
1108
|
+
*/const isAllowedToBeNotified=event=>{const errorMessage=event.message;if(errorMessage&&typeof errorMessage==='string'){return !ERROR_MESSAGES_TO_BE_FILTERED.some(e=>errorMessage.includes(e));}return true;};/**
|
1109
|
+
* A function to determine if the error is from Rudder SDK
|
1110
|
+
* @param {Error} event
|
1111
|
+
* @returns
|
1112
|
+
*/const isRudderSDKError=event=>{const errorOrigin=event.stacktrace?.[0]?.file;if(!errorOrigin||typeof errorOrigin!=='string'){return false;}const srcFileName=errorOrigin.substring(errorOrigin.lastIndexOf('/')+1);const paths=errorOrigin.split('/');// extract the parent folder name from the error origin file path
|
1124
1113
|
// Ex: parentFolderName will be 'sample' for url: https://example.com/sample/file.min.js
|
1125
1114
|
const parentFolderName=paths[paths.length-2];return parentFolderName===CDN_INT_DIR||SDK_FILE_NAME_PREFIXES().some(prefix=>srcFileName.startsWith(prefix)&&srcFileName.endsWith('.js'));};const getErrorDeliveryPayload=(payload,state)=>{const data={version:METRICS_PAYLOAD_VERSION,message_id:generateUUID(),source:{name:SOURCE_NAME,sdk_version:state.context.app.value.version,write_key:state.lifecycle.writeKey.value,install_type:state.context.app.value.installType},errors:payload};return stringifyWithoutCircular(data);};
|
1126
1115
|
|
@@ -1164,19 +1153,10 @@ const formatStackframe=frame=>{const f={file:frame.fileName,method:normaliseFunc
|
|
1164
1153
|
// This adds one.
|
1165
1154
|
if(f.lineNumber>-1&&!f.file&&!f.method){f.file='global code';}return f;};const ensureString=str=>typeof str==='string'?str:'';function createBugsnagError(errorClass,errorMessage,stacktrace){return {errorClass:ensureString(errorClass),message:ensureString(errorMessage),type:'browserjs',stacktrace:stacktrace.reduce((accum,frame)=>{const f=formatStackframe(frame);// don't include a stackframe if none of its properties are defined
|
1166
1155
|
try{if(JSON.stringify(f)==='{}')return accum;return accum.concat(f);}catch(e){return accum;}},[])};}// Helpers
|
1167
|
-
const getStacktrace=(error,errorFramesToSkip)=>{if(hasStack(error))return ErrorStackParser.parse(error).slice(errorFramesToSkip);return [];};const hasNecessaryFields=error=>(typeof error.name==='string'||typeof error.errorClass==='string')&&(typeof error.message==='string'||typeof error.errorMessage==='string');const normaliseError=(maybeError,
|
1168
|
-
//
|
1169
|
-
// - the promise rejection handler (both in the browser and node)
|
1170
|
-
// - the node uncaughtException handler
|
1171
|
-
//
|
1172
|
-
// We are really limited in what we can do to get a stacktrace. So we use the
|
1173
|
-
// tolerateNonErrors option to ensure that the resulting error communicates as
|
1174
|
-
// such.
|
1175
|
-
if(!tolerateNonErrors){if(isError(maybeError)){error=maybeError;}else {error=createAndLogInputError(typeof maybeError);internalFrames+=2;}}else {switch(typeof maybeError){case'string':case'number':case'boolean':error=new Error(String(maybeError));internalFrames+=1;break;case'function':error=createAndLogInputError('function');internalFrames+=2;break;case'object':if(maybeError!==null&&isError(maybeError)){error=maybeError;}else if(maybeError!==null&&hasNecessaryFields(maybeError)){error=new Error(maybeError.message||maybeError.errorMessage);error.name=maybeError.name||maybeError.errorClass;internalFrames+=1;}else {error=createAndLogInputError(maybeError===null?'null':'unsupported object');internalFrames+=2;}break;default:error=createAndLogInputError('nothing');internalFrames+=2;}}if(!hasStack(error)){// in IE10/11 a new Error() doesn't have a stacktrace until you throw it, so try that here
|
1156
|
+
const getStacktrace=(error,errorFramesToSkip)=>{if(hasStack(error))return ErrorStackParser.parse(error).slice(errorFramesToSkip);return [];};const hasNecessaryFields=error=>(typeof error.name==='string'||typeof error.errorClass==='string')&&(typeof error.message==='string'||typeof error.errorMessage==='string');const normaliseError=(maybeError,component,logger)=>{let error;let internalFrames=0;if(isError(maybeError)){error=maybeError;}else if(typeof maybeError==='object'&&hasNecessaryFields(maybeError)){error=new Error(maybeError.message||maybeError.errorMessage);error.name=maybeError.name||maybeError.errorClass;internalFrames+=1;}else {logger?.warn(`${ERROR_REPORTING_PLUGIN}:: ${component} received a non-error: ${stringifyWithoutCircular(error)}`);error=undefined;}if(error&&!hasStack(error)){// in IE10/11 a new Error() doesn't have a stacktrace until you throw it, so try that here
|
1176
1157
|
try{throw error;}catch(e){if(hasStack(e)){error=e;// if the error only got a stacktrace after we threw it here, we know it
|
1177
|
-
// will only have one extra internal frame from this function
|
1178
|
-
|
1179
|
-
internalFrames=1;}}}return [error,internalFrames];};class ErrorFormat{constructor(errorClass,errorMessage,stacktrace){this.errors=[createBugsnagError(errorClass,errorMessage,stacktrace)];}static create(maybeError,tolerateNonErrors,handledState,component,errorFramesToSkip=0,logger){const[error,internalFrames]=normaliseError(maybeError,tolerateNonErrors,component,logger);let event;try{const stacktrace=getStacktrace(error,// if an error was created/throw in the normaliseError() function, we need to
|
1158
|
+
// will only have one extra internal frame from this function
|
1159
|
+
internalFrames=1;}}}return [error,internalFrames];};class ErrorFormat{constructor(errorClass,errorMessage,stacktrace){this.errors=[createBugsnagError(errorClass,errorMessage,stacktrace)];}static create(maybeError,tolerateNonErrors,handledState,component,errorFramesToSkip=0,logger){const[error,internalFrames]=normaliseError(maybeError,component,logger);if(!error){return undefined;}let event;try{const stacktrace=getStacktrace(error,// if an error was created/throw in the normaliseError() function, we need to
|
1180
1160
|
// tell the getStacktrace() function to skip the number of frames we know will
|
1181
1161
|
// be from our own functions. This is added to the number of frames deep we
|
1182
1162
|
// were told about
|
@@ -1187,7 +1167,7 @@ const INVALID_SOURCE_CONFIG_ERROR=`Invalid source configuration or source id.`;
|
|
1187
1167
|
const pluginName$9='ErrorReporting';const ErrorReporting=()=>({name:pluginName$9,deps:[],initialize:state=>{state.plugins.loadedPlugins.value=[...state.plugins.loadedPlugins.value,pluginName$9];state.reporting.isErrorReportingPluginLoaded.value=true;if(state.reporting.breadcrumbs?.value){state.reporting.breadcrumbs.value=[createNewBreadcrumb('Error Reporting Plugin Loaded')];}},errorReporting:{// This extension point is deprecated
|
1188
1168
|
// TODO: Remove this in the next major release
|
1189
1169
|
init:(state,pluginEngine,externalSrcLoader,logger,isInvokedFromLatestCore)=>{if(isInvokedFromLatestCore){return undefined;}if(!state.source.value?.config||!state.source.value?.id){return Promise.reject(new Error(INVALID_SOURCE_CONFIG_ERROR));}return pluginEngine.invokeSingle('errorReportingProvider.init',state,externalSrcLoader,logger);},notify:(pluginEngine,client,error,state,logger,httpClient,errorState)=>{if(httpClient){const{component,tolerateNonErrors,errorFramesToSkip,normalizedError}=getConfigForPayloadCreation(error,errorState?.severityReason.type);// Generate the error payload
|
1190
|
-
const errorPayload=ErrorFormat.create(normalizedError,tolerateNonErrors,errorState,component,errorFramesToSkip,logger)
|
1170
|
+
const errorPayload=ErrorFormat.create(normalizedError,tolerateNonErrors,errorState,component,errorFramesToSkip,logger);if(!errorPayload||!isAllowedToBeNotified(errorPayload.errors[0])){return;}// filter errors
|
1191
1171
|
if(!isRudderSDKError(errorPayload.errors[0])){return;}// enrich error payload
|
1192
1172
|
const bugsnagPayload=getBugsnagErrorEvent(errorPayload,errorState,state);// send it to metrics service
|
1193
1173
|
httpClient?.getAsyncData({url:state.metrics.metricsServiceUrl.value,options:{method:'POST',data:getErrorDeliveryPayload(bugsnagPayload,state),sendRawData:true},isRawResponse:true,timeout:REQUEST_TIMEOUT_MS$1,callback:(result,details)=>{// do nothing
|
@@ -2706,9 +2686,14 @@ if(utmParam==='campaign'){utmParam='name';}result[utmParam]=value;}});}catch(err
|
|
2706
2686
|
*/const getUrlWithoutHash=url=>{let urlWithoutHash=url;try{const urlObj=new URL(url);urlWithoutHash=urlObj.origin+urlObj.pathname+urlObj.search;}catch(error){// Do nothing
|
2707
2687
|
}return urlWithoutHash;};
|
2708
2688
|
|
2689
|
+
/**
|
2690
|
+
* Determines if the SDK is running inside a chrome extension
|
2691
|
+
* @returns boolean
|
2692
|
+
*/const isSDKRunningInChromeExtension=()=>!!(window.chrome&&window.chrome.runtime&&window.chrome.runtime.id);
|
2693
|
+
|
2709
2694
|
const DEFAULT_PRE_CONSENT_STORAGE_STRATEGY='none';const DEFAULT_PRE_CONSENT_EVENTS_DELIVERY_TYPE='immediate';
|
2710
2695
|
|
2711
|
-
const isMetricsReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.metrics?.enabled===true;
|
2696
|
+
const isErrorReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.errors?.enabled===true;const isMetricsReportingEnabled=sourceConfig=>sourceConfig?.statsCollection?.metrics?.enabled===true;
|
2712
2697
|
|
2713
2698
|
/**
|
2714
2699
|
* Validates and normalizes the consent options provided by the user
|
@@ -2742,10 +2727,7 @@ for(const script of scripts){const src=script.getAttribute('src');if(src&&sdkFil
|
|
2742
2727
|
* Updates the reporting state variables from the source config data
|
2743
2728
|
* @param res Source config
|
2744
2729
|
* @param logger Logger instance
|
2745
|
-
*/const updateReportingState=res=>{state.reporting.isErrorReportingEnabled.value=
|
2746
|
-
// state.reporting.isErrorReportingEnabled.value =
|
2747
|
-
// isErrorReportingEnabled(res.source.config) && !isSDKRunningInChromeExtension();
|
2748
|
-
state.reporting.isMetricsReportingEnabled.value=isMetricsReportingEnabled(res.source.config);};const updateStorageStateFromLoadOptions=logger=>{const{useServerSideCookies,dataServiceEndpoint,storage:storageOptsFromLoad,setCookieDomain,sameDomainCookiesOnly}=state.loadOptions.value;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
|
2730
|
+
*/const updateReportingState=res=>{state.reporting.isErrorReportingEnabled.value=isErrorReportingEnabled(res.source.config)&&!isSDKRunningInChromeExtension();state.reporting.isMetricsReportingEnabled.value=isMetricsReportingEnabled(res.source.config);};const updateStorageStateFromLoadOptions=logger=>{const{useServerSideCookies,dataServiceEndpoint,storage:storageOptsFromLoad,setCookieDomain,sameDomainCookiesOnly}=state.loadOptions.value;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
|
2749
2731
|
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
|
2750
2732
|
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));}r(()=>{state.storage.type.value=storageType;let cookieOptions=storageOptsFromLoad?.cookie??{};if(useServerSideCookies){state.serverCookies.isEnabledServerSideCookies.value=useServerSideCookies;const providedCookieDomain=cookieOptions.domain??setCookieDomain;/**
|
2751
2733
|
* Based on the following conditions, we decide whether to use the exact domain or not to determine the data service URL:
|