@rudderstack/analytics-js 3.32.0 → 3.33.1
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 +27 -0
- package/README.md +6 -3
- package/dist/npm/index.d.cts +26 -13
- package/dist/npm/index.d.mts +26 -13
- package/dist/npm/legacy/bundled/cjs/index.cjs +126 -48
- package/dist/npm/legacy/bundled/esm/index.mjs +126 -48
- package/dist/npm/legacy/bundled/umd/index.js +126 -48
- package/dist/npm/legacy/cjs/index.cjs +126 -48
- package/dist/npm/legacy/content-script/cjs/index.cjs +126 -48
- package/dist/npm/legacy/content-script/esm/index.mjs +126 -48
- package/dist/npm/legacy/content-script/umd/index.js +126 -48
- package/dist/npm/legacy/esm/index.mjs +126 -48
- package/dist/npm/legacy/lite/cjs/index.cjs +107 -31
- package/dist/npm/legacy/lite/esm/index.mjs +107 -31
- package/dist/npm/legacy/lite/umd/index.js +107 -31
- package/dist/npm/legacy/umd/index.js +126 -48
- package/dist/npm/modern/bundled/cjs/index.cjs +126 -48
- package/dist/npm/modern/bundled/esm/index.mjs +126 -48
- package/dist/npm/modern/bundled/umd/index.js +126 -48
- package/dist/npm/modern/cjs/index.cjs +108 -31
- package/dist/npm/modern/content-script/cjs/index.cjs +126 -48
- package/dist/npm/modern/content-script/esm/index.mjs +126 -48
- package/dist/npm/modern/content-script/umd/index.js +126 -48
- package/dist/npm/modern/esm/index.mjs +108 -31
- package/dist/npm/modern/lite/cjs/index.cjs +107 -31
- package/dist/npm/modern/lite/esm/index.mjs +107 -31
- package/dist/npm/modern/lite/umd/index.js +107 -31
- package/dist/npm/modern/umd/index.js +108 -31
- package/package.json +1 -1
|
@@ -411,7 +411,7 @@
|
|
|
411
411
|
// Also, to clone the incoming object type arguments
|
|
412
412
|
payload.groupId=tryStringify(payload.groupId);if(isObjectLiteralAndNotNull(payload.traits)){payload.traits=clone(payload.traits);}else {payload.traits=undefined;}if(isDefined(payload.options)){payload.options=clone(payload.options);}else {payload.options=undefined;}return payload;};
|
|
413
413
|
|
|
414
|
-
|
|
414
|
+
/* eslint-disable sonarjs/deprecation *//**
|
|
415
415
|
* Represents the options parameter for anonymousId
|
|
416
416
|
*//**
|
|
417
417
|
* Represents the beacon queue options parameter in loadOptions type
|
|
@@ -419,13 +419,15 @@
|
|
|
419
419
|
* Represents the queue options parameter in loadOptions type
|
|
420
420
|
*//**
|
|
421
421
|
* Represents the destinations queue options parameter in loadOptions type
|
|
422
|
+
*//**
|
|
423
|
+
* @deprecated Use the `storage` load API option to control what is persisted before consent is given. It will be removed in the next major version.
|
|
422
424
|
*/let PageLifecycleEvents=/*#__PURE__*/function(PageLifecycleEvents){PageLifecycleEvents["UNLOADED"]="Page Unloaded";return PageLifecycleEvents;}({});/**
|
|
423
425
|
* Represents the source configuration override options for destinations
|
|
424
426
|
*//**
|
|
425
427
|
* Represents the options parameter in the load API
|
|
426
428
|
*/
|
|
427
429
|
|
|
428
|
-
const API_SUFFIX='API';const CAPABILITIES_MANAGER='CapabilitiesManager';const CONFIG_MANAGER='ConfigManager';const EVENT_MANAGER='EventManager';const PLUGINS_MANAGER='PluginsManager';const USER_SESSION_MANAGER='UserSessionManager';const ERROR_HANDLER='ErrorHandler';const PLUGIN_ENGINE='PluginEngine';const STORE_MANAGER='StoreManager';const READY_API=`Ready${API_SUFFIX}`;const LOAD_API=`Load${API_SUFFIX}`;const HTTP_CLIENT='HttpClient';const RSA='RudderStackAnalytics';const ANALYTICS_CORE='AnalyticsCore';
|
|
430
|
+
const API_SUFFIX='API';const CAPABILITIES_MANAGER='CapabilitiesManager';const CONFIG_MANAGER='ConfigManager';const EVENT_MANAGER='EventManager';const PLUGINS_MANAGER='PluginsManager';const USER_SESSION_MANAGER='UserSessionManager';const ERROR_HANDLER='ErrorHandler';const PLUGIN_ENGINE='PluginEngine';const STORE_MANAGER='StoreManager';const READY_API=`Ready${API_SUFFIX}`;const LOAD_API=`Load${API_SUFFIX}`;const CONSENT_API=`Consent${API_SUFFIX}`;const HTTP_CLIENT='HttpClient';const RSA='RudderStackAnalytics';const ANALYTICS_CORE='AnalyticsCore';
|
|
429
431
|
|
|
430
432
|
function random(len){return crypto.getRandomValues(new Uint8Array(len));}
|
|
431
433
|
|
|
@@ -519,7 +521,7 @@
|
|
|
519
521
|
}}});return newError;}catch{return new Error(`${issue}: ${stringifyWithoutCircular(err)}`);}};const dispatchErrorEvent=error=>{if(isTypeOfError(error)){const errStack=getStacktrace(error);if(errStack){// eslint-disable-next-line no-param-reassign
|
|
520
522
|
error.stack=`${errStack}\n${MANUAL_ERROR_IDENTIFIER}`;}}globalThis.dispatchEvent(new ErrorEvent('error',{error,bubbles:true,cancelable:true,composed:true}));};
|
|
521
523
|
|
|
522
|
-
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.
|
|
524
|
+
const APP_NAME='RudderLabs JavaScript SDK';const APP_VERSION='3.33.1';const APP_NAMESPACE='com.rudderlabs.javascript';const MODULE_TYPE='npm';const BUILD_VARIANT='content-script';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';
|
|
523
525
|
|
|
524
526
|
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';
|
|
525
527
|
|
|
@@ -638,8 +640,8 @@
|
|
|
638
640
|
const SUPPORTED_STORAGE_TYPES=['localStorage','memoryStorage','cookieStorage','sessionStorage','none'];const DEFAULT_STORAGE_TYPE='cookieStorage';
|
|
639
641
|
|
|
640
642
|
const SOURCE_CONFIG_RESOLUTION_ERROR=`Unable to process/parse source configuration response`;const SOURCE_DISABLED_ERROR=`The source is disabled. Please enable the source in the dashboard to send events.`;const XHR_PAYLOAD_PREP_ERROR=`Failed to prepare data for the request.`;const PLUGIN_EXT_POINT_MISSING_ERROR=`Failed to invoke plugin because the extension point name is missing.`;const PLUGIN_EXT_POINT_INVALID_ERROR=`Failed to invoke plugin because the extension point name is invalid.`;const SOURCE_CONFIG_OPTION_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}The "getSourceConfig" load API option must be a function that returns valid source configuration data.`;const COMPONENT_BASE_URL_ERROR=(context,component,url)=>`${context}${LOG_CONTEXT_SEPARATOR}The base URL "${url}" for ${component} is not valid.`;// ERROR
|
|
641
|
-
const UNSUPPORTED_CONSENT_MANAGER_ERROR=(context,selectedConsentManager,consentManagersToPluginNameMap)=>`${context}${LOG_CONTEXT_SEPARATOR}The consent manager "${selectedConsentManager}" is not supported. Please choose one of the following supported consent managers: "${Object.keys(consentManagersToPluginNameMap)}".`;const NON_ERROR_WARNING=(context,errStr)=>`${context}${LOG_CONTEXT_SEPARATOR}Ignoring a non-error: ${errStr}.`;const BREADCRUMB_ERROR=`Failed to log breadcrumb`;const HANDLE_ERROR_FAILURE=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to handle the error.`;const PLUGIN_NAME_MISSING_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin name is missing.`;const PLUGIN_ALREADY_EXISTS_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" already exists.`;const PLUGIN_NOT_FOUND_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" not found.`;const PLUGIN_ENGINE_BUG_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" not found in plugins but found in byName. This indicates a bug in the plugin engine. Please report this issue to the development team.`;const PLUGIN_DEPS_ERROR=(context,pluginName,notExistDeps)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" could not be loaded because some of its dependencies "${notExistDeps}" do not exist.`;const PLUGIN_INVOCATION_ERROR=(context,extPoint,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to invoke the "${extPoint}" extension point of plugin "${pluginName}".`;const SOURCE_CONFIG_FETCH_ERROR='Failed to fetch the source config';const WRITE_KEY_VALIDATION_ERROR=(context,writeKey)=>`${context}${LOG_CONTEXT_SEPARATOR}The write key "${writeKey}" is invalid. It must be a non-empty string. Please check that the write key is correct and try again.`;const DATA_PLANE_URL_VALIDATION_ERROR=(context,dataPlaneUrl)=>`${context}${LOG_CONTEXT_SEPARATOR}The data plane URL "${dataPlaneUrl}" is invalid. It must be a valid URL string. Please check that the data plane URL is correct and try again.`;const INVALID_CALLBACK_FN_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}The provided callback parameter is not a function.`;const XHR_DELIVERY_ERROR=(prefix,status,statusText,url,response)=>`${prefix} with status ${status} (${statusText}) for URL: ${url}. Response: ${response.trim()}`;const XHR_REQUEST_ERROR=(prefix,e,url)=>`${prefix} due to timeout or no connection (${e?e.type:''}) at the client side for URL: ${url}`;const XHR_SEND_ERROR=(prefix,url)=>`${prefix} for URL: ${url}`;const STORE_DATA_SAVE_ERROR=key=>`Failed to save the value for "${key}" to storage`;const STORE_DATA_FETCH_ERROR=key=>`Failed to retrieve or parse data for "${key}" from storage`;const DATA_SERVER_REQUEST_FAIL_ERROR=status=>`The server responded with status ${status} while setting the cookies. As a fallback, the cookies will be set client side.`;const FAILED_SETTING_COOKIE_FROM_SERVER_ERROR=key=>`The server failed to set the ${key} cookie. As a fallback, the cookies will be set client side.`;const FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR=`Failed to set/remove cookies via server. As a fallback, the cookies will be managed client side.`;// WARNING
|
|
642
|
-
const STORAGE_TYPE_VALIDATION_WARNING=(context,storageType
|
|
643
|
+
const UNSUPPORTED_CONSENT_MANAGER_ERROR=(context,selectedConsentManager,consentManagersToPluginNameMap)=>`${context}${LOG_CONTEXT_SEPARATOR}The consent manager "${selectedConsentManager}" is not supported. Please choose one of the following supported consent managers: "${Object.keys(consentManagersToPluginNameMap)}".`;const NON_ERROR_WARNING=(context,errStr)=>`${context}${LOG_CONTEXT_SEPARATOR}Ignoring a non-error: ${errStr}.`;const BREADCRUMB_ERROR=`Failed to log breadcrumb`;const HANDLE_ERROR_FAILURE=context=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to handle the error.`;const PLUGIN_NAME_MISSING_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin name is missing.`;const PLUGIN_ALREADY_EXISTS_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" already exists.`;const PLUGIN_NOT_FOUND_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" not found.`;const PLUGIN_ENGINE_BUG_ERROR=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" not found in plugins but found in byName. This indicates a bug in the plugin engine. Please report this issue to the development team.`;const PLUGIN_DEPS_ERROR=(context,pluginName,notExistDeps)=>`${context}${LOG_CONTEXT_SEPARATOR}Plugin "${pluginName}" could not be loaded because some of its dependencies "${notExistDeps}" do not exist.`;const PLUGIN_INVOCATION_ERROR=(context,extPoint,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to invoke the "${extPoint}" extension point of plugin "${pluginName}".`;const SOURCE_CONFIG_FETCH_ERROR='Failed to fetch the source config';const WRITE_KEY_VALIDATION_ERROR=(context,writeKey)=>`${context}${LOG_CONTEXT_SEPARATOR}The write key "${writeKey}" is invalid. It must be a non-empty string. Please check that the write key is correct and try again.`;const DATA_PLANE_URL_VALIDATION_ERROR=(context,dataPlaneUrl)=>`${context}${LOG_CONTEXT_SEPARATOR}The data plane URL "${dataPlaneUrl}" is invalid. It must be a valid URL string. Please check that the data plane URL is correct and try again.`;const INVALID_CALLBACK_FN_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}The provided callback parameter is not a function.`;const XHR_DELIVERY_ERROR=(prefix,status,statusText,url,response)=>`${prefix} with status ${status} (${statusText}) for URL: ${url}. Response: ${response.trim()}`;const XHR_REQUEST_ERROR=(prefix,e,url)=>`${prefix} due to timeout or no connection (${e?e.type:''}) at the client side for URL: ${url}`;const XHR_SEND_ERROR=(prefix,url)=>`${prefix} for URL: ${url}`;const STORE_DATA_SAVE_ERROR=key=>`Failed to save the value for "${key}" to storage`;const STORE_DATA_FETCH_ERROR=key=>`Failed to retrieve or parse data for "${key}" from storage`;const DATA_SERVER_REQUEST_FAIL_ERROR=status=>`The server responded with status ${status} while setting the cookies. As a fallback, the cookies will be set client side.`;const FAILED_SETTING_COOKIE_FROM_SERVER_ERROR=key=>`The server failed to set the ${key} cookie. As a fallback, the cookies will be set client side.`;const FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR=`Failed to set/remove cookies via server. As a fallback, the cookies will be managed client side.`;const COLLAPSED_COOKIE_BATCH_ERROR=(missingCookies,batchSize)=>`The server did not set ${missingCookies.length} of the ${batchSize} cookies sent in one request: ${missingCookies.join(', ')}. A fallback to set them client side was attempted. Check that the data service and any proxy preserve every "Set-Cookie" header, and that the cookie domain and SameSite/Secure attributes are valid.`;// WARNING
|
|
644
|
+
const STORAGE_TYPE_VALIDATION_WARNING=(context,storageType)=>`${context}${LOG_CONTEXT_SEPARATOR}The storage type "${storageType}" is not supported. Please choose one of the following supported types: "${SUPPORTED_STORAGE_TYPES}". The default storage type will be used instead.`;const UNSUPPORTED_STORAGE_ENTRY_TYPE_WARNING=(context,entry,storageType)=>`${context}${LOG_CONTEXT_SEPARATOR}The storage type "${storageType}" configured for the entry "${entry}" is not supported. Please choose one of the following supported types: "${SUPPORTED_STORAGE_TYPES}". The default storage type will be used instead.`;const UNSUPPORTED_STORAGE_ENCRYPTION_VERSION_WARNING=(context,selectedStorageEncryptionVersion,storageEncryptionVersionsToPluginNameMap,defaultVersion)=>`${context}${LOG_CONTEXT_SEPARATOR}The storage encryption version "${selectedStorageEncryptionVersion}" is not supported. Please choose one of the following supported versions: "${Object.keys(storageEncryptionVersionsToPluginNameMap)}". The default version "${defaultVersion}" will be used instead.`;const STORAGE_DATA_MIGRATION_OVERRIDE_WARNING=(context,storageEncryptionVersion,defaultVersion)=>`${context}${LOG_CONTEXT_SEPARATOR}The storage data migration has been disabled because the configured storage encryption version (${storageEncryptionVersion}) is not the latest (${defaultVersion}). To enable storage data migration, please update the storage encryption version to the latest version.`;const SERVER_SIDE_COOKIE_FEATURE_OVERRIDE_WARNING=(context,providedCookieDomain,currentCookieDomain)=>`${context}${LOG_CONTEXT_SEPARATOR}The provided cookie domain (${providedCookieDomain}) does not match the current webpage's domain (${currentCookieDomain}). Hence, the cookies will be set client-side.`;const RESERVED_KEYWORD_WARNING=(context,property,parentKeyPath,reservedElements)=>`${context}${LOG_CONTEXT_SEPARATOR}The "${property}" property defined under "${parentKeyPath}" is a reserved keyword. Please choose a different property name to avoid conflicts with reserved keywords (${reservedElements}).`;const RESERVED_CUSTOM_CONTEXT_KEY_WARNING=(logContext,property)=>`${logContext}${LOG_CONTEXT_SEPARATOR}The top-level custom context property "${property}" is reserved and was ignored.`;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 INVALID_CUSTOM_CONTEXT_WARNING=logContext=>`${logContext}${LOG_CONTEXT_SEPARATOR}Invalid custom context. Use a plain object without prototype pollution keys.`;const UNSUPPORTED_BEACON_API_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}The Beacon API is not supported by your browser. The events will be sent using XHR instead.`;const TIMEOUT_NOT_NUMBER_WARNING=(context,timeout,defaultValue)=>`${context}${LOG_CONTEXT_SEPARATOR}The session timeout value "${timeout}" is not a number. The default timeout of ${defaultValue} ms will be used instead.`;const CUT_OFF_DURATION_NOT_NUMBER_WARNING=(context,cutOffDuration,defaultValue)=>`${context}${LOG_CONTEXT_SEPARATOR}The session cut off duration value "${cutOffDuration}" is not a number. The default cut off duration of ${defaultValue} ms will be used instead.`;const CUT_OFF_DURATION_LESS_THAN_TIMEOUT_WARNING=(context,cutOffDuration,timeout)=>`${context}${LOG_CONTEXT_SEPARATOR}The session cut off duration value "${cutOffDuration}" ms is less than the session timeout value "${timeout}" ms. The cut off functionality will be disabled.`;const TIMEOUT_ZERO_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}The session timeout value is 0, which disables the automatic session tracking feature. If you want to enable session tracking, please provide a positive integer value for the timeout.`;const TIMEOUT_NOT_RECOMMENDED_WARNING=(context,timeout,minTimeout)=>`${context}${LOG_CONTEXT_SEPARATOR}The session timeout value ${timeout} ms is less than the recommended minimum of ${minTimeout} ms. Please consider increasing the timeout value to ensure optimal performance and reliability.`;const INVALID_SESSION_ID_WARNING=(context,sessionId,minSessionIdLength)=>`${context}${LOG_CONTEXT_SEPARATOR}The provided session ID (${sessionId}) is either invalid, not a positive integer, or not at least "${minSessionIdLength}" digits long. A new session ID will be auto-generated instead.`;const STORAGE_QUOTA_EXCEEDED_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}The storage is either full or unavailable, so the data will not be persisted. Switching to in-memory storage.`;const STORAGE_UNAVAILABLE_WARNING=(context,entry,selectedStorageType,finalStorageType)=>`${context}${LOG_CONTEXT_SEPARATOR}The storage type "${selectedStorageType}" is not available for entry "${entry}". The SDK will initialize the entry with "${finalStorageType}" storage type instead.`;const CALLBACK_INVOKE_ERROR=context=>`${context}${LOG_CONTEXT_SEPARATOR}The callback threw an exception`;const INVALID_CONFIG_URL_WARNING=(context,configUrl)=>`${context}${LOG_CONTEXT_SEPARATOR}The provided source config URL "${configUrl}" is invalid. Using the default source config URL instead.`;const POLYFILL_SCRIPT_LOAD_ERROR=(scriptId,url)=>`Failed to load the polyfill script with ID "${scriptId}" from URL ${url}.`;const UNSUPPORTED_PRE_CONSENT_STORAGE_STRATEGY=(context,selectedStrategy,defaultStrategy)=>`${context}${LOG_CONTEXT_SEPARATOR}The pre-consent storage strategy "${selectedStrategy}" is not supported. Please choose one of the following supported strategies: "none, session, anonymousId". The default strategy "${defaultStrategy}" will be used instead.`;const DEPRECATED_PRE_CONSENT_STORAGE_STRATEGY=context=>`${context}${LOG_CONTEXT_SEPARATOR}The pre-consent storage strategy option is deprecated. Please enable "storage" in the pre-consent options and use the "storage" load API option instead.`;const UNSUPPORTED_PRE_CONSENT_EVENTS_DELIVERY_TYPE=(context,selectedDeliveryType,defaultDeliveryType)=>`${context}${LOG_CONTEXT_SEPARATOR}The pre-consent events delivery type "${selectedDeliveryType}" is not supported. Please choose one of the following supported types: "immediate, buffer". The default type "${defaultDeliveryType}" will be used instead.`;const DEPRECATED_PLUGIN_WARNING=(context,pluginName)=>`${context}${LOG_CONTEXT_SEPARATOR}${pluginName} plugin is deprecated. Please exclude it from the load API options.`;const generateMisconfiguredPluginsWarning=(context,configurationStatus,missingPlugins,shouldAddMissingPlugins)=>{const isSinglePlugin=missingPlugins.length===1;const pluginsString=isSinglePlugin?` '${missingPlugins[0]}' plugin was`:` ['${missingPlugins.join("', '")}'] plugins were`;const baseWarning=`${context}${LOG_CONTEXT_SEPARATOR}${configurationStatus}, but${pluginsString} not configured to load.`;if(shouldAddMissingPlugins){return `${baseWarning} So, ${isSinglePlugin?'the plugin':'those plugins'} will be loaded automatically.`;}return `${baseWarning} Ignore if this was intentional. Otherwise, consider adding ${isSinglePlugin?'it':'them'} to the 'plugins' load API option.`;};const INVALID_POLYFILL_URL_WARNING=(context,customPolyfillUrl)=>`${context}${LOG_CONTEXT_SEPARATOR}The provided polyfill URL "${customPolyfillUrl}" is invalid. The default polyfill URL will be used instead.`;const PAGE_UNLOAD_ON_BEACON_DISABLED_WARNING=context=>`${context}${LOG_CONTEXT_SEPARATOR}Page Unloaded event can only be tracked when the Beacon transport is active. Please enable "useBeacon" load API option.`;const UNKNOWN_PLUGINS_WARNING=(context,unknownPlugins)=>`${context}${LOG_CONTEXT_SEPARATOR}Ignoring unknown plugins: ${unknownPlugins.join(', ')}.`;const UNAVAILABLE_PLUGINS_ERROR=(context,unavailablePlugins)=>`${context}${LOG_CONTEXT_SEPARATOR}Failed to load the following unavailable local plugins: ${unavailablePlugins.join(', ')}. Some features of the SDK may not work as expected. Make sure you are using the correct SDK bundle variant.`;const CUSTOM_INTEGRATION_CANNOT_BE_ADDED_ERROR=(context,destinationId)=>`${context}${LOG_CONTEXT_SEPARATOR}Cannot add custom integration for destination ID "${destinationId}" after the SDK is loaded.`;
|
|
643
645
|
|
|
644
646
|
const DEFAULT_INTEGRATIONS_CONFIG={All:true};
|
|
645
647
|
|
|
@@ -688,9 +690,9 @@
|
|
|
688
690
|
|
|
689
691
|
const pluginsState={ready:y(false),loadedPlugins:y([]),failedPlugins:y([]),pluginsToLoadFromConfig:y([]),activePlugins:y([]),totalPluginsToLoad:y(0)};
|
|
690
692
|
|
|
691
|
-
const storageState={encryptionPluginName:y(undefined),migrate:y(false),
|
|
693
|
+
const storageState={encryptionPluginName:y(undefined),migrate:y(false),cookie:y(undefined),entries:y({}),trulyAnonymousTracking:y(false)};
|
|
692
694
|
|
|
693
|
-
const serverSideCookiesState={isEnabledServerSideCookies:y(false),dataServiceUrl:y(undefined)};
|
|
695
|
+
const serverSideCookiesState={isEnabledServerSideCookies:y(false),dataServiceUrl:y(undefined),isCollapsedBatchErrorLogged:y(false)};
|
|
694
696
|
|
|
695
697
|
const dataPlaneEventsState={eventsQueuePluginName:y(undefined),deliveryEnabled:y(true)// Delivery should always happen
|
|
696
698
|
};
|
|
@@ -1147,37 +1149,39 @@
|
|
|
1147
1149
|
* @returns Destinations array filtered based on the integration options
|
|
1148
1150
|
*/const filterDestinations=(intgOpts,destinations)=>{const allOptVal=intgOpts.All??true;return destinations.filter(dest=>{const destDisplayName=dest.displayName;let isDestEnabled;if(allOptVal){isDestEnabled=true;if(isDestIntgConfigFalsy(intgOpts[destDisplayName])){isDestEnabled=false;}}else {isDestEnabled=false;if(isDestIntgConfigTruthy(intgOpts[destDisplayName])){isDestEnabled=true;}}return isDestEnabled;});};
|
|
1149
1151
|
|
|
1150
|
-
const ACTIVE_CAMPAIGN_DISPLAY_NAME='ActiveCampaign';const ADOBE_ANALYTICS_DISPLAY_NAME='Adobe Analytics';const ADROLL_DISPLAY_NAME='Adroll';const AM_DISPLAY_NAME='Amplitude';const APPCUES_DISPLAY_NAME='Appcues';const AXEPTIO_DISPLAY_NAME='Axeptio';const BINGADS_DISPLAY_NAME='Bing Ads';const BRAZE_DISPLAY_NAME='Braze';const BUGSNAG_DISPLAY_NAME='Bugsnag';const CHARTBEAT_DISPLAY_NAME='Chartbeat';const CLEVERTAP_DISPLAY_NAME='CleverTap';const COMMANDBAR_DISPLAY_NAME='CommandBar';const COMSCORE_DISPLAY_NAME='Comscore';const CONVERTFLOW_DISPLAY_NAME='Convertflow';const CRITEO_DISPLAY_NAME='Criteo';const CUSTOMERIO_DISPLAY_NAME='Customer IO';const DCM_FLOODLIGHT_DISPLAY_NAME='DCM Floodlight';const DRIP_DISPLAY_NAME='Drip';const ENGAGE_DISPLAY_NAME='Engage';const FACEBOOK_PIXEL_DISPLAY_NAME='Facebook Pixel';const FULLSTORY_DISPLAY_NAME='Fullstory';const GA_DISPLAY_NAME='Google Analytics';const GA360_DISPLAY_NAME='Google Analytics 360';const GA4_DISPLAY_NAME='Google Analytics 4 (GA4)';const GA4_V2_DISPLAY_NAME='Google Analytics 4 (GA4) V2';const GAINSIGHT_PX_DISPLAY_NAME='Gainsight PX';const GOOGLE_OPTIMIZE_DISPLAY_NAME='Google Optimize';const GOOGLEADS_DISPLAY_NAME='Google Ads';const GTM_DISPLAY_NAME='Google Tag Manager';const HEAP_DISPLAY_NAME='Heap.io';const HOTJAR_DISPLAY_NAME='Hotjar';const HS_DISPLAY_NAME='HubSpot';const INTERCOM_DISPLAY_NAME='Intercom';const ITERABLE_DISPLAY_NAME='Iterable';const JUNE_DISPLAY_NAME='JUNE';const KEEN_DISPLAY_NAME='Keen';const KISSMETRICS_DISPLAY_NAME='Kiss Metrics';const KLAVIYO_DISPLAY_NAME='Klaviyo';const LAUNCHDARKLY_DISPLAY_NAME='LaunchDarkly';const LEMNISK_DISPLAY_NAME='Lemnisk Marketing Automation';const LINKEDIN_INSIGHT_TAG_DISPLAY_NAME='Linkedin Insight Tag';const LIVECHAT_DISPLAY_NAME='livechat';const LOTAME_DISPLAY_NAME='Lotame';const LYTICS_DISPLAY_NAME='Lytics';const MATOMO_DISPLAY_NAME='Matomo';const MICROSOFT_CLARITY_DISPLAY_NAME='Microsoft Clarity';const MOENGAGE_DISPLAY_NAME='MoEngage';const MOUSEFLOW_DISPLAY_NAME='Mouseflow';const MP_DISPLAY_NAME='Mixpanel';const NINETAILED_DISPLAY_NAME='Ninetailed';const OLARK_DISPLAY_NAME='Olark';const OPTIMIZELY_DISPLAY_NAME='Optimizely Web';const PENDO_DISPLAY_NAME='Pendo';const PINTEREST_TAG_DISPLAY_NAME='Pinterest Tag';const PODSIGHTS_DISPLAY_NAME='Podsights';const POST_AFFILIATE_PRO_DISPLAY_NAME='Post Affiliate Pro';const POSTHOG_DISPLAY_NAME='PostHog';const PROFITWELL_DISPLAY_NAME='ProfitWell';const QUALAROO_DISPLAY_NAME='Qualaroo';const QUALTRICS_DISPLAY_NAME='Qualtrics';const QUANTUMMETRIC_DISPLAY_NAME='Quantum Metric';const QUORA_PIXEL_DISPLAY_NAME='Quora Pixel';const REDDIT_PIXEL_DISPLAY_NAME='Reddit Pixel';const REFINER_DISPLAY_NAME='Refiner';const ROCKERBOX_DISPLAY_NAME='Rockerbox';const ROLLBAR_DISPLAY_NAME='rollbar';const SATISMETER_DISPLAY_NAME='SatisMeter';const SENDINBLUE_DISPLAY_NAME='Sendinblue';const SENTRY_DISPLAY_NAME='Sentry';const SHYNET_DISPLAY_NAME='Shynet';const SNAP_PIXEL_DISPLAY_NAME='Snap Pixel';const SNAPENGAGE_DISPLAY_NAME='SnapEngage';const SPOTIFYPIXEL_DISPLAY_NAME='Spotify Pixel';const SPRIG_DISPLAY_NAME='Sprig';const TIKTOK_ADS_DISPLAY_NAME='TikTok Ads';const TVSQUARED_DISPLAY_NAME='TVSquared';const USERPILOT_DISPLAY_NAME='Userpilot';const VERO_DISPLAY_NAME='Vero';const VWO_DISPLAY_NAME='VWO';const WOOPRA_DISPLAY_NAME='WOOPRA';const XPIXEL_DISPLAY_NAME='XPixel';const YANDEX_METRICA_DISPLAY_NAME='Yandex.Metrica';
|
|
1152
|
+
const ACTIVE_CAMPAIGN_DISPLAY_NAME='ActiveCampaign';const ADOBE_ANALYTICS_DISPLAY_NAME='Adobe Analytics';const ADROLL_DISPLAY_NAME='Adroll';const AM_DISPLAY_NAME='Amplitude';const APPCUES_DISPLAY_NAME='Appcues';const AXEPTIO_DISPLAY_NAME='Axeptio';const BINGADS_DISPLAY_NAME='Bing Ads';const BRAZE_DISPLAY_NAME='Braze';const BUGSNAG_DISPLAY_NAME='Bugsnag';const CHARTBEAT_DISPLAY_NAME='Chartbeat';const CLEVERTAP_DISPLAY_NAME='CleverTap';const COMMANDBAR_DISPLAY_NAME='CommandBar';const COMSCORE_DISPLAY_NAME='Comscore';const CONVERTFLOW_DISPLAY_NAME='Convertflow';const CRITEO_DISPLAY_NAME='Criteo';const CUSTOMERIO_DISPLAY_NAME='Customer IO';const DCM_FLOODLIGHT_DISPLAY_NAME='DCM Floodlight';const DRIP_DISPLAY_NAME='Drip';const ENGAGE_DISPLAY_NAME='Engage';const FACEBOOK_PIXEL_DISPLAY_NAME='Facebook Pixel';const FULLSTORY_DISPLAY_NAME='Fullstory';const GA_DISPLAY_NAME='Google Analytics';const GA360_DISPLAY_NAME='Google Analytics 360';const GA4_DISPLAY_NAME='Google Analytics 4 (GA4)';const GA4_V2_DISPLAY_NAME='Google Analytics 4 (GA4) V2';const GAINSIGHT_PX_DISPLAY_NAME='Gainsight PX';const GOOGLE_OPTIMIZE_DISPLAY_NAME='Google Optimize';const GOOGLEADS_DISPLAY_NAME='Google Ads';const GTM_DISPLAY_NAME='Google Tag Manager';const HEAP_DISPLAY_NAME='Heap.io';const HOTJAR_DISPLAY_NAME='Hotjar';const HS_DISPLAY_NAME='HubSpot';const INTERCOM_DISPLAY_NAME='Intercom';const ITERABLE_DISPLAY_NAME='Iterable';const JUNE_DISPLAY_NAME='JUNE';const KEEN_DISPLAY_NAME='Keen';const KISSMETRICS_DISPLAY_NAME='Kiss Metrics';const KLAVIYO_DISPLAY_NAME='Klaviyo';const LAUNCHDARKLY_DISPLAY_NAME='LaunchDarkly';const LEMNISK_DISPLAY_NAME='Lemnisk Marketing Automation';const LINKEDIN_INSIGHT_TAG_DISPLAY_NAME='Linkedin Insight Tag';const LIVECHAT_DISPLAY_NAME='livechat';const LOTAME_DISPLAY_NAME='Lotame';const LYTICS_DISPLAY_NAME='Lytics';const MATOMO_DISPLAY_NAME='Matomo';const MICROSOFT_CLARITY_DISPLAY_NAME='Microsoft Clarity';const MOENGAGE_DISPLAY_NAME='MoEngage';const MOUSEFLOW_DISPLAY_NAME='Mouseflow';const MP_DISPLAY_NAME='Mixpanel';const NINETAILED_DISPLAY_NAME='Ninetailed';const OLARK_DISPLAY_NAME='Olark';const OPENAI_ADS_DISPLAY_NAME='OpenAI Ads';const OPTIMIZELY_DISPLAY_NAME='Optimizely Web';const PENDO_DISPLAY_NAME='Pendo';const PINTEREST_TAG_DISPLAY_NAME='Pinterest Tag';const PODSIGHTS_DISPLAY_NAME='Podsights';const POST_AFFILIATE_PRO_DISPLAY_NAME='Post Affiliate Pro';const POSTHOG_DISPLAY_NAME='PostHog';const PROFITWELL_DISPLAY_NAME='ProfitWell';const QUALAROO_DISPLAY_NAME='Qualaroo';const QUALTRICS_DISPLAY_NAME='Qualtrics';const QUANTUMMETRIC_DISPLAY_NAME='Quantum Metric';const QUORA_PIXEL_DISPLAY_NAME='Quora Pixel';const REDDIT_PIXEL_DISPLAY_NAME='Reddit Pixel';const REFINER_DISPLAY_NAME='Refiner';const ROCKERBOX_DISPLAY_NAME='Rockerbox';const ROLLBAR_DISPLAY_NAME='rollbar';const SATISMETER_DISPLAY_NAME='SatisMeter';const SENDINBLUE_DISPLAY_NAME='Sendinblue';const SENTRY_DISPLAY_NAME='Sentry';const SHYNET_DISPLAY_NAME='Shynet';const SNAP_PIXEL_DISPLAY_NAME='Snap Pixel';const SNAPENGAGE_DISPLAY_NAME='SnapEngage';const SPOTIFYPIXEL_DISPLAY_NAME='Spotify Pixel';const SPRIG_DISPLAY_NAME='Sprig';const TIKTOK_ADS_DISPLAY_NAME='TikTok Ads';const TVSQUARED_DISPLAY_NAME='TVSquared';const USERPILOT_DISPLAY_NAME='Userpilot';const VERO_DISPLAY_NAME='Vero';const VWO_DISPLAY_NAME='VWO';const WOOPRA_DISPLAY_NAME='WOOPRA';const XPIXEL_DISPLAY_NAME='XPixel';const YANDEX_METRICA_DISPLAY_NAME='Yandex.Metrica';
|
|
1153
|
+
|
|
1154
|
+
const DIR_NAME$1i='HubSpot';
|
|
1151
1155
|
|
|
1152
|
-
const DIR_NAME$1h='
|
|
1156
|
+
const DIR_NAME$1h='GA';
|
|
1153
1157
|
|
|
1154
|
-
const DIR_NAME$1g='
|
|
1158
|
+
const DIR_NAME$1g='Hotjar';
|
|
1155
1159
|
|
|
1156
|
-
const DIR_NAME$1f='
|
|
1160
|
+
const DIR_NAME$1f='GoogleAds';
|
|
1157
1161
|
|
|
1158
|
-
const DIR_NAME$1e='
|
|
1162
|
+
const DIR_NAME$1e='VWO';
|
|
1159
1163
|
|
|
1160
|
-
const DIR_NAME$1d='
|
|
1164
|
+
const DIR_NAME$1d='GoogleTagManager';
|
|
1161
1165
|
|
|
1162
|
-
const DIR_NAME$1c='
|
|
1166
|
+
const DIR_NAME$1c='Braze';
|
|
1163
1167
|
|
|
1164
|
-
const DIR_NAME$1b='
|
|
1168
|
+
const DIR_NAME$1b='INTERCOM';
|
|
1165
1169
|
|
|
1166
|
-
const DIR_NAME$1a='
|
|
1170
|
+
const DIR_NAME$1a='Keen';
|
|
1167
1171
|
|
|
1168
|
-
const DIR_NAME$19='
|
|
1172
|
+
const DIR_NAME$19='Kissmetrics';
|
|
1169
1173
|
|
|
1170
|
-
const DIR_NAME$18='
|
|
1174
|
+
const DIR_NAME$18='CustomerIO';
|
|
1171
1175
|
|
|
1172
|
-
const DIR_NAME$17='
|
|
1176
|
+
const DIR_NAME$17='Chartbeat';
|
|
1173
1177
|
|
|
1174
|
-
const DIR_NAME$16='
|
|
1178
|
+
const DIR_NAME$16='FacebookPixel';
|
|
1175
1179
|
|
|
1176
|
-
const DIR_NAME$15='
|
|
1180
|
+
const DIR_NAME$15='Lotame';
|
|
1177
1181
|
|
|
1178
|
-
const DIR_NAME$14='
|
|
1182
|
+
const DIR_NAME$14='Optimizely';
|
|
1179
1183
|
|
|
1180
|
-
const DIR_NAME$13='
|
|
1184
|
+
const DIR_NAME$13='OpenAIAds';
|
|
1181
1185
|
|
|
1182
1186
|
const DIR_NAME$12='Bugsnag';
|
|
1183
1187
|
|
|
@@ -1315,7 +1319,7 @@
|
|
|
1315
1319
|
|
|
1316
1320
|
// map of the destination display names to the destination directory names
|
|
1317
1321
|
// Import display names and directory names from analytics-js-integrations
|
|
1318
|
-
const destDisplayNamesToFileNamesMap={[HS_DISPLAY_NAME]:DIR_NAME$
|
|
1322
|
+
const destDisplayNamesToFileNamesMap={[HS_DISPLAY_NAME]:DIR_NAME$1i,[GA_DISPLAY_NAME]:DIR_NAME$1h,[HOTJAR_DISPLAY_NAME]:DIR_NAME$1g,[GOOGLEADS_DISPLAY_NAME]:DIR_NAME$1f,[VWO_DISPLAY_NAME]:DIR_NAME$1e,[GTM_DISPLAY_NAME]:DIR_NAME$1d,[BRAZE_DISPLAY_NAME]:DIR_NAME$1c,[INTERCOM_DISPLAY_NAME]:DIR_NAME$1b,[KEEN_DISPLAY_NAME]:DIR_NAME$1a,[KISSMETRICS_DISPLAY_NAME]:DIR_NAME$19,[CUSTOMERIO_DISPLAY_NAME]:DIR_NAME$18,[CHARTBEAT_DISPLAY_NAME]:DIR_NAME$17,[FACEBOOK_PIXEL_DISPLAY_NAME]:DIR_NAME$16,[LOTAME_DISPLAY_NAME]:DIR_NAME$15,[OPTIMIZELY_DISPLAY_NAME]:DIR_NAME$14,[OPENAI_ADS_DISPLAY_NAME]:DIR_NAME$13,[BUGSNAG_DISPLAY_NAME]:DIR_NAME$12,[FULLSTORY_DISPLAY_NAME]:DIR_NAME$11,[TVSQUARED_DISPLAY_NAME]:DIR_NAME$10,[GA4_DISPLAY_NAME]:DIR_NAME$$,[GA4_V2_DISPLAY_NAME]:DIR_NAME$_,[MOENGAGE_DISPLAY_NAME]:DIR_NAME$Z,[AM_DISPLAY_NAME]:DIR_NAME$Y,[PENDO_DISPLAY_NAME]:DIR_NAME$X,[LYTICS_DISPLAY_NAME]:DIR_NAME$W,[APPCUES_DISPLAY_NAME]:DIR_NAME$V,[POSTHOG_DISPLAY_NAME]:DIR_NAME$U,[KLAVIYO_DISPLAY_NAME]:DIR_NAME$T,[CLEVERTAP_DISPLAY_NAME]:DIR_NAME$S,[BINGADS_DISPLAY_NAME]:DIR_NAME$R,[PINTEREST_TAG_DISPLAY_NAME]:DIR_NAME$Q,[ADOBE_ANALYTICS_DISPLAY_NAME]:DIR_NAME$P,[LINKEDIN_INSIGHT_TAG_DISPLAY_NAME]:DIR_NAME$O,[REDDIT_PIXEL_DISPLAY_NAME]:DIR_NAME$N,[DRIP_DISPLAY_NAME]:DIR_NAME$M,[HEAP_DISPLAY_NAME]:DIR_NAME$L,[CRITEO_DISPLAY_NAME]:DIR_NAME$K,[MP_DISPLAY_NAME]:DIR_NAME$J,[QUALTRICS_DISPLAY_NAME]:DIR_NAME$I,[PROFITWELL_DISPLAY_NAME]:DIR_NAME$H,[SENTRY_DISPLAY_NAME]:DIR_NAME$G,[QUANTUMMETRIC_DISPLAY_NAME]:DIR_NAME$F,[SNAP_PIXEL_DISPLAY_NAME]:DIR_NAME$E,[POST_AFFILIATE_PRO_DISPLAY_NAME]:DIR_NAME$D,[GOOGLE_OPTIMIZE_DISPLAY_NAME]:DIR_NAME$C,[LAUNCHDARKLY_DISPLAY_NAME]:DIR_NAME$B,[GA360_DISPLAY_NAME]:DIR_NAME$A,[ADROLL_DISPLAY_NAME]:DIR_NAME$z,[DCM_FLOODLIGHT_DISPLAY_NAME]:DIR_NAME$y,[MATOMO_DISPLAY_NAME]:DIR_NAME$x,[VERO_DISPLAY_NAME]:DIR_NAME$w,[MOUSEFLOW_DISPLAY_NAME]:DIR_NAME$v,[ROCKERBOX_DISPLAY_NAME]:DIR_NAME$u,[CONVERTFLOW_DISPLAY_NAME]:DIR_NAME$t,[SNAPENGAGE_DISPLAY_NAME]:DIR_NAME$s,[LIVECHAT_DISPLAY_NAME]:DIR_NAME$r,[SHYNET_DISPLAY_NAME]:DIR_NAME$q,[WOOPRA_DISPLAY_NAME]:DIR_NAME$p,[ROLLBAR_DISPLAY_NAME]:DIR_NAME$o,[QUORA_PIXEL_DISPLAY_NAME]:DIR_NAME$n,[JUNE_DISPLAY_NAME]:DIR_NAME$m,[ENGAGE_DISPLAY_NAME]:DIR_NAME$l,[ITERABLE_DISPLAY_NAME]:DIR_NAME$k,[YANDEX_METRICA_DISPLAY_NAME]:DIR_NAME$j,[REFINER_DISPLAY_NAME]:DIR_NAME$i,[QUALAROO_DISPLAY_NAME]:DIR_NAME$h,[PODSIGHTS_DISPLAY_NAME]:DIR_NAME$g,[AXEPTIO_DISPLAY_NAME]:DIR_NAME$f,[SATISMETER_DISPLAY_NAME]:DIR_NAME$e,[MICROSOFT_CLARITY_DISPLAY_NAME]:DIR_NAME$d,[SENDINBLUE_DISPLAY_NAME]:DIR_NAME$c,[OLARK_DISPLAY_NAME]:DIR_NAME$b,[LEMNISK_DISPLAY_NAME]:DIR_NAME$a,[TIKTOK_ADS_DISPLAY_NAME]:DIR_NAME$9,[ACTIVE_CAMPAIGN_DISPLAY_NAME]:DIR_NAME$8,[SPRIG_DISPLAY_NAME]:DIR_NAME$7,[SPOTIFYPIXEL_DISPLAY_NAME]:DIR_NAME$6,[COMMANDBAR_DISPLAY_NAME]:DIR_NAME$5,[NINETAILED_DISPLAY_NAME]:DIR_NAME$4,[GAINSIGHT_PX_DISPLAY_NAME]:DIR_NAME$3,[XPIXEL_DISPLAY_NAME]:DIR_NAME$2,[USERPILOT_DISPLAY_NAME]:DIR_NAME$1,[COMSCORE_DISPLAY_NAME]:DIR_NAME};
|
|
1319
1323
|
|
|
1320
1324
|
/**
|
|
1321
1325
|
* Determines if the destination SDK code is evaluated
|
|
@@ -2915,16 +2919,27 @@
|
|
|
2915
2919
|
// TODO: should we pass the keys for all in order to validate or leave free as v1.1?
|
|
2916
2920
|
// Initializing all the enabled store because previous user data might be in different storage
|
|
2917
2921
|
// that needs auto migration
|
|
2918
|
-
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,errorHandler:this.errorHandler,logger:this.logger});}});}initializeStorageState(){let globalStorageType=state.storage
|
|
2919
|
-
const postConsentStorageOpts=state.consents.postConsent.value.storage;if(isDefined(postConsentStorageOpts?.type)||isDefined(postConsentStorageOpts?.entries)){globalStorageType=postConsentStorageOpts?.type;entriesOptions=postConsentStorageOpts?.entries;}
|
|
2920
|
-
|
|
2922
|
+
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,errorHandler:this.errorHandler,logger:this.logger});}});}initializeStorageState(){let globalStorageType=state.loadOptions.value.storage?.type;let entriesOptions=state.loadOptions.value.storage?.entries;// Use the storage options from post consent if anything is defined
|
|
2923
|
+
const postConsentStorageOpts=state.consents.postConsent.value.storage;if(isDefined(postConsentStorageOpts?.type)||isDefined(postConsentStorageOpts?.entries)){globalStorageType=postConsentStorageOpts?.type;entriesOptions=postConsentStorageOpts?.entries;}// Without the deprecated pre-consent storage strategy, the storage options decide what is
|
|
2924
|
+
// persisted before consent is given. Only the fallback changes: nothing is persisted unless
|
|
2925
|
+
// a storage type has been explicitly configured.
|
|
2926
|
+
const preConsentOpts=state.consents.preConsent.value;const isStorageFromLoadOptionsBeforeConsent=preConsentOpts.enabled===true&&!preConsentOpts.storage?.strategy;const defaultStorageType=isStorageFromLoadOptionsBeforeConsent?NO_STORAGE:DEFAULT_STORAGE_TYPE;// The unsupported values are reported where the options enter the SDK, so they are only
|
|
2927
|
+
// resolved here, against the default that applies to the current consent phase
|
|
2928
|
+
if(globalStorageType!==undefined&&!SUPPORTED_STORAGE_TYPES.includes(globalStorageType)){globalStorageType=undefined;}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
|
|
2929
|
+
let storageType=preConsentStorageType??configuredStorageType??globalStorageType??defaultStorageType;if(!SUPPORTED_STORAGE_TYPES.includes(storageType)){storageType=defaultStorageType;}const finalStorageType=this.getResolvedStorageTypeForEntry(storageType,sessionKey);if(finalStorageType!==NO_STORAGE){trulyAnonymousTracking=false;}storageEntries={...storageEntries,[sessionKey]:{type:finalStorageType,key:COOKIE_KEYS[storageKey]}};});n(()=>{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
|
|
2921
2930
|
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;}/**
|
|
2922
2931
|
* Create a new store
|
|
2923
2932
|
*/setStore(storeConfig){const storageEngine=getStorageEngine(storeConfig.type);this.stores[storeConfig.id]=new Store(storeConfig,storageEngine,this.pluginsManager);return this.stores[storeConfig.id];}/**
|
|
2924
2933
|
* Retrieve a store
|
|
2925
2934
|
*/getStore(id){return this.stores[id];}}
|
|
2926
2935
|
|
|
2927
|
-
const isValidSourceConfig=res=>isObjectLiteralAndNotNull(res)&&isObjectLiteralAndNotNull(res.source)&&!isNullOrUndefined(res.source.id)&&isObjectLiteralAndNotNull(res.source.config)&&Array.isArray(res.source.destinations);const isValidStorageType=storageType=>typeof storageType==='string'&&SUPPORTED_STORAGE_TYPES.includes(storageType)
|
|
2936
|
+
const isValidSourceConfig=res=>isObjectLiteralAndNotNull(res)&&isObjectLiteralAndNotNull(res.source)&&!isNullOrUndefined(res.source.id)&&isObjectLiteralAndNotNull(res.source.config)&&Array.isArray(res.source.destinations);const isValidStorageType=storageType=>typeof storageType==='string'&&SUPPORTED_STORAGE_TYPES.includes(storageType);/**
|
|
2937
|
+
* Warns about the unsupported storage types in the storage options. It only reports them, as the
|
|
2938
|
+
* applicable default depends on the consent phase and is determined at resolution time.
|
|
2939
|
+
* @param storageOpts Storage options from the load API options or the consent API options
|
|
2940
|
+
* @param context Logger context
|
|
2941
|
+
* @param logger Logger instance
|
|
2942
|
+
*/const validateStorageOptions=(storageOpts,context,logger)=>{if(!isObjectLiteralAndNotNull(storageOpts)){return;}const{type,entries}=storageOpts;if(isDefined(type)&&!isValidStorageType(type)){logger?.warn(STORAGE_TYPE_VALIDATION_WARNING(context,type));}if(entries){Object.entries(entries).forEach(([entryKey,entryOpts])=>{const entryType=entryOpts?.type;if(isDefined(entryType)&&!isValidStorageType(entryType)){logger?.warn(UNSUPPORTED_STORAGE_ENTRY_TYPE_WARNING(context,entryKey,entryType));}});}};const getTopDomain=url=>{// Create a URL object
|
|
2928
2943
|
const urlObj=new URL(url);// Extract the host and protocol
|
|
2929
2944
|
const{host,protocol}=urlObj;// Split the host into parts
|
|
2930
2945
|
const parts=host.split('.');let topDomain;// Handle different cases, especially for co.uk or similar TLDs
|
|
@@ -2961,7 +2976,9 @@
|
|
|
2961
2976
|
* Validates and normalizes the consent options provided by the user
|
|
2962
2977
|
* @param options Consent options provided by the user
|
|
2963
2978
|
* @returns Validated and normalized consent options
|
|
2964
|
-
*/const getValidPostConsentOptions=options=>{const validOptions={sendPageEvent:false,trackConsent:false,discardPreConsentEvents:false}
|
|
2979
|
+
*/const getValidPostConsentOptions=(options,logger)=>{const validOptions={sendPageEvent:false,trackConsent:false,discardPreConsentEvents:false};// The storage options persist across consent API invocations, so an invocation that does not
|
|
2980
|
+
// provide them leaves the storage as it is
|
|
2981
|
+
validOptions.storage=state.consents.postConsent.value.storage;if(isObjectLiteralAndNotNull(options)){const clonedOptions=clone(options);if(isDefined(clonedOptions.storage)){validateStorageOptions(clonedOptions.storage,CONSENT_API,logger);validOptions.storage=clonedOptions.storage;}if(isNonEmptyObject(clonedOptions.integrations)){validOptions.integrations=clonedOptions.integrations;}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
|
|
2965
2982
|
validOptions.consentManagement=mergeDeepRight(clonedOptions.consentManagement,{enabled:state.consents.enabled.value});}}return validOptions;};/**
|
|
2966
2983
|
* Validates if the input is a valid consents data
|
|
2967
2984
|
* @param value Input consents data
|
|
@@ -3007,10 +3024,16 @@
|
|
|
3007
3024
|
* If the sameDomainCookiesOnly flag is not set and the cookie domain is provided(not top level domain),
|
|
3008
3025
|
* and the data service host is different from the provided cookie domain, then we disable server-side cookies
|
|
3009
3026
|
* ex: provided cookie domain: 'random.com', data service host: 'sub.example.com'
|
|
3010
|
-
*/if(!sameDomainCookiesOnly&&useExactDomain&&dataServiceHost!==removeLeadingPeriod(providedCookieDomain)){sscEnabled=false;logger.warn(SERVER_SIDE_COOKIE_FEATURE_OVERRIDE_WARNING(CONFIG_MANAGER,providedCookieDomain,dataServiceHost));}}else {sscEnabled=false;}}return {sscEnabled,cookieOptions,finalDataServiceUrl};};const updateStorageStateFromLoadOptions=logger=>{const{storage:storageOptsFromLoad}=state.loadOptions.value
|
|
3027
|
+
*/if(!sameDomainCookiesOnly&&useExactDomain&&dataServiceHost!==removeLeadingPeriod(providedCookieDomain)){sscEnabled=false;logger.warn(SERVER_SIDE_COOKIE_FEATURE_OVERRIDE_WARNING(CONFIG_MANAGER,providedCookieDomain,dataServiceHost));}}else {sscEnabled=false;}}return {sscEnabled,cookieOptions,finalDataServiceUrl};};const updateStorageStateFromLoadOptions=logger=>{const{storage:storageOptsFromLoad}=state.loadOptions.value;// Only reported here. The applicable default depends on the consent phase, so the unsupported
|
|
3028
|
+
// values are resolved in the store manager.
|
|
3029
|
+
validateStorageOptions(storageOptsFromLoad,CONFIG_MANAGER,logger);let storageEncryptionVersion=storageOptsFromLoad?.encryption?.version;const encryptionPluginName=storageEncryptionVersion&&StorageEncryptionVersionsToPluginNameMap[storageEncryptionVersion];if(!isUndefined(storageEncryptionVersion)&&isUndefined(encryptionPluginName)){// set the default encryption plugin
|
|
3011
3030
|
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
|
|
3012
|
-
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));}const{sscEnabled,finalDataServiceUrl,cookieOptions}=getServerSideCookiesStateData(logger);n(()=>{state.storage.
|
|
3013
|
-
const preConsentOpts=state.loadOptions.value.preConsent;
|
|
3031
|
+
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));}const{sscEnabled,finalDataServiceUrl,cookieOptions}=getServerSideCookiesStateData(logger);n(()=>{state.storage.cookie.value=cookieOptions;state.serverCookies.isEnabledServerSideCookies.value=sscEnabled;state.serverCookies.dataServiceUrl.value=finalDataServiceUrl;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
|
|
3032
|
+
const preConsentOpts=state.loadOptions.value.preConsent;const configuredStrategy=preConsentOpts?.storage?.strategy;if(isDefined(configuredStrategy)){logger.warn(DEPRECATED_PRE_CONSENT_STORAGE_STRATEGY(CONFIG_MANAGER));}// The storage load API options drive the pre-consent phase only when it is explicitly enabled,
|
|
3033
|
+
// so an existing configuration keeps persisting nothing before consent is given. Enabling it
|
|
3034
|
+
// takes precedence over the deprecated strategy, otherwise a migration that leaves the strategy
|
|
3035
|
+
// in place would silently do nothing.
|
|
3036
|
+
let storageStrategy;if(preConsentOpts?.storage?.enabled!==true){storageStrategy=configuredStrategy??DEFAULT_PRE_CONSENT_STORAGE_STRATEGY;const StorageStrategies=['none','session','anonymousId'];if(!StorageStrategies.includes(storageStrategy)){storageStrategy=DEFAULT_PRE_CONSENT_STORAGE_STRATEGY;logger.warn(UNSUPPORTED_PRE_CONSENT_STORAGE_STRATEGY(CONFIG_MANAGER,configuredStrategy,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
|
|
3014
3037
|
// if it is not already initialized and
|
|
3015
3038
|
// if consent management is enabled
|
|
3016
3039
|
enabled:state.loadOptions.value.preConsent?.enabled===true&&initialized===false&&enabled===true,storage:{strategy:storageStrategy},events:{delivery:eventsDeliveryType}};});};/**
|
|
@@ -3053,8 +3076,10 @@
|
|
|
3053
3076
|
* A function to validate, construct and store loadOption, lifecycle, source and destination
|
|
3054
3077
|
* config related information in global state
|
|
3055
3078
|
*/init(){const{logLevel,configUrl,lockIntegrationsVersion,lockPluginsVersion,destSDKBaseURL,pluginsSDKBaseURL,integrations}=state.loadOptions.value;// determine the path to fetch integration SDK from
|
|
3056
|
-
const intgCdnUrl=getIntegrationsCDNPath(APP_VERSION,lockIntegrationsVersion,destSDKBaseURL,this.logger);if(isNull(intgCdnUrl)){return;}let pluginsCDNPath
|
|
3057
|
-
|
|
3079
|
+
const intgCdnUrl=getIntegrationsCDNPath(APP_VERSION,lockIntegrationsVersion,destSDKBaseURL,this.logger);if(isNull(intgCdnUrl)){return;}let pluginsCDNPath;// to the logger does not pin the logger at the default level and swallow the
|
|
3080
|
+
// warnings emitted while processing the rest of the load options
|
|
3081
|
+
if(logLevel){state.lifecycle.logLevel.value=logLevel;}this.attachEffects();state.lifecycle.activeDataplaneUrl.value=removeTrailingSlashes(state.lifecycle.dataPlaneUrl.value);updateStorageStateFromLoadOptions(this.logger);updateConsentsStateFromLoadOptions(this.logger);updateDataPlaneEventsStateFromLoadOptions(this.logger);// set application lifecycle state in global state
|
|
3082
|
+
n(()=>{state.lifecycle.integrationsCDNPath.value=intgCdnUrl;state.lifecycle.pluginsCDNPath.value=pluginsCDNPath;state.lifecycle.sourceConfigUrl.value=getSourceConfigURL(configUrl,state.lifecycle.writeKey.value,lockIntegrationsVersion,lockPluginsVersion,this.logger);state.metrics.metricsServiceUrl.value=`${state.lifecycle.activeDataplaneUrl.value}/${METRICS_SERVICE_ENDPOINT}`;// Data in the loadOptions state is already normalized
|
|
3058
3083
|
state.nativeDestinations.loadOnlyIntegrations.value=integrations;});this.getConfig();}/**
|
|
3059
3084
|
* Handle errors
|
|
3060
3085
|
*/onError(error,customMessage,groupingHash){this.errorHandler.onError({error,context:CONFIG_MANAGER,customMessage,groupingHash});}/**
|
|
@@ -3194,9 +3219,9 @@
|
|
|
3194
3219
|
*/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);/**
|
|
3195
3220
|
* Generate a new anonymousId
|
|
3196
3221
|
* @returns string anonymousID
|
|
3197
|
-
*/const generateAnonymousId=()=>generateUUID();const getFinalResetOptions=options=>{// Legacy behavior: toggle only anonymousId without mutating defaults
|
|
3222
|
+
*/const generateAnonymousId=()=>generateUUID();const isKnownResetEntry=key=>Object.prototype.hasOwnProperty.call(DEFAULT_RESET_OPTIONS.entries,key);const getFinalResetOptions=options=>{// Legacy behavior: toggle only anonymousId without mutating defaults
|
|
3198
3223
|
if(isBoolean(options)){const{entries,...rest}=DEFAULT_RESET_OPTIONS;return {...rest,entries:{...entries,anonymousId:options}};}// Override any defaults with the user provided options
|
|
3199
|
-
if(isObjectLiteralAndNotNull(options)&&isObjectLiteralAndNotNull(options.entries)){return mergeDeepRight(DEFAULT_RESET_OPTIONS,
|
|
3224
|
+
if(isObjectLiteralAndNotNull(options)&&isObjectLiteralAndNotNull(options.entries)){const optionEntries=options.entries;const validEntries=Object.keys(optionEntries).reduce((entries,key)=>{if(isKnownResetEntry(key)){const value=optionEntries[key];if(isBoolean(value)){entries[key]=value;}}return entries;},{});return mergeDeepRight(DEFAULT_RESET_OPTIONS,{entries:validEntries});}return {...DEFAULT_RESET_OPTIONS};};
|
|
3200
3225
|
|
|
3201
3226
|
/**
|
|
3202
3227
|
* To get the page properties for context object
|
|
@@ -3307,8 +3332,17 @@
|
|
|
3307
3332
|
*/addEvent(event,customContext){this.userSessionManager.refreshSession();const rudderEvent=this.eventFactory.create(event,customContext);this.eventRepository.enqueue(rudderEvent,event.callback);}}
|
|
3308
3333
|
|
|
3309
3334
|
class UserSessionManager{/**
|
|
3335
|
+
* The single debounce timer shared by every key. Server-side cookie writes are collected
|
|
3336
|
+
* into one request rather than one per key.
|
|
3337
|
+
*//**
|
|
3338
|
+
* Session keys waiting to be written, mapped to the cookie name each one is stored under.
|
|
3339
|
+
* Drained into a single request when the debounce timer fires.
|
|
3340
|
+
*//**
|
|
3310
3341
|
* Tracks whether a server-side cookie setting request is in progress or not.
|
|
3311
|
-
|
|
3342
|
+
*//**
|
|
3343
|
+
* The value each key was last handed to storage with, recorded by the sync effect.
|
|
3344
|
+
* Anything else in the state means storage has not been given the current value yet.
|
|
3345
|
+
*/constructor(pluginsManager,storeManager,httpClient,errorHandler,logger){this.storeManager=storeManager;this.pluginsManager=pluginsManager;this.logger=logger;this.errorHandler=errorHandler;this.httpClient=httpClient;this.onError=this.onError.bind(this);this.serverSideCookiesDebounceTimer=0;this.serverSideCookiesPending={};this.serverSideCookiesRequestInProgress={};this.lastSyncedValues={};}/**
|
|
3312
3346
|
* Initialize User session with values from storage
|
|
3313
3347
|
*/init(){this.syncStorageDataToState();// Register the effect to sync with storage
|
|
3314
3348
|
this.registerEffects();}syncStorageDataToState(){this.migrateStorageIfNeeded();this.migrateDataFromPreviousStorage();// get the values from storage and set it again
|
|
@@ -3346,23 +3380,52 @@
|
|
|
3346
3380
|
const originalCookieValues={};sessionKeys.forEach(sessionKey=>{originalCookieValues[sessionToCookiesMap[sessionKey].name]=store?.get(sessionToCookiesMap[sessionKey].name);});const clearInProgressFlags=()=>{sessionKeys.forEach(sessionKey=>{this.serverSideCookiesRequestInProgress[sessionKey]=false;});};const setCookiesClientSide=()=>{getCurrentCookieValuesFromState().forEach(each=>{if(cb){cb(each.name,each.value);}});};try{const expectedCookieValues={};sessionKeys.forEach(sessionKey=>{expectedCookieValues[sessionToCookiesMap[sessionKey].name]=state.session[sessionKey].value;});// encrypt cookies values
|
|
3347
3381
|
const encryptedCookieData=this.getEncryptedCookieData(getCurrentCookieValuesFromState(),store);if(encryptedCookieData.length>0){// make request to data service to set the cookie from server side
|
|
3348
3382
|
this.makeRequestToSetCookie(encryptedCookieData,(res,details)=>{// Mark the cookie req status as done
|
|
3349
|
-
clearInProgressFlags();if(details?.xhr?.status===200){
|
|
3383
|
+
clearInProgressFlags();if(details?.xhr?.status===200){// Only the cookies that were actually sent can be reported as unapplied, so
|
|
3384
|
+
// both halves of the diagnostic are drawn from the same set
|
|
3385
|
+
const sentCookieNames=new Set(encryptedCookieData.map(each=>each.name));const unappliedCookies=[];getCurrentCookieValuesFromState().forEach(cData=>{const originalCookieVal=originalCookieValues[cData.name];const currentCookieVal=store?.get(cData.name);// Check if the expected cookie values are set.
|
|
3350
3386
|
if(stringifyWithoutCircular(expectedCookieValues[cData.name],false,[])!==stringifyWithoutCircular(currentCookieVal,false,[])){// It's fine if the values don't match as other active SDK sessions might have updated the cookie values
|
|
3351
3387
|
// or other cookie requests might have updated the cookie value.
|
|
3352
|
-
//
|
|
3353
|
-
|
|
3388
|
+
// Left exactly as the request found it, so the server did not apply this
|
|
3389
|
+
// write. A value that moved to something else was set by another tab or
|
|
3390
|
+
// request, which is expected rather than a failure.
|
|
3391
|
+
if(sentCookieNames.has(cData.name)&&stringifyWithoutCircular(originalCookieVal,false,[])===stringifyWithoutCircular(currentCookieVal,false,[])){unappliedCookies.push(cData.name);}// Log an error only when cookie didn't exist previously and currently also doesn't exist.
|
|
3392
|
+
if(isNull(originalCookieVal)&&isNull(currentCookieVal)){this.logger.error(FAILED_SETTING_COOKIE_FROM_SERVER_ERROR(cData.name));}if(cb){cb(cData.name,cData.value);}}});// A batch coming back with cookies missing points at something shared rather
|
|
3393
|
+
// than at any one cookie, so say so once instead of leaving the operator with
|
|
3394
|
+
// a per-cookie error and no cause. Purely diagnostic: it never changes how the
|
|
3395
|
+
// SDK sends the next batch.
|
|
3396
|
+
//
|
|
3397
|
+
// The message lists candidate causes rather than asserting one, because this
|
|
3398
|
+
// condition cannot tell them apart. A data service that collapses the batch
|
|
3399
|
+
// still sets the last cookie, so exactly one survives, whereas rejected cookie
|
|
3400
|
+
// attributes usually leave none of them set.
|
|
3401
|
+
// Counted from what was actually sent, not from the queued keys: encryption can
|
|
3402
|
+
// drop a key, and reporting it as sent would overstate the batch.
|
|
3403
|
+
if(encryptedCookieData.length>1&&unappliedCookies.length>0&&!state.serverCookies.isCollapsedBatchErrorLogged.value){state.serverCookies.isCollapsedBatchErrorLogged.value=true;this.logger.error(COLLAPSED_COOKIE_BATCH_ERROR(unappliedCookies,encryptedCookieData.length));}}else {this.logger.error(DATA_SERVER_REQUEST_FAIL_ERROR(details?.xhr?.status));setCookiesClientSide();}});}else {setCookiesClientSide();// Mark the cookie req status as done
|
|
3354
3404
|
clearInProgressFlags();}}catch(e){this.onError(e,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR,FAILED_SETTING_COOKIE_FROM_SERVER_GLOBAL_ERROR);setCookiesClientSide();// Mark the cookie req status as done
|
|
3355
3405
|
clearInProgressFlags();}}/**
|
|
3406
|
+
* A function to send every queued server-side cookie as a single request
|
|
3407
|
+
*/flushServerSideCookies(){// The timer has fired, so drop its id rather than leaving a stale one behind
|
|
3408
|
+
this.serverSideCookiesDebounceTimer=0;const sessionToCookiesMap=Object.entries(this.serverSideCookiesPending).reduce((acc,[sessionKey,cookieName])=>{acc[sessionKey]={name:cookieName};return acc;},{});// Drain before sending, so anything that changes while the request is in flight is
|
|
3409
|
+
// queued for the next batch rather than being sent twice
|
|
3410
|
+
this.serverSideCookiesPending={};if(Object.keys(sessionToCookiesMap).length===0){return;}// Every batched key is backed by cookie storage by construction, so they share a store
|
|
3411
|
+
const curStore=this.storeManager.getStore(storageClientDataStoreNameMap[COOKIE_STORAGE]);this.setServerSideCookies(sessionToCookiesMap,(cookieName,cookieValue)=>{curStore?.set(cookieName,cookieValue);},curStore);}/**
|
|
3356
3412
|
* A function to sync values in storage
|
|
3357
3413
|
* @param sessionKey
|
|
3358
3414
|
*/syncValueToStorage(sessionKey){const entries=state.storage.entries.value;const storageType=entries[sessionKey]?.type;if(isStorageTypeValidForStoringData(storageType)){const curStore=this.storeManager.getStore(storageClientDataStoreNameMap[storageType]);const cookieName=entries[sessionKey]?.key;const cookieValue=state.session[sessionKey].value;if(cookieValue&&(isString(cookieValue)||isNonEmptyObject(cookieValue))){// if useServerSideCookies load option is set to true
|
|
3359
3415
|
// set the cookie from server side
|
|
3360
3416
|
if(state.serverCookies.isEnabledServerSideCookies.value&&storageType===COOKIE_STORAGE){// Mark the requests as in progress.
|
|
3361
|
-
this.serverSideCookiesRequestInProgress[sessionKey]=true
|
|
3362
|
-
|
|
3417
|
+
this.serverSideCookiesRequestInProgress[sessionKey]=true;// Queue this key and restart the shared debounce, so everything that changes in
|
|
3418
|
+
// the same window goes to the data service as one request instead of one each.
|
|
3419
|
+
this.serverSideCookiesPending[sessionKey]=cookieName;// Restarting the shared timer means a steady stream of changes to any key can
|
|
3420
|
+
// keep postponing the flush for every other key, where per-key timers only ever
|
|
3421
|
+
// delayed their own. That needs changes arriving closer together than the
|
|
3422
|
+
// debounce, continuously, so it is accepted rather than capped with a max wait.
|
|
3423
|
+
if(this.serverSideCookiesDebounceTimer){globalThis.clearTimeout(this.serverSideCookiesDebounceTimer);}this.serverSideCookiesDebounceTimer=globalThis.setTimeout(()=>{this.flushServerSideCookies();},SERVER_SIDE_COOKIES_DEBOUNCE_TIME);}else {curStore?.set(cookieName,cookieValue);}}else {curStore?.remove(cookieName);}}}/**
|
|
3363
3424
|
* Function to update storage whenever state value changes
|
|
3364
3425
|
*/registerEffects(){// This will work as long as the user session entry key names are same as the state keys
|
|
3365
|
-
USER_SESSION_KEYS.forEach(sessionKey=>{j(()=>{
|
|
3426
|
+
USER_SESSION_KEYS.forEach(sessionKey=>{j(()=>{// Read before syncing so the effect subscribes to the signal, and record after
|
|
3427
|
+
// so that reads can tell whether storage has been given the current value yet
|
|
3428
|
+
const value=state.session[sessionKey].value;this.syncValueToStorage(sessionKey);this.lastSyncedValues[sessionKey]=value;});});}/**
|
|
3366
3429
|
* Sets anonymous id in the following precedence:
|
|
3367
3430
|
*
|
|
3368
3431
|
* 1. anonymousId: Id directly provided to the function.
|
|
@@ -3379,12 +3442,27 @@
|
|
|
3379
3442
|
// This is needed for entries that are fetched from the storage
|
|
3380
3443
|
// during the current session (for example, session info)
|
|
3381
3444
|
this.migrateStorageIfNeeded([store],[sessionKey]);const storageKey=entries[sessionKey]?.key;return store?.get(storageKey)??null;}return null;}getExternalAnonymousIdByCookieName(key){const storageEngine=getStorageEngine(COOKIE_STORAGE);if(storageEngine?.isEnabled){return storageEngine.getItem(key)??null;}return null;}/**
|
|
3382
|
-
* Fetches the value for a session key. Preferably from storage,
|
|
3383
|
-
*
|
|
3445
|
+
* Fetches the value for a session key. Preferably from storage, so that changes made by
|
|
3446
|
+
* other tabs are picked up. Falls back to the state whenever storage is known to be
|
|
3447
|
+
* behind it.
|
|
3384
3448
|
* @param sessionKey - The session key to fetch the value for
|
|
3385
3449
|
* @returns - The value for the session key
|
|
3386
|
-
*/getUserSessionValue(sessionKey){//
|
|
3387
|
-
|
|
3450
|
+
*/getUserSessionValue(sessionKey){// peek() rather than value, as this is a plain read; subscribing here would make
|
|
3451
|
+
// every enclosing effect depend on all the user session signals
|
|
3452
|
+
const stateValue=state.session[sessionKey].peek();// Until the sync effect has run for this key there is nothing to compare against, so
|
|
3453
|
+
// storage stays authoritative. That is the case throughout init, where the state is
|
|
3454
|
+
// still being hydrated from storage and the effects are not registered yet.
|
|
3455
|
+
//
|
|
3456
|
+
// The persistence check matters for storage types that hold nothing at all ('none'),
|
|
3457
|
+
// where the state can never be ahead of storage because there is no destination.
|
|
3458
|
+
// Without it, a session started during a replay would survive the replay and then
|
|
3459
|
+
// disappear on the next event, once the sync effect had caught up.
|
|
3460
|
+
const isSyncRecorded=this.isPersistenceEnabledForStorageEntry(sessionKey)&&sessionKey in this.lastSyncedValues;// Storage has not been given this value yet. Buffered events are replayed from within
|
|
3461
|
+
// the lifecycle effect, so the sync effects are queued behind that batch and do not
|
|
3462
|
+
// run in between, leaving storage behind the state for the whole replay. Direct state
|
|
3463
|
+
// writes such as start(), end() and reset() are in the same position.
|
|
3464
|
+
if(isSyncRecorded&&stateValue!==this.lastSyncedValues[sessionKey]){return stateValue;}// Storage has the value, but for server-side cookies it is only on its way there.
|
|
3465
|
+
if(this.serverSideCookiesRequestInProgress[sessionKey]){return stateValue;}// Otherwise, fetch the value from storage.
|
|
3388
3466
|
return this.getEntryValue(sessionKey);}/**
|
|
3389
3467
|
* Fetches User Id
|
|
3390
3468
|
* @returns
|
|
@@ -3598,7 +3676,7 @@
|
|
|
3598
3676
|
getUserTraits(){return state.session.userTraits.value;}// eslint-disable-next-line class-methods-use-this
|
|
3599
3677
|
getGroupId(){return state.session.groupId.value;}// eslint-disable-next-line class-methods-use-this
|
|
3600
3678
|
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
|
|
3601
|
-
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.data.value=consentsData;});// Update consents data in state
|
|
3679
|
+
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,this.logger);const{initialized,consentsData}=getConsentManagementData(state.consents.postConsent.value.consentManagement,this.logger);state.consents.initialized.value=initialized;state.consents.data.value=consentsData;});// Update consents data in state
|
|
3602
3680
|
if(state.consents.enabled.value&&!state.consents.initialized.value){this.pluginsManager?.invokeSingle(`consentManager.updateConsentsInfo`,state,this.storeManager,this.logger);}// Re-init store manager
|
|
3603
3681
|
this.storeManager?.initializeStorageState();// Re-init user session manager
|
|
3604
3682
|
this.userSessionManager?.syncStorageDataToState();// Resume event manager to process the events to destinations
|