From 2fa424532181a5928bc811d0fd7014c039e69b9f Mon Sep 17 00:00:00 2001 From: Cris Ryan Tan Date: Mon, 24 Aug 2026 13:48:01 -0400 Subject: [PATCH 1/2] feat: sync Rokt kit with upstream v1.35.0 Bring the monorepo kit to the latest standalone release while preserving v3 packaging metadata. --- kits/rokt/CHANGELOG.md | 72 ++ kits/rokt/dist/Rokt-Kit.common.js | 2 +- kits/rokt/dist/Rokt-Kit.common.js.map | 2 +- kits/rokt/dist/Rokt-Kit.d.ts | 34 + kits/rokt/dist/Rokt-Kit.esm.js | 829 ++++++++++++-------- kits/rokt/dist/Rokt-Kit.esm.js.map | 2 +- kits/rokt/dist/Rokt-Kit.iife.js | 3 +- kits/rokt/dist/Rokt-Kit.iife.js.map | 2 +- kits/rokt/package-lock.json | 4 +- kits/rokt/package.json | 2 +- kits/rokt/src/Rokt-Kit.ts | 256 +++--- kits/rokt/src/pageViewStorage.ts | 151 ++++ kits/rokt/src/storage.ts | 65 ++ kits/rokt/src/utils.ts | 32 + kits/rokt/test/src/pageViewStorage.spec.ts | 311 ++++++++ kits/rokt/test/src/storage.spec.ts | 175 +++++ kits/rokt/test/src/tests.spec.ts | 859 +++++++++++++++++++-- kits/rokt/test/src/utils.spec.ts | 96 +++ kits/rokt/test/vitest.setup.ts | 1 + 19 files changed, 2376 insertions(+), 522 deletions(-) create mode 100644 kits/rokt/src/pageViewStorage.ts create mode 100644 kits/rokt/src/storage.ts create mode 100644 kits/rokt/src/utils.ts create mode 100644 kits/rokt/test/src/pageViewStorage.spec.ts create mode 100644 kits/rokt/test/src/storage.spec.ts create mode 100644 kits/rokt/test/src/utils.spec.ts diff --git a/kits/rokt/CHANGELOG.md b/kits/rokt/CHANGELOG.md index 29c605430..ee975e15b 100644 --- a/kits/rokt/CHANGELOG.md +++ b/kits/rokt/CHANGELOG.md @@ -1,3 +1,75 @@ +# [1.35.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.34.1...v1.35.0) (2026-08-21) + + +### Features + +* capture UTM params from page views and forward to selectPlacements ([#129](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/129)) ([e1f70d1](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/e1f70d132c06f30efd15a45dbd34285b51715457)) + +## [1.34.1](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.34.0...v1.34.1) (2026-08-20) + + +### Bug Fixes + +* retry page-view storage writes on quota failure and log eviction ([#126](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/126)) ([2e88327](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/2e88327d658e9adca21948ed736c81a9e74d262c)) + +# [1.34.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.33.4...v1.34.0) (2026-08-19) + + +### Features + +* send the mParticle device id as a selectPlacements attribute ([#121](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/121)) ([bb754ca](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/bb754ca5d4a313358c3cb9ec612ce98009a46724)) + +## [1.33.4](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.33.3...v1.33.4) (2026-08-18) + + +### Bug Fixes + +* stop retrying legacy page-view migration on every page load ([#118](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/118)) ([c4772f8](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/c4772f8c6b490acaf81f211ad369474bf683fc0b)) + +## [1.33.3](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.33.2...v1.33.3) (2026-08-18) + + +### Bug Fixes + +* limit page-view history to 25 most-recent records ([#123](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/123)) ([26f5a5b](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/26f5a5b1f1dc39ad02f896a2c8b6a900c24a56dd)) + +## [1.33.2](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.33.1...v1.33.2) (2026-08-18) + + +### Bug Fixes + +* add reason codes to PAGE_VIEW_CAPTURE_FAILED logs ([#119](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/119)) ([a4e5255](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/a4e5255ce5b749b406f0938cb8ad7acb5fc1bacc)) + +## [1.33.1](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.33.0...v1.33.1) (2026-08-17) + + +### Bug Fixes + +* read the mParticle session id from the public sessionManager facade ([#117](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/117)) ([ae19fd6](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/ae19fd690feafdfd7240ec296588008274370d9c)) + +# [1.33.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.32.0...v1.33.0) (2026-08-17) + + +### Features + +* send the current mParticle session id as a selectPlacements attribute ([#116](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/116)) ([b96ef4a](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/b96ef4a8474c4eb5cddfb9046c469cc666d6b648)) + +# [1.32.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.31.0...v1.32.0) (2026-08-14) + + +### Features + +* allow a full origin in domain so the launcher can load from a bundled extension ([#115](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/115)) ([c13e719](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/c13e719f051587a9e1a83e1f4a4c4c63bb37c743)) + +# [1.31.0](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.30.2...v1.31.0) (2026-08-14) + + +### Features + +* cap page-view storage by byte budget instead of fixed count ([#114](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/114)) ([4b041a5](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/4b041a5065a74c589640ec147fcd6b4d3a48b78f)) +* capture page title and canonical URL in page view events ([#112](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/112)) ([7b65606](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/7b6560624832e99f2e8f894a1257cd58df587e5a)) +* namespace page-view localStorage key and migrate legacy key ([#113](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/issues/113)) ([b428b15](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/commit/b428b15c101786885d462f3c27125113c558f534)) + ## [1.30.2](https://github.com/mparticle-integrations/mparticle-javascript-integration-rokt/compare/v1.30.1...v1.30.2) (2026-08-05) diff --git a/kits/rokt/dist/Rokt-Kit.common.js b/kits/rokt/dist/Rokt-Kit.common.js index c174b6984..a4f463950 100644 --- a/kits/rokt/dist/Rokt-Kit.common.js +++ b/kits/rokt/dist/Rokt-Kit.common.js @@ -1,2 +1,2 @@ -"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const B=["billingaddress1","billingaddress2","billingcity","billingstate","billingzipcode","cartitems","ccbin","confirmationref","conversiontype","country","couponcode","currency","language","paymentserviceprovider","paymentserviceproviderattribute","paymenttype","shippingaddress1","shippingcity","shippingcountry","shippingmethod","shippingstate","shippingzipcode","totalprice"],J=new Set(B);function G(n){return J.has(n.toLowerCase())}function w(n){const t={},e=n||{},i=Object.keys(e);for(let r=0;r=$)return;const r=window.__rokt_li_guid__;if(!r)return;const s=window.location.href.split("?")[0].split("#")[0],o="version="+encodeURIComponent(t??"")+"&launcherInstanceGuid="+encodeURIComponent(r)+"&pageUrl="+encodeURIComponent(s);O("https://"+(n||"apps.rokt.com")+"/v1/wsdk-init/index.html?"+o),O("https://"+X+"/v1/wsdk-init/index.html?"+o+"&isControl=true")}function ut(){return typeof window<"u"&&!!window.location?.search?.toLowerCase().includes("mp_enable_logging=true")}function dt(){return typeof window<"u"?window.location?.href:void 0}function ht(){return typeof window<"u"?window.navigator?.userAgent:void 0}class q{constructor(){this._logCount={}}incrementAndCheck(t){const i=(this._logCount[t]||0)+1;return this._logCount[t]=i,i>at}}class C{constructor(t,e,i,r,s){this._reporter="mp-wsdk";const o=t.isLoggingEnabled;this._integrationName=e||"",this._launcherInstanceGuid=i,this._accountId=r||null,this._rateLimiter=s||new q,this._isEnabled=ut()||o}send(t,e,i,r,s,o){if(!(!this._isEnabled||this._rateLimiter.incrementAndCheck(e)))try{const c={additionalInformation:{message:i,version:this._integrationName},severity:e,code:r||N.UNKNOWN_ERROR,url:dt(),deviceInfo:ht(),stackTrace:s,reporter:this._reporter,integration:this._integrationName},u={Accept:"text/plain;charset=UTF-8","Content-Type":"application/json","rokt-launcher-version":this._integrationName,"rokt-wsdk-version":"joint"};this._launcherInstanceGuid&&(u["rokt-launcher-instance-guid"]=this._launcherInstanceGuid),this._accountId&&(u["rokt-account-id"]=this._accountId),fetch(t,{method:"POST",headers:u,body:JSON.stringify(c)}).then(l=>{if(!l.ok){const h=new Error("HTTP "+l.status+" from log endpoint");throw h.statusCode=l.status,h}}).catch(l=>{console.error("ReportingTransport: Failed to send log",l),o&&o(l)})}catch(c){console.error("ReportingTransport: Failed to send log",c),o&&o(c)}}}class H{constructor(t,e,i,r,s){this._transport=new C(t,e,i,r,s),this._errorUrl=z(t?.errorUrl,t?.integrationDomain,ot)}report(t){if(!t)return;const e=t.severity||I.ERROR;this._transport.send(this._errorUrl,e,t.message,t.code,t.stackTrace)}}class W{constructor(t,e,i,r,s,o){this._transport=new C(t,i,r,s,o),this._loggingUrl=z(t?.loggingUrl,t?.integrationDomain,st),this._errorReportingService=e}log(t){t&&this._transport.send(this._loggingUrl,I.INFO,t.message,t.code,void 0,e=>{if(this._errorReportingService){const i=typeof e.statusCode=="number";this._errorReportingService.report({message:"LoggingService: Failed to send log: "+e.message,code:N.LOG_DELIVERY_FAILURE,severity:i?I.ERROR:I.WARNING})}})}}const p=class p{constructor(){this.name=d,this.id=b,this.moduleId=b,this.isInitialized=!1,this.launcher=null,this.filters={},this.userAttributes={},this.userIdentifiedInWorkspace=!1,this.testHelpers=null,this.placementEventMappingLookup={},this.placementEventAttributeMappingLookup={},this.integrationName=null,this.errorReportingService=null,this.loggingService=null,this._thankYouElementOnLoadCallback=null,this._isThankYouElementLoaded=!1,this._workspaceSearchInFlightPromise=null}getEventAttributeValue(t,e){const i=t&&t.EventAttributes;return!i||typeof i[e]>"u"?null:i[e]}doesEventAttributeConditionMatch(t,e){if(!t||!m(t.operator))return!1;const i=t.operator.toLowerCase(),r=t.attributeValue;return i==="exists"?e!==null:e==null?!1:i==="equals"?String(e)===String(r):i==="contains"?String(e).indexOf(String(r))!==-1:!1}doesEventMatchRule(t,e){if(!e||!m(e.eventAttributeKey))return!1;const i=e.conditions;if(!Array.isArray(i))return!1;const r=this.getEventAttributeValue(t,e.eventAttributeKey);if(i.length===0)return r!==null;for(let s=0;s{await ct(i,c),this.initRoktLauncher(c)}).catch(c=>{console.error("Error creating Rokt launcher:",c)})}initRoktLauncher(t){window.Rokt&&(window.Rokt.currentLauncher=t),this.launcher=t;const e=a().Rokt?.filters;e?(this.filters=e,e.filteredUser?this._workspaceSearchInFlightPromise=this.search(e.filteredUser):console.warn("Rokt Kit: No filtered user has been set.")):console.warn("Rokt Kit: No filters have been set."),this.isInitialized=!0,F(this.domain,this.integrationName),a().Rokt.attachKit(this)}fetchOptimizely(){const t=a()._getActiveForwarders().filter(e=>e.name==="Optimizely");try{if(t.length>0&&window.optimizely){const e=window.optimizely.get("state");return!e||!e.getActiveExperimentIds?{}:e.getActiveExperimentIds().reduce((s,o)=>(s["rokt.custom.optimizely.experiment."+o+".variationId"]=e.getVariationMap()[o].id,s),{})}}catch(e){console.error("Error fetching Optimizely attributes:",e)}return{}}isKitReady(){return!!(this.isInitialized&&this.launcher)}isPartnerInLocalLauncherTestGroup(){return!!(a().config&&a().config.isLocalLauncherEnabled&&this.isAssignedToSampleGroup())}isAssignedToSampleGroup(){return Math.random()>.5}captureTiming(t){window&&a()&&a().captureTiming&&t&&a().captureTiming(t)}init(t,e,i,r,s){const o=t,c=o.accountId;this.userAttributes=w(s),this._onboardingExpProvider=o.onboardingExpProvider;const u=L(o.placementEventMapping);this.placementEventMappingLookup=x(u);const l=L(o.placementEventAttributeMapping);this.placementEventAttributeMappingLookup=Y(l),o.hashedEmailUserIdentityType&&(this._mappedEmailSha256Key=o.hashedEmailUserIdentityType.toLowerCase()),this._workspaceIdSyncApiKey=m(o.workspaceIdSyncApiKey)?o.workspaceIdSyncApiKey:void 0;const h=a().Rokt?.domain,{roktExtensionsQueryParams:v,legacyRoktExtensions:R,loadThankYouElement:A}=D(o.roktExtensions),g={...a().Rokt?.launcherOptions||{}};this.integrationName=lt(g.integrationName),g.integrationName=this.integrationName,this.domain=h;const _={loggingUrl:o.loggingUrl,errorUrl:o.errorUrl,integrationDomain:h,isLoggingEnabled:a().config?.isLoggingEnabled===!0},y=new H(_,this.integrationName,window.__rokt_li_guid__,o.accountId),S=new W(_,y,this.integrationName,window.__rokt_li_guid__,o.accountId);return this.errorReportingService=y,this.loggingService=S,a()._registerErrorReportingService&&a()._registerErrorReportingService(y),a()._registerLoggingService&&a()._registerLoggingService(S),i?(this.testHelpers={generateLauncherScript:U,generateThankYouElementScript:K,extractRoktExtensionConfig:D,hashEventMessage:j,parseSettingsString:L,generateMappedEventLookup:x,generateMappedEventAttributeLookup:Y,sendAdBlockMeasurementSignals:F,createAutoRemovedIframe:O,djb2:V,setAllowedOriginHashes:f=>{p._allowedOriginHashes=f},ReportingTransport:C,ErrorReportingService:H,LoggingService:W,RateLimiter:q,ErrorCodes:N,WSDKErrorSeverity:I},this.attachLauncher(c,g),"Successfully initialized: "+d):(A&&(a().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this),M(et,K(h),{onLoad:()=>{this._isThankYouElementLoaded=!0,this._thankYouElementOnLoadCallback&&this._thankYouElementOnLoadCallback()},onError:f=>{console.error("Error loading Rokt Thank You Element script:",f)}})),this.isLauncherReadyToAttach()?this.attachLauncher(c,g,R):(M(tt,U(h,v),{onLoad:()=>{this.isLauncherReadyToAttach()?this.attachLauncher(c,g,R):console.error("Rokt object is not available after script load.")},onError:f=>{console.error("Error loading Rokt launcher script:",f)}}),this.captureTiming(p.PERFORMANCE_MARKS.RoktScriptAppended)),"Successfully initialized: "+d)}process(t){if(!this.isKitReady())return"Kit not ready for forwarder: "+d;if(typeof a().Rokt?.setLocalSessionAttribute=="function"&&(k(this.placementEventAttributeMappingLookup)||this.applyPlacementEventAttributeMapping(t),!k(this.placementEventMappingLookup))){const e=j(t.EventDataType,t.EventCategory,t.EventName??"");this.placementEventMappingLookup[String(e)]&&a().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(e)],!0)}return"Successfully sent to forwarder: "+d}setExtensionData(t){if(!this.isKitReady()){console.error("Rokt Kit: Not initialized");return}window.Rokt.setExtensionData(t)}setUserAttribute(t,e){return G(t)||(this.userAttributes[t]=e),"Successfully set user attribute for forwarder: "+d}removeUserAttribute(t){return delete this.userAttributes[t],"Successfully removed user attribute for forwarder: "+d}handleIdentityComplete(t,e){return this.userAttributes=w(t.getAllUserAttributes()),"Successfully called "+e+" for forwarder: "+d}onUserIdentified(t){const e=t;return this.filters.filteredUser=e,this._workspaceSearchInFlightPromise=this.search(e),this.handleIdentityComplete(t,"onUserIdentified")}search(t){const e=this._workspaceIdSyncApiKey;if(!e)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const i=a().Identity?.search;if(typeof i!="function")return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const r=t.getUserIdentities?t.getUserIdentities().userIdentities:null,s={};if(r)for(const u of Object.keys(r)){const l=r[u];m(l)&&l.length>0&&(s[u]=l)}const o=Object.keys(s);if(o.length===0)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const c=o.sort().map(u=>`${u}=${s[u]}`).join("&");return c===this._workspaceLastSearchedIdentitiesKey?this._workspaceSearchInFlightPromise||Promise.resolve():(this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=c,new Promise(u=>{try{i(e,s,l=>{l?.httpCode===200&&(this.userIdentifiedInWorkspace=!0),u()})}catch(l){console.error("Rokt Kit: Workspace IDSync search failed",l),this._workspaceLastSearchedIdentitiesKey=void 0,u()}}))}onLoginComplete(t,e){return this.handleIdentityComplete(t,"onLoginComplete")}onLogoutComplete(t,e){return this.userIdentifiedInWorkspace=!1,this._workspaceSearchInFlightPromise=null,this._workspaceLastSearchedIdentitiesKey=void 0,this.handleIdentityComplete(t,"onLogoutComplete")}onModifyComplete(t,e){return this.handleIdentityComplete(t,"onModifyComplete")}selectPlacements(t){if(this._workspaceSearchInFlightPromise){const e=this._workspaceSearchInFlightPromise;return Promise.race([e,new Promise(i=>setTimeout(i,nt))]).then(()=>this._dispatchPlacements(t))}return this._dispatchPlacements(t)}_dispatchPlacements(t){const e=t&&t.attributes||{},r={...w(this.userAttributes),...e},s=this.filters||{},o=s.userAttributeFilters||[],c=s.filteredUser||null,u=c?c.getMPID():null;let l;s?s.filterUserAttributes?l=s.filterUserAttributes(r,o):l=r:(console.warn("Rokt Kit: No filters available, using user attributes"),l=r),this.userAttributes=w(l);const h=this._onboardingExpProvider==="Optimizely"?this.fetchOptimizely():{},v=this.returnUserIdentities(c),R=this.returnLocalSessionAttributes(),A={...v,...l,...h,...R,...this.userIdentifiedInWorkspace?{[it]:!0}:{},mpid:u},g={...t,attributes:A},_=this.launcher.selectPlacements(g),y=()=>this.logSelectPlacementsEvent(A);return Promise.resolve(_).then(S=>S?.context?.sessionId?.then(f=>this.setRoktSessionId(f))).catch(()=>{}).finally(y),_}hashAttributes(t){return this.isKitReady()?this.launcher.hashAttributes(t):(console.error("Rokt Kit: Not initialized"),null)}use(t){return this.isKitReady()?!t||!m(t)?Promise.reject(new Error("Rokt Kit: Invalid extension name")):this.launcher.use(t):(console.error("Rokt Kit: Not initialized"),Promise.reject(new Error("Rokt Kit: Not initialized")))}onShoppableAdsReady(t){this._isThankYouElementLoaded?t():this._thankYouElementOnLoadCallback=t}};p._allowedOriginHashes=[-553112570,549508659],p.PERFORMANCE_MARKS={RoktScriptAppended:"mp:RoktScriptAppended"},p.EMAIL_SHA256_KEY="emailsha256";let E=p;function pt(){return b}function gt(n){if(!n){window.console.log("You must pass a config object to register the kit "+d);return}if(!T(n)){window.console.log("'config' must be an object. You passed in a "+typeof n);return}T(n.kits)?n.kits[d]={constructor:E}:(n.kits={},n.kits[d]={constructor:E}),window.console.log("Successfully registered "+d+" to your mParticle configuration")}typeof window<"u"&&window.mParticle&&a().addForwarder&&a().addForwarder({name:d,constructor:E,getId:pt});exports.register=gt; +"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _e=["active_time_on_site_ms","billingaddress1","billingaddress2","billingcity","billingstate","billingzipcode","cartitems","ccbin","confirmationref","conversiontype","country","couponcode","currency","language","paymentserviceprovider","paymentserviceproviderattribute","paymenttype","shippingaddress1","shippingcity","shippingcountry","shippingmethod","shippingstate","shippingzipcode","totalprice"],Ie=new Set(_e);function se(i){return Ie.has(i.toLowerCase())}function b(i){const e={},t=i||{},n=Object.keys(t);for(let r=0;r{const r=t.activeTimeOnSite,s=r!==void 0&&Number.isFinite(r),c=e[n+1]?.activeTimeOnSite,u=c!==void 0&&Number.isFinite(c),l=s&&u?c-r:void 0;return{pageUrl:t.pageUrl,sourceMessageId:t.sourceMessageId,timestamp:t.timestamp,...t.pageTitle!==void 0?{pageTitle:t.pageTitle}:{},...t.canonicalUrl!==void 0?{canonicalUrl:t.canonicalUrl}:{},...s?{activeTimeOnSite:r}:{},...l!==void 0&&l>=0?{activeTimeOnPage:l}:{}}})}function ke(i){if(U(p,O)!==void 0)return;const e=new URLSearchParams(window.location.search),t={};for(const r of Se){const s=e.get(r);s&&(t[r]=s)}if(Object.keys(t).length===0)return;const n=Object.keys(t).join(", ");if(!G(p,O,t)){const r=D()?"quota":"ls_unavailable";i?.log({message:`Rokt Kit: Failed to persist UTM params [reason: ${r}]`,code:"UTM_CAPTURE_FAILED"});return}i?.log({message:`Rokt Kit: Captured UTM params [${n}]`,code:"UTM_CAPTURE_SUCCESS"})}function ve(){const i=U(p,O);return _(i)?i:null}function $(){ce(p,O)}function Re(){const e=document.querySelector('link[rel="canonical"]')?.href;if(e)return Y(e)}const d="Rokt",L=181,we="selectPlacements",be="apps.roktecommerce.com",Te=.1,Le="ThankYouPageJourney",Pe="rokt-launcher",Oe="rokt-thank-you-element",Ne="userIdentifiedInWorkspace",Ue=3,Ce=2,Me="page_events",Ke="page_view_attributes",De="mparticle_session_id",Fe="mparticle_device_id",Ye=500,x={UNKNOWN_ERROR:"UNKNOWN_ERROR",UNHANDLED_EXCEPTION:"UNHANDLED_EXCEPTION",IDENTITY_REQUEST:"IDENTITY_REQUEST",LOG_DELIVERY_FAILURE:"LOG_DELIVERY_FAILURE"},S={ERROR:"ERROR",INFO:"INFO",WARNING:"WARNING"},Ge="apps.rokt-api.com",xe="/v1/log",We="/v1/errors",je=10;function a(){return window.mParticle}function J(i,e){const n=[C(i),"/wsdk/integrations/launcher.js"].join("");return!e||e.length===0?n:n+"?extensions="+e.join(",")}function B(i){return[C(i),"/rokt-elements/rokt-element-thank-you.js"].join("")}function C(i){const e=typeof i<"u"?i:Ge;return e.includes("://")?e.replace(/\/+$/,""):["https://",e].join("")}function he(i,e,t){if(i)return i.startsWith("http://")||i.startsWith("https://")?i:"https://"+i;const r=e?.includes("://")&&!/^https?:\/\//i.test(e)?void 0:e;return C(r)+t}function Q(i,e,t){if(document.getElementById(i))return;const n=document.head||document.body,r=document.createElement("script");r.id=i,r.type="text/javascript",r.src=e,r.async=!0,r.crossOrigin="anonymous",r.fetchPriority="high",t?.onLoad&&(r.onload=t.onLoad),t?.onError&&(r.onerror=t.onError),n.appendChild(r)}function P(i){if(!i)return[];try{return JSON.parse(i.replace(/"/g,'"'))}catch{console.error("Settings string contains invalid JSON")}return[]}function X(i){const e=i?P(i):[],t=[],n=[];let r=!1;for(let s=0;s=Te)return;const r=window.__rokt_li_guid__;if(!r||i&&i.includes("://")&&!/^https:\/\//i.test(i))return;const s=window.location.href.split("?")[0].split("#")[0],o="version="+encodeURIComponent(e??"")+"&launcherInstanceGuid="+encodeURIComponent(r)+"&pageUrl="+encodeURIComponent(s),c=i?C(i):"https://apps.rokt.com";F(c+"/v1/wsdk-init/index.html?"+o),F("https://"+be+"/v1/wsdk-init/index.html?"+o+"&isControl=true")}function ze(){return typeof window<"u"&&!!window.location?.search?.toLowerCase().includes("mp_enable_logging=true")}function qe(){return typeof window<"u"?window.location?.href:void 0}function $e(){return typeof window<"u"?window.navigator?.userAgent:void 0}class pe{constructor(){this._logCount={}}incrementAndCheck(e){const n=(this._logCount[e]||0)+1;return this._logCount[e]=n,n>je}}class W{constructor(e,t,n,r,s){this._reporter="mp-wsdk";const o=e.isLoggingEnabled;this._integrationName=t||"",this._launcherInstanceGuid=n,this._accountId=r||null,this._rateLimiter=s||new pe,this._isEnabled=ze()||o}send(e,t,n,r,s,o){if(!(!this._isEnabled||this._rateLimiter.incrementAndCheck(t)))try{const c={additionalInformation:{message:n,version:this._integrationName},severity:t,code:r||x.UNKNOWN_ERROR,url:qe(),deviceInfo:$e(),stackTrace:s,reporter:this._reporter,integration:this._integrationName},u={Accept:"text/plain;charset=UTF-8","Content-Type":"application/json","rokt-launcher-version":this._integrationName,"rokt-wsdk-version":"joint"};this._launcherInstanceGuid&&(u["rokt-launcher-instance-guid"]=this._launcherInstanceGuid),this._accountId&&(u["rokt-account-id"]=this._accountId),fetch(e,{method:"POST",headers:u,body:JSON.stringify(c)}).then(l=>{if(!l.ok){const g=new Error("HTTP "+l.status+" from log endpoint");throw g.statusCode=l.status,g}}).catch(l=>{console.error("ReportingTransport: Failed to send log",l),o&&o(l)})}catch(c){console.error("ReportingTransport: Failed to send log",c),o&&o(c)}}}class ne{constructor(e,t,n,r,s){this._transport=new W(e,t,n,r,s),this._errorUrl=he(e?.errorUrl,e?.integrationDomain,We)}report(e){if(!e)return;const t=e.severity||S.ERROR;this._transport.send(this._errorUrl,t,e.message,e.code,e.stackTrace)}}class re{constructor(e,t,n,r,s,o){this._transport=new W(e,n,r,s,o),this._loggingUrl=he(e?.loggingUrl,e?.integrationDomain,xe),this._errorReportingService=t}log(e){e&&this._transport.send(this._loggingUrl,S.INFO,e.message,e.code,void 0,t=>{if(this._errorReportingService){const n=typeof t.statusCode=="number";this._errorReportingService.report({message:"LoggingService: Failed to send log: "+t.message,code:x.LOG_DELIVERY_FAILURE,severity:n?S.ERROR:S.WARNING})}})}}function Je(i){const e=Y(window.location.href),t=i.EventAttributes?.title||document.title,n=Re(),r=i.ActiveTimeOnSite;return{pageUrl:e,sourceMessageId:i.SourceMessageId,timestamp:i.Timestamp,...t?{pageTitle:t}:{},...n!==void 0?{canonicalUrl:n}:{},...Number.isFinite(r)?{activeTimeOnSite:r}:{}}}const m=class m{constructor(){this.name=d,this.id=L,this.moduleId=L,this.isInitialized=!1,this.launcher=null,this.filters={},this.userAttributes={},this.userIdentifiedInWorkspace=!1,this.testHelpers=null,this.placementEventMappingLookup={},this.placementEventAttributeMappingLookup={},this.integrationName=null,this.errorReportingService=null,this.loggingService=null,this._thankYouElementOnLoadCallback=null,this._isThankYouElementLoaded=!1,this._workspaceSearchInFlightPromise=null}getEventAttributeValue(e,t){const n=e&&e.EventAttributes;return!n||typeof n[t]>"u"?null:n[t]}doesEventAttributeConditionMatch(e,t){if(!e||!E(e.operator))return!1;const n=e.operator.toLowerCase(),r=e.attributeValue;return n==="exists"?t!==null:t==null?!1:n==="equals"?String(t)===String(r):n==="contains"?String(t).indexOf(String(r))!==-1:!1}doesEventMatchRule(e,t){if(!t||!E(t.eventAttributeKey))return!1;const n=t.conditions;if(!Array.isArray(n))return!1;const r=this.getEventAttributeValue(e,t.eventAttributeKey);if(n.length===0)return r!==null;for(let s=0;s{await Ve(n,o),this.initRoktLauncher(o)}).catch(o=>{console.error("Error creating Rokt launcher:",o)})}initRoktLauncher(e){window.Rokt&&(window.Rokt.currentLauncher=e),this.launcher=e;const t=a().Rokt?.filters;t?(this.filters=t,t.filteredUser?this._workspaceSearchInFlightPromise=this.search(t.filteredUser):console.warn("Rokt Kit: No filtered user has been set.")):console.warn("Rokt Kit: No filters have been set."),this.isInitialized=!0,ie(this.domain,this.integrationName),a().Rokt.attachKit(this)}fetchOptimizely(){const e=a()._getActiveForwarders().filter(t=>t.name==="Optimizely");try{if(e.length>0&&window.optimizely){const t=window.optimizely.get("state");return!t||!t.getActiveExperimentIds?{}:t.getActiveExperimentIds().reduce((s,o)=>(s["rokt.custom.optimizely.experiment."+o+".variationId"]=t.getVariationMap()[o].id,s),{})}}catch(t){console.error("Error fetching Optimizely attributes:",t)}return{}}isKitReady(){return!!(this.isInitialized&&this.launcher)}isTargetingDisabled(){return a().Rokt?.launcherOptions?.noTargeting===!0}isPartnerInLocalLauncherTestGroup(){return!!(a().config&&a().config.isLocalLauncherEnabled&&this.isAssignedToSampleGroup())}isAssignedToSampleGroup(){return Math.random()>.5}captureTiming(e){window&&a()&&a().captureTiming&&e&&a().captureTiming(e)}init(e,t,n,r,s){const o=e,c=o.accountId;this.userAttributes=b(s),this._onboardingExpProvider=o.onboardingExpProvider;const u=P(o.placementEventMapping);this.placementEventMappingLookup=Z(u);const l=P(o.placementEventAttributeMapping);this.placementEventAttributeMappingLookup=ee(l),o.hashedEmailUserIdentityType&&(this._mappedEmailSha256Key=o.hashedEmailUserIdentityType.toLowerCase()),this._workspaceIdSyncApiKey=E(o.workspaceIdSyncApiKey)?o.workspaceIdSyncApiKey:void 0;const g=a().Rokt?.domain,{roktExtensionsQueryParams:M,legacyRoktExtensions:R,loadThankYouElement:w}=X(o.roktExtensions),f={...a().Rokt?.launcherOptions||{}};this.integrationName=He(f.integrationName),f.integrationName=this.integrationName,this.domain=g;const A={loggingUrl:o.loggingUrl,errorUrl:o.errorUrl,integrationDomain:g,isLoggingEnabled:a().config?.isLoggingEnabled===!0},I=new ne(A,this.integrationName,window.__rokt_li_guid__,o.accountId),k=new re(A,I,this.integrationName,window.__rokt_li_guid__,o.accountId);if(this.errorReportingService=I,this.loggingService=k,this.isTargetingDisabled())try{q(),$()}catch(h){this.errorReportingService?.report({message:"Rokt Kit: Failed to clear page views when targeting is disabled",code:"PAGE_VIEW_CAPTURE_FAILED",severity:S.INFO,stackTrace:h instanceof Error?h.stack:void 0})}return a()._registerErrorReportingService&&a()._registerErrorReportingService(I),a()._registerLoggingService&&a()._registerLoggingService(k),n?(this.testHelpers={generateLauncherScript:J,generateThankYouElementScript:B,extractRoktExtensionConfig:X,hashEventMessage:te,parseSettingsString:P,generateMappedEventLookup:Z,generateMappedEventAttributeLookup:ee,sendAdBlockMeasurementSignals:ie,createAutoRemovedIframe:F,djb2:ge,setAllowedOriginHashes:h=>{m._allowedOriginHashes=h},ReportingTransport:W,ErrorReportingService:ne,LoggingService:re,RateLimiter:pe,ErrorCodes:x,WSDKErrorSeverity:S},this.attachLauncher(c,f),"Successfully initialized: "+d):(w&&(a().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this),Q(Oe,B(g),{onLoad:()=>{this._isThankYouElementLoaded=!0,this._thankYouElementOnLoadCallback&&this._thankYouElementOnLoadCallback()},onError:h=>{console.error("Error loading Rokt Thank You Element script:",h)}})),this.isLauncherReadyToAttach()?this.attachLauncher(c,f,R):(Q(Pe,J(g,M),{onLoad:()=>{this.isLauncherReadyToAttach()?this.attachLauncher(c,f,R):console.error("Rokt object is not available after script load.")},onError:h=>{console.error("Error loading Rokt launcher script:",h)}}),this.captureTiming(m.PERFORMANCE_MARKS.RoktScriptAppended)),"Successfully initialized: "+d)}process(e){if(this.isTargetingDisabled()||(e.EventDataType===Ue&&(ke(this.loggingService),this.capturePageView(e)),e.EventDataType===Ce&&(de(this.loggingService),q(),$())),!this.isKitReady())return"Kit not ready for forwarder: "+d;if(T(a().Rokt?.setLocalSessionAttribute)&&(K(this.placementEventAttributeMappingLookup)||this.applyPlacementEventAttributeMapping(e),!K(this.placementEventMappingLookup))){const t=te(e.EventDataType,e.EventCategory,e.EventName??"");this.placementEventMappingLookup[String(t)]&&a().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(t)],!0)}return"Successfully sent to forwarder: "+d}setExtensionData(e){if(!this.isKitReady()){console.error("Rokt Kit: Not initialized");return}window.Rokt.setExtensionData(e)}setUserAttribute(e,t){return se(e)||(this.userAttributes[e]=t),"Successfully set user attribute for forwarder: "+d}removeUserAttribute(e){return delete this.userAttributes[e],"Successfully removed user attribute for forwarder: "+d}handleIdentityComplete(e,t){return this.userAttributes=b(e.getAllUserAttributes()),"Successfully called "+t+" for forwarder: "+d}onUserIdentified(e){const t=e;return this.filters.filteredUser=t,this._workspaceSearchInFlightPromise=this.search(t),this.handleIdentityComplete(e,"onUserIdentified")}search(e){const t=this._workspaceIdSyncApiKey;if(!t)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const n=a().Identity?.search;if(typeof n!="function")return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const r=e.getUserIdentities?e.getUserIdentities().userIdentities:null,s={};if(r)for(const u of Object.keys(r)){const l=r[u];E(l)&&l.length>0&&(s[u]=l)}const o=Object.keys(s);if(o.length===0)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const c=o.sort().map(u=>`${u}=${s[u]}`).join("&");return c===this._workspaceLastSearchedIdentitiesKey?this._workspaceSearchInFlightPromise||Promise.resolve():(this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=c,new Promise(u=>{try{n(t,s,l=>{l?.httpCode===200&&(this.userIdentifiedInWorkspace=!0),u()})}catch(l){console.error("Rokt Kit: Workspace IDSync search failed",l),this._workspaceLastSearchedIdentitiesKey=void 0,u()}}))}onLoginComplete(e,t){return this.handleIdentityComplete(e,"onLoginComplete")}onLogoutComplete(e,t){return this.userIdentifiedInWorkspace=!1,this._workspaceSearchInFlightPromise=null,this._workspaceLastSearchedIdentitiesKey=void 0,this.handleIdentityComplete(e,"onLogoutComplete")}onModifyComplete(e,t){return this.handleIdentityComplete(e,"onModifyComplete")}selectPlacements(e){if(this._workspaceSearchInFlightPromise){const t=this._workspaceSearchInFlightPromise;return Promise.race([t,new Promise(n=>setTimeout(n,Ye))]).then(()=>this._dispatchPlacements(e))}return this._dispatchPlacements(e)}_dispatchPlacements(e){const t=e&&e.attributes||{},r={...b(this.userAttributes),...t},s=this.filters||{},o=s.userAttributeFilters||[],c=s.filteredUser||null,u=c?c.getMPID():null;let l;s?s.filterUserAttributes?l=s.filterUserAttributes(r,o):l=r:(console.warn("Rokt Kit: No filters available, using user attributes"),l=r),this.userAttributes=b(l);const g=this._onboardingExpProvider==="Optimizely"?this.fetchOptimizely():{},M=this.returnUserIdentities(c),R=this.returnLocalSessionAttributes(),w=Ae(z(this.loggingService)),f=ve(),A=this.readMpSessionId(),I=this.readMpDeviceId(),k={...M,...l,...g,...R,...w.length?{[Me]:JSON.stringify(w)}:{},...f?{[Ke]:f}:{},...this.userIdentifiedInWorkspace?{[Ne]:!0}:{},...A?{[De]:A}:{},...I?{[Fe]:I}:{},mpid:u},h={...e,attributes:k},j=this.launcher.selectPlacements(h),fe=()=>this.logSelectPlacementsEvent(k);return Promise.resolve(j).then(me=>me?.context?.sessionId?.then(Ee=>this.setRoktSessionId(Ee))).catch(()=>{}).finally(fe),j}hashAttributes(e){return this.isKitReady()?this.launcher.hashAttributes(e):(console.error("Rokt Kit: Not initialized"),null)}use(e){return this.isKitReady()?!e||!E(e)?Promise.reject(new Error("Rokt Kit: Invalid extension name")):this.launcher.use(e):(console.error("Rokt Kit: Not initialized"),Promise.reject(new Error("Rokt Kit: Not initialized")))}onShoppableAdsReady(e){this._isThankYouElementLoaded?e():this._thankYouElementOnLoadCallback=e}};m._allowedOriginHashes=[-553112570,549508659],m.PERFORMANCE_MARKS={RoktScriptAppended:"mp:RoktScriptAppended"},m.EMAIL_SHA256_KEY="emailsha256";let y=m;function Be(){return L}function Qe(i){if(!i){window.console.log("You must pass a config object to register the kit "+d);return}if(!_(i)){window.console.log("'config' must be an object. You passed in a "+typeof i);return}_(i.kits)?i.kits[d]={constructor:y}:(i.kits={},i.kits[d]={constructor:y}),window.console.log("Successfully registered "+d+" to your mParticle configuration")}typeof window<"u"&&window.mParticle&&a().addForwarder&&a().addForwarder({name:d,constructor:y,getId:Be});exports.register=Qe; //# sourceMappingURL=Rokt-Kit.common.js.map diff --git a/kits/rokt/dist/Rokt-Kit.common.js.map b/kits/rokt/dist/Rokt-Kit.common.js.map index 04eaf0f9e..3312d861d 100644 --- a/kits/rokt/dist/Rokt-Kit.common.js.map +++ b/kits/rokt/dist/Rokt-Kit.common.js.map @@ -1 +1 @@ -{"version":3,"file":"Rokt-Kit.common.js","sources":["../src/selectPlacementsAttributePersistence.ts","../src/Rokt-Kit.ts"],"sourcesContent":["const SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST = [\n 'billingaddress1',\n 'billingaddress2',\n 'billingcity',\n 'billingstate',\n 'billingzipcode',\n 'cartitems',\n 'ccbin',\n 'confirmationref',\n 'conversiontype',\n 'country',\n 'couponcode',\n 'currency',\n 'language',\n 'paymentserviceprovider',\n 'paymentserviceproviderattribute',\n 'paymenttype',\n 'shippingaddress1',\n 'shippingcity',\n 'shippingcountry',\n 'shippingmethod',\n 'shippingstate',\n 'shippingzipcode',\n 'totalprice',\n];\nconst SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET = new Set(SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST);\n\nexport function isSelectPlacementsAttributePersistenceDenied(key: string): boolean {\n return SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET.has(key.toLowerCase());\n}\n\nexport function removeSelectPlacementsAttributePersistenceDeniedAttributes(\n attributes: Record | null | undefined,\n): Record {\n const filteredAttributes: Record = {};\n const sourceAttributes = attributes || {};\n const attributeKeys = Object.keys(sourceAttributes);\n\n for (let i = 0; i < attributeKeys.length; i++) {\n const key = attributeKeys[i];\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n filteredAttributes[key] = sourceAttributes[key];\n }\n }\n\n return filteredAttributes;\n}\n","// Copyright 2025 mParticle, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// ============================================================\n// Types\n// ============================================================\n\nimport { KitInterface, IMParticleUser, SDKEvent } from '@mparticle/web-sdk/internal';\nimport type { IUserIdentities } from '@mparticle/web-sdk';\n\nimport {\n isSelectPlacementsAttributePersistenceDenied,\n removeSelectPlacementsAttributePersistenceDeniedAttributes,\n} from './selectPlacementsAttributePersistence';\n\ninterface RoktKitSettings {\n accountId: string;\n roktExtensions?: string;\n placementEventMapping?: string;\n placementEventAttributeMapping?: string;\n hashedEmailUserIdentityType?: string;\n onboardingExpProvider?: string;\n loggingUrl?: string;\n errorUrl?: string;\n workspaceIdSyncApiKey?: string;\n}\n\ninterface EventAttributeCondition {\n operator: string;\n attributeValue: string;\n}\n\ninterface PlacementEventRule {\n eventAttributeKey: string;\n conditions: EventAttributeCondition[];\n}\n\ninterface EventAttributeMapping {\n value: string;\n map: string;\n conditions?: EventAttributeCondition[];\n}\n\ninterface PlacementEventMappingEntry {\n jsmap: string;\n value: string;\n}\n\ninterface RoktExtensionEntry {\n value: string;\n}\n\ninterface RoktSelection {\n context?: {\n sessionId?: Promise;\n };\n then?: (callback: (sel: RoktSelection) => void) => Promise;\n catch?: (callback: () => void) => void;\n}\n\ninterface RoktLauncher {\n selectPlacements(options: Record): RoktSelection | Promise;\n hashAttributes(attributes: Record): Promise>;\n use(extensionName: string): Promise;\n}\n\ninterface RoktGlobal {\n createLauncher(options: Record): Promise;\n createLocalLauncher(options: Record): RoktLauncher;\n currentLauncher?: RoktLauncher;\n setExtensionData(data: Record): void;\n}\n\n// FilteredUser is the IMParticleUser shape we receive after kit filtering.\n// `getMPID` and `getUserIdentities` are inherited from the SDK's `User` base type.\ntype FilteredUser = IMParticleUser;\n\n// TODO: Replace with `IIdentitySearchResult` from `@mparticle/web-sdk` once\n// a version that exports it is published (currently on a feature branch in\n// mParticle/mparticle-web-sdk PR #1255). The shape below is intentionally\n// structurally identical so the swap is a one-line import change.\ninterface WorkspaceIdSyncResult {\n httpCode: number;\n body?: {\n context?: string | null;\n mpid?: string;\n matched_identities?: Record;\n is_ephemeral?: boolean;\n is_logged_in?: boolean;\n };\n}\n\n// TODO: Replace with `IdentitySearchCallback`-compatible reference from\n// `@mparticle/web-sdk` once published (mirrors `SDKIdentityApi.search`).\ntype WorkspaceIdSyncSearcher = (\n apiKey: string,\n knownIdentities: IUserIdentities,\n callback: (result: WorkspaceIdSyncResult) => void,\n) => void;\n\ninterface KitFilters {\n userAttributeFilters?: string[];\n filterUserAttributes?: (attributes: Record, filters?: string[]) => Record;\n filteredUser?: FilteredUser | null;\n}\n\ninterface RoktManager {\n attachKit(kit: RoktKit): void | Promise;\n flushOnShoppableAdsReadyMessageQueue?(kit: RoktKit): void;\n filters?: KitFilters;\n domain?: string;\n launcherOptions?: Record;\n getLocalSessionAttributes?(): Record;\n setLocalSessionAttribute?(key: string, value: unknown): void;\n}\n\ninterface MParticleInstance {\n setIntegrationAttribute(moduleId: number, attrs: Record): void;\n}\n\ninterface OptimizelyState {\n getActiveExperimentIds(): string[];\n getVariationMap(): Record;\n}\n\ninterface OptimizelyGlobal {\n get(key: 'state'): OptimizelyState;\n}\n\n// Our view of the mParticle global with Rokt-specific extensions.\n// We access window.mParticle via an explicit cast (see `mp()` helper below)\n// rather than augmenting Window to avoid conflicts with @mparticle/web-sdk declarations.\ninterface MParticleExtended {\n Rokt: RoktManager;\n addForwarder(config: ForwarderRegistration): void;\n getVersion(): string;\n generateHash(value: string): string | number;\n logEvent(name: string, type: number, attrs?: Record): void;\n EventType: { Other: number };\n getInstance(): MParticleInstance;\n sessionManager?: { getSession(): string };\n _getActiveForwarders(): Array<{ name: string }>;\n config?: { isLocalLauncherEnabled?: boolean; isLoggingEnabled?: boolean };\n captureTiming?(metricName: string): void;\n forwarder?: RoktKit;\n loggedEvents?: Array>;\n _registerErrorReportingService?(service: ErrorReportingService): void;\n _registerLoggingService?(service: LoggingService): void;\n Identity?: { search?: WorkspaceIdSyncSearcher };\n}\n\ninterface TestHelpers {\n generateLauncherScript: (domain: string | undefined, extensions: string[]) => string;\n generateThankYouElementScript: (domain: string | undefined) => string;\n extractRoktExtensionConfig: (settingsString?: string) => RoktExtensionConfig;\n hashEventMessage: (messageType: number, eventType: number, eventName: string) => string | number;\n parseSettingsString: (settingsString?: string) => T[];\n generateMappedEventLookup: (placementEventMapping: PlacementEventMappingEntry[]) => Record;\n generateMappedEventAttributeLookup: (mapping: EventAttributeMapping[]) => Record;\n sendAdBlockMeasurementSignals: (domain: string | undefined, version: string | null) => void;\n createAutoRemovedIframe: (src: string) => void;\n djb2: (str: string) => number;\n setAllowedOriginHashes: (hashes: number[]) => void;\n ReportingTransport: typeof ReportingTransport;\n ErrorReportingService: typeof ErrorReportingService;\n LoggingService: typeof LoggingService;\n RateLimiter: typeof RateLimiter;\n ErrorCodes: typeof ErrorCodes;\n WSDKErrorSeverity: typeof WSDKErrorSeverity;\n}\n\ninterface ForwarderRegistration {\n name: string;\n constructor: new () => RoktKit;\n getId: () => number;\n}\n\ninterface ReportingConfig {\n loggingUrl?: string;\n errorUrl?: string;\n integrationDomain?: string;\n isLoggingEnabled: boolean;\n}\n\ninterface ErrorReport {\n message: string;\n code?: string;\n severity?: string;\n stackTrace?: string;\n}\n\n// A log-delivery failure. statusCode is set when the request reached the server\n// and returned a non-2xx status (server-side); it is absent for network-level\n// failures such as ad-blockers, offline, or CORS rejections (client-side).\ninterface DeliveryError extends Error {\n statusCode?: number;\n}\n\ninterface LogEntry {\n message: string;\n code?: string;\n}\n\ninterface RoktExtensionConfig {\n roktExtensionsQueryParams: string[];\n legacyRoktExtensions: string[];\n loadThankYouElement: boolean;\n}\n\ndeclare global {\n interface Window {\n Rokt?: RoktGlobal;\n __rokt_li_guid__?: string;\n optimizely?: OptimizelyGlobal;\n // mParticle is declared as any to avoid conflicts with @mparticle/web-sdk type declarations.\n // We use the typed mp() accessor for all internal accesses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mParticle: any;\n }\n}\n\n// ============================================================\n// Module-level constants\n// ============================================================\n\nconst name = 'Rokt';\nconst moduleId = 181;\nconst EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements';\nconst ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com';\nconst INIT_LOG_SAMPLING_RATE = 0.1;\nconst ROKT_THANK_YOU_JOURNEY_EXTENSION = 'ThankYouPageJourney';\nconst ROKT_INTEGRATION_SCRIPT_ID = 'rokt-launcher';\nconst ROKT_THANK_YOU_ELEMENT_SCRIPT_ID = 'rokt-thank-you-element';\nconst USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace';\n\n// Bound on how long selectPlacements will wait for an in-flight Workspace\n// IDSync search before proceeding without the userIdentifiedInWorkspace flag.\n// Long enough to cover the typical /v1/search round-trip (~50ms); short enough that a\n// stalled search never blocks placement rendering on a thank-you page.\nconst WORKSPACE_SEARCH_SELECT_TIMEOUT_MS = 500;\n\n// ============================================================\n// Reporting service constants\n// ============================================================\n\nconst ErrorCodes = {\n UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION',\n IDENTITY_REQUEST: 'IDENTITY_REQUEST',\n LOG_DELIVERY_FAILURE: 'LOG_DELIVERY_FAILURE',\n} as const;\n\nconst WSDKErrorSeverity = {\n ERROR: 'ERROR',\n INFO: 'INFO',\n WARNING: 'WARNING',\n} as const;\n\nconst DEFAULT_ROKT_DOMAIN = 'apps.rokt-api.com';\nconst LOGGING_ENDPOINT = '/v1/log';\nconst ERROR_ENDPOINT = '/v1/errors';\nconst RATE_LIMIT_PER_SEVERITY = 10;\n\n// ============================================================\n// Helper: typed accessor for window.mParticle\n// We use an explicit cast here to avoid conflicts with @mparticle/web-sdk\n// type declarations while still providing full type safety for our usages.\n// ============================================================\n\nfunction mp(): MParticleExtended {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (window as any).mParticle as MParticleExtended;\n}\n\n// ============================================================\n// Module-level utility functions\n// ============================================================\n\nfunction generateLauncherScript(domain: string | undefined, extensions: string[]): string {\n const launcherPath = '/wsdk/integrations/launcher.js';\n const baseUrl = [generateBaseUrl(domain), launcherPath].join('');\n\n if (!extensions || extensions.length === 0) {\n return baseUrl;\n }\n return baseUrl + '?extensions=' + extensions.join(',');\n}\n\nfunction generateThankYouElementScript(domain: string | undefined) {\n const thankYouElementPath = '/rokt-elements/rokt-element-thank-you.js';\n return [generateBaseUrl(domain), thankYouElementPath].join('');\n}\n\nfunction generateBaseUrl(domain: string | undefined) {\n const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN;\n const protocol = 'https://';\n\n return [protocol, resolvedDomain].join('');\n}\n\nfunction generateReportingUrl(configuredUrl: string | undefined, domain: string | undefined, endpoint: string): string {\n if (configuredUrl) {\n if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://')) {\n return configuredUrl;\n }\n return 'https://' + configuredUrl;\n }\n\n return generateBaseUrl(domain) + endpoint;\n}\n\nfunction loadRoktScript(\n scriptId: string,\n source: string,\n handlers?: { onLoad?: () => void; onError?: (e: Event | string) => void },\n): void {\n if (document.getElementById(scriptId)) return; // resolves the preexisting script issue\n\n const target = document.head || document.body;\n const script = document.createElement('script');\n script.id = scriptId;\n script.type = 'text/javascript';\n script.src = source;\n script.async = true;\n script.crossOrigin = 'anonymous';\n (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high';\n if (handlers?.onLoad) script.onload = handlers.onLoad;\n if (handlers?.onError) script.onerror = handlers.onError;\n target.appendChild(script);\n}\n\nfunction isObject(val: unknown): val is Record {\n return val != null && typeof val === 'object' && Array.isArray(val) === false;\n}\n\nfunction parseSettingsString(settingsString?: string): T[] {\n if (!settingsString) {\n return [];\n }\n try {\n return JSON.parse(settingsString.replace(/"/g, '\"')) as T[];\n } catch (_error) {\n console.error('Settings string contains invalid JSON');\n }\n return [];\n}\n\nfunction extractRoktExtensionConfig(settingsString?: string): RoktExtensionConfig {\n const settings = settingsString ? parseSettingsString(settingsString) : [];\n const roktExtensionsQueryParams: string[] = [];\n const legacyRoktExtensions: string[] = [];\n let loadThankYouElement = false;\n\n for (let i = 0; i < settings.length; i++) {\n const extensionName = settings[i].value;\n if (extensionName === 'thank-you-journey') {\n loadThankYouElement = true;\n legacyRoktExtensions.push(ROKT_THANK_YOU_JOURNEY_EXTENSION);\n } else {\n roktExtensionsQueryParams.push(extensionName);\n }\n }\n\n return {\n roktExtensionsQueryParams,\n legacyRoktExtensions,\n loadThankYouElement,\n };\n}\n\nasync function registerLegacyExtensions(legacyExtensions: string[], launcher: RoktLauncher | null) {\n const extensions: Promise[] = [];\n if (launcher) {\n for (const extension of legacyExtensions) {\n extensions.push(launcher.use(extension));\n }\n }\n\n return Promise.all(extensions);\n}\n\nfunction generateMappedEventLookup(placementEventMapping: PlacementEventMappingEntry[]): Record {\n if (!placementEventMapping) {\n return {};\n }\n\n const mappedEvents: Record = {};\n for (let i = 0; i < placementEventMapping.length; i++) {\n const mapping = placementEventMapping[i];\n mappedEvents[mapping.jsmap] = mapping.value;\n }\n return mappedEvents;\n}\n\nfunction generateMappedEventAttributeLookup(\n placementEventAttributeMapping: EventAttributeMapping[],\n): Record {\n const mappedAttributeKeys: Record = {};\n if (!Array.isArray(placementEventAttributeMapping)) {\n return mappedAttributeKeys;\n }\n for (let i = 0; i < placementEventAttributeMapping.length; i++) {\n const mapping = placementEventAttributeMapping[i];\n if (!mapping || !isString(mapping.value) || !isString(mapping.map)) {\n continue;\n }\n\n const mappedAttributeKey = mapping.value;\n const eventAttributeKey = mapping.map;\n\n if (!mappedAttributeKeys[mappedAttributeKey]) {\n mappedAttributeKeys[mappedAttributeKey] = [];\n }\n\n mappedAttributeKeys[mappedAttributeKey].push({\n eventAttributeKey: eventAttributeKey,\n conditions: Array.isArray(mapping.conditions) ? mapping.conditions : [],\n });\n }\n return mappedAttributeKeys;\n}\n\nfunction hashEventMessage(messageType: number, eventType: number, eventName: string): string | number {\n return mp().generateHash([messageType, eventType, eventName].join(''));\n}\n\nfunction isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'object') {\n return Object.keys(value as object).length === 0;\n }\n if (Array.isArray(value)) {\n return (value as unknown[]).length === 0;\n }\n return false;\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nfunction generateIntegrationName(customIntegrationName?: string): string {\n const coreSdkVersion = mp().getVersion();\n const kitVersion = process.env.PACKAGE_VERSION;\n let integrationName = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion;\n\n if (customIntegrationName) {\n integrationName += '_' + customIntegrationName;\n }\n return integrationName;\n}\n\nfunction djb2(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return hash;\n}\n\nfunction createAutoRemovedIframe(src: string): void {\n const iframe = document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');\n iframe.src = src;\n iframe.onload = function () {\n iframe.onload = null;\n if (iframe.parentNode) {\n iframe.parentNode.removeChild(iframe);\n }\n };\n const target = document.body || document.head;\n if (target) {\n target.appendChild(iframe);\n }\n}\n\nfunction sendAdBlockMeasurementSignals(domain: string | undefined, version: string | null): void {\n const originHash = djb2(window.location.origin);\n const allowedOriginHashes = RoktKit._allowedOriginHashes;\n if (allowedOriginHashes.indexOf(originHash) === -1) {\n return;\n }\n\n if (Math.random() >= INIT_LOG_SAMPLING_RATE) {\n return;\n }\n\n const guid = window.__rokt_li_guid__;\n if (!guid) {\n return;\n }\n\n const pageUrl = window.location.href.split('?')[0].split('#')[0];\n const params =\n 'version=' +\n encodeURIComponent(version ?? '') +\n '&launcherInstanceGuid=' +\n encodeURIComponent(guid) +\n '&pageUrl=' +\n encodeURIComponent(pageUrl);\n\n const existingDomain = domain || 'apps.rokt.com';\n createAutoRemovedIframe('https://' + existingDomain + '/v1/wsdk-init/index.html?' + params);\n\n createAutoRemovedIframe(\n 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true',\n );\n}\n\n// ============================================================\n// Reporting helpers\n// ============================================================\n\nfunction _isDebugModeEnabled(): boolean {\n return typeof window !== 'undefined' && !!window.location?.search?.toLowerCase().includes('mp_enable_logging=true');\n}\n\nfunction _getReportingUrl(): string | undefined {\n return typeof window !== 'undefined' ? window.location?.href : undefined;\n}\n\nfunction _getUserAgent(): string | undefined {\n return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined;\n}\n\nclass RateLimiter {\n private _logCount: Record = {};\n\n incrementAndCheck(severity: string): boolean {\n const count = this._logCount[severity] || 0;\n const newCount = count + 1;\n this._logCount[severity] = newCount;\n return newCount > RATE_LIMIT_PER_SEVERITY;\n }\n}\n\nclass ReportingTransport {\n private _isEnabled: boolean;\n private _integrationName: string;\n private _launcherInstanceGuid: string | undefined;\n private _accountId: string | null;\n private _rateLimiter: RateLimiter;\n private readonly _reporter = 'mp-wsdk';\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid: string | undefined,\n accountId: string | null | undefined,\n rateLimiter?: RateLimiter,\n ) {\n const isLoggingEnabled = config.isLoggingEnabled;\n this._integrationName = integrationName || '';\n this._launcherInstanceGuid = launcherInstanceGuid;\n this._accountId = accountId || null;\n this._rateLimiter = rateLimiter || new RateLimiter();\n this._isEnabled = _isDebugModeEnabled() || isLoggingEnabled;\n }\n\n send(\n url: string,\n severity: string,\n msg: string,\n code?: string,\n stackTrace?: string,\n onError?: (error: DeliveryError) => void,\n ): void {\n if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) {\n return;\n }\n\n try {\n const logRequest = {\n additionalInformation: {\n message: msg,\n version: this._integrationName,\n },\n severity,\n code: code || ErrorCodes.UNKNOWN_ERROR,\n url: _getReportingUrl(),\n deviceInfo: _getUserAgent(),\n stackTrace,\n reporter: this._reporter,\n integration: this._integrationName,\n };\n\n const headers: Record = {\n Accept: 'text/plain;charset=UTF-8',\n 'Content-Type': 'application/json',\n 'rokt-launcher-version': this._integrationName,\n 'rokt-wsdk-version': 'joint',\n };\n\n if (this._launcherInstanceGuid) {\n headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid;\n }\n if (this._accountId) {\n headers['rokt-account-id'] = this._accountId;\n }\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(logRequest),\n })\n .then((response: Response) => {\n // fetch only rejects on network failures; an HTTP 5xx resolves with\n // ok === false. Surface server-side failures so they are not swallowed.\n if (!response.ok) {\n const serverError: DeliveryError = new Error('HTTP ' + response.status + ' from log endpoint');\n serverError.statusCode = response.status;\n throw serverError;\n }\n })\n .catch((error: DeliveryError) => {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error);\n });\n } catch (error) {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error as DeliveryError);\n }\n }\n}\n\nclass ErrorReportingService {\n private _transport: ReportingTransport;\n private _errorUrl: string;\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._errorUrl = generateReportingUrl(config?.errorUrl, config?.integrationDomain, ERROR_ENDPOINT);\n }\n\n report(error: ErrorReport | null | undefined): void {\n if (!error) return;\n const severity = error.severity || WSDKErrorSeverity.ERROR;\n this._transport.send(this._errorUrl, severity, error.message, error.code, error.stackTrace);\n }\n}\n\nclass LoggingService {\n private _transport: ReportingTransport;\n private _loggingUrl: string;\n private _errorReportingService: { report: (e: ErrorReport) => void };\n\n constructor(\n config: ReportingConfig,\n errorReportingService: { report: (e: ErrorReport) => void },\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._loggingUrl = generateReportingUrl(config?.loggingUrl, config?.integrationDomain, LOGGING_ENDPOINT);\n this._errorReportingService = errorReportingService;\n }\n\n log(entry: LogEntry | null | undefined): void {\n if (!entry) return;\n this._transport.send(\n this._loggingUrl,\n WSDKErrorSeverity.INFO,\n entry.message,\n entry.code,\n undefined,\n (error: DeliveryError) => {\n if (this._errorReportingService) {\n // A failed log POST is not itself an SDK error. Network-level failures\n // (ad-blockers, offline, CORS) are client-side noise and reported as a\n // WARNING; only a server-side non-2xx response stays at ERROR severity.\n const isServerSide = typeof error.statusCode === 'number';\n this._errorReportingService.report({\n message: 'LoggingService: Failed to send log: ' + error.message,\n code: ErrorCodes.LOG_DELIVERY_FAILURE,\n severity: isServerSide ? WSDKErrorSeverity.ERROR : WSDKErrorSeverity.WARNING,\n });\n }\n },\n );\n }\n}\n\n// ============================================================\n// RoktKit class\n// ============================================================\n\nclass RoktKit implements KitInterface {\n // Static field for allowed origin hashes (mutable by testHelpers)\n public static _allowedOriginHashes: number[] = [-553112570, 549508659];\n\n private static readonly PERFORMANCE_MARKS = {\n RoktScriptAppended: 'mp:RoktScriptAppended',\n };\n\n private static readonly EMAIL_SHA256_KEY = 'emailsha256';\n\n // Public fields (accessed by tests and the mParticle framework)\n public name = name;\n public id = moduleId;\n public moduleId = moduleId;\n public isInitialized = false;\n public launcher: RoktLauncher | null = null;\n public filters: KitFilters = {};\n public userAttributes: Record = {};\n // Flag set by the Workspace IDSync flow on a 200 response. Stored on the\n // kit instance and merged into placement attributes inside selectPlacements.\n public userIdentifiedInWorkspace = false;\n public testHelpers: TestHelpers | null = null;\n public placementEventMappingLookup: Record = {};\n public placementEventAttributeMappingLookup: Record = {};\n public integrationName: string | null = null;\n public domain?: string;\n public errorReportingService: ErrorReportingService | null = null;\n public loggingService: LoggingService | null = null;\n\n // Private fields\n private _mappedEmailSha256Key?: string;\n private _onboardingExpProvider?: string;\n private _thankYouElementOnLoadCallback: (() => void) | null = null;\n private _isThankYouElementLoaded = false;\n private _workspaceIdSyncApiKey?: string;\n\n // Held during a search dispatch so the next selectPlacements call;\n // can wait for the HTTP response before reading userIdentifiedInWorkspace;\n // — otherwise the first placement call ships without the flag.\n private _workspaceSearchInFlightPromise: Promise | null = null;\n // Stable serialization of the identifier set sent in the most recent\n // successful search dispatch. If a subsequent identification arrives with\n // an identical set, we skip the network call (the flag is still correct\n // from the prior search). Keyed over the full IUserIdentities map — not\n // just email — so partners passing hashed email through `other`/`other2-10`\n // or any other identifier benefit from the same dedupe. Cleared on logout\n // so a re-login re-evaluates fresh.\n private _workspaceLastSearchedIdentitiesKey?: string;\n\n // ---- Private helpers ----\n\n private getEventAttributeValue(event: SDKEvent, eventAttributeKey: string): unknown {\n const attributes = event && event.EventAttributes;\n if (!attributes) {\n return null;\n }\n\n if (typeof attributes[eventAttributeKey] === 'undefined') {\n return null;\n }\n\n return attributes[eventAttributeKey];\n }\n\n private doesEventAttributeConditionMatch(condition: EventAttributeCondition, actualValue: unknown): boolean {\n if (!condition || !isString(condition.operator)) {\n return false;\n }\n\n const operator = condition.operator.toLowerCase();\n const expectedValue = condition.attributeValue;\n\n if (operator === 'exists') {\n return actualValue !== null;\n }\n\n if (actualValue == null) {\n return false;\n }\n\n if (operator === 'equals') {\n return String(actualValue) === String(expectedValue);\n }\n\n if (operator === 'contains') {\n return String(actualValue).indexOf(String(expectedValue)) !== -1;\n }\n\n return false;\n }\n\n private doesEventMatchRule(event: SDKEvent, rule: PlacementEventRule): boolean {\n if (!rule || !isString(rule.eventAttributeKey)) {\n return false;\n }\n\n const conditions = rule.conditions;\n if (!Array.isArray(conditions)) {\n return false;\n }\n\n const actualValue = this.getEventAttributeValue(event, rule.eventAttributeKey);\n\n if (conditions.length === 0) {\n return actualValue !== null;\n }\n for (let i = 0; i < conditions.length; i++) {\n if (!this.doesEventAttributeConditionMatch(conditions[i], actualValue)) {\n return false;\n }\n }\n\n return true;\n }\n\n private applyPlacementEventAttributeMapping(event: SDKEvent): void {\n const mappedAttributeKeys = Object.keys(this.placementEventAttributeMappingLookup);\n for (let i = 0; i < mappedAttributeKeys.length; i++) {\n const mappedAttributeKey = mappedAttributeKeys[i];\n const rulesForMappedAttributeKey = this.placementEventAttributeMappingLookup[mappedAttributeKey];\n if (isEmpty(rulesForMappedAttributeKey)) {\n continue;\n }\n\n // Require ALL rules for the same key to match (AND).\n let allMatch = true;\n for (let j = 0; j < rulesForMappedAttributeKey.length; j++) {\n if (!this.doesEventMatchRule(event, rulesForMappedAttributeKey[j])) {\n allMatch = false;\n break;\n }\n }\n if (!allMatch) {\n continue;\n }\n\n mp().Rokt.setLocalSessionAttribute?.(mappedAttributeKey, true);\n }\n }\n\n private isLauncherReadyToAttach(): boolean {\n return !!window.Rokt && typeof window.Rokt.createLauncher === 'function';\n }\n\n /**\n * Returns the user identities from the filtered user, if any.\n */\n private returnUserIdentities(filteredUser: FilteredUser | null | undefined): Record {\n if (!filteredUser || !filteredUser.getUserIdentities) {\n return {};\n }\n\n const userIdentities: IUserIdentities = filteredUser.getUserIdentities().userIdentities;\n\n return this.replaceOtherIdentityWithEmailsha256(userIdentities);\n }\n\n private returnLocalSessionAttributes(): Record {\n if (!mp().Rokt || typeof mp().Rokt.getLocalSessionAttributes !== 'function') {\n return {};\n }\n if (isEmpty(this.placementEventMappingLookup) && isEmpty(this.placementEventAttributeMappingLookup)) {\n return {};\n }\n return mp().Rokt.getLocalSessionAttributes!();\n }\n\n private replaceOtherIdentityWithEmailsha256(userIdentities: IUserIdentities): Record {\n const newUserIdentities: Record = { ...(userIdentities || {}) };\n const key = this._mappedEmailSha256Key;\n if (key && userIdentities[key as keyof IUserIdentities]) {\n newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key as keyof IUserIdentities] as string;\n }\n if (key) {\n delete newUserIdentities[key];\n }\n\n return newUserIdentities;\n }\n\n private logSelectPlacementsEvent(attributes: unknown): void {\n if (!window.mParticle || typeof mp().logEvent !== 'function') {\n return;\n }\n\n if (!isObject(attributes)) {\n return;\n }\n\n const EVENT_TYPE_OTHER = mp().EventType.Other;\n\n mp().logEvent(EVENT_NAME_SELECT_PLACEMENTS, EVENT_TYPE_OTHER, attributes as Record);\n }\n\n private setRoktSessionId(sessionId: string): void {\n if (!sessionId || typeof sessionId !== 'string') {\n return;\n }\n try {\n const mpInstance = mp().getInstance();\n if (mpInstance && typeof mpInstance.setIntegrationAttribute === 'function') {\n mpInstance.setIntegrationAttribute(moduleId, {\n roktSessionId: sessionId,\n });\n }\n } catch (_e) {\n // Best effort — never let this break the partner page\n }\n }\n\n private attachLauncher(\n accountId: string,\n launcherOptions: Record,\n legacyRoktExtensions: string[] = [],\n ): void {\n const mpSessionId =\n mp() && mp().sessionManager && typeof mp().sessionManager!.getSession === 'function'\n ? mp().sessionManager!.getSession()\n : undefined;\n\n const options: Record = {\n accountId,\n ...(launcherOptions || {}),\n ...(mpSessionId ? { mpSessionId } : {}),\n };\n\n let launcherPromise: Promise;\n if (this.isPartnerInLocalLauncherTestGroup()) {\n launcherPromise = Promise.resolve(window.Rokt!.createLocalLauncher(options));\n } else {\n launcherPromise = window.Rokt!.createLauncher(options);\n }\n\n launcherPromise\n .then(async (launcher) => {\n await registerLegacyExtensions(legacyRoktExtensions, launcher);\n this.initRoktLauncher(launcher);\n })\n .catch((err: unknown) => {\n console.error('Error creating Rokt launcher:', err);\n });\n }\n\n private initRoktLauncher(launcher: RoktLauncher): void {\n // Assign the launcher to a global variable for later access\n if (window.Rokt) {\n window.Rokt.currentLauncher = launcher;\n }\n // Locally cache the launcher and filters\n this.launcher = launcher;\n\n const roktFilters = mp().Rokt?.filters;\n\n if (!roktFilters) {\n console.warn('Rokt Kit: No filters have been set.');\n } else {\n this.filters = roktFilters;\n if (!roktFilters.filteredUser) {\n console.warn('Rokt Kit: No filtered user has been set.');\n } else {\n this._workspaceSearchInFlightPromise = this.search(roktFilters.filteredUser);\n }\n }\n\n // Kit must be initialized before attaching to the Rokt manager\n this.isInitialized = true;\n\n sendAdBlockMeasurementSignals(this.domain, this.integrationName);\n\n // Attaches the kit to the Rokt manager\n mp().Rokt.attachKit(this);\n }\n\n private fetchOptimizely(): Record {\n const forwarders = mp()\n ._getActiveForwarders()\n .filter((forwarder) => forwarder.name === 'Optimizely');\n\n try {\n if (forwarders.length > 0 && window.optimizely) {\n const optimizelyState = window.optimizely.get('state');\n if (!optimizelyState || !optimizelyState.getActiveExperimentIds) {\n return {};\n }\n const activeExperimentIds = optimizelyState.getActiveExperimentIds();\n const activeExperiments = activeExperimentIds.reduce((acc: Record, expId: string) => {\n acc['rokt.custom.optimizely.experiment.' + expId + '.variationId'] =\n optimizelyState.getVariationMap()[expId].id;\n return acc;\n }, {});\n return activeExperiments;\n }\n } catch (error) {\n console.error('Error fetching Optimizely attributes:', error);\n }\n return {};\n }\n\n private isKitReady(): boolean {\n return !!(this.isInitialized && this.launcher);\n }\n\n private isPartnerInLocalLauncherTestGroup(): boolean {\n return !!(mp().config && mp().config!.isLocalLauncherEnabled && this.isAssignedToSampleGroup());\n }\n\n private isAssignedToSampleGroup(): boolean {\n const LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5;\n return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD;\n }\n\n private captureTiming(metricName: string): void {\n if (window && mp() && mp().captureTiming && metricName) {\n mp().captureTiming!(metricName);\n }\n }\n\n // ---- Public methods (mParticle Kit Callbacks) ----\n\n /**\n * Initializes the Rokt forwarder with settings from the mParticle server.\n */\n public init(\n settings: Record,\n _service: unknown,\n testMode: boolean,\n _trackerId: unknown,\n filteredUserAttributes?: Record,\n ): string {\n const kitSettings = settings as unknown as RoktKitSettings;\n const accountId = kitSettings.accountId;\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredUserAttributes);\n this._onboardingExpProvider = kitSettings.onboardingExpProvider;\n\n const placementEventMapping = parseSettingsString(kitSettings.placementEventMapping);\n this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping);\n\n const placementEventAttributeMapping = parseSettingsString(\n kitSettings.placementEventAttributeMapping,\n );\n this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping);\n\n // Set dynamic OTHER_IDENTITY based on server settings\n if (kitSettings.hashedEmailUserIdentityType) {\n this._mappedEmailSha256Key = kitSettings.hashedEmailUserIdentityType.toLowerCase();\n }\n\n this._workspaceIdSyncApiKey = isString(kitSettings.workspaceIdSyncApiKey)\n ? kitSettings.workspaceIdSyncApiKey\n : undefined;\n\n const domain = mp().Rokt?.domain;\n const { roktExtensionsQueryParams, legacyRoktExtensions, loadThankYouElement } = extractRoktExtensionConfig(\n kitSettings.roktExtensions,\n );\n const launcherOptions: Record = {\n ...((mp().Rokt?.launcherOptions as Record) || {}),\n };\n this.integrationName = generateIntegrationName(launcherOptions.integrationName as string | undefined);\n launcherOptions.integrationName = this.integrationName;\n\n this.domain = domain;\n\n const reportingConfig: ReportingConfig = {\n loggingUrl: kitSettings.loggingUrl,\n errorUrl: kitSettings.errorUrl,\n integrationDomain: domain,\n isLoggingEnabled: mp().config?.isLoggingEnabled === true,\n };\n const errorReportingService = new ErrorReportingService(\n reportingConfig,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n const loggingService = new LoggingService(\n reportingConfig,\n errorReportingService,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n\n this.errorReportingService = errorReportingService;\n this.loggingService = loggingService;\n\n if (mp()._registerErrorReportingService) {\n mp()._registerErrorReportingService!(errorReportingService);\n }\n if (mp()._registerLoggingService) {\n mp()._registerLoggingService!(loggingService);\n }\n\n if (testMode) {\n this.testHelpers = {\n generateLauncherScript: generateLauncherScript,\n generateThankYouElementScript: generateThankYouElementScript,\n extractRoktExtensionConfig: extractRoktExtensionConfig,\n hashEventMessage: hashEventMessage,\n parseSettingsString: parseSettingsString,\n generateMappedEventLookup: generateMappedEventLookup,\n generateMappedEventAttributeLookup: generateMappedEventAttributeLookup,\n sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals,\n createAutoRemovedIframe: createAutoRemovedIframe,\n djb2: djb2,\n setAllowedOriginHashes: (hashes: number[]) => {\n RoktKit._allowedOriginHashes = hashes;\n },\n ReportingTransport: ReportingTransport,\n ErrorReportingService: ErrorReportingService,\n LoggingService: LoggingService,\n RateLimiter: RateLimiter,\n ErrorCodes: ErrorCodes,\n WSDKErrorSeverity: WSDKErrorSeverity,\n };\n this.attachLauncher(accountId, launcherOptions);\n return 'Successfully initialized: ' + name;\n }\n\n if (loadThankYouElement) {\n mp().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this);\n loadRoktScript(ROKT_THANK_YOU_ELEMENT_SCRIPT_ID, generateThankYouElementScript(domain), {\n onLoad: () => {\n this._isThankYouElementLoaded = true;\n if (this._thankYouElementOnLoadCallback) {\n this._thankYouElementOnLoadCallback();\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt Thank You Element script:', error);\n },\n });\n }\n\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n loadRoktScript(ROKT_INTEGRATION_SCRIPT_ID, generateLauncherScript(domain, roktExtensionsQueryParams), {\n onLoad: () => {\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n console.error('Rokt object is not available after script load.');\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt launcher script:', error);\n },\n });\n\n this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended);\n }\n\n return 'Successfully initialized: ' + name;\n }\n\n public process(event: SDKEvent): string {\n if (!this.isKitReady()) {\n return 'Kit not ready for forwarder: ' + name;\n }\n if (typeof mp().Rokt?.setLocalSessionAttribute === 'function') {\n if (!isEmpty(this.placementEventAttributeMappingLookup)) {\n this.applyPlacementEventAttributeMapping(event);\n }\n\n if (!isEmpty(this.placementEventMappingLookup)) {\n const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? '');\n if (this.placementEventMappingLookup[String(hashedEvent)]) {\n mp().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(hashedEvent)], true);\n }\n }\n }\n\n return 'Successfully sent to forwarder: ' + name;\n }\n\n public setExtensionData(partnerExtensionData: Record): void {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return;\n }\n\n window.Rokt!.setExtensionData(partnerExtensionData);\n }\n\n public setUserAttribute(key: string, value: unknown): string {\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n this.userAttributes[key] = value;\n }\n return 'Successfully set user attribute for forwarder: ' + name;\n }\n\n public removeUserAttribute(key: string): string {\n delete this.userAttributes[key];\n return 'Successfully removed user attribute for forwarder: ' + name;\n }\n\n private handleIdentityComplete(user: IMParticleUser, callbackName: string): string {\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(user.getAllUserAttributes());\n return 'Successfully called ' + callbackName + ' for forwarder: ' + name;\n }\n\n public onUserIdentified(user: IMParticleUser): string {\n const filteredUser = user as FilteredUser;\n this.filters.filteredUser = filteredUser;\n this._workspaceSearchInFlightPromise = this.search(filteredUser);\n return this.handleIdentityComplete(user, 'onUserIdentified');\n }\n\n private search(filteredUser: FilteredUser): Promise {\n const apiKey = this._workspaceIdSyncApiKey;\n if (!apiKey) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n const search = mp().Identity?.search;\n if (typeof search !== 'function') {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n const userIdentities: IUserIdentities | null = filteredUser.getUserIdentities\n ? filteredUser.getUserIdentities().userIdentities\n : null;\n\n // Forward every non-empty string identifier the user has — email,\n // customerid, other/other2-10 (commonly used for hashed email),\n // mobile_number, facebook, etc. The host SDK's Identity.search accepts\n // the full IUserIdentities surface and the server validates it.\n const knownIdentities: Record = {};\n if (userIdentities) {\n for (const key of Object.keys(userIdentities) as Array) {\n const value = userIdentities[key];\n if (isString(value) && value.length > 0) {\n knownIdentities[key] = value;\n }\n }\n }\n\n const identityKeys = Object.keys(knownIdentities);\n if (identityKeys.length === 0) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n // Stable cache key: sort keys so insertion-order differences don't\n // cause false misses. The values are partner-supplied strings; no\n // hashing needed — equality on this serialization is sufficient.\n const identitiesKey = identityKeys\n .sort()\n .map((k) => `${k}=${knownIdentities[k]}`)\n .join('&');\n\n // Same identifier set as the last successful dispatch → skip the\n // network call. The current flag value still reflects the correct\n // match status.\n if (identitiesKey === this._workspaceLastSearchedIdentitiesKey) {\n return this._workspaceSearchInFlightPromise || Promise.resolve();\n }\n\n // New / different identifier set → reset and re-search. Cache the key\n // up front so a second concurrent invocation with the same set also\n // dedupes.\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = identitiesKey;\n\n return new Promise((resolve) => {\n try {\n search(apiKey, knownIdentities as IUserIdentities, (result: WorkspaceIdSyncResult) => {\n if (result?.httpCode === 200) {\n this.userIdentifiedInWorkspace = true;\n }\n resolve();\n });\n } catch (err) {\n console.error('Rokt Kit: Workspace IDSync search failed', err);\n // Dispatch failed — clear the cache so the same identifier set\n // can retry on the next identification rather than being stuck\n // behind a poisoned entry that short-circuits future searches.\n this._workspaceLastSearchedIdentitiesKey = undefined;\n resolve();\n }\n });\n }\n\n public onLoginComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onLoginComplete');\n }\n\n public onLogoutComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n // Anonymous sessions must not carry the previous user's match forward.\n // Clear the flag explicitly here. Also clear the identities cache so a\n // re-login (possibly with the same identifiers) dispatches a fresh\n // search rather than reusing a stale answer.\n this.userIdentifiedInWorkspace = false;\n this._workspaceSearchInFlightPromise = null;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return this.handleIdentityComplete(user, 'onLogoutComplete');\n }\n\n public onModifyComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onModifyComplete');\n }\n\n /**\n * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options.\n *\n * If a Workspace IDSync search is in flight from a recent onUserIdentified\n * call, this method waits up to `WORKSPACE_SEARCH_SELECT_TIMEOUT_MS` for it\n * to settle so the first placement call can include the\n * `userIdentifiedInWorkspace` flag without racing the network response.\n * The timeout protects against a stalled or slow search blocking placement\n * rendering — if it fires, selectPlacements proceeds without the flag.\n *\n * Implementation note: this method stays non-async deliberately. First,\n * the public return type is `RoktSelection | Promise |\n * undefined` — a superset of the `RoktSelection | Promise`\n * shape declared for `RoktLauncher.selectPlacements` above (line ~70).\n * Marking this `async` would narrow it to `Promise` and silently change the contract for callers that read\n * the result synchronously. Second, `RoktSelection` has an optional\n * `then?` member, so TS treats it as ambiguously promise-like and\n * rejects it as the awaited return of an async function (TS1058) —\n * working around that would require a cast or wrapping every return in\n * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`;\n * this wrapper just gates it on the in-flight search via `Promise.race`.\n */\n public selectPlacements(options: Record): RoktSelection | Promise | undefined {\n if (this._workspaceSearchInFlightPromise) {\n const inFlight = this._workspaceSearchInFlightPromise;\n return Promise.race([\n inFlight,\n new Promise((resolve) => setTimeout(resolve, WORKSPACE_SEARCH_SELECT_TIMEOUT_MS)),\n ]).then(() => this._dispatchPlacements(options)) as Promise;\n }\n return this._dispatchPlacements(options);\n }\n\n private _dispatchPlacements(options: Record): RoktSelection | Promise | undefined {\n const attributes = ((options && (options.attributes as Record)) || {}) as Record;\n const cachedUserAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(this.userAttributes);\n const placementAttributes: Record = { ...cachedUserAttributes, ...attributes };\n\n const filters = this.filters || {};\n const userAttributeFilters = (filters.userAttributeFilters as string[]) || [];\n const filteredUser = filters.filteredUser || null;\n const mpid = filteredUser ? filteredUser.getMPID() : null;\n\n let filteredAttributes: Record;\n\n if (!filters) {\n console.warn('Rokt Kit: No filters available, using user attributes');\n filteredAttributes = placementAttributes;\n } else if (filters.filterUserAttributes) {\n filteredAttributes = filters.filterUserAttributes(placementAttributes, userAttributeFilters);\n } else {\n filteredAttributes = placementAttributes;\n }\n\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredAttributes);\n\n const optimizelyAttributes = this._onboardingExpProvider === 'Optimizely' ? this.fetchOptimizely() : {};\n\n const filteredUserIdentities = this.returnUserIdentities(filteredUser);\n\n const localSessionAttributes = this.returnLocalSessionAttributes();\n\n const selectPlacementsAttributes: Record = {\n ...(filteredUserIdentities as Record),\n ...filteredAttributes,\n ...optimizelyAttributes,\n ...localSessionAttributes,\n ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}),\n mpid,\n };\n\n const selectPlacementsOptions: Record = { ...options, attributes: selectPlacementsAttributes };\n\n const selection = this.launcher!.selectPlacements(selectPlacementsOptions);\n\n // After selection resolves, sync the Rokt session ID back to mParticle, then log\n const logSelection = () => this.logSelectPlacementsEvent(selectPlacementsAttributes);\n\n void Promise.resolve(selection)\n .then((sel) => sel?.context?.sessionId?.then((sessionId) => this.setRoktSessionId(sessionId)))\n .catch(() => undefined)\n .finally(logSelection);\n\n return selection;\n }\n\n /**\n * Passes attributes to the Rokt Web SDK for client-side hashing.\n */\n public hashAttributes(attributes: Record): Promise> | null {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return null;\n }\n return this.launcher!.hashAttributes(attributes);\n }\n\n /**\n * Enables optional Integration Launcher extensions before selecting placements.\n *\n * @deprecated This functionality has been internalized and will be removed in a future release.\n */\n public use(extensionName: string): Promise {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return Promise.reject(new Error('Rokt Kit: Not initialized'));\n }\n if (!extensionName || !isString(extensionName)) {\n return Promise.reject(new Error('Rokt Kit: Invalid extension name'));\n }\n return this.launcher!.use(extensionName);\n }\n\n /**\n * Registers a callback to be invoked once rokt-thank-you-element.js becomes available.\n */\n public onShoppableAdsReady(callback: () => void) {\n if (this._isThankYouElementLoaded) {\n callback();\n } else {\n this._thankYouElementOnLoadCallback = callback;\n }\n }\n}\n\n// ============================================================\n// Kit registration\n// ============================================================\n\nfunction getId(): number {\n return moduleId;\n}\n\nfunction register(config: { kits?: Record }): void {\n if (!config) {\n window.console.log('You must pass a config object to register the kit ' + name);\n return;\n }\n if (!isObject(config)) {\n window.console.log(\"'config' must be an object. You passed in a \" + typeof config);\n return;\n }\n\n if (isObject(config.kits)) {\n (config.kits as Record)[name] = {\n constructor: RoktKit,\n };\n } else {\n config.kits = {};\n config.kits[name] = {\n constructor: RoktKit,\n };\n }\n window.console.log('Successfully registered ' + name + ' to your mParticle configuration');\n}\n\nif (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) {\n mp().addForwarder({\n name: name,\n constructor: RoktKit,\n getId: getId,\n });\n}\n\nexport { register };\n"],"names":["SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST","SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET","isSelectPlacementsAttributePersistenceDenied","key","removeSelectPlacementsAttributePersistenceDeniedAttributes","attributes","filteredAttributes","sourceAttributes","attributeKeys","i","name","moduleId","EVENT_NAME_SELECT_PLACEMENTS","ADBLOCK_CONTROL_DOMAIN","INIT_LOG_SAMPLING_RATE","ROKT_THANK_YOU_JOURNEY_EXTENSION","ROKT_INTEGRATION_SCRIPT_ID","ROKT_THANK_YOU_ELEMENT_SCRIPT_ID","USER_IDENTIFIED_IN_WORKSPACE_KEY","WORKSPACE_SEARCH_SELECT_TIMEOUT_MS","ErrorCodes","WSDKErrorSeverity","DEFAULT_ROKT_DOMAIN","LOGGING_ENDPOINT","ERROR_ENDPOINT","RATE_LIMIT_PER_SEVERITY","mp","generateLauncherScript","domain","extensions","baseUrl","generateBaseUrl","generateThankYouElementScript","generateReportingUrl","configuredUrl","endpoint","loadRoktScript","scriptId","source","handlers","target","script","isObject","val","parseSettingsString","settingsString","extractRoktExtensionConfig","settings","roktExtensionsQueryParams","legacyRoktExtensions","loadThankYouElement","extensionName","registerLegacyExtensions","legacyExtensions","launcher","extension","generateMappedEventLookup","placementEventMapping","mappedEvents","mapping","generateMappedEventAttributeLookup","placementEventAttributeMapping","mappedAttributeKeys","isString","mappedAttributeKey","eventAttributeKey","hashEventMessage","messageType","eventType","eventName","isEmpty","value","generateIntegrationName","customIntegrationName","integrationName","djb2","str","hash","createAutoRemovedIframe","src","iframe","sendAdBlockMeasurementSignals","version","originHash","RoktKit","guid","pageUrl","params","_isDebugModeEnabled","_getReportingUrl","_getUserAgent","RateLimiter","severity","newCount","ReportingTransport","config","launcherInstanceGuid","accountId","rateLimiter","isLoggingEnabled","url","msg","code","stackTrace","onError","logRequest","headers","response","serverError","error","ErrorReportingService","LoggingService","errorReportingService","entry","isServerSide","_RoktKit","event","condition","actualValue","operator","expectedValue","rule","conditions","rulesForMappedAttributeKey","allMatch","j","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","launcherOptions","mpSessionId","options","launcherPromise","err","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","loggingService","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","search","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","localSessionAttributes","selectPlacementsAttributes","selectPlacementsOptions","selection","logSelection","sel","callback","getId","register"],"mappings":"gFAAA,MAAMA,EAAoD,CACxD,kBACA,kBACA,cACA,eACA,iBACA,YACA,QACA,kBACA,iBACA,UACA,aACA,WACA,WACA,yBACA,kCACA,cACA,mBACA,eACA,kBACA,iBACA,gBACA,kBACA,YACF,EACMC,EAAmD,IAAI,IAAID,CAAiD,EAE3G,SAASE,EAA6CC,EAAsB,CACjF,OAAOF,EAAiD,IAAIE,EAAI,YAAA,CAAa,CAC/E,CAEO,SAASC,EACdC,EACyB,CACzB,MAAMC,EAA8C,CAAA,EAC9CC,EAAmBF,GAAc,CAAA,EACjCG,EAAgB,OAAO,KAAKD,CAAgB,EAElD,QAASE,EAAI,EAAGA,EAAID,EAAc,OAAQC,IAAK,CAC7C,MAAMN,EAAMK,EAAcC,CAAC,EACtBP,EAA6CC,CAAG,IACnDG,EAAmBH,CAAG,EAAII,EAAiBJ,CAAG,EAElD,CAEA,OAAOG,CACT,CC8LA,MAAMI,EAAO,OACPC,EAAW,IACXC,EAA+B,mBAC/BC,EAAyB,yBACzBC,EAAyB,GACzBC,EAAmC,sBACnCC,GAA6B,gBAC7BC,GAAmC,yBACnCC,GAAmC,4BAMnCC,GAAqC,IAMrCC,EAAa,CACjB,cAAe,gBACf,oBAAqB,sBACrB,iBAAkB,mBAClB,qBAAsB,sBACxB,EAEMC,EAAoB,CACxB,MAAO,QACP,KAAM,OACN,QAAS,SACX,EAEMC,GAAsB,oBACtBC,GAAmB,UACnBC,GAAiB,aACjBC,GAA0B,GAQhC,SAASC,GAAwB,CAE/B,OAAQ,OAAe,SACzB,CAMA,SAASC,EAAuBC,EAA4BC,EAA8B,CAExF,MAAMC,EAAU,CAACC,EAAgBH,CAAM,EADlB,gCACiC,EAAE,KAAK,EAAE,EAE/D,MAAI,CAACC,GAAcA,EAAW,SAAW,EAChCC,EAEFA,EAAU,eAAiBD,EAAW,KAAK,GAAG,CACvD,CAEA,SAASG,EAA8BJ,EAA4B,CAEjE,MAAO,CAACG,EAAgBH,CAAM,EADF,0CACwB,EAAE,KAAK,EAAE,CAC/D,CAEA,SAASG,EAAgBH,EAA4B,CAInD,MAAO,CAFU,WADM,OAAOA,EAAW,IAAcA,EAASN,EAGhC,EAAE,KAAK,EAAE,CAC3C,CAEA,SAASW,EAAqBC,EAAmCN,EAA4BO,EAA0B,CACrH,OAAID,EACEA,EAAc,WAAW,SAAS,GAAKA,EAAc,WAAW,UAAU,EACrEA,EAEF,WAAaA,EAGfH,EAAgBH,CAAM,EAAIO,CACnC,CAEA,SAASC,EACPC,EACAC,EACAC,EACM,CACN,GAAI,SAAS,eAAeF,CAAQ,EAAG,OAEvC,MAAMG,EAAS,SAAS,MAAQ,SAAS,KACnCC,EAAS,SAAS,cAAc,QAAQ,EAC9CA,EAAO,GAAKJ,EACZI,EAAO,KAAO,kBACdA,EAAO,IAAMH,EACbG,EAAO,MAAQ,GACfA,EAAO,YAAc,YACpBA,EAAyD,cAAgB,OACtEF,GAAU,SAAQE,EAAO,OAASF,EAAS,QAC3CA,GAAU,UAASE,EAAO,QAAUF,EAAS,SACjDC,EAAO,YAAYC,CAAM,CAC3B,CAEA,SAASC,EAASC,EAA8C,CAC9D,OAAOA,GAAO,MAAQ,OAAOA,GAAQ,UAAY,MAAM,QAAQA,CAAG,IAAM,EAC1E,CAEA,SAASC,EAAuBC,EAA8B,CAC5D,GAAI,CAACA,EACH,MAAO,CAAA,EAET,GAAI,CACF,OAAO,KAAK,MAAMA,EAAe,QAAQ,UAAW,GAAG,CAAC,CAC1D,MAAiB,CACf,QAAQ,MAAM,uCAAuC,CACvD,CACA,MAAO,CAAA,CACT,CAEA,SAASC,EAA2BD,EAA8C,CAChF,MAAME,EAAWF,EAAiBD,EAAwCC,CAAc,EAAI,CAAA,EACtFG,EAAsC,CAAA,EACtCC,EAAiC,CAAA,EACvC,IAAIC,EAAsB,GAE1B,QAASzC,EAAI,EAAGA,EAAIsC,EAAS,OAAQtC,IAAK,CACxC,MAAM0C,EAAgBJ,EAAStC,CAAC,EAAE,MAC9B0C,IAAkB,qBACpBD,EAAsB,GACtBD,EAAqB,KAAKlC,CAAgC,GAE1DiC,EAA0B,KAAKG,CAAa,CAEhD,CAEA,MAAO,CACL,0BAAAH,EACA,qBAAAC,EACA,oBAAAC,CAAA,CAEJ,CAEA,eAAeE,GAAyBC,EAA4BC,EAA+B,CACjG,MAAMzB,EAAiC,CAAA,EACvC,GAAIyB,EACF,UAAWC,KAAaF,EACtBxB,EAAW,KAAKyB,EAAS,IAAIC,CAAS,CAAC,EAI3C,OAAO,QAAQ,IAAI1B,CAAU,CAC/B,CAEA,SAAS2B,EAA0BC,EAA6E,CAC9G,GAAI,CAACA,EACH,MAAO,CAAA,EAGT,MAAMC,EAAuC,CAAA,EAC7C,QAASjD,EAAI,EAAGA,EAAIgD,EAAsB,OAAQhD,IAAK,CACrD,MAAMkD,EAAUF,EAAsBhD,CAAC,EACvCiD,EAAaC,EAAQ,KAAK,EAAIA,EAAQ,KACxC,CACA,OAAOD,CACT,CAEA,SAASE,EACPC,EACsC,CACtC,MAAMC,EAA4D,CAAA,EAClE,GAAI,CAAC,MAAM,QAAQD,CAA8B,EAC/C,OAAOC,EAET,QAASrD,EAAI,EAAGA,EAAIoD,EAA+B,OAAQpD,IAAK,CAC9D,MAAMkD,EAAUE,EAA+BpD,CAAC,EAChD,GAAI,CAACkD,GAAW,CAACI,EAASJ,EAAQ,KAAK,GAAK,CAACI,EAASJ,EAAQ,GAAG,EAC/D,SAGF,MAAMK,EAAqBL,EAAQ,MAC7BM,EAAoBN,EAAQ,IAE7BG,EAAoBE,CAAkB,IACzCF,EAAoBE,CAAkB,EAAI,CAAA,GAG5CF,EAAoBE,CAAkB,EAAE,KAAK,CAC3C,kBAAAC,EACA,WAAY,MAAM,QAAQN,EAAQ,UAAU,EAAIA,EAAQ,WAAa,CAAA,CAAC,CACvE,CACH,CACA,OAAOG,CACT,CAEA,SAASI,EAAiBC,EAAqBC,EAAmBC,EAAoC,CACpG,OAAO3C,EAAA,EAAK,aAAa,CAACyC,EAAaC,EAAWC,CAAS,EAAE,KAAK,EAAE,CAAC,CACvE,CAEA,SAASC,EAAQC,EAAyB,CACxC,OAAIA,GAAS,KAAa,GACtB,OAAOA,GAAU,SACZ,OAAO,KAAKA,CAAe,EAAE,SAAW,EAE7C,MAAM,QAAQA,CAAK,EACbA,EAAoB,SAAW,EAElC,EACT,CAEA,SAASR,EAASQ,EAAiC,CACjD,OAAO,OAAOA,GAAU,QAC1B,CAEA,SAASC,GAAwBC,EAAwC,CAGvE,IAAIC,EAAkB,mBAFChD,EAAA,EAAK,WAAA,EAEqC,SAD9C,SAGnB,OAAI+C,IACFC,GAAmB,IAAMD,GAEpBC,CACT,CAEA,SAASC,EAAKC,EAAqB,CACjC,IAAIC,EAAO,KACX,QAASpE,EAAI,EAAGA,EAAImE,EAAI,OAAQnE,IAC9BoE,GAAQA,GAAQ,GAAKA,EAAOD,EAAI,WAAWnE,CAAC,EAC5CoE,EAAOA,EAAOA,EAEhB,OAAOA,CACT,CAEA,SAASC,EAAwBC,EAAmB,CAClD,MAAMC,EAAS,SAAS,cAAc,QAAQ,EAC9CA,EAAO,MAAM,QAAU,OACvBA,EAAO,aAAa,UAAW,iCAAiC,EAChEA,EAAO,IAAMD,EACbC,EAAO,OAAS,UAAY,CAC1BA,EAAO,OAAS,KACZA,EAAO,YACTA,EAAO,WAAW,YAAYA,CAAM,CAExC,EACA,MAAMxC,EAAS,SAAS,MAAQ,SAAS,KACrCA,GACFA,EAAO,YAAYwC,CAAM,CAE7B,CAEA,SAASC,EAA8BrD,EAA4BsD,EAA8B,CAC/F,MAAMC,EAAaR,EAAK,OAAO,SAAS,MAAM,EAM9C,GAL4BS,EAAQ,qBACZ,QAAQD,CAAU,IAAM,IAI5C,KAAK,OAAA,GAAYrE,EACnB,OAGF,MAAMuE,EAAO,OAAO,iBACpB,GAAI,CAACA,EACH,OAGF,MAAMC,EAAU,OAAO,SAAS,KAAK,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC,EACzDC,EACJ,WACA,mBAAmBL,GAAW,EAAE,EAChC,yBACA,mBAAmBG,CAAI,EACvB,YACA,mBAAmBC,CAAO,EAG5BR,EAAwB,YADDlD,GAAU,iBACqB,4BAA8B2D,CAAM,EAE1FT,EACE,WAAajE,EAAyB,4BAA8B0E,EAAS,iBAAA,CAEjF,CAMA,SAASC,IAA+B,CACtC,OAAO,OAAO,OAAW,KAAe,CAAC,CAAC,OAAO,UAAU,QAAQ,YAAA,EAAc,SAAS,wBAAwB,CACpH,CAEA,SAASC,IAAuC,CAC9C,OAAO,OAAO,OAAW,IAAc,OAAO,UAAU,KAAO,MACjE,CAEA,SAASC,IAAoC,CAC3C,OAAO,OAAO,OAAW,IAAc,OAAO,WAAW,UAAY,MACvE,CAEA,MAAMC,CAAY,CAAlB,aAAA,CACE,KAAQ,UAAoC,CAAA,CAAC,CAE7C,kBAAkBC,EAA2B,CAE3C,MAAMC,GADQ,KAAK,UAAUD,CAAQ,GAAK,GACjB,EACzB,YAAK,UAAUA,CAAQ,EAAIC,EACpBA,EAAWpE,EACpB,CACF,CAEA,MAAMqE,CAAmB,CAQvB,YACEC,EACArB,EACAsB,EACAC,EACAC,EACA,CARF,KAAiB,UAAY,UAS3B,MAAMC,EAAmBJ,EAAO,iBAChC,KAAK,iBAAmBrB,GAAmB,GAC3C,KAAK,sBAAwBsB,EAC7B,KAAK,WAAaC,GAAa,KAC/B,KAAK,aAAeC,GAAe,IAAIP,EACvC,KAAK,WAAaH,MAAyBW,CAC7C,CAEA,KACEC,EACAR,EACAS,EACAC,EACAC,EACAC,EACM,CACN,GAAI,GAAC,KAAK,YAAc,KAAK,aAAa,kBAAkBZ,CAAQ,GAIpE,GAAI,CACF,MAAMa,EAAa,CACjB,sBAAuB,CACrB,QAASJ,EACT,QAAS,KAAK,gBAAA,EAEhB,SAAAT,EACA,KAAMU,GAAQlF,EAAW,cACzB,IAAKqE,GAAA,EACL,WAAYC,GAAA,EACZ,WAAAa,EACA,SAAU,KAAK,UACf,YAAa,KAAK,gBAAA,EAGdG,EAAkC,CACtC,OAAQ,2BACR,eAAgB,mBAChB,wBAAyB,KAAK,iBAC9B,oBAAqB,OAAA,EAGnB,KAAK,wBACPA,EAAQ,6BAA6B,EAAI,KAAK,uBAE5C,KAAK,aACPA,EAAQ,iBAAiB,EAAI,KAAK,YAGpC,MAAMN,EAAK,CACT,OAAQ,OACR,QAAAM,EACA,KAAM,KAAK,UAAUD,CAAU,CAAA,CAChC,EACE,KAAME,GAAuB,CAG5B,GAAI,CAACA,EAAS,GAAI,CAChB,MAAMC,EAA6B,IAAI,MAAM,QAAUD,EAAS,OAAS,oBAAoB,EAC7F,MAAAC,EAAY,WAAaD,EAAS,OAC5BC,CACR,CACF,CAAC,EACA,MAAOC,GAAyB,CAC/B,QAAQ,MAAM,yCAA0CA,CAAK,EACzDL,KAAiBK,CAAK,CAC5B,CAAC,CACL,OAASA,EAAO,CACd,QAAQ,MAAM,yCAA0CA,CAAK,EACzDL,KAAiBK,CAAsB,CAC7C,CACF,CACF,CAEA,MAAMC,CAAsB,CAI1B,YACEf,EACArB,EACAsB,EACAC,EACAC,EACA,CACA,KAAK,WAAa,IAAIJ,EAAmBC,EAAQrB,EAAiBsB,EAAsBC,EAAWC,CAAW,EAC9G,KAAK,UAAYjE,EAAqB8D,GAAQ,SAAUA,GAAQ,kBAAmBvE,EAAc,CACnG,CAEA,OAAOqF,EAA6C,CAClD,GAAI,CAACA,EAAO,OACZ,MAAMjB,EAAWiB,EAAM,UAAYxF,EAAkB,MACrD,KAAK,WAAW,KAAK,KAAK,UAAWuE,EAAUiB,EAAM,QAASA,EAAM,KAAMA,EAAM,UAAU,CAC5F,CACF,CAEA,MAAME,CAAe,CAKnB,YACEhB,EACAiB,EACAtC,EACAsB,EACAC,EACAC,EACA,CACA,KAAK,WAAa,IAAIJ,EAAmBC,EAAQrB,EAAiBsB,EAAsBC,EAAWC,CAAW,EAC9G,KAAK,YAAcjE,EAAqB8D,GAAQ,WAAYA,GAAQ,kBAAmBxE,EAAgB,EACvG,KAAK,uBAAyByF,CAChC,CAEA,IAAIC,EAA0C,CACvCA,GACL,KAAK,WAAW,KACd,KAAK,YACL5F,EAAkB,KAClB4F,EAAM,QACNA,EAAM,KACN,OACCJ,GAAyB,CACxB,GAAI,KAAK,uBAAwB,CAI/B,MAAMK,EAAe,OAAOL,EAAM,YAAe,SACjD,KAAK,uBAAuB,OAAO,CACjC,QAAS,uCAAyCA,EAAM,QACxD,KAAMzF,EAAW,qBACjB,SAAU8F,EAAe7F,EAAkB,MAAQA,EAAkB,OAAA,CACtE,CACH,CACF,CAAA,CAEJ,CACF,CAMA,MAAM8F,EAAN,MAAMA,CAAgC,CAAtC,aAAA,CAWE,KAAO,KAAOzG,EACd,KAAO,GAAKC,EACZ,KAAO,SAAWA,EAClB,KAAO,cAAgB,GACvB,KAAO,SAAgC,KACvC,KAAO,QAAsB,CAAA,EAC7B,KAAO,eAA0C,CAAA,EAGjD,KAAO,0BAA4B,GACnC,KAAO,YAAkC,KACzC,KAAO,4BAAsD,CAAA,EAC7D,KAAO,qCAA6E,CAAA,EACpF,KAAO,gBAAiC,KAExC,KAAO,sBAAsD,KAC7D,KAAO,eAAwC,KAK/C,KAAQ,+BAAsD,KAC9D,KAAQ,yBAA2B,GAMnC,KAAQ,gCAAwD,IAAA,CAYxD,uBAAuByG,EAAiBnD,EAAoC,CAClF,MAAM5D,EAAa+G,GAASA,EAAM,gBAKlC,MAJI,CAAC/G,GAID,OAAOA,EAAW4D,CAAiB,EAAM,IACpC,KAGF5D,EAAW4D,CAAiB,CACrC,CAEQ,iCAAiCoD,EAAoCC,EAA+B,CAC1G,GAAI,CAACD,GAAa,CAACtD,EAASsD,EAAU,QAAQ,EAC5C,MAAO,GAGT,MAAME,EAAWF,EAAU,SAAS,YAAA,EAC9BG,EAAgBH,EAAU,eAEhC,OAAIE,IAAa,SACRD,IAAgB,KAGrBA,GAAe,KACV,GAGLC,IAAa,SACR,OAAOD,CAAW,IAAM,OAAOE,CAAa,EAGjDD,IAAa,WACR,OAAOD,CAAW,EAAE,QAAQ,OAAOE,CAAa,CAAC,IAAM,GAGzD,EACT,CAEQ,mBAAmBJ,EAAiBK,EAAmC,CAC7E,GAAI,CAACA,GAAQ,CAAC1D,EAAS0D,EAAK,iBAAiB,EAC3C,MAAO,GAGT,MAAMC,EAAaD,EAAK,WACxB,GAAI,CAAC,MAAM,QAAQC,CAAU,EAC3B,MAAO,GAGT,MAAMJ,EAAc,KAAK,uBAAuBF,EAAOK,EAAK,iBAAiB,EAE7E,GAAIC,EAAW,SAAW,EACxB,OAAOJ,IAAgB,KAEzB,QAAS7G,EAAI,EAAGA,EAAIiH,EAAW,OAAQjH,IACrC,GAAI,CAAC,KAAK,iCAAiCiH,EAAWjH,CAAC,EAAG6G,CAAW,EACnE,MAAO,GAIX,MAAO,EACT,CAEQ,oCAAoCF,EAAuB,CACjE,MAAMtD,EAAsB,OAAO,KAAK,KAAK,oCAAoC,EACjF,QAAS,EAAI,EAAG,EAAIA,EAAoB,OAAQ,IAAK,CACnD,MAAME,EAAqBF,EAAoB,CAAC,EAC1C6D,EAA6B,KAAK,qCAAqC3D,CAAkB,EAC/F,GAAIM,EAAQqD,CAA0B,EACpC,SAIF,IAAIC,EAAW,GACf,QAASC,EAAI,EAAGA,EAAIF,EAA2B,OAAQE,IACrD,GAAI,CAAC,KAAK,mBAAmBT,EAAOO,EAA2BE,CAAC,CAAC,EAAG,CAClED,EAAW,GACX,KACF,CAEGA,GAILlG,EAAA,EAAK,KAAK,2BAA2BsC,EAAoB,EAAI,CAC/D,CACF,CAEQ,yBAAmC,CACzC,MAAO,CAAC,CAAC,OAAO,MAAQ,OAAO,OAAO,KAAK,gBAAmB,UAChE,CAKQ,qBAAqB8D,EAAuE,CAClG,GAAI,CAACA,GAAgB,CAACA,EAAa,kBACjC,MAAO,CAAA,EAGT,MAAMC,EAAkCD,EAAa,kBAAA,EAAoB,eAEzE,OAAO,KAAK,oCAAoCC,CAAc,CAChE,CAEQ,8BAAwD,CAC9D,MAAI,CAACrG,IAAK,MAAQ,OAAOA,EAAA,EAAK,KAAK,2BAA8B,WACxD,CAAA,EAEL4C,EAAQ,KAAK,2BAA2B,GAAKA,EAAQ,KAAK,oCAAoC,EACzF,CAAA,EAEF5C,EAAA,EAAK,KAAK,0BAAA,CACnB,CAEQ,oCAAoCqG,EAAyD,CACnG,MAAMC,EAA4C,CAAE,GAAID,GAAkB,EAAC,EACrE5H,EAAM,KAAK,sBACjB,OAAIA,GAAO4H,EAAe5H,CAA4B,IACpD6H,EAAkBb,EAAQ,gBAAgB,EAAIY,EAAe5H,CAA4B,GAEvFA,GACF,OAAO6H,EAAkB7H,CAAG,EAGvB6H,CACT,CAEQ,yBAAyB3H,EAA2B,CAK1D,GAJI,CAAC,OAAO,WAAa,OAAOqB,EAAA,EAAK,UAAa,YAI9C,CAACgB,EAASrC,CAAU,EACtB,OAGF,MAAM4H,EAAmBvG,IAAK,UAAU,MAExCA,EAAA,EAAK,SAASd,EAA8BqH,EAAkB5H,CAAqC,CACrG,CAEQ,iBAAiB6H,EAAyB,CAChD,GAAI,GAACA,GAAa,OAAOA,GAAc,UAGvC,GAAI,CACF,MAAMC,EAAazG,EAAA,EAAK,YAAA,EACpByG,GAAc,OAAOA,EAAW,yBAA4B,YAC9DA,EAAW,wBAAwBxH,EAAU,CAC3C,cAAeuH,CAAA,CAChB,CAEL,MAAa,CAEb,CACF,CAEQ,eACNjC,EACAmC,EACAnF,EAAiC,CAAA,EAC3B,CACN,MAAMoF,EACJ3G,EAAA,GAAQA,EAAA,EAAK,gBAAkB,OAAOA,EAAA,EAAK,eAAgB,YAAe,WACtEA,EAAA,EAAK,eAAgB,aACrB,OAEA4G,EAAmC,CACvC,UAAArC,EACA,GAAImC,GAAmB,CAAA,EACvB,GAAIC,EAAc,CAAE,YAAAA,GAAgB,CAAA,CAAC,EAGvC,IAAIE,EACA,KAAK,oCACPA,EAAkB,QAAQ,QAAQ,OAAO,KAAM,oBAAoBD,CAAO,CAAC,EAE3EC,EAAkB,OAAO,KAAM,eAAeD,CAAO,EAGvDC,EACG,KAAK,MAAOjF,GAAa,CACxB,MAAMF,GAAyBH,EAAsBK,CAAQ,EAC7D,KAAK,iBAAiBA,CAAQ,CAChC,CAAC,EACA,MAAOkF,GAAiB,CACvB,QAAQ,MAAM,gCAAiCA,CAAG,CACpD,CAAC,CACL,CAEQ,iBAAiBlF,EAA8B,CAEjD,OAAO,OACT,OAAO,KAAK,gBAAkBA,GAGhC,KAAK,SAAWA,EAEhB,MAAMmF,EAAc/G,IAAK,MAAM,QAE1B+G,GAGH,KAAK,QAAUA,EACVA,EAAY,aAGf,KAAK,gCAAkC,KAAK,OAAOA,EAAY,YAAY,EAF3E,QAAQ,KAAK,0CAA0C,GAJzD,QAAQ,KAAK,qCAAqC,EAWpD,KAAK,cAAgB,GAErBxD,EAA8B,KAAK,OAAQ,KAAK,eAAe,EAG/DvD,IAAK,KAAK,UAAU,IAAI,CAC1B,CAEQ,iBAA2C,CACjD,MAAMgH,EAAahH,EAAA,EAChB,qBAAA,EACA,OAAQiH,GAAcA,EAAU,OAAS,YAAY,EAExD,GAAI,CACF,GAAID,EAAW,OAAS,GAAK,OAAO,WAAY,CAC9C,MAAME,EAAkB,OAAO,WAAW,IAAI,OAAO,EACrD,MAAI,CAACA,GAAmB,CAACA,EAAgB,uBAChC,CAAA,EAEmBA,EAAgB,uBAAA,EACE,OAAO,CAACC,EAA6BC,KACjFD,EAAI,qCAAuCC,EAAQ,cAAc,EAC/DF,EAAgB,gBAAA,EAAkBE,CAAK,EAAE,GACpCD,GACN,CAAA,CAAE,CAEP,CACF,OAAShC,EAAO,CACd,QAAQ,MAAM,wCAAyCA,CAAK,CAC9D,CACA,MAAO,CAAA,CACT,CAEQ,YAAsB,CAC5B,MAAO,CAAC,EAAE,KAAK,eAAiB,KAAK,SACvC,CAEQ,mCAA6C,CACnD,MAAO,CAAC,EAAEnF,EAAA,EAAK,QAAUA,IAAK,OAAQ,wBAA0B,KAAK,0BACvE,CAEQ,yBAAmC,CAEzC,OAAO,KAAK,SAAW,EACzB,CAEQ,cAAcqH,EAA0B,CAC1C,QAAUrH,EAAA,GAAQA,EAAA,EAAK,eAAiBqH,GAC1CrH,EAAA,EAAK,cAAeqH,CAAU,CAElC,CAOO,KACLhG,EACAiG,EACAC,EACAC,EACAC,EACQ,CACR,MAAMC,EAAcrG,EACdkD,EAAYmD,EAAY,UAC9B,KAAK,eAAiBhJ,EAA2D+I,CAAsB,EACvG,KAAK,uBAAyBC,EAAY,sBAE1C,MAAM3F,EAAwBb,EAAgDwG,EAAY,qBAAqB,EAC/G,KAAK,4BAA8B5F,EAA0BC,CAAqB,EAElF,MAAMI,EAAiCjB,EACrCwG,EAAY,8BAAA,EAEd,KAAK,qCAAuCxF,EAAmCC,CAA8B,EAGzGuF,EAAY,8BACd,KAAK,sBAAwBA,EAAY,4BAA4B,YAAA,GAGvE,KAAK,uBAAyBrF,EAASqF,EAAY,qBAAqB,EACpEA,EAAY,sBACZ,OAEJ,MAAMxH,EAASF,IAAK,MAAM,OACpB,CAAE,0BAAAsB,EAA2B,qBAAAC,EAAsB,oBAAAC,CAAA,EAAwBJ,EAC/EsG,EAAY,cAAA,EAERhB,EAA2C,CAC/C,GAAK1G,EAAA,EAAK,MAAM,iBAA+C,CAAA,CAAC,EAElE,KAAK,gBAAkB8C,GAAwB4D,EAAgB,eAAqC,EACpGA,EAAgB,gBAAkB,KAAK,gBAEvC,KAAK,OAASxG,EAEd,MAAMyH,EAAmC,CACvC,WAAYD,EAAY,WACxB,SAAUA,EAAY,SACtB,kBAAmBxH,EACnB,iBAAkBF,EAAA,EAAK,QAAQ,mBAAqB,EAAA,EAEhDsF,EAAwB,IAAIF,EAChCuC,EACA,KAAK,gBACL,OAAO,iBACPD,EAAY,SAAA,EAERE,EAAiB,IAAIvC,EACzBsC,EACArC,EACA,KAAK,gBACL,OAAO,iBACPoC,EAAY,SAAA,EAad,OAVA,KAAK,sBAAwBpC,EAC7B,KAAK,eAAiBsC,EAElB5H,EAAA,EAAK,gCACPA,EAAA,EAAK,+BAAgCsF,CAAqB,EAExDtF,EAAA,EAAK,yBACPA,EAAA,EAAK,wBAAyB4H,CAAc,EAG1CL,GACF,KAAK,YAAc,CACjB,uBAAAtH,EACA,8BAAAK,EACA,2BAAAc,EACA,iBAAAoB,EACA,oBAAAtB,EACA,0BAAAY,EACA,mCAAAI,EACA,8BAAAqB,EACA,wBAAAH,EACA,KAAAH,EACA,uBAAyB4E,GAAqB,CAC5CpC,EAAQ,qBAAuBoC,CACjC,EACA,mBAAAzD,EACA,sBAAAgB,EACA,eAAAC,EACA,YAAApB,EACA,WAAAvE,EACA,kBAAAC,CAAA,EAEF,KAAK,eAAe4E,EAAWmC,CAAe,EACvC,6BAA+B1H,IAGpCwC,IACFxB,IAAK,KAAK,uCAAuC,IAAI,EACrDU,EAAenB,GAAkCe,EAA8BJ,CAAM,EAAG,CACtF,OAAQ,IAAM,CACZ,KAAK,yBAA2B,GAC5B,KAAK,gCACP,KAAK,+BAAA,CAET,EACA,QAAUiF,GAAU,CAClB,QAAQ,MAAM,+CAAgDA,CAAK,CACrE,CAAA,CACD,GAGC,KAAK,0BACP,KAAK,eAAeZ,EAAWmC,EAAiBnF,CAAoB,GAEpEb,EAAepB,GAA4BW,EAAuBC,EAAQoB,CAAyB,EAAG,CACpG,OAAQ,IAAM,CACR,KAAK,0BACP,KAAK,eAAeiD,EAAWmC,EAAiBnF,CAAoB,EAEpE,QAAQ,MAAM,iDAAiD,CAEnE,EACA,QAAU4D,GAAU,CAClB,QAAQ,MAAM,sCAAuCA,CAAK,CAC5D,CAAA,CACD,EAED,KAAK,cAAcM,EAAQ,kBAAkB,kBAAkB,GAG1D,6BAA+BzG,EACxC,CAEO,QAAQ0G,EAAyB,CACtC,GAAI,CAAC,KAAK,aACR,MAAO,gCAAkC1G,EAE3C,GAAI,OAAOgB,EAAA,EAAK,MAAM,0BAA6B,aAC5C4C,EAAQ,KAAK,oCAAoC,GACpD,KAAK,oCAAoC8C,CAAK,EAG5C,CAAC9C,EAAQ,KAAK,2BAA2B,GAAG,CAC9C,MAAMkF,EAActF,EAAiBkD,EAAM,cAAeA,EAAM,cAAeA,EAAM,WAAa,EAAE,EAChG,KAAK,4BAA4B,OAAOoC,CAAW,CAAC,GACtD9H,EAAA,EAAK,KAAK,2BAA2B,KAAK,4BAA4B,OAAO8H,CAAW,CAAC,EAAG,EAAI,CAEpG,CAGF,MAAO,mCAAqC9I,CAC9C,CAEO,iBAAiB+I,EAAqD,CAC3E,GAAI,CAAC,KAAK,aAAc,CACtB,QAAQ,MAAM,2BAA2B,EACzC,MACF,CAEA,OAAO,KAAM,iBAAiBA,CAAoB,CACpD,CAEO,iBAAiBtJ,EAAaoE,EAAwB,CAC3D,OAAKrE,EAA6CC,CAAG,IACnD,KAAK,eAAeA,CAAG,EAAIoE,GAEtB,kDAAoD7D,CAC7D,CAEO,oBAAoBP,EAAqB,CAC9C,cAAO,KAAK,eAAeA,CAAG,EACvB,sDAAwDO,CACjE,CAEQ,uBAAuBgJ,EAAsBC,EAA8B,CACjF,YAAK,eAAiBvJ,EAA2DsJ,EAAK,qBAAA,CAAsB,EACrG,uBAAyBC,EAAe,mBAAqBjJ,CACtE,CAEO,iBAAiBgJ,EAA8B,CACpD,MAAM5B,EAAe4B,EACrB,YAAK,QAAQ,aAAe5B,EAC5B,KAAK,gCAAkC,KAAK,OAAOA,CAAY,EACxD,KAAK,uBAAuB4B,EAAM,kBAAkB,CAC7D,CAEQ,OAAO5B,EAA2C,CACxD,MAAM8B,EAAS,KAAK,uBACpB,GAAI,CAACA,EACH,YAAK,0BAA4B,GACjC,KAAK,oCAAsC,OACpC,QAAQ,QAAA,EAEjB,MAAMC,EAASnI,IAAK,UAAU,OAC9B,GAAI,OAAOmI,GAAW,WACpB,YAAK,0BAA4B,GACjC,KAAK,oCAAsC,OACpC,QAAQ,QAAA,EAGjB,MAAM9B,EAAyCD,EAAa,kBACxDA,EAAa,kBAAA,EAAoB,eACjC,KAMEgC,EAA0C,CAAA,EAChD,GAAI/B,EACF,UAAW5H,KAAO,OAAO,KAAK4H,CAAc,EAAmC,CAC7E,MAAMxD,EAAQwD,EAAe5H,CAAG,EAC5B4D,EAASQ,CAAK,GAAKA,EAAM,OAAS,IACpCuF,EAAgB3J,CAAG,EAAIoE,EAE3B,CAGF,MAAMwF,EAAe,OAAO,KAAKD,CAAe,EAChD,GAAIC,EAAa,SAAW,EAC1B,YAAK,0BAA4B,GACjC,KAAK,oCAAsC,OACpC,QAAQ,QAAA,EAMjB,MAAMC,EAAgBD,EACnB,KAAA,EACA,IAAKE,GAAM,GAAGA,CAAC,IAAIH,EAAgBG,CAAC,CAAC,EAAE,EACvC,KAAK,GAAG,EAKX,OAAID,IAAkB,KAAK,oCAClB,KAAK,iCAAmC,QAAQ,QAAA,GAMzD,KAAK,0BAA4B,GACjC,KAAK,oCAAsCA,EAEpC,IAAI,QAAeE,GAAY,CACpC,GAAI,CACFL,EAAOD,EAAQE,EAAqCK,GAAkC,CAChFA,GAAQ,WAAa,MACvB,KAAK,0BAA4B,IAEnCD,EAAA,CACF,CAAC,CACH,OAAS1B,EAAK,CACZ,QAAQ,MAAM,2CAA4CA,CAAG,EAI7D,KAAK,oCAAsC,OAC3C0B,EAAA,CACF,CACF,CAAC,EACH,CAEO,gBAAgBR,EAAsBU,EAA2C,CACtF,OAAO,KAAK,uBAAuBV,EAAM,iBAAiB,CAC5D,CAEO,iBAAiBA,EAAsBU,EAA2C,CAKvF,YAAK,0BAA4B,GACjC,KAAK,gCAAkC,KACvC,KAAK,oCAAsC,OACpC,KAAK,uBAAuBV,EAAM,kBAAkB,CAC7D,CAEO,iBAAiBA,EAAsBU,EAA2C,CACvF,OAAO,KAAK,uBAAuBV,EAAM,kBAAkB,CAC7D,CAyBO,iBAAiBpB,EAAsF,CAC5G,GAAI,KAAK,gCAAiC,CACxC,MAAM+B,EAAW,KAAK,gCACtB,OAAO,QAAQ,KAAK,CAClBA,EACA,IAAI,QAAeH,GAAY,WAAWA,EAAS/I,EAAkC,CAAC,CAAA,CACvF,EAAE,KAAK,IAAM,KAAK,oBAAoBmH,CAAO,CAAC,CACjD,CACA,OAAO,KAAK,oBAAoBA,CAAO,CACzC,CAEQ,oBAAoBA,EAAsF,CAChH,MAAMjI,EAAeiI,GAAYA,EAAQ,YAA2C,CAAA,EAE9EgC,EAA+C,CAAE,GAD1BlK,EAA2D,KAAK,cAAc,EAC3B,GAAGC,CAAA,EAE7EkK,EAAU,KAAK,SAAW,CAAA,EAC1BC,EAAwBD,EAAQ,sBAAqC,CAAA,EACrEzC,EAAeyC,EAAQ,cAAgB,KACvCE,EAAO3C,EAAeA,EAAa,QAAA,EAAY,KAErD,IAAIxH,EAECiK,EAGMA,EAAQ,qBACjBjK,EAAqBiK,EAAQ,qBAAqBD,EAAqBE,CAAoB,EAE3FlK,EAAqBgK,GALrB,QAAQ,KAAK,uDAAuD,EACpEhK,EAAqBgK,GAOvB,KAAK,eAAiBlK,EAA2DE,CAAkB,EAEnG,MAAMoK,EAAuB,KAAK,yBAA2B,aAAe,KAAK,gBAAA,EAAoB,CAAA,EAE/FC,EAAyB,KAAK,qBAAqB7C,CAAY,EAE/D8C,EAAyB,KAAK,6BAAA,EAE9BC,EAAsD,CAC1D,GAAIF,EACJ,GAAGrK,EACH,GAAGoK,EACH,GAAGE,EACH,GAAI,KAAK,0BAA4B,CAAE,CAAC1J,EAAgC,EAAG,EAAA,EAAS,CAAA,EACpF,KAAAuJ,CAAA,EAGIK,EAAmD,CAAE,GAAGxC,EAAS,WAAYuC,CAAA,EAE7EE,EAAY,KAAK,SAAU,iBAAiBD,CAAuB,EAGnEE,EAAe,IAAM,KAAK,yBAAyBH,CAA0B,EAEnF,OAAK,QAAQ,QAAQE,CAAS,EAC3B,KAAME,GAAQA,GAAK,SAAS,WAAW,KAAM/C,GAAc,KAAK,iBAAiBA,CAAS,CAAC,CAAC,EAC5F,MAAM,MAAe,EACrB,QAAQ8C,CAAY,EAEhBD,CACT,CAKO,eAAe1K,EAA8E,CAClG,OAAK,KAAK,aAIH,KAAK,SAAU,eAAeA,CAAU,GAH7C,QAAQ,MAAM,2BAA2B,EAClC,KAGX,CAOO,IAAI8C,EAAyC,CAClD,OAAK,KAAK,aAIN,CAACA,GAAiB,CAACY,EAASZ,CAAa,EACpC,QAAQ,OAAO,IAAI,MAAM,kCAAkC,CAAC,EAE9D,KAAK,SAAU,IAAIA,CAAa,GANrC,QAAQ,MAAM,2BAA2B,EAClC,QAAQ,OAAO,IAAI,MAAM,2BAA2B,CAAC,EAMhE,CAKO,oBAAoB+H,EAAsB,CAC3C,KAAK,yBACPA,EAAA,EAEA,KAAK,+BAAiCA,CAE1C,CACF,EAztBE/D,EAAc,qBAAiC,CAAC,WAAY,SAAS,EAErEA,EAAwB,kBAAoB,CAC1C,mBAAoB,uBAAA,EAGtBA,EAAwB,iBAAmB,cAR7C,IAAM/B,EAAN+B,EAiuBA,SAASgE,IAAgB,CACvB,OAAOxK,CACT,CAEA,SAASyK,GAASrF,EAAkD,CAClE,GAAI,CAACA,EAAQ,CACX,OAAO,QAAQ,IAAI,qDAAuDrF,CAAI,EAC9E,MACF,CACA,GAAI,CAACgC,EAASqD,CAAM,EAAG,CACrB,OAAO,QAAQ,IAAI,+CAAiD,OAAOA,CAAM,EACjF,MACF,CAEIrD,EAASqD,EAAO,IAAI,EACrBA,EAAO,KAAiCrF,CAAI,EAAI,CAC/C,YAAa0E,CAAA,GAGfW,EAAO,KAAO,CAAA,EACdA,EAAO,KAAKrF,CAAI,EAAI,CAClB,YAAa0E,CAAA,GAGjB,OAAO,QAAQ,IAAI,2BAA6B1E,EAAO,kCAAkC,CAC3F,CAEI,OAAO,OAAW,KAAe,OAAO,WAAagB,EAAA,EAAK,cAC5DA,EAAA,EAAK,aAAa,CAChB,KAAAhB,EACA,YAAa0E,EACb,MAAA+F,EAAA,CACD"} \ No newline at end of file +{"version":3,"file":"Rokt-Kit.common.js","sources":["../src/selectPlacementsAttributePersistence.ts","../src/utils.ts","../src/storage.ts","../src/pageViewStorage.ts","../src/Rokt-Kit.ts"],"sourcesContent":["const SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST = [\n 'active_time_on_site_ms',\n 'billingaddress1',\n 'billingaddress2',\n 'billingcity',\n 'billingstate',\n 'billingzipcode',\n 'cartitems',\n 'ccbin',\n 'confirmationref',\n 'conversiontype',\n 'country',\n 'couponcode',\n 'currency',\n 'language',\n 'paymentserviceprovider',\n 'paymentserviceproviderattribute',\n 'paymenttype',\n 'shippingaddress1',\n 'shippingcity',\n 'shippingcountry',\n 'shippingmethod',\n 'shippingstate',\n 'shippingzipcode',\n 'totalprice',\n];\nconst SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET = new Set(SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST);\n\nexport function isSelectPlacementsAttributePersistenceDenied(key: string): boolean {\n return SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET.has(key.toLowerCase());\n}\n\nexport function removeSelectPlacementsAttributePersistenceDeniedAttributes(\n attributes: Record | null | undefined,\n): Record {\n const filteredAttributes: Record = {};\n const sourceAttributes = attributes || {};\n const attributeKeys = Object.keys(sourceAttributes);\n\n for (let i = 0; i < attributeKeys.length; i++) {\n const key = attributeKeys[i];\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n filteredAttributes[key] = sourceAttributes[key];\n }\n }\n\n return filteredAttributes;\n}\n","export function isObject(value: unknown): value is Record {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nexport function isFunction(value: unknown): value is (...args: Array) => unknown {\n return typeof value === 'function';\n}\n\nexport function isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'object') {\n return Object.keys(value as object).length === 0;\n }\n return false;\n}\n\n// Strips the query string from a URL before it is persisted and sent to Rokt,\n// since query params commonly carry PII (emails, tokens, order refs).\n// Returns the input unchanged if it can't be parsed as a URL.\nexport function sanitizeUrl(href: string): string {\n try {\n const url = new URL(href);\n url.search = '';\n return url.toString();\n } catch {\n return href;\n }\n}\n","import { isObject } from './utils';\n\nconst LS_PROBE_KEY = '__rokt_ls_probe__';\n\nexport function isLocalStorageAvailable(): boolean {\n try {\n window.localStorage.setItem(LS_PROBE_KEY, '1');\n window.localStorage.removeItem(LS_PROBE_KEY);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function readJSON(key: string): unknown {\n try {\n const stored = window.localStorage.getItem(key);\n return stored === null ? null : JSON.parse(stored);\n } catch {\n return null;\n }\n}\n\nexport function writeJSON(key: string, value: unknown): boolean {\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n return true;\n } catch {\n return false;\n }\n}\n\nexport function removeKey(key: string): void {\n try {\n window.localStorage.removeItem(key);\n } catch {\n /* empty */\n }\n}\n\nexport function readNamespacedField(namespaceKey: string, field: string): unknown {\n const blob = readJSON(namespaceKey);\n return isObject(blob) ? blob[field] : undefined;\n}\n\nexport function writeNamespacedField(namespaceKey: string, field: string, value: unknown): boolean {\n const blob = readJSON(namespaceKey);\n const next = isObject(blob) ? { ...blob } : {};\n next[field] = value;\n return writeJSON(namespaceKey, next);\n}\n\nexport function removeNamespacedField(namespaceKey: string, field: string): void {\n const blob = readJSON(namespaceKey);\n if (!isObject(blob) || !(field in blob)) {\n return;\n }\n const next = { ...blob };\n delete next[field];\n if (Object.keys(next).length === 0) {\n removeKey(namespaceKey);\n } else {\n writeJSON(namespaceKey, next);\n }\n}\n","import type { LoggingService } from './Rokt-Kit';\nimport {\n readJSON,\n removeKey,\n readNamespacedField,\n writeNamespacedField,\n removeNamespacedField,\n isLocalStorageAvailable,\n} from './storage';\nimport { sanitizeUrl, isObject } from './utils';\n\nconst LS_NAMESPACE_KEY = 'mp-rokt-kit';\nconst LS_PAGE_VIEWS_FIELD = 'pageViews';\nconst LS_UTM_PARAMS_FIELD = 'utmParams';\nconst LEGACY_PAGE_VIEWS_KEY = 'mpPageViews';\nexport const PAGE_VIEWS_MAX_COUNT = 25;\n\nconst UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'] as const;\ntype UtmKey = (typeof UTM_KEYS)[number];\nexport type UtmParams = Partial>;\n\nexport interface PageEvent {\n pageUrl: string;\n sourceMessageId: string;\n timestamp: number;\n pageTitle?: string;\n canonicalUrl?: string;\n activeTimeOnSite?: number;\n activeTimeOnPage?: number;\n}\n\nfunction capPageViews(views: PageEvent[]): PageEvent[] {\n return views.slice(-PAGE_VIEWS_MAX_COUNT);\n}\n\nexport function migrateLegacyPageViewStorage(loggingService: LoggingService | null): void {\n const legacyViews = readJSON(LEGACY_PAGE_VIEWS_KEY);\n if (legacyViews === null) {\n return;\n }\n\n const alreadyMigrated = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD) !== undefined;\n const needsMigration = !alreadyMigrated && Array.isArray(legacyViews);\n\n if (needsMigration) {\n loggingService?.log({\n message: 'Rokt Kit: Migrating legacy page-view storage',\n code: 'PAGE_VIEW_LEGACY_MIGRATION',\n });\n const migrated = writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, legacyViews);\n if (!migrated) {\n loggingService?.log({\n message: 'Rokt Kit: Failed to migrate legacy page-view storage [reason: migration_retry]',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n removeKey(LEGACY_PAGE_VIEWS_KEY);\n}\n\nexport function loadPageViews(loggingService: LoggingService | null): PageEvent[] {\n migrateLegacyPageViewStorage(loggingService);\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n return Array.isArray(stored) ? (stored as PageEvent[]) : [];\n}\n\nexport function writePageViews(pageViews: PageEvent[]): number {\n const views = capPageViews(pageViews);\n for (let i = 0; i < views.length; i++) {\n const toWrite = views.slice(i);\n if (writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, toWrite)) {\n return toWrite.length;\n }\n }\n return 0;\n}\n\nexport function clearPageViews(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n}\n\nexport function buildPageEvents(pageViews: PageEvent[]): PageEvent[] {\n const views = capPageViews(pageViews);\n return views.map((pageView, index) => {\n const activeTimeOnSite = pageView.activeTimeOnSite;\n const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite);\n\n const next = views[index + 1];\n const nextActiveTimeOnSite = next?.activeTimeOnSite;\n const hasNextActiveTimeOnSite = nextActiveTimeOnSite !== undefined && Number.isFinite(nextActiveTimeOnSite);\n\n const diff = hasActiveTime && hasNextActiveTimeOnSite ? nextActiveTimeOnSite - activeTimeOnSite : undefined;\n\n return {\n pageUrl: pageView.pageUrl,\n sourceMessageId: pageView.sourceMessageId,\n timestamp: pageView.timestamp,\n ...(pageView.pageTitle !== undefined ? { pageTitle: pageView.pageTitle } : {}),\n ...(pageView.canonicalUrl !== undefined ? { canonicalUrl: pageView.canonicalUrl } : {}),\n ...(hasActiveTime ? { activeTimeOnSite } : {}),\n ...(diff !== undefined && diff >= 0 ? { activeTimeOnPage: diff } : {}),\n };\n });\n}\n\nexport function captureUtmParams(loggingService: LoggingService | null): void {\n if (readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD) !== undefined) {\n return;\n }\n const search = new URLSearchParams(window.location.search);\n const params: UtmParams = {};\n for (const key of UTM_KEYS) {\n const value = search.get(key);\n if (value) params[key] = value;\n }\n if (Object.keys(params).length === 0) {\n return;\n }\n const captured = Object.keys(params).join(', ');\n if (!writeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD, params)) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n loggingService?.log({\n message: `Rokt Kit: Failed to persist UTM params [reason: ${reason}]`,\n code: 'UTM_CAPTURE_FAILED',\n });\n return;\n }\n loggingService?.log({\n message: `Rokt Kit: Captured UTM params [${captured}]`,\n code: 'UTM_CAPTURE_SUCCESS',\n });\n}\n\nexport function loadUtmParams(): UtmParams | null {\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n return isObject(stored) ? (stored as UtmParams) : null;\n}\n\nexport function clearUtmParams(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n}\n\nexport function readCanonicalUrl(): string | undefined {\n const link = document.querySelector('link[rel=\"canonical\"]');\n const href = link?.href;\n if (!href) {\n return undefined;\n }\n return sanitizeUrl(href);\n}\n","// Copyright 2025 mParticle, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// ============================================================\n// Types\n// ============================================================\n\nimport { KitInterface, IMParticleUser, SDKEvent } from '@mparticle/web-sdk/internal';\nimport type { IUserIdentities } from '@mparticle/web-sdk';\n\nimport {\n isSelectPlacementsAttributePersistenceDenied,\n removeSelectPlacementsAttributePersistenceDeniedAttributes,\n} from './selectPlacementsAttributePersistence';\n\nimport {\n PageEvent,\n PAGE_VIEWS_MAX_COUNT,\n buildPageEvents,\n migrateLegacyPageViewStorage,\n loadPageViews,\n writePageViews,\n clearPageViews,\n readCanonicalUrl,\n captureUtmParams,\n loadUtmParams,\n clearUtmParams,\n} from './pageViewStorage';\nimport { isLocalStorageAvailable } from './storage';\n\nimport { isObject, isString, isEmpty, isFunction, sanitizeUrl } from './utils';\n\ninterface RoktKitSettings {\n accountId: string;\n roktExtensions?: string;\n placementEventMapping?: string;\n placementEventAttributeMapping?: string;\n hashedEmailUserIdentityType?: string;\n onboardingExpProvider?: string;\n loggingUrl?: string;\n errorUrl?: string;\n workspaceIdSyncApiKey?: string;\n}\n\ninterface EventAttributeCondition {\n operator: string;\n attributeValue: string;\n}\n\ninterface PlacementEventRule {\n eventAttributeKey: string;\n conditions: EventAttributeCondition[];\n}\n\ninterface EventAttributeMapping {\n value: string;\n map: string;\n conditions?: EventAttributeCondition[];\n}\n\ninterface PlacementEventMappingEntry {\n jsmap: string;\n value: string;\n}\n\ninterface RoktExtensionEntry {\n value: string;\n}\n\ninterface RoktSelection {\n context?: {\n sessionId?: Promise;\n };\n then?: (callback: (sel: RoktSelection) => void) => Promise;\n catch?: (callback: () => void) => void;\n}\n\ninterface RoktLauncher {\n selectPlacements(options: Record): RoktSelection | Promise;\n hashAttributes(attributes: Record): Promise>;\n use(extensionName: string): Promise;\n}\n\ninterface RoktGlobal {\n createLauncher(options: Record): Promise;\n createLocalLauncher(options: Record): RoktLauncher;\n currentLauncher?: RoktLauncher;\n setExtensionData(data: Record): void;\n}\n\n// FilteredUser is the IMParticleUser shape we receive after kit filtering.\n// `getMPID` and `getUserIdentities` are inherited from the SDK's `User` base type.\ntype FilteredUser = IMParticleUser;\n\n// TODO: Replace with `IIdentitySearchResult` from `@mparticle/web-sdk` once\n// a version that exports it is published (currently on a feature branch in\n// mParticle/mparticle-web-sdk PR #1255). The shape below is intentionally\n// structurally identical so the swap is a one-line import change.\ninterface WorkspaceIdSyncResult {\n httpCode: number;\n body?: {\n context?: string | null;\n mpid?: string;\n matched_identities?: Record;\n is_ephemeral?: boolean;\n is_logged_in?: boolean;\n };\n}\n\n// TODO: Replace with `IdentitySearchCallback`-compatible reference from\n// `@mparticle/web-sdk` once published (mirrors `SDKIdentityApi.search`).\ntype WorkspaceIdSyncSearcher = (\n apiKey: string,\n knownIdentities: IUserIdentities,\n callback: (result: WorkspaceIdSyncResult) => void,\n) => void;\n\ninterface KitFilters {\n userAttributeFilters?: string[];\n filterUserAttributes?: (attributes: Record, filters?: string[]) => Record;\n filteredUser?: FilteredUser | null;\n}\n\ninterface RoktManager {\n attachKit(kit: RoktKit): void | Promise;\n flushOnShoppableAdsReadyMessageQueue?(kit: RoktKit): void;\n filters?: KitFilters;\n domain?: string;\n launcherOptions?: Record;\n getLocalSessionAttributes?(): Record;\n setLocalSessionAttribute?(key: string, value: unknown): void;\n}\n\ninterface MParticleInstance {\n setIntegrationAttribute(moduleId: number, attrs: Record): void;\n}\n\ninterface OptimizelyState {\n getActiveExperimentIds(): string[];\n getVariationMap(): Record;\n}\n\ninterface OptimizelyGlobal {\n get(key: 'state'): OptimizelyState;\n}\n\n// Our view of the mParticle global with Rokt-specific extensions.\n// We access window.mParticle via an explicit cast (see `mp()` helper below)\n// rather than augmenting Window to avoid conflicts with @mparticle/web-sdk declarations.\ninterface MParticleExtended {\n Rokt: RoktManager;\n addForwarder(config: ForwarderRegistration): void;\n getVersion(): string;\n generateHash(value: string): string | number;\n logEvent(name: string, type: number, attrs?: Record): void;\n EventType: { Other: number };\n getInstance(): MParticleInstance;\n getDeviceId?(): string;\n sessionManager?: { getSession?(): string; getSessionId?(): string };\n _getActiveForwarders(): Array<{ name: string }>;\n config?: { isLocalLauncherEnabled?: boolean; isLoggingEnabled?: boolean };\n captureTiming?(metricName: string): void;\n forwarder?: RoktKit;\n loggedEvents?: Array>;\n _registerErrorReportingService?(service: ErrorReportingService): void;\n _registerLoggingService?(service: LoggingService): void;\n Identity?: { search?: WorkspaceIdSyncSearcher };\n}\n\ninterface TestHelpers {\n generateLauncherScript: (domain: string | undefined, extensions: string[]) => string;\n generateThankYouElementScript: (domain: string | undefined) => string;\n extractRoktExtensionConfig: (settingsString?: string) => RoktExtensionConfig;\n hashEventMessage: (messageType: number, eventType: number, eventName: string) => string | number;\n parseSettingsString: (settingsString?: string) => T[];\n generateMappedEventLookup: (placementEventMapping: PlacementEventMappingEntry[]) => Record;\n generateMappedEventAttributeLookup: (mapping: EventAttributeMapping[]) => Record;\n sendAdBlockMeasurementSignals: (domain: string | undefined, version: string | null) => void;\n createAutoRemovedIframe: (src: string) => void;\n djb2: (str: string) => number;\n setAllowedOriginHashes: (hashes: number[]) => void;\n ReportingTransport: typeof ReportingTransport;\n ErrorReportingService: typeof ErrorReportingService;\n LoggingService: typeof LoggingService;\n RateLimiter: typeof RateLimiter;\n ErrorCodes: typeof ErrorCodes;\n WSDKErrorSeverity: typeof WSDKErrorSeverity;\n}\n\ninterface ForwarderRegistration {\n name: string;\n constructor: new () => RoktKit;\n getId: () => number;\n}\n\ninterface ReportingConfig {\n loggingUrl?: string;\n errorUrl?: string;\n integrationDomain?: string;\n isLoggingEnabled: boolean;\n}\n\ninterface ErrorReport {\n message: string;\n code?: string;\n severity?: string;\n stackTrace?: string;\n}\n\n// A log-delivery failure. statusCode is set when the request reached the server\n// and returned a non-2xx status (server-side); it is absent for network-level\n// failures such as ad-blockers, offline, or CORS rejections (client-side).\ninterface DeliveryError extends Error {\n statusCode?: number;\n}\n\ninterface LogEntry {\n message: string;\n code?: string;\n}\n\ninterface RoktExtensionConfig {\n roktExtensionsQueryParams: string[];\n legacyRoktExtensions: string[];\n loadThankYouElement: boolean;\n}\n\ndeclare global {\n interface Window {\n Rokt?: RoktGlobal;\n __rokt_li_guid__?: string;\n optimizely?: OptimizelyGlobal;\n // mParticle is declared as any to avoid conflicts with @mparticle/web-sdk type declarations.\n // We use the typed mp() accessor for all internal accesses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mParticle: any;\n }\n}\n\n// ============================================================\n// Module-level constants\n// ============================================================\n\nconst name = 'Rokt';\nconst moduleId = 181;\nconst EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements';\nconst ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com';\nconst INIT_LOG_SAMPLING_RATE = 0.1;\nconst ROKT_THANK_YOU_JOURNEY_EXTENSION = 'ThankYouPageJourney';\nconst ROKT_INTEGRATION_SCRIPT_ID = 'rokt-launcher';\nconst ROKT_THANK_YOU_ELEMENT_SCRIPT_ID = 'rokt-thank-you-element';\nconst USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace';\n\nconst MESSAGE_TYPE_PAGE_VIEW = 3; // mParticle MessageType.PageView\nconst MESSAGE_TYPE_SESSION_END = 2; // mParticle MessageType.SessionEnd\nconst PAGE_EVENTS_KEY = 'page_events';\nconst PAGE_VIEW_ATTRIBUTES_KEY = 'page_view_attributes';\nconst MPARTICLE_SESSION_ID_KEY = 'mparticle_session_id';\nconst MPARTICLE_DEVICE_ID_KEY = 'mparticle_device_id';\n\n// Bound on how long selectPlacements will wait for an in-flight Workspace\n// IDSync search before proceeding without the userIdentifiedInWorkspace flag.\n// Long enough to cover the typical /v1/search round-trip (~50ms); short enough that a\n// stalled search never blocks placement rendering on a thank-you page.\nconst WORKSPACE_SEARCH_SELECT_TIMEOUT_MS = 500;\n\n// ============================================================\n// Reporting service constants\n// ============================================================\n\nconst ErrorCodes = {\n UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION',\n IDENTITY_REQUEST: 'IDENTITY_REQUEST',\n LOG_DELIVERY_FAILURE: 'LOG_DELIVERY_FAILURE',\n} as const;\n\nconst WSDKErrorSeverity = {\n ERROR: 'ERROR',\n INFO: 'INFO',\n WARNING: 'WARNING',\n} as const;\n\nconst DEFAULT_ROKT_DOMAIN = 'apps.rokt-api.com';\nconst LOGGING_ENDPOINT = '/v1/log';\nconst ERROR_ENDPOINT = '/v1/errors';\nconst RATE_LIMIT_PER_SEVERITY = 10;\n\n// ============================================================\n// Helper: typed accessor for window.mParticle\n// We use an explicit cast here to avoid conflicts with @mparticle/web-sdk\n// type declarations while still providing full type safety for our usages.\n// ============================================================\n\nfunction mp(): MParticleExtended {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (window as any).mParticle as MParticleExtended;\n}\n\n// ============================================================\n// Module-level utility functions\n// ============================================================\n\nfunction generateLauncherScript(domain: string | undefined, extensions: string[]): string {\n const launcherPath = '/wsdk/integrations/launcher.js';\n const baseUrl = [generateBaseUrl(domain), launcherPath].join('');\n\n if (!extensions || extensions.length === 0) {\n return baseUrl;\n }\n return baseUrl + '?extensions=' + extensions.join(',');\n}\n\nfunction generateThankYouElementScript(domain: string | undefined) {\n const thankYouElementPath = '/rokt-elements/rokt-element-thank-you.js';\n return [generateBaseUrl(domain), thankYouElementPath].join('');\n}\n\nfunction generateBaseUrl(domain: string | undefined) {\n const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN;\n\n if (resolvedDomain.includes('://')) {\n return resolvedDomain.replace(/\\/+$/, '');\n }\n\n const protocol = 'https://';\n\n return [protocol, resolvedDomain].join('');\n}\n\nfunction generateReportingUrl(configuredUrl: string | undefined, domain: string | undefined, endpoint: string): string {\n if (configuredUrl) {\n if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://')) {\n return configuredUrl;\n }\n return 'https://' + configuredUrl;\n }\n\n const hasNonHttpScheme = domain?.includes('://') && !/^https?:\\/\\//i.test(domain);\n const reportingDomain = hasNonHttpScheme ? undefined : domain;\n\n return generateBaseUrl(reportingDomain) + endpoint;\n}\n\nfunction loadRoktScript(\n scriptId: string,\n source: string,\n handlers?: { onLoad?: () => void; onError?: (e: Event | string) => void },\n): void {\n if (document.getElementById(scriptId)) return; // resolves the preexisting script issue\n\n const target = document.head || document.body;\n const script = document.createElement('script');\n script.id = scriptId;\n script.type = 'text/javascript';\n script.src = source;\n script.async = true;\n script.crossOrigin = 'anonymous';\n (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high';\n if (handlers?.onLoad) script.onload = handlers.onLoad;\n if (handlers?.onError) script.onerror = handlers.onError;\n target.appendChild(script);\n}\n\nfunction parseSettingsString(settingsString?: string): T[] {\n if (!settingsString) {\n return [];\n }\n try {\n return JSON.parse(settingsString.replace(/"/g, '\"')) as T[];\n } catch (_error) {\n console.error('Settings string contains invalid JSON');\n }\n return [];\n}\n\nfunction extractRoktExtensionConfig(settingsString?: string): RoktExtensionConfig {\n const settings = settingsString ? parseSettingsString(settingsString) : [];\n const roktExtensionsQueryParams: string[] = [];\n const legacyRoktExtensions: string[] = [];\n let loadThankYouElement = false;\n\n for (let i = 0; i < settings.length; i++) {\n const extensionName = settings[i].value;\n if (extensionName === 'thank-you-journey') {\n loadThankYouElement = true;\n legacyRoktExtensions.push(ROKT_THANK_YOU_JOURNEY_EXTENSION);\n } else {\n roktExtensionsQueryParams.push(extensionName);\n }\n }\n\n return {\n roktExtensionsQueryParams,\n legacyRoktExtensions,\n loadThankYouElement,\n };\n}\n\nasync function registerLegacyExtensions(legacyExtensions: string[], launcher: RoktLauncher | null) {\n const extensions: Promise[] = [];\n if (launcher) {\n for (const extension of legacyExtensions) {\n extensions.push(launcher.use(extension));\n }\n }\n\n return Promise.all(extensions);\n}\n\nfunction generateMappedEventLookup(placementEventMapping: PlacementEventMappingEntry[]): Record {\n if (!placementEventMapping) {\n return {};\n }\n\n const mappedEvents: Record = {};\n for (let i = 0; i < placementEventMapping.length; i++) {\n const mapping = placementEventMapping[i];\n mappedEvents[mapping.jsmap] = mapping.value;\n }\n return mappedEvents;\n}\n\nfunction generateMappedEventAttributeLookup(\n placementEventAttributeMapping: EventAttributeMapping[],\n): Record {\n const mappedAttributeKeys: Record = {};\n if (!Array.isArray(placementEventAttributeMapping)) {\n return mappedAttributeKeys;\n }\n for (let i = 0; i < placementEventAttributeMapping.length; i++) {\n const mapping = placementEventAttributeMapping[i];\n if (!mapping || !isString(mapping.value) || !isString(mapping.map)) {\n continue;\n }\n\n const mappedAttributeKey = mapping.value;\n const eventAttributeKey = mapping.map;\n\n if (!mappedAttributeKeys[mappedAttributeKey]) {\n mappedAttributeKeys[mappedAttributeKey] = [];\n }\n\n mappedAttributeKeys[mappedAttributeKey].push({\n eventAttributeKey: eventAttributeKey,\n conditions: Array.isArray(mapping.conditions) ? mapping.conditions : [],\n });\n }\n return mappedAttributeKeys;\n}\n\nfunction hashEventMessage(messageType: number, eventType: number, eventName: string): string | number {\n return mp().generateHash([messageType, eventType, eventName].join(''));\n}\n\nfunction generateIntegrationName(customIntegrationName?: string): string {\n const coreSdkVersion = mp().getVersion();\n const kitVersion = process.env.PACKAGE_VERSION;\n let integrationName = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion;\n\n if (customIntegrationName) {\n integrationName += '_' + customIntegrationName;\n }\n return integrationName;\n}\n\nfunction djb2(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return hash;\n}\n\nfunction createAutoRemovedIframe(src: string): void {\n const iframe = document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');\n iframe.src = src;\n iframe.onload = function () {\n iframe.onload = null;\n if (iframe.parentNode) {\n iframe.parentNode.removeChild(iframe);\n }\n };\n const target = document.body || document.head;\n if (target) {\n target.appendChild(iframe);\n }\n}\n\nfunction sendAdBlockMeasurementSignals(domain: string | undefined, version: string | null): void {\n const originHash = djb2(window.location.origin);\n const allowedOriginHashes = RoktKit._allowedOriginHashes;\n if (allowedOriginHashes.indexOf(originHash) === -1) {\n return;\n }\n\n if (Math.random() >= INIT_LOG_SAMPLING_RATE) {\n return;\n }\n\n const guid = window.__rokt_li_guid__;\n if (!guid) {\n return;\n }\n\n if (domain && domain.includes('://') && !/^https:\\/\\//i.test(domain)) {\n return;\n }\n\n const pageUrl = window.location.href.split('?')[0].split('#')[0];\n const params =\n 'version=' +\n encodeURIComponent(version ?? '') +\n '&launcherInstanceGuid=' +\n encodeURIComponent(guid) +\n '&pageUrl=' +\n encodeURIComponent(pageUrl);\n\n const existingBaseUrl = domain ? generateBaseUrl(domain) : 'https://apps.rokt.com';\n createAutoRemovedIframe(existingBaseUrl + '/v1/wsdk-init/index.html?' + params);\n\n createAutoRemovedIframe(\n 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true',\n );\n}\n\n// ============================================================\n// Reporting helpers\n// ============================================================\n\nfunction _isDebugModeEnabled(): boolean {\n return typeof window !== 'undefined' && !!window.location?.search?.toLowerCase().includes('mp_enable_logging=true');\n}\n\nfunction _getReportingUrl(): string | undefined {\n return typeof window !== 'undefined' ? window.location?.href : undefined;\n}\n\nfunction _getUserAgent(): string | undefined {\n return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined;\n}\n\nclass RateLimiter {\n private _logCount: Record = {};\n\n incrementAndCheck(severity: string): boolean {\n const count = this._logCount[severity] || 0;\n const newCount = count + 1;\n this._logCount[severity] = newCount;\n return newCount > RATE_LIMIT_PER_SEVERITY;\n }\n}\n\nclass ReportingTransport {\n private _isEnabled: boolean;\n private _integrationName: string;\n private _launcherInstanceGuid: string | undefined;\n private _accountId: string | null;\n private _rateLimiter: RateLimiter;\n private readonly _reporter = 'mp-wsdk';\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid: string | undefined,\n accountId: string | null | undefined,\n rateLimiter?: RateLimiter,\n ) {\n const isLoggingEnabled = config.isLoggingEnabled;\n this._integrationName = integrationName || '';\n this._launcherInstanceGuid = launcherInstanceGuid;\n this._accountId = accountId || null;\n this._rateLimiter = rateLimiter || new RateLimiter();\n this._isEnabled = _isDebugModeEnabled() || isLoggingEnabled;\n }\n\n send(\n url: string,\n severity: string,\n msg: string,\n code?: string,\n stackTrace?: string,\n onError?: (error: DeliveryError) => void,\n ): void {\n if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) {\n return;\n }\n\n try {\n const logRequest = {\n additionalInformation: {\n message: msg,\n version: this._integrationName,\n },\n severity,\n code: code || ErrorCodes.UNKNOWN_ERROR,\n url: _getReportingUrl(),\n deviceInfo: _getUserAgent(),\n stackTrace,\n reporter: this._reporter,\n integration: this._integrationName,\n };\n\n const headers: Record = {\n Accept: 'text/plain;charset=UTF-8',\n 'Content-Type': 'application/json',\n 'rokt-launcher-version': this._integrationName,\n 'rokt-wsdk-version': 'joint',\n };\n\n if (this._launcherInstanceGuid) {\n headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid;\n }\n if (this._accountId) {\n headers['rokt-account-id'] = this._accountId;\n }\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(logRequest),\n })\n .then((response: Response) => {\n // fetch only rejects on network failures; an HTTP 5xx resolves with\n // ok === false. Surface server-side failures so they are not swallowed.\n if (!response.ok) {\n const serverError: DeliveryError = new Error('HTTP ' + response.status + ' from log endpoint');\n serverError.statusCode = response.status;\n throw serverError;\n }\n })\n .catch((error: DeliveryError) => {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error);\n });\n } catch (error) {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error as DeliveryError);\n }\n }\n}\n\nclass ErrorReportingService {\n private _transport: ReportingTransport;\n private _errorUrl: string;\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._errorUrl = generateReportingUrl(config?.errorUrl, config?.integrationDomain, ERROR_ENDPOINT);\n }\n\n report(error: ErrorReport | null | undefined): void {\n if (!error) return;\n const severity = error.severity || WSDKErrorSeverity.ERROR;\n this._transport.send(this._errorUrl, severity, error.message, error.code, error.stackTrace);\n }\n}\n\nclass LoggingService {\n private _transport: ReportingTransport;\n private _loggingUrl: string;\n private _errorReportingService: { report: (e: ErrorReport) => void };\n\n constructor(\n config: ReportingConfig,\n errorReportingService: { report: (e: ErrorReport) => void },\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._loggingUrl = generateReportingUrl(config?.loggingUrl, config?.integrationDomain, LOGGING_ENDPOINT);\n this._errorReportingService = errorReportingService;\n }\n\n log(entry: LogEntry | null | undefined): void {\n if (!entry) return;\n this._transport.send(\n this._loggingUrl,\n WSDKErrorSeverity.INFO,\n entry.message,\n entry.code,\n undefined,\n (error: DeliveryError) => {\n if (this._errorReportingService) {\n // A failed log POST is not itself an SDK error. Network-level failures\n // (ad-blockers, offline, CORS) are client-side noise and reported as a\n // WARNING; only a server-side non-2xx response stays at ERROR severity.\n const isServerSide = typeof error.statusCode === 'number';\n this._errorReportingService.report({\n message: 'LoggingService: Failed to send log: ' + error.message,\n code: ErrorCodes.LOG_DELIVERY_FAILURE,\n severity: isServerSide ? WSDKErrorSeverity.ERROR : WSDKErrorSeverity.WARNING,\n });\n }\n },\n );\n }\n}\n\nfunction buildPageEvent(event: SDKEvent): PageEvent {\n const pageUrl = sanitizeUrl(window.location.href);\n const pageTitle = event.EventAttributes?.title || document.title;\n const canonicalUrl = readCanonicalUrl();\n const activeTimeOnSite = event.ActiveTimeOnSite;\n\n return {\n pageUrl,\n sourceMessageId: event.SourceMessageId,\n timestamp: event.Timestamp,\n ...(pageTitle ? { pageTitle } : {}),\n ...(canonicalUrl !== undefined ? { canonicalUrl } : {}),\n ...(Number.isFinite(activeTimeOnSite) ? { activeTimeOnSite } : {}),\n };\n}\n\n// ============================================================\n// RoktKit class\n// ============================================================\n\nclass RoktKit implements KitInterface {\n // Static field for allowed origin hashes (mutable by testHelpers)\n public static _allowedOriginHashes: number[] = [-553112570, 549508659];\n\n private static readonly PERFORMANCE_MARKS = {\n RoktScriptAppended: 'mp:RoktScriptAppended',\n };\n\n private static readonly EMAIL_SHA256_KEY = 'emailsha256';\n\n // Public fields (accessed by tests and the mParticle framework)\n public name = name;\n public id = moduleId;\n public moduleId = moduleId;\n public isInitialized = false;\n public launcher: RoktLauncher | null = null;\n public filters: KitFilters = {};\n public userAttributes: Record = {};\n // Flag set by the Workspace IDSync flow on a 200 response. Stored on the\n // kit instance and merged into placement attributes inside selectPlacements.\n public userIdentifiedInWorkspace = false;\n public testHelpers: TestHelpers | null = null;\n public placementEventMappingLookup: Record = {};\n public placementEventAttributeMappingLookup: Record = {};\n public integrationName: string | null = null;\n public domain?: string;\n public errorReportingService: ErrorReportingService | null = null;\n public loggingService: LoggingService | null = null;\n\n // Private fields\n private _mappedEmailSha256Key?: string;\n private _onboardingExpProvider?: string;\n private _thankYouElementOnLoadCallback: (() => void) | null = null;\n private _isThankYouElementLoaded = false;\n private _workspaceIdSyncApiKey?: string;\n\n // Held during a search dispatch so the next selectPlacements call;\n // can wait for the HTTP response before reading userIdentifiedInWorkspace;\n // — otherwise the first placement call ships without the flag.\n private _workspaceSearchInFlightPromise: Promise | null = null;\n // Stable serialization of the identifier set sent in the most recent\n // successful search dispatch. If a subsequent identification arrives with\n // an identical set, we skip the network call (the flag is still correct\n // from the prior search). Keyed over the full IUserIdentities map — not\n // just email — so partners passing hashed email through `other`/`other2-10`\n // or any other identifier benefit from the same dedupe. Cleared on logout\n // so a re-login re-evaluates fresh.\n private _workspaceLastSearchedIdentitiesKey?: string;\n\n // ---- Private helpers ----\n\n private getEventAttributeValue(event: SDKEvent, eventAttributeKey: string): unknown {\n const attributes = event && event.EventAttributes;\n if (!attributes) {\n return null;\n }\n\n if (typeof attributes[eventAttributeKey] === 'undefined') {\n return null;\n }\n\n return attributes[eventAttributeKey];\n }\n\n private doesEventAttributeConditionMatch(condition: EventAttributeCondition, actualValue: unknown): boolean {\n if (!condition || !isString(condition.operator)) {\n return false;\n }\n\n const operator = condition.operator.toLowerCase();\n const expectedValue = condition.attributeValue;\n\n if (operator === 'exists') {\n return actualValue !== null;\n }\n\n if (actualValue == null) {\n return false;\n }\n\n if (operator === 'equals') {\n return String(actualValue) === String(expectedValue);\n }\n\n if (operator === 'contains') {\n return String(actualValue).indexOf(String(expectedValue)) !== -1;\n }\n\n return false;\n }\n\n private doesEventMatchRule(event: SDKEvent, rule: PlacementEventRule): boolean {\n if (!rule || !isString(rule.eventAttributeKey)) {\n return false;\n }\n\n const conditions = rule.conditions;\n if (!Array.isArray(conditions)) {\n return false;\n }\n\n const actualValue = this.getEventAttributeValue(event, rule.eventAttributeKey);\n\n if (conditions.length === 0) {\n return actualValue !== null;\n }\n for (let i = 0; i < conditions.length; i++) {\n if (!this.doesEventAttributeConditionMatch(conditions[i], actualValue)) {\n return false;\n }\n }\n\n return true;\n }\n\n private applyPlacementEventAttributeMapping(event: SDKEvent): void {\n const mappedAttributeKeys = Object.keys(this.placementEventAttributeMappingLookup);\n for (let i = 0; i < mappedAttributeKeys.length; i++) {\n const mappedAttributeKey = mappedAttributeKeys[i];\n const rulesForMappedAttributeKey = this.placementEventAttributeMappingLookup[mappedAttributeKey];\n if (isEmpty(rulesForMappedAttributeKey)) {\n continue;\n }\n\n // Require ALL rules for the same key to match (AND).\n let allMatch = true;\n for (let j = 0; j < rulesForMappedAttributeKey.length; j++) {\n if (!this.doesEventMatchRule(event, rulesForMappedAttributeKey[j])) {\n allMatch = false;\n break;\n }\n }\n if (!allMatch) {\n continue;\n }\n\n mp().Rokt.setLocalSessionAttribute?.(mappedAttributeKey, true);\n }\n }\n\n private capturePageView(event: SDKEvent): void {\n let pageUrl: string | undefined;\n\n try {\n pageUrl = sanitizeUrl(window.location.href);\n\n const pageViews = loadPageViews(this.loggingService);\n const pageView = buildPageEvent(event);\n pageViews.push(pageView);\n\n const requested = Math.min(pageViews.length, PAGE_VIEWS_MAX_COUNT);\n const stored = writePageViews(pageViews);\n if (stored === 0) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n this.loggingService?.log({\n message: `Rokt Kit: Failed to persist page view for ${pageUrl} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n } else if (stored < requested) {\n this.loggingService?.log({\n message: `Rokt Kit: Page view storage reduced from ${requested} to ${stored} record(s) under quota pressure [reason: quota_eviction]`,\n code: 'PAGE_VIEW_QUOTA_EVICTION',\n });\n }\n } catch (err) {\n const reason = isLocalStorageAvailable() ? 'exception' : 'ls_unavailable';\n const errMessage = err instanceof Error ? err.message : String(err);\n this.loggingService?.log({\n message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${errMessage} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n private isLauncherReadyToAttach(): boolean {\n return !!window.Rokt && isFunction(window.Rokt.createLauncher);\n }\n\n /**\n * Returns the user identities from the filtered user, if any.\n */\n private returnUserIdentities(filteredUser: FilteredUser | null | undefined): Record {\n if (!filteredUser || !filteredUser.getUserIdentities) {\n return {};\n }\n\n const userIdentities: IUserIdentities = filteredUser.getUserIdentities().userIdentities;\n\n return this.replaceOtherIdentityWithEmailsha256(userIdentities);\n }\n\n private returnLocalSessionAttributes(): Record {\n if (!mp().Rokt || typeof mp().Rokt.getLocalSessionAttributes !== 'function') {\n return {};\n }\n return mp().Rokt.getLocalSessionAttributes!();\n }\n\n private replaceOtherIdentityWithEmailsha256(userIdentities: IUserIdentities): Record {\n const newUserIdentities: Record = { ...(userIdentities || {}) };\n const key = this._mappedEmailSha256Key;\n if (key && userIdentities[key as keyof IUserIdentities]) {\n newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key as keyof IUserIdentities] as string;\n }\n if (key) {\n delete newUserIdentities[key];\n }\n\n return newUserIdentities;\n }\n\n private logSelectPlacementsEvent(attributes: unknown): void {\n if (!window.mParticle || typeof mp().logEvent !== 'function') {\n return;\n }\n\n if (!isObject(attributes)) {\n return;\n }\n\n const EVENT_TYPE_OTHER = mp().EventType.Other;\n\n mp().logEvent(EVENT_NAME_SELECT_PLACEMENTS, EVENT_TYPE_OTHER, attributes as Record);\n }\n\n private setRoktSessionId(sessionId: string): void {\n if (!sessionId || typeof sessionId !== 'string') {\n return;\n }\n try {\n const mpInstance = mp().getInstance();\n if (mpInstance && isFunction(mpInstance.setIntegrationAttribute)) {\n mpInstance.setIntegrationAttribute(moduleId, {\n roktSessionId: sessionId,\n });\n }\n } catch (_e) {\n // Best effort — never let this break the partner page\n }\n }\n\n private readMpSessionId(): string | undefined {\n // The public mParticle.sessionManager facade exposes only getSession(), which already returns\n // the session id. getSessionId() lives on the internal _SessionManager and has never been\n // re-exported, so prefer it if a future core adds it and fall back to getSession() until then.\n const sessionManager = mp()?.sessionManager;\n const readSessionId = sessionManager?.getSessionId ?? sessionManager?.getSession;\n if (!isFunction(readSessionId)) {\n return undefined;\n }\n\n return readSessionId.call(sessionManager) || undefined;\n }\n\n private readMpDeviceId(): string | undefined {\n // The device application stamp (`das`) outlives the session id: core clears the session on\n // timeout, cross-tab rotation and endSession(), but never the device id, which lives in\n // localStorage/cookie for cookieExpiration days (365 by default) and survives login/logout.\n // Read it per call anyway — a partner can reassign it at any time via setDeviceId().\n return mp()?.getDeviceId?.() || undefined;\n }\n\n private attachLauncher(\n accountId: string,\n launcherOptions: Record,\n legacyRoktExtensions: string[] = [],\n ): void {\n const options: Record = {\n accountId,\n ...(launcherOptions || {}),\n };\n\n let launcherPromise: Promise;\n if (this.isPartnerInLocalLauncherTestGroup()) {\n launcherPromise = Promise.resolve(window.Rokt!.createLocalLauncher(options));\n } else {\n launcherPromise = window.Rokt!.createLauncher(options);\n }\n\n launcherPromise\n .then(async (launcher) => {\n await registerLegacyExtensions(legacyRoktExtensions, launcher);\n this.initRoktLauncher(launcher);\n })\n .catch((err: unknown) => {\n console.error('Error creating Rokt launcher:', err);\n });\n }\n\n private initRoktLauncher(launcher: RoktLauncher): void {\n // Assign the launcher to a global variable for later access\n if (window.Rokt) {\n window.Rokt.currentLauncher = launcher;\n }\n // Locally cache the launcher and filters\n this.launcher = launcher;\n\n const roktFilters = mp().Rokt?.filters;\n\n if (!roktFilters) {\n console.warn('Rokt Kit: No filters have been set.');\n } else {\n this.filters = roktFilters;\n if (!roktFilters.filteredUser) {\n console.warn('Rokt Kit: No filtered user has been set.');\n } else {\n this._workspaceSearchInFlightPromise = this.search(roktFilters.filteredUser);\n }\n }\n\n // Kit must be initialized before attaching to the Rokt manager\n this.isInitialized = true;\n\n sendAdBlockMeasurementSignals(this.domain, this.integrationName);\n\n // Attaches the kit to the Rokt manager\n mp().Rokt.attachKit(this);\n }\n\n private fetchOptimizely(): Record {\n const forwarders = mp()\n ._getActiveForwarders()\n .filter((forwarder) => forwarder.name === 'Optimizely');\n\n try {\n if (forwarders.length > 0 && window.optimizely) {\n const optimizelyState = window.optimizely.get('state');\n if (!optimizelyState || !optimizelyState.getActiveExperimentIds) {\n return {};\n }\n const activeExperimentIds = optimizelyState.getActiveExperimentIds();\n const activeExperiments = activeExperimentIds.reduce((acc: Record, expId: string) => {\n acc['rokt.custom.optimizely.experiment.' + expId + '.variationId'] =\n optimizelyState.getVariationMap()[expId].id;\n return acc;\n }, {});\n return activeExperiments;\n }\n } catch (error) {\n console.error('Error fetching Optimizely attributes:', error);\n }\n return {};\n }\n\n private isKitReady(): boolean {\n return !!(this.isInitialized && this.launcher);\n }\n\n // When the partner has opted out of targeting (noTargeting launcher option),\n // the kit must not collect behavioral targeting signals such as page views.\n private isTargetingDisabled(): boolean {\n return (mp().Rokt?.launcherOptions as Record | undefined)?.noTargeting === true;\n }\n\n private isPartnerInLocalLauncherTestGroup(): boolean {\n return !!(mp().config && mp().config!.isLocalLauncherEnabled && this.isAssignedToSampleGroup());\n }\n\n private isAssignedToSampleGroup(): boolean {\n const LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5;\n return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD;\n }\n\n private captureTiming(metricName: string): void {\n if (window && mp() && mp().captureTiming && metricName) {\n mp().captureTiming!(metricName);\n }\n }\n\n // ---- Public methods (mParticle Kit Callbacks) ----\n\n /**\n * Initializes the Rokt forwarder with settings from the mParticle server.\n */\n public init(\n settings: Record,\n _service: unknown,\n testMode: boolean,\n _trackerId: unknown,\n filteredUserAttributes?: Record,\n ): string {\n const kitSettings = settings as unknown as RoktKitSettings;\n const accountId = kitSettings.accountId;\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredUserAttributes);\n this._onboardingExpProvider = kitSettings.onboardingExpProvider;\n\n const placementEventMapping = parseSettingsString(kitSettings.placementEventMapping);\n this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping);\n\n const placementEventAttributeMapping = parseSettingsString(\n kitSettings.placementEventAttributeMapping,\n );\n this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping);\n\n // Set dynamic OTHER_IDENTITY based on server settings\n if (kitSettings.hashedEmailUserIdentityType) {\n this._mappedEmailSha256Key = kitSettings.hashedEmailUserIdentityType.toLowerCase();\n }\n\n this._workspaceIdSyncApiKey = isString(kitSettings.workspaceIdSyncApiKey)\n ? kitSettings.workspaceIdSyncApiKey\n : undefined;\n\n const domain = mp().Rokt?.domain;\n const { roktExtensionsQueryParams, legacyRoktExtensions, loadThankYouElement } = extractRoktExtensionConfig(\n kitSettings.roktExtensions,\n );\n const launcherOptions: Record = {\n ...((mp().Rokt?.launcherOptions as Record) || {}),\n };\n this.integrationName = generateIntegrationName(launcherOptions.integrationName as string | undefined);\n launcherOptions.integrationName = this.integrationName;\n\n this.domain = domain;\n\n const reportingConfig: ReportingConfig = {\n loggingUrl: kitSettings.loggingUrl,\n errorUrl: kitSettings.errorUrl,\n integrationDomain: domain,\n isLoggingEnabled: mp().config?.isLoggingEnabled === true,\n };\n const errorReportingService = new ErrorReportingService(\n reportingConfig,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n const loggingService = new LoggingService(\n reportingConfig,\n errorReportingService,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n\n this.errorReportingService = errorReportingService;\n this.loggingService = loggingService;\n\n if (this.isTargetingDisabled()) {\n try {\n clearPageViews();\n clearUtmParams();\n } catch (err) {\n this.errorReportingService?.report({\n message: 'Rokt Kit: Failed to clear page views when targeting is disabled',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n severity: WSDKErrorSeverity.INFO,\n stackTrace: err instanceof Error ? err.stack : undefined,\n });\n }\n }\n\n if (mp()._registerErrorReportingService) {\n mp()._registerErrorReportingService!(errorReportingService);\n }\n if (mp()._registerLoggingService) {\n mp()._registerLoggingService!(loggingService);\n }\n\n if (testMode) {\n this.testHelpers = {\n generateLauncherScript: generateLauncherScript,\n generateThankYouElementScript: generateThankYouElementScript,\n extractRoktExtensionConfig: extractRoktExtensionConfig,\n hashEventMessage: hashEventMessage,\n parseSettingsString: parseSettingsString,\n generateMappedEventLookup: generateMappedEventLookup,\n generateMappedEventAttributeLookup: generateMappedEventAttributeLookup,\n sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals,\n createAutoRemovedIframe: createAutoRemovedIframe,\n djb2: djb2,\n setAllowedOriginHashes: (hashes: number[]) => {\n RoktKit._allowedOriginHashes = hashes;\n },\n ReportingTransport: ReportingTransport,\n ErrorReportingService: ErrorReportingService,\n LoggingService: LoggingService,\n RateLimiter: RateLimiter,\n ErrorCodes: ErrorCodes,\n WSDKErrorSeverity: WSDKErrorSeverity,\n };\n this.attachLauncher(accountId, launcherOptions);\n return 'Successfully initialized: ' + name;\n }\n\n if (loadThankYouElement) {\n mp().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this);\n loadRoktScript(ROKT_THANK_YOU_ELEMENT_SCRIPT_ID, generateThankYouElementScript(domain), {\n onLoad: () => {\n this._isThankYouElementLoaded = true;\n if (this._thankYouElementOnLoadCallback) {\n this._thankYouElementOnLoadCallback();\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt Thank You Element script:', error);\n },\n });\n }\n\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n loadRoktScript(ROKT_INTEGRATION_SCRIPT_ID, generateLauncherScript(domain, roktExtensionsQueryParams), {\n onLoad: () => {\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n console.error('Rokt object is not available after script load.');\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt launcher script:', error);\n },\n });\n\n this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended);\n }\n\n return 'Successfully initialized: ' + name;\n }\n\n public process(event: SDKEvent): string {\n if (!this.isTargetingDisabled()) {\n if (event.EventDataType === MESSAGE_TYPE_PAGE_VIEW) {\n captureUtmParams(this.loggingService);\n this.capturePageView(event);\n }\n\n if (event.EventDataType === MESSAGE_TYPE_SESSION_END) {\n migrateLegacyPageViewStorage(this.loggingService);\n clearPageViews();\n clearUtmParams();\n }\n }\n\n // The forwarding work below (LSA mapping) depends on the launcher, so guard\n // it here and surface the not-ready signal to the core SDK.\n if (!this.isKitReady()) {\n return 'Kit not ready for forwarder: ' + name;\n }\n\n if (isFunction(mp().Rokt?.setLocalSessionAttribute)) {\n if (!isEmpty(this.placementEventAttributeMappingLookup)) {\n this.applyPlacementEventAttributeMapping(event);\n }\n\n if (!isEmpty(this.placementEventMappingLookup)) {\n const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? '');\n if (this.placementEventMappingLookup[String(hashedEvent)]) {\n mp().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(hashedEvent)], true);\n }\n }\n }\n\n return 'Successfully sent to forwarder: ' + name;\n }\n\n public setExtensionData(partnerExtensionData: Record): void {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return;\n }\n\n window.Rokt!.setExtensionData(partnerExtensionData);\n }\n\n public setUserAttribute(key: string, value: unknown): string {\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n this.userAttributes[key] = value;\n }\n return 'Successfully set user attribute for forwarder: ' + name;\n }\n\n public removeUserAttribute(key: string): string {\n delete this.userAttributes[key];\n return 'Successfully removed user attribute for forwarder: ' + name;\n }\n\n private handleIdentityComplete(user: IMParticleUser, callbackName: string): string {\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(user.getAllUserAttributes());\n return 'Successfully called ' + callbackName + ' for forwarder: ' + name;\n }\n\n public onUserIdentified(user: IMParticleUser): string {\n const filteredUser = user as FilteredUser;\n this.filters.filteredUser = filteredUser;\n this._workspaceSearchInFlightPromise = this.search(filteredUser);\n return this.handleIdentityComplete(user, 'onUserIdentified');\n }\n\n private search(filteredUser: FilteredUser): Promise {\n const apiKey = this._workspaceIdSyncApiKey;\n if (!apiKey) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n const search = mp().Identity?.search;\n if (typeof search !== 'function') {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n const userIdentities: IUserIdentities | null = filteredUser.getUserIdentities\n ? filteredUser.getUserIdentities().userIdentities\n : null;\n\n // Forward every non-empty string identifier the user has — email,\n // customerid, other/other2-10 (commonly used for hashed email),\n // mobile_number, facebook, etc. The host SDK's Identity.search accepts\n // the full IUserIdentities surface and the server validates it.\n const knownIdentities: Record = {};\n if (userIdentities) {\n for (const key of Object.keys(userIdentities) as Array) {\n const value = userIdentities[key];\n if (isString(value) && value.length > 0) {\n knownIdentities[key] = value;\n }\n }\n }\n\n const identityKeys = Object.keys(knownIdentities);\n if (identityKeys.length === 0) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n // Stable cache key: sort keys so insertion-order differences don't\n // cause false misses. The values are partner-supplied strings; no\n // hashing needed — equality on this serialization is sufficient.\n const identitiesKey = identityKeys\n .sort()\n .map((k) => `${k}=${knownIdentities[k]}`)\n .join('&');\n\n // Same identifier set as the last successful dispatch → skip the\n // network call. The current flag value still reflects the correct\n // match status.\n if (identitiesKey === this._workspaceLastSearchedIdentitiesKey) {\n return this._workspaceSearchInFlightPromise || Promise.resolve();\n }\n\n // New / different identifier set → reset and re-search. Cache the key\n // up front so a second concurrent invocation with the same set also\n // dedupes.\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = identitiesKey;\n\n return new Promise((resolve) => {\n try {\n search(apiKey, knownIdentities as IUserIdentities, (result: WorkspaceIdSyncResult) => {\n if (result?.httpCode === 200) {\n this.userIdentifiedInWorkspace = true;\n }\n resolve();\n });\n } catch (err) {\n console.error('Rokt Kit: Workspace IDSync search failed', err);\n // Dispatch failed — clear the cache so the same identifier set\n // can retry on the next identification rather than being stuck\n // behind a poisoned entry that short-circuits future searches.\n this._workspaceLastSearchedIdentitiesKey = undefined;\n resolve();\n }\n });\n }\n\n public onLoginComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onLoginComplete');\n }\n\n public onLogoutComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n // Anonymous sessions must not carry the previous user's match forward.\n // Clear the flag explicitly here. Also clear the identities cache so a\n // re-login (possibly with the same identifiers) dispatches a fresh\n // search rather than reusing a stale answer.\n this.userIdentifiedInWorkspace = false;\n this._workspaceSearchInFlightPromise = null;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return this.handleIdentityComplete(user, 'onLogoutComplete');\n }\n\n public onModifyComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onModifyComplete');\n }\n\n /**\n * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options.\n *\n * If a Workspace IDSync search is in flight from a recent onUserIdentified\n * call, this method waits up to `WORKSPACE_SEARCH_SELECT_TIMEOUT_MS` for it\n * to settle so the first placement call can include the\n * `userIdentifiedInWorkspace` flag without racing the network response.\n * The timeout protects against a stalled or slow search blocking placement\n * rendering — if it fires, selectPlacements proceeds without the flag.\n *\n * Implementation note: this method stays non-async deliberately. First,\n * the public return type is `RoktSelection | Promise |\n * undefined` — a superset of the `RoktSelection | Promise`\n * shape declared for `RoktLauncher.selectPlacements` above (line ~70).\n * Marking this `async` would narrow it to `Promise` and silently change the contract for callers that read\n * the result synchronously. Second, `RoktSelection` has an optional\n * `then?` member, so TS treats it as ambiguously promise-like and\n * rejects it as the awaited return of an async function (TS1058) —\n * working around that would require a cast or wrapping every return in\n * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`;\n * this wrapper just gates it on the in-flight search via `Promise.race`.\n */\n public selectPlacements(options: Record): RoktSelection | Promise | undefined {\n if (this._workspaceSearchInFlightPromise) {\n const inFlight = this._workspaceSearchInFlightPromise;\n return Promise.race([\n inFlight,\n new Promise((resolve) => setTimeout(resolve, WORKSPACE_SEARCH_SELECT_TIMEOUT_MS)),\n ]).then(() => this._dispatchPlacements(options)) as Promise;\n }\n return this._dispatchPlacements(options);\n }\n\n private _dispatchPlacements(options: Record): RoktSelection | Promise | undefined {\n const attributes = ((options && (options.attributes as Record)) || {}) as Record;\n const cachedUserAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(this.userAttributes);\n const placementAttributes: Record = { ...cachedUserAttributes, ...attributes };\n\n const filters = this.filters || {};\n const userAttributeFilters = (filters.userAttributeFilters as string[]) || [];\n const filteredUser = filters.filteredUser || null;\n const mpid = filteredUser ? filteredUser.getMPID() : null;\n\n let filteredAttributes: Record;\n\n if (!filters) {\n console.warn('Rokt Kit: No filters available, using user attributes');\n filteredAttributes = placementAttributes;\n } else if (filters.filterUserAttributes) {\n filteredAttributes = filters.filterUserAttributes(placementAttributes, userAttributeFilters);\n } else {\n filteredAttributes = placementAttributes;\n }\n\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredAttributes);\n\n const optimizelyAttributes = this._onboardingExpProvider === 'Optimizely' ? this.fetchOptimizely() : {};\n\n const filteredUserIdentities = this.returnUserIdentities(filteredUser);\n\n const sessionAttributes = this.returnLocalSessionAttributes();\n const pageEvents = buildPageEvents(loadPageViews(this.loggingService));\n const utmParams = loadUtmParams();\n const mpSessionId = this.readMpSessionId();\n const mpDeviceId = this.readMpDeviceId();\n\n const selectPlacementsAttributes: Record = {\n ...(filteredUserIdentities as Record),\n ...filteredAttributes,\n ...optimizelyAttributes,\n ...sessionAttributes,\n ...(pageEvents.length ? { [PAGE_EVENTS_KEY]: JSON.stringify(pageEvents) } : {}),\n ...(utmParams ? { [PAGE_VIEW_ATTRIBUTES_KEY]: utmParams } : {}),\n ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}),\n ...(mpSessionId ? { [MPARTICLE_SESSION_ID_KEY]: mpSessionId } : {}),\n ...(mpDeviceId ? { [MPARTICLE_DEVICE_ID_KEY]: mpDeviceId } : {}),\n mpid,\n };\n\n const selectPlacementsOptions: Record = { ...options, attributes: selectPlacementsAttributes };\n\n const selection = this.launcher!.selectPlacements(selectPlacementsOptions);\n\n // After selection resolves, sync the Rokt session ID back to mParticle, then log\n const logSelection = () => this.logSelectPlacementsEvent(selectPlacementsAttributes);\n\n void Promise.resolve(selection)\n .then((sel) => sel?.context?.sessionId?.then((sessionId) => this.setRoktSessionId(sessionId)))\n .catch(() => undefined)\n .finally(logSelection);\n\n return selection;\n }\n\n /**\n * Passes attributes to the Rokt Web SDK for client-side hashing.\n */\n public hashAttributes(attributes: Record): Promise> | null {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return null;\n }\n return this.launcher!.hashAttributes(attributes);\n }\n\n /**\n * Enables optional Integration Launcher extensions before selecting placements.\n *\n * @deprecated This functionality has been internalized and will be removed in a future release.\n */\n public use(extensionName: string): Promise {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return Promise.reject(new Error('Rokt Kit: Not initialized'));\n }\n if (!extensionName || !isString(extensionName)) {\n return Promise.reject(new Error('Rokt Kit: Invalid extension name'));\n }\n return this.launcher!.use(extensionName);\n }\n\n /**\n * Registers a callback to be invoked once rokt-thank-you-element.js becomes available.\n */\n public onShoppableAdsReady(callback: () => void) {\n if (this._isThankYouElementLoaded) {\n callback();\n } else {\n this._thankYouElementOnLoadCallback = callback;\n }\n }\n}\n\n// ============================================================\n// Kit registration\n// ============================================================\n\nfunction getId(): number {\n return moduleId;\n}\n\nfunction register(config: { kits?: Record }): void {\n if (!config) {\n window.console.log('You must pass a config object to register the kit ' + name);\n return;\n }\n if (!isObject(config)) {\n window.console.log(\"'config' must be an object. You passed in a \" + typeof config);\n return;\n }\n\n if (isObject(config.kits)) {\n (config.kits as Record)[name] = {\n constructor: RoktKit,\n };\n } else {\n config.kits = {};\n config.kits[name] = {\n constructor: RoktKit,\n };\n }\n window.console.log('Successfully registered ' + name + ' to your mParticle configuration');\n}\n\nif (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) {\n mp().addForwarder({\n name: name,\n constructor: RoktKit,\n getId: getId,\n });\n}\n\nexport { register };\nexport type { LoggingService };\n"],"names":["SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST","SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET","isSelectPlacementsAttributePersistenceDenied","key","removeSelectPlacementsAttributePersistenceDeniedAttributes","attributes","filteredAttributes","sourceAttributes","attributeKeys","i","isObject","value","isString","isFunction","isEmpty","sanitizeUrl","href","url","LS_PROBE_KEY","isLocalStorageAvailable","readJSON","stored","writeJSON","removeKey","readNamespacedField","namespaceKey","field","blob","writeNamespacedField","next","removeNamespacedField","LS_NAMESPACE_KEY","LS_PAGE_VIEWS_FIELD","LS_UTM_PARAMS_FIELD","LEGACY_PAGE_VIEWS_KEY","PAGE_VIEWS_MAX_COUNT","UTM_KEYS","capPageViews","views","migrateLegacyPageViewStorage","loggingService","legacyViews","loadPageViews","writePageViews","pageViews","toWrite","clearPageViews","buildPageEvents","pageView","index","activeTimeOnSite","hasActiveTime","nextActiveTimeOnSite","hasNextActiveTimeOnSite","diff","captureUtmParams","search","params","captured","reason","loadUtmParams","clearUtmParams","readCanonicalUrl","name","moduleId","EVENT_NAME_SELECT_PLACEMENTS","ADBLOCK_CONTROL_DOMAIN","INIT_LOG_SAMPLING_RATE","ROKT_THANK_YOU_JOURNEY_EXTENSION","ROKT_INTEGRATION_SCRIPT_ID","ROKT_THANK_YOU_ELEMENT_SCRIPT_ID","USER_IDENTIFIED_IN_WORKSPACE_KEY","MESSAGE_TYPE_PAGE_VIEW","MESSAGE_TYPE_SESSION_END","PAGE_EVENTS_KEY","PAGE_VIEW_ATTRIBUTES_KEY","MPARTICLE_SESSION_ID_KEY","MPARTICLE_DEVICE_ID_KEY","WORKSPACE_SEARCH_SELECT_TIMEOUT_MS","ErrorCodes","WSDKErrorSeverity","DEFAULT_ROKT_DOMAIN","LOGGING_ENDPOINT","ERROR_ENDPOINT","RATE_LIMIT_PER_SEVERITY","mp","generateLauncherScript","domain","extensions","baseUrl","generateBaseUrl","generateThankYouElementScript","resolvedDomain","generateReportingUrl","configuredUrl","endpoint","reportingDomain","loadRoktScript","scriptId","source","handlers","target","script","parseSettingsString","settingsString","extractRoktExtensionConfig","settings","roktExtensionsQueryParams","legacyRoktExtensions","loadThankYouElement","extensionName","registerLegacyExtensions","legacyExtensions","launcher","extension","generateMappedEventLookup","placementEventMapping","mappedEvents","mapping","generateMappedEventAttributeLookup","placementEventAttributeMapping","mappedAttributeKeys","mappedAttributeKey","eventAttributeKey","hashEventMessage","messageType","eventType","eventName","generateIntegrationName","customIntegrationName","integrationName","djb2","str","hash","createAutoRemovedIframe","src","iframe","sendAdBlockMeasurementSignals","version","originHash","RoktKit","guid","pageUrl","existingBaseUrl","_isDebugModeEnabled","_getReportingUrl","_getUserAgent","RateLimiter","severity","newCount","ReportingTransport","config","launcherInstanceGuid","accountId","rateLimiter","isLoggingEnabled","msg","code","stackTrace","onError","logRequest","headers","response","serverError","error","ErrorReportingService","LoggingService","errorReportingService","entry","isServerSide","buildPageEvent","event","pageTitle","canonicalUrl","_RoktKit","condition","actualValue","operator","expectedValue","rule","conditions","rulesForMappedAttributeKey","allMatch","j","requested","err","errMessage","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","sessionManager","readSessionId","launcherOptions","options","launcherPromise","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","sessionAttributes","pageEvents","utmParams","mpSessionId","mpDeviceId","selectPlacementsAttributes","selectPlacementsOptions","selection","logSelection","sel","callback","getId","register"],"mappings":"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"} \ No newline at end of file diff --git a/kits/rokt/dist/Rokt-Kit.d.ts b/kits/rokt/dist/Rokt-Kit.d.ts index 2fef482d9..38587898a 100644 --- a/kits/rokt/dist/Rokt-Kit.d.ts +++ b/kits/rokt/dist/Rokt-Kit.d.ts @@ -1,7 +1,41 @@ +declare interface ErrorReport { + message: string; + code?: string; + severity?: string; + stackTrace?: string; +} + +declare interface LogEntry { + message: string; + code?: string; +} + +export declare class LoggingService { + private _transport; + private _loggingUrl; + private _errorReportingService; + constructor(config: ReportingConfig, errorReportingService: { + report: (e: ErrorReport) => void; + }, integrationName: string | null | undefined, launcherInstanceGuid?: string, accountId?: string | null, rateLimiter?: RateLimiter); + log(entry: LogEntry | null | undefined): void; +} + +declare class RateLimiter { + private _logCount; + incrementAndCheck(severity: string): boolean; +} + export declare function register(config: { kits?: Record; }): void; +declare interface ReportingConfig { + loggingUrl?: string; + errorUrl?: string; + integrationDomain?: string; + isLoggingEnabled: boolean; +} + export { } diff --git a/kits/rokt/dist/Rokt-Kit.esm.js b/kits/rokt/dist/Rokt-Kit.esm.js index c040ba5fb..128fd8ce7 100644 --- a/kits/rokt/dist/Rokt-Kit.esm.js +++ b/kits/rokt/dist/Rokt-Kit.esm.js @@ -1,4 +1,5 @@ -const B = [ +const _e = [ + "active_time_on_site_ms", "billingaddress1", "billingaddress2", "billingcity", @@ -22,183 +23,326 @@ const B = [ "shippingstate", "shippingzipcode", "totalprice" -], J = new Set(B); -function G(n) { - return J.has(n.toLowerCase()); +], Ie = new Set(_e); +function se(i) { + return Ie.has(i.toLowerCase()); } -function w(n) { - const t = {}, e = n || {}, i = Object.keys(e); - for (let r = 0; r < i.length; r++) { - const s = i[r]; - G(s) || (t[s] = e[s]); +function b(i) { + const e = {}, t = i || {}, n = Object.keys(t); + for (let r = 0; r < n.length; r++) { + const s = n[r]; + se(s) || (e[s] = t[s]); } - return t; + return e; } -const d = "Rokt", b = 181, Q = "selectPlacements", X = "apps.roktecommerce.com", $ = 0.1, Z = "ThankYouPageJourney", tt = "rokt-launcher", et = "rokt-thank-you-element", it = "userIdentifiedInWorkspace", nt = 500, O = { +function _(i) { + return typeof i == "object" && i !== null && !Array.isArray(i); +} +function E(i) { + return typeof i == "string"; +} +function T(i) { + return typeof i == "function"; +} +function K(i) { + return i == null ? !0 : typeof i == "object" ? Object.keys(i).length === 0 : !1; +} +function Y(i) { + try { + const e = new URL(i); + return e.search = "", e.toString(); + } catch { + return i; + } +} +const j = "__rokt_ls_probe__"; +function D() { + try { + return window.localStorage.setItem(j, "1"), window.localStorage.removeItem(j), !0; + } catch { + return !1; + } +} +function N(i) { + try { + const e = window.localStorage.getItem(i); + return e === null ? null : JSON.parse(e); + } catch { + return null; + } +} +function oe(i, e) { + try { + return window.localStorage.setItem(i, JSON.stringify(e)), !0; + } catch { + return !1; + } +} +function ae(i) { + try { + window.localStorage.removeItem(i); + } catch { + } +} +function U(i, e) { + const t = N(i); + return _(t) ? t[e] : void 0; +} +function x(i, e, t) { + const n = N(i), r = _(n) ? { ...n } : {}; + return r[e] = t, oe(i, r); +} +function ce(i, e) { + const t = N(i); + if (!_(t) || !(e in t)) + return; + const n = { ...t }; + delete n[e], Object.keys(n).length === 0 ? ae(i) : oe(i, n); +} +const p = "mp-rokt-kit", R = "pageViews", O = "utmParams", H = "mpPageViews", le = 25, Se = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"]; +function ue(i) { + return i.slice(-le); +} +function de(i) { + const e = N(H); + if (e === null) + return; + !(U(p, R) !== void 0) && Array.isArray(e) && (i?.log({ + message: "Rokt Kit: Migrating legacy page-view storage", + code: "PAGE_VIEW_LEGACY_MIGRATION" + }), x(p, R, e) || i?.log({ + message: "Rokt Kit: Failed to migrate legacy page-view storage [reason: migration_retry]", + code: "PAGE_VIEW_CAPTURE_FAILED" + })), ae(H); +} +function z(i) { + de(i); + const e = U(p, R); + return Array.isArray(e) ? e : []; +} +function ye(i) { + const e = ue(i); + for (let t = 0; t < e.length; t++) { + const n = e.slice(t); + if (x(p, R, n)) + return n.length; + } + return 0; +} +function q() { + ce(p, R); +} +function Ae(i) { + const e = ue(i); + return e.map((t, n) => { + const r = t.activeTimeOnSite, s = r !== void 0 && Number.isFinite(r), c = e[n + 1]?.activeTimeOnSite, u = c !== void 0 && Number.isFinite(c), l = s && u ? c - r : void 0; + return { + pageUrl: t.pageUrl, + sourceMessageId: t.sourceMessageId, + timestamp: t.timestamp, + ...t.pageTitle !== void 0 ? { pageTitle: t.pageTitle } : {}, + ...t.canonicalUrl !== void 0 ? { canonicalUrl: t.canonicalUrl } : {}, + ...s ? { activeTimeOnSite: r } : {}, + ...l !== void 0 && l >= 0 ? { activeTimeOnPage: l } : {} + }; + }); +} +function ke(i) { + if (U(p, O) !== void 0) + return; + const e = new URLSearchParams(window.location.search), t = {}; + for (const r of Se) { + const s = e.get(r); + s && (t[r] = s); + } + if (Object.keys(t).length === 0) + return; + const n = Object.keys(t).join(", "); + if (!x(p, O, t)) { + const r = D() ? "quota" : "ls_unavailable"; + i?.log({ + message: `Rokt Kit: Failed to persist UTM params [reason: ${r}]`, + code: "UTM_CAPTURE_FAILED" + }); + return; + } + i?.log({ + message: `Rokt Kit: Captured UTM params [${n}]`, + code: "UTM_CAPTURE_SUCCESS" + }); +} +function Re() { + const i = U(p, O); + return _(i) ? i : null; +} +function $() { + ce(p, O); +} +function ve() { + const e = document.querySelector('link[rel="canonical"]')?.href; + if (e) + return Y(e); +} +const d = "Rokt", L = 181, we = "selectPlacements", be = "apps.roktecommerce.com", Te = 0.1, Le = "ThankYouPageJourney", Pe = "rokt-launcher", Oe = "rokt-thank-you-element", Ne = "userIdentifiedInWorkspace", Ue = 3, Ce = 2, Me = "page_events", Ke = "page_view_attributes", De = "mparticle_session_id", Fe = "mparticle_device_id", Ye = 500, G = { UNKNOWN_ERROR: "UNKNOWN_ERROR", UNHANDLED_EXCEPTION: "UNHANDLED_EXCEPTION", IDENTITY_REQUEST: "IDENTITY_REQUEST", LOG_DELIVERY_FAILURE: "LOG_DELIVERY_FAILURE" -}, I = { +}, S = { ERROR: "ERROR", INFO: "INFO", WARNING: "WARNING" -}, rt = "apps.rokt-api.com", st = "/v1/log", ot = "/v1/errors", at = 10; +}, xe = "apps.rokt-api.com", Ge = "/v1/log", We = "/v1/errors", Ve = 10; function a() { return window.mParticle; } -function U(n, t) { - const i = [P(n), "/wsdk/integrations/launcher.js"].join(""); - return !t || t.length === 0 ? i : i + "?extensions=" + t.join(","); -} -function K(n) { - return [P(n), "/rokt-elements/rokt-element-thank-you.js"].join(""); +function J(i, e) { + const n = [C(i), "/wsdk/integrations/launcher.js"].join(""); + return !e || e.length === 0 ? n : n + "?extensions=" + e.join(","); } -function P(n) { - return ["https://", typeof n < "u" ? n : rt].join(""); +function B(i) { + return [C(i), "/rokt-elements/rokt-element-thank-you.js"].join(""); } -function z(n, t, e) { - return n ? n.startsWith("http://") || n.startsWith("https://") ? n : "https://" + n : P(t) + e; +function C(i) { + const e = typeof i < "u" ? i : xe; + return e.includes("://") ? e.replace(/\/+$/, "") : ["https://", e].join(""); } -function M(n, t, e) { - if (document.getElementById(n)) return; - const i = document.head || document.body, r = document.createElement("script"); - r.id = n, r.type = "text/javascript", r.src = t, r.async = !0, r.crossOrigin = "anonymous", r.fetchPriority = "high", e?.onLoad && (r.onload = e.onLoad), e?.onError && (r.onerror = e.onError), i.appendChild(r); +function he(i, e, t) { + if (i) + return i.startsWith("http://") || i.startsWith("https://") ? i : "https://" + i; + const r = e?.includes("://") && !/^https?:\/\//i.test(e) ? void 0 : e; + return C(r) + t; } -function T(n) { - return n != null && typeof n == "object" && Array.isArray(n) === !1; +function Q(i, e, t) { + if (document.getElementById(i)) return; + const n = document.head || document.body, r = document.createElement("script"); + r.id = i, r.type = "text/javascript", r.src = e, r.async = !0, r.crossOrigin = "anonymous", r.fetchPriority = "high", t?.onLoad && (r.onload = t.onLoad), t?.onError && (r.onerror = t.onError), n.appendChild(r); } -function L(n) { - if (!n) +function P(i) { + if (!i) return []; try { - return JSON.parse(n.replace(/"/g, '"')); + return JSON.parse(i.replace(/"/g, '"')); } catch { console.error("Settings string contains invalid JSON"); } return []; } -function D(n) { - const t = n ? L(n) : [], e = [], i = []; +function X(i) { + const e = i ? P(i) : [], t = [], n = []; let r = !1; - for (let s = 0; s < t.length; s++) { - const o = t[s].value; - o === "thank-you-journey" ? (r = !0, i.push(Z)) : e.push(o); + for (let s = 0; s < e.length; s++) { + const o = e[s].value; + o === "thank-you-journey" ? (r = !0, n.push(Le)) : t.push(o); } return { - roktExtensionsQueryParams: e, - legacyRoktExtensions: i, + roktExtensionsQueryParams: t, + legacyRoktExtensions: n, loadThankYouElement: r }; } -async function ct(n, t) { - const e = []; - if (t) - for (const i of n) - e.push(t.use(i)); - return Promise.all(e); +async function je(i, e) { + const t = []; + if (e) + for (const n of i) + t.push(e.use(n)); + return Promise.all(t); } -function x(n) { - if (!n) +function Z(i) { + if (!i) return {}; - const t = {}; - for (let e = 0; e < n.length; e++) { - const i = n[e]; - t[i.jsmap] = i.value; - } - return t; -} -function Y(n) { - const t = {}; - if (!Array.isArray(n)) - return t; - for (let e = 0; e < n.length; e++) { - const i = n[e]; - if (!i || !m(i.value) || !m(i.map)) + const e = {}; + for (let t = 0; t < i.length; t++) { + const n = i[t]; + e[n.jsmap] = n.value; + } + return e; +} +function ee(i) { + const e = {}; + if (!Array.isArray(i)) + return e; + for (let t = 0; t < i.length; t++) { + const n = i[t]; + if (!n || !E(n.value) || !E(n.map)) continue; - const r = i.value, s = i.map; - t[r] || (t[r] = []), t[r].push({ + const r = n.value, s = n.map; + e[r] || (e[r] = []), e[r].push({ eventAttributeKey: s, - conditions: Array.isArray(i.conditions) ? i.conditions : [] + conditions: Array.isArray(n.conditions) ? n.conditions : [] }); } - return t; -} -function F(n, t, e) { - return a().generateHash([n, t, e].join("")); -} -function k(n) { - return n == null ? !0 : typeof n == "object" ? Object.keys(n).length === 0 : Array.isArray(n) ? n.length === 0 : !1; + return e; } -function m(n) { - return typeof n == "string"; +function te(i, e, t) { + return a().generateHash([i, e, t].join("")); } -function lt(n) { - let i = "mParticle_wsdkv_" + a().getVersion() + "_kitv_" + "1.28.3"; - return n && (i += "_" + n), i; +function He(i) { + let n = "mParticle_wsdkv_" + a().getVersion() + "_kitv_" + "1.35.0"; + return i && (n += "_" + i), n; } -function V(n) { - let t = 5381; - for (let e = 0; e < n.length; e++) - t = (t << 5) + t + n.charCodeAt(e), t = t & t; - return t; +function ge(i) { + let e = 5381; + for (let t = 0; t < i.length; t++) + e = (e << 5) + e + i.charCodeAt(t), e = e & e; + return e; } -function N(n) { - const t = document.createElement("iframe"); - t.style.display = "none", t.setAttribute("sandbox", "allow-scripts allow-same-origin"), t.src = n, t.onload = function() { - t.onload = null, t.parentNode && t.parentNode.removeChild(t); +function F(i) { + const e = document.createElement("iframe"); + e.style.display = "none", e.setAttribute("sandbox", "allow-scripts allow-same-origin"), e.src = i, e.onload = function() { + e.onload = null, e.parentNode && e.parentNode.removeChild(e); }; - const e = document.body || document.head; - e && e.appendChild(t); + const t = document.body || document.head; + t && t.appendChild(e); } -function j(n, t) { - const e = V(window.location.origin); - if (E._allowedOriginHashes.indexOf(e) === -1 || Math.random() >= $) +function ie(i, e) { + const t = ge(window.location.origin); + if (y._allowedOriginHashes.indexOf(t) === -1 || Math.random() >= Te) return; const r = window.__rokt_li_guid__; - if (!r) + if (!r || i && i.includes("://") && !/^https:\/\//i.test(i)) return; - const s = window.location.href.split("?")[0].split("#")[0], o = "version=" + encodeURIComponent(t ?? "") + "&launcherInstanceGuid=" + encodeURIComponent(r) + "&pageUrl=" + encodeURIComponent(s); - N("https://" + (n || "apps.rokt.com") + "/v1/wsdk-init/index.html?" + o), N( - "https://" + X + "/v1/wsdk-init/index.html?" + o + "&isControl=true" + const s = window.location.href.split("?")[0].split("#")[0], o = "version=" + encodeURIComponent(e ?? "") + "&launcherInstanceGuid=" + encodeURIComponent(r) + "&pageUrl=" + encodeURIComponent(s), c = i ? C(i) : "https://apps.rokt.com"; + F(c + "/v1/wsdk-init/index.html?" + o), F( + "https://" + be + "/v1/wsdk-init/index.html?" + o + "&isControl=true" ); } -function ut() { +function ze() { return typeof window < "u" && !!window.location?.search?.toLowerCase().includes("mp_enable_logging=true"); } -function dt() { +function qe() { return typeof window < "u" ? window.location?.href : void 0; } -function ht() { +function $e() { return typeof window < "u" ? window.navigator?.userAgent : void 0; } -class q { +class pe { constructor() { this._logCount = {}; } - incrementAndCheck(t) { - const i = (this._logCount[t] || 0) + 1; - return this._logCount[t] = i, i > at; + incrementAndCheck(e) { + const n = (this._logCount[e] || 0) + 1; + return this._logCount[e] = n, n > Ve; } } -class C { - constructor(t, e, i, r, s) { +class W { + constructor(e, t, n, r, s) { this._reporter = "mp-wsdk"; - const o = t.isLoggingEnabled; - this._integrationName = e || "", this._launcherInstanceGuid = i, this._accountId = r || null, this._rateLimiter = s || new q(), this._isEnabled = ut() || o; + const o = e.isLoggingEnabled; + this._integrationName = t || "", this._launcherInstanceGuid = n, this._accountId = r || null, this._rateLimiter = s || new pe(), this._isEnabled = ze() || o; } - send(t, e, i, r, s, o) { - if (!(!this._isEnabled || this._rateLimiter.incrementAndCheck(e))) + send(e, t, n, r, s, o) { + if (!(!this._isEnabled || this._rateLimiter.incrementAndCheck(t))) try { const c = { additionalInformation: { - message: i, + message: n, version: this._integrationName }, - severity: e, - code: r || O.UNKNOWN_ERROR, - url: dt(), - deviceInfo: ht(), + severity: t, + code: r || G.UNKNOWN_ERROR, + url: qe(), + deviceInfo: $e(), stackTrace: s, reporter: this._reporter, integration: this._integrationName @@ -208,14 +352,14 @@ class C { "rokt-launcher-version": this._integrationName, "rokt-wsdk-version": "joint" }; - this._launcherInstanceGuid && (u["rokt-launcher-instance-guid"] = this._launcherInstanceGuid), this._accountId && (u["rokt-account-id"] = this._accountId), fetch(t, { + this._launcherInstanceGuid && (u["rokt-launcher-instance-guid"] = this._launcherInstanceGuid), this._accountId && (u["rokt-account-id"] = this._accountId), fetch(e, { method: "POST", headers: u, body: JSON.stringify(c) }).then((l) => { if (!l.ok) { - const h = new Error("HTTP " + l.status + " from log endpoint"); - throw h.statusCode = l.status, h; + const g = new Error("HTTP " + l.status + " from log endpoint"); + throw g.statusCode = l.status, g; } }).catch((l) => { console.error("ReportingTransport: Failed to send log", l), o && o(l); @@ -225,274 +369,333 @@ class C { } } } -class H { - constructor(t, e, i, r, s) { - this._transport = new C(t, e, i, r, s), this._errorUrl = z(t?.errorUrl, t?.integrationDomain, ot); +class ne { + constructor(e, t, n, r, s) { + this._transport = new W(e, t, n, r, s), this._errorUrl = he(e?.errorUrl, e?.integrationDomain, We); } - report(t) { - if (!t) return; - const e = t.severity || I.ERROR; - this._transport.send(this._errorUrl, e, t.message, t.code, t.stackTrace); + report(e) { + if (!e) return; + const t = e.severity || S.ERROR; + this._transport.send(this._errorUrl, t, e.message, e.code, e.stackTrace); } } -class W { - constructor(t, e, i, r, s, o) { - this._transport = new C(t, i, r, s, o), this._loggingUrl = z(t?.loggingUrl, t?.integrationDomain, st), this._errorReportingService = e; +class re { + constructor(e, t, n, r, s, o) { + this._transport = new W(e, n, r, s, o), this._loggingUrl = he(e?.loggingUrl, e?.integrationDomain, Ge), this._errorReportingService = t; } - log(t) { - t && this._transport.send( + log(e) { + e && this._transport.send( this._loggingUrl, - I.INFO, - t.message, - t.code, + S.INFO, + e.message, + e.code, void 0, - (e) => { + (t) => { if (this._errorReportingService) { - const i = typeof e.statusCode == "number"; + const n = typeof t.statusCode == "number"; this._errorReportingService.report({ - message: "LoggingService: Failed to send log: " + e.message, - code: O.LOG_DELIVERY_FAILURE, - severity: i ? I.ERROR : I.WARNING + message: "LoggingService: Failed to send log: " + t.message, + code: G.LOG_DELIVERY_FAILURE, + severity: n ? S.ERROR : S.WARNING }); } } ); } } -const p = class p { +function Je(i) { + const e = Y(window.location.href), t = i.EventAttributes?.title || document.title, n = ve(), r = i.ActiveTimeOnSite; + return { + pageUrl: e, + sourceMessageId: i.SourceMessageId, + timestamp: i.Timestamp, + ...t ? { pageTitle: t } : {}, + ...n !== void 0 ? { canonicalUrl: n } : {}, + ...Number.isFinite(r) ? { activeTimeOnSite: r } : {} + }; +} +const m = class m { constructor() { - this.name = d, this.id = b, this.moduleId = b, this.isInitialized = !1, this.launcher = null, this.filters = {}, this.userAttributes = {}, this.userIdentifiedInWorkspace = !1, this.testHelpers = null, this.placementEventMappingLookup = {}, this.placementEventAttributeMappingLookup = {}, this.integrationName = null, this.errorReportingService = null, this.loggingService = null, this._thankYouElementOnLoadCallback = null, this._isThankYouElementLoaded = !1, this._workspaceSearchInFlightPromise = null; + this.name = d, this.id = L, this.moduleId = L, this.isInitialized = !1, this.launcher = null, this.filters = {}, this.userAttributes = {}, this.userIdentifiedInWorkspace = !1, this.testHelpers = null, this.placementEventMappingLookup = {}, this.placementEventAttributeMappingLookup = {}, this.integrationName = null, this.errorReportingService = null, this.loggingService = null, this._thankYouElementOnLoadCallback = null, this._isThankYouElementLoaded = !1, this._workspaceSearchInFlightPromise = null; } // ---- Private helpers ---- - getEventAttributeValue(t, e) { - const i = t && t.EventAttributes; - return !i || typeof i[e] > "u" ? null : i[e]; + getEventAttributeValue(e, t) { + const n = e && e.EventAttributes; + return !n || typeof n[t] > "u" ? null : n[t]; } - doesEventAttributeConditionMatch(t, e) { - if (!t || !m(t.operator)) + doesEventAttributeConditionMatch(e, t) { + if (!e || !E(e.operator)) return !1; - const i = t.operator.toLowerCase(), r = t.attributeValue; - return i === "exists" ? e !== null : e == null ? !1 : i === "equals" ? String(e) === String(r) : i === "contains" ? String(e).indexOf(String(r)) !== -1 : !1; + const n = e.operator.toLowerCase(), r = e.attributeValue; + return n === "exists" ? t !== null : t == null ? !1 : n === "equals" ? String(t) === String(r) : n === "contains" ? String(t).indexOf(String(r)) !== -1 : !1; } - doesEventMatchRule(t, e) { - if (!e || !m(e.eventAttributeKey)) + doesEventMatchRule(e, t) { + if (!t || !E(t.eventAttributeKey)) return !1; - const i = e.conditions; - if (!Array.isArray(i)) + const n = t.conditions; + if (!Array.isArray(n)) return !1; - const r = this.getEventAttributeValue(t, e.eventAttributeKey); - if (i.length === 0) + const r = this.getEventAttributeValue(e, t.eventAttributeKey); + if (n.length === 0) return r !== null; - for (let s = 0; s < i.length; s++) - if (!this.doesEventAttributeConditionMatch(i[s], r)) + for (let s = 0; s < n.length; s++) + if (!this.doesEventAttributeConditionMatch(n[s], r)) return !1; return !0; } - applyPlacementEventAttributeMapping(t) { - const e = Object.keys(this.placementEventAttributeMappingLookup); - for (let i = 0; i < e.length; i++) { - const r = e[i], s = this.placementEventAttributeMappingLookup[r]; - if (k(s)) + applyPlacementEventAttributeMapping(e) { + const t = Object.keys(this.placementEventAttributeMappingLookup); + for (let n = 0; n < t.length; n++) { + const r = t[n], s = this.placementEventAttributeMappingLookup[r]; + if (K(s)) continue; let o = !0; for (let c = 0; c < s.length; c++) - if (!this.doesEventMatchRule(t, s[c])) { + if (!this.doesEventMatchRule(e, s[c])) { o = !1; break; } o && a().Rokt.setLocalSessionAttribute?.(r, !0); } } + capturePageView(e) { + let t; + try { + t = Y(window.location.href); + const n = z(this.loggingService), r = Je(e); + n.push(r); + const s = Math.min(n.length, le), o = ye(n); + if (o === 0) { + const c = D() ? "quota" : "ls_unavailable"; + this.loggingService?.log({ + message: `Rokt Kit: Failed to persist page view for ${t} [reason: ${c}]`, + code: "PAGE_VIEW_CAPTURE_FAILED" + }); + } else o < s && this.loggingService?.log({ + message: `Rokt Kit: Page view storage reduced from ${s} to ${o} record(s) under quota pressure [reason: quota_eviction]`, + code: "PAGE_VIEW_QUOTA_EVICTION" + }); + } catch (n) { + const r = D() ? "exception" : "ls_unavailable", s = n instanceof Error ? n.message : String(n); + this.loggingService?.log({ + message: `Rokt Kit: Failed to capture page view for ${t}: ${s} [reason: ${r}]`, + code: "PAGE_VIEW_CAPTURE_FAILED" + }); + } + } isLauncherReadyToAttach() { - return !!window.Rokt && typeof window.Rokt.createLauncher == "function"; + return !!window.Rokt && T(window.Rokt.createLauncher); } /** * Returns the user identities from the filtered user, if any. */ - returnUserIdentities(t) { - if (!t || !t.getUserIdentities) + returnUserIdentities(e) { + if (!e || !e.getUserIdentities) return {}; - const e = t.getUserIdentities().userIdentities; - return this.replaceOtherIdentityWithEmailsha256(e); + const t = e.getUserIdentities().userIdentities; + return this.replaceOtherIdentityWithEmailsha256(t); } returnLocalSessionAttributes() { - return !a().Rokt || typeof a().Rokt.getLocalSessionAttributes != "function" ? {} : k(this.placementEventMappingLookup) && k(this.placementEventAttributeMappingLookup) ? {} : a().Rokt.getLocalSessionAttributes(); + return !a().Rokt || typeof a().Rokt.getLocalSessionAttributes != "function" ? {} : a().Rokt.getLocalSessionAttributes(); } - replaceOtherIdentityWithEmailsha256(t) { - const e = { ...t || {} }, i = this._mappedEmailSha256Key; - return i && t[i] && (e[p.EMAIL_SHA256_KEY] = t[i]), i && delete e[i], e; + replaceOtherIdentityWithEmailsha256(e) { + const t = { ...e || {} }, n = this._mappedEmailSha256Key; + return n && e[n] && (t[m.EMAIL_SHA256_KEY] = e[n]), n && delete t[n], t; } - logSelectPlacementsEvent(t) { - if (!window.mParticle || typeof a().logEvent != "function" || !T(t)) + logSelectPlacementsEvent(e) { + if (!window.mParticle || typeof a().logEvent != "function" || !_(e)) return; - const e = a().EventType.Other; - a().logEvent(Q, e, t); + const t = a().EventType.Other; + a().logEvent(we, t, e); } - setRoktSessionId(t) { - if (!(!t || typeof t != "string")) + setRoktSessionId(e) { + if (!(!e || typeof e != "string")) try { - const e = a().getInstance(); - e && typeof e.setIntegrationAttribute == "function" && e.setIntegrationAttribute(b, { - roktSessionId: t + const t = a().getInstance(); + t && T(t.setIntegrationAttribute) && t.setIntegrationAttribute(L, { + roktSessionId: e }); } catch { } } - attachLauncher(t, e, i = []) { - const r = a() && a().sessionManager && typeof a().sessionManager.getSession == "function" ? a().sessionManager.getSession() : void 0, s = { - accountId: t, - ...e || {}, - ...r ? { mpSessionId: r } : {} + readMpSessionId() { + const e = a()?.sessionManager, t = e?.getSessionId ?? e?.getSession; + if (T(t)) + return t.call(e) || void 0; + } + readMpDeviceId() { + return a()?.getDeviceId?.() || void 0; + } + attachLauncher(e, t, n = []) { + const r = { + accountId: e, + ...t || {} }; - let o; - this.isPartnerInLocalLauncherTestGroup() ? o = Promise.resolve(window.Rokt.createLocalLauncher(s)) : o = window.Rokt.createLauncher(s), o.then(async (c) => { - await ct(i, c), this.initRoktLauncher(c); - }).catch((c) => { - console.error("Error creating Rokt launcher:", c); + let s; + this.isPartnerInLocalLauncherTestGroup() ? s = Promise.resolve(window.Rokt.createLocalLauncher(r)) : s = window.Rokt.createLauncher(r), s.then(async (o) => { + await je(n, o), this.initRoktLauncher(o); + }).catch((o) => { + console.error("Error creating Rokt launcher:", o); }); } - initRoktLauncher(t) { - window.Rokt && (window.Rokt.currentLauncher = t), this.launcher = t; - const e = a().Rokt?.filters; - e ? (this.filters = e, e.filteredUser ? this._workspaceSearchInFlightPromise = this.search(e.filteredUser) : console.warn("Rokt Kit: No filtered user has been set.")) : console.warn("Rokt Kit: No filters have been set."), this.isInitialized = !0, j(this.domain, this.integrationName), a().Rokt.attachKit(this); + initRoktLauncher(e) { + window.Rokt && (window.Rokt.currentLauncher = e), this.launcher = e; + const t = a().Rokt?.filters; + t ? (this.filters = t, t.filteredUser ? this._workspaceSearchInFlightPromise = this.search(t.filteredUser) : console.warn("Rokt Kit: No filtered user has been set.")) : console.warn("Rokt Kit: No filters have been set."), this.isInitialized = !0, ie(this.domain, this.integrationName), a().Rokt.attachKit(this); } fetchOptimizely() { - const t = a()._getActiveForwarders().filter((e) => e.name === "Optimizely"); + const e = a()._getActiveForwarders().filter((t) => t.name === "Optimizely"); try { - if (t.length > 0 && window.optimizely) { - const e = window.optimizely.get("state"); - return !e || !e.getActiveExperimentIds ? {} : e.getActiveExperimentIds().reduce((s, o) => (s["rokt.custom.optimizely.experiment." + o + ".variationId"] = e.getVariationMap()[o].id, s), {}); + if (e.length > 0 && window.optimizely) { + const t = window.optimizely.get("state"); + return !t || !t.getActiveExperimentIds ? {} : t.getActiveExperimentIds().reduce((s, o) => (s["rokt.custom.optimizely.experiment." + o + ".variationId"] = t.getVariationMap()[o].id, s), {}); } - } catch (e) { - console.error("Error fetching Optimizely attributes:", e); + } catch (t) { + console.error("Error fetching Optimizely attributes:", t); } return {}; } isKitReady() { return !!(this.isInitialized && this.launcher); } + // When the partner has opted out of targeting (noTargeting launcher option), + // the kit must not collect behavioral targeting signals such as page views. + isTargetingDisabled() { + return a().Rokt?.launcherOptions?.noTargeting === !0; + } isPartnerInLocalLauncherTestGroup() { return !!(a().config && a().config.isLocalLauncherEnabled && this.isAssignedToSampleGroup()); } isAssignedToSampleGroup() { return Math.random() > 0.5; } - captureTiming(t) { - window && a() && a().captureTiming && t && a().captureTiming(t); + captureTiming(e) { + window && a() && a().captureTiming && e && a().captureTiming(e); } // ---- Public methods (mParticle Kit Callbacks) ---- /** * Initializes the Rokt forwarder with settings from the mParticle server. */ - init(t, e, i, r, s) { - const o = t, c = o.accountId; - this.userAttributes = w(s), this._onboardingExpProvider = o.onboardingExpProvider; - const u = L(o.placementEventMapping); - this.placementEventMappingLookup = x(u); - const l = L( + init(e, t, n, r, s) { + const o = e, c = o.accountId; + this.userAttributes = b(s), this._onboardingExpProvider = o.onboardingExpProvider; + const u = P(o.placementEventMapping); + this.placementEventMappingLookup = Z(u); + const l = P( o.placementEventAttributeMapping ); - this.placementEventAttributeMappingLookup = Y(l), o.hashedEmailUserIdentityType && (this._mappedEmailSha256Key = o.hashedEmailUserIdentityType.toLowerCase()), this._workspaceIdSyncApiKey = m(o.workspaceIdSyncApiKey) ? o.workspaceIdSyncApiKey : void 0; - const h = a().Rokt?.domain, { roktExtensionsQueryParams: v, legacyRoktExtensions: R, loadThankYouElement: A } = D( + this.placementEventAttributeMappingLookup = ee(l), o.hashedEmailUserIdentityType && (this._mappedEmailSha256Key = o.hashedEmailUserIdentityType.toLowerCase()), this._workspaceIdSyncApiKey = E(o.workspaceIdSyncApiKey) ? o.workspaceIdSyncApiKey : void 0; + const g = a().Rokt?.domain, { roktExtensionsQueryParams: M, legacyRoktExtensions: v, loadThankYouElement: w } = X( o.roktExtensions - ), g = { + ), f = { ...a().Rokt?.launcherOptions || {} }; - this.integrationName = lt(g.integrationName), g.integrationName = this.integrationName, this.domain = h; - const _ = { + this.integrationName = He(f.integrationName), f.integrationName = this.integrationName, this.domain = g; + const A = { loggingUrl: o.loggingUrl, errorUrl: o.errorUrl, - integrationDomain: h, + integrationDomain: g, isLoggingEnabled: a().config?.isLoggingEnabled === !0 - }, y = new H( - _, + }, I = new ne( + A, this.integrationName, window.__rokt_li_guid__, o.accountId - ), S = new W( - _, - y, + ), k = new re( + A, + I, this.integrationName, window.__rokt_li_guid__, o.accountId ); - return this.errorReportingService = y, this.loggingService = S, a()._registerErrorReportingService && a()._registerErrorReportingService(y), a()._registerLoggingService && a()._registerLoggingService(S), i ? (this.testHelpers = { - generateLauncherScript: U, - generateThankYouElementScript: K, - extractRoktExtensionConfig: D, - hashEventMessage: F, - parseSettingsString: L, - generateMappedEventLookup: x, - generateMappedEventAttributeLookup: Y, - sendAdBlockMeasurementSignals: j, - createAutoRemovedIframe: N, - djb2: V, - setAllowedOriginHashes: (f) => { - p._allowedOriginHashes = f; + if (this.errorReportingService = I, this.loggingService = k, this.isTargetingDisabled()) + try { + q(), $(); + } catch (h) { + this.errorReportingService?.report({ + message: "Rokt Kit: Failed to clear page views when targeting is disabled", + code: "PAGE_VIEW_CAPTURE_FAILED", + severity: S.INFO, + stackTrace: h instanceof Error ? h.stack : void 0 + }); + } + return a()._registerErrorReportingService && a()._registerErrorReportingService(I), a()._registerLoggingService && a()._registerLoggingService(k), n ? (this.testHelpers = { + generateLauncherScript: J, + generateThankYouElementScript: B, + extractRoktExtensionConfig: X, + hashEventMessage: te, + parseSettingsString: P, + generateMappedEventLookup: Z, + generateMappedEventAttributeLookup: ee, + sendAdBlockMeasurementSignals: ie, + createAutoRemovedIframe: F, + djb2: ge, + setAllowedOriginHashes: (h) => { + m._allowedOriginHashes = h; }, - ReportingTransport: C, - ErrorReportingService: H, - LoggingService: W, - RateLimiter: q, - ErrorCodes: O, - WSDKErrorSeverity: I - }, this.attachLauncher(c, g), "Successfully initialized: " + d) : (A && (a().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this), M(et, K(h), { + ReportingTransport: W, + ErrorReportingService: ne, + LoggingService: re, + RateLimiter: pe, + ErrorCodes: G, + WSDKErrorSeverity: S + }, this.attachLauncher(c, f), "Successfully initialized: " + d) : (w && (a().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this), Q(Oe, B(g), { onLoad: () => { this._isThankYouElementLoaded = !0, this._thankYouElementOnLoadCallback && this._thankYouElementOnLoadCallback(); }, - onError: (f) => { - console.error("Error loading Rokt Thank You Element script:", f); + onError: (h) => { + console.error("Error loading Rokt Thank You Element script:", h); } - })), this.isLauncherReadyToAttach() ? this.attachLauncher(c, g, R) : (M(tt, U(h, v), { + })), this.isLauncherReadyToAttach() ? this.attachLauncher(c, f, v) : (Q(Pe, J(g, M), { onLoad: () => { - this.isLauncherReadyToAttach() ? this.attachLauncher(c, g, R) : console.error("Rokt object is not available after script load."); + this.isLauncherReadyToAttach() ? this.attachLauncher(c, f, v) : console.error("Rokt object is not available after script load."); }, - onError: (f) => { - console.error("Error loading Rokt launcher script:", f); + onError: (h) => { + console.error("Error loading Rokt launcher script:", h); } - }), this.captureTiming(p.PERFORMANCE_MARKS.RoktScriptAppended)), "Successfully initialized: " + d); + }), this.captureTiming(m.PERFORMANCE_MARKS.RoktScriptAppended)), "Successfully initialized: " + d); } - process(t) { - if (!this.isKitReady()) + process(e) { + if (this.isTargetingDisabled() || (e.EventDataType === Ue && (ke(this.loggingService), this.capturePageView(e)), e.EventDataType === Ce && (de(this.loggingService), q(), $())), !this.isKitReady()) return "Kit not ready for forwarder: " + d; - if (typeof a().Rokt?.setLocalSessionAttribute == "function" && (k(this.placementEventAttributeMappingLookup) || this.applyPlacementEventAttributeMapping(t), !k(this.placementEventMappingLookup))) { - const e = F(t.EventDataType, t.EventCategory, t.EventName ?? ""); - this.placementEventMappingLookup[String(e)] && a().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(e)], !0); + if (T(a().Rokt?.setLocalSessionAttribute) && (K(this.placementEventAttributeMappingLookup) || this.applyPlacementEventAttributeMapping(e), !K(this.placementEventMappingLookup))) { + const t = te(e.EventDataType, e.EventCategory, e.EventName ?? ""); + this.placementEventMappingLookup[String(t)] && a().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(t)], !0); } return "Successfully sent to forwarder: " + d; } - setExtensionData(t) { + setExtensionData(e) { if (!this.isKitReady()) { console.error("Rokt Kit: Not initialized"); return; } - window.Rokt.setExtensionData(t); + window.Rokt.setExtensionData(e); } - setUserAttribute(t, e) { - return G(t) || (this.userAttributes[t] = e), "Successfully set user attribute for forwarder: " + d; + setUserAttribute(e, t) { + return se(e) || (this.userAttributes[e] = t), "Successfully set user attribute for forwarder: " + d; } - removeUserAttribute(t) { - return delete this.userAttributes[t], "Successfully removed user attribute for forwarder: " + d; + removeUserAttribute(e) { + return delete this.userAttributes[e], "Successfully removed user attribute for forwarder: " + d; } - handleIdentityComplete(t, e) { - return this.userAttributes = w(t.getAllUserAttributes()), "Successfully called " + e + " for forwarder: " + d; + handleIdentityComplete(e, t) { + return this.userAttributes = b(e.getAllUserAttributes()), "Successfully called " + t + " for forwarder: " + d; } - onUserIdentified(t) { - const e = t; - return this.filters.filteredUser = e, this._workspaceSearchInFlightPromise = this.search(e), this.handleIdentityComplete(t, "onUserIdentified"); + onUserIdentified(e) { + const t = e; + return this.filters.filteredUser = t, this._workspaceSearchInFlightPromise = this.search(t), this.handleIdentityComplete(e, "onUserIdentified"); } - search(t) { - const e = this._workspaceIdSyncApiKey; - if (!e) + search(e) { + const t = this._workspaceIdSyncApiKey; + if (!t) return this.userIdentifiedInWorkspace = !1, this._workspaceLastSearchedIdentitiesKey = void 0, Promise.resolve(); - const i = a().Identity?.search; - if (typeof i != "function") + const n = a().Identity?.search; + if (typeof n != "function") return this.userIdentifiedInWorkspace = !1, this._workspaceLastSearchedIdentitiesKey = void 0, Promise.resolve(); - const r = t.getUserIdentities ? t.getUserIdentities().userIdentities : null, s = {}; + const r = e.getUserIdentities ? e.getUserIdentities().userIdentities : null, s = {}; if (r) for (const u of Object.keys(r)) { const l = r[u]; - m(l) && l.length > 0 && (s[u] = l); + E(l) && l.length > 0 && (s[u] = l); } const o = Object.keys(s); if (o.length === 0) @@ -500,7 +703,7 @@ const p = class p { const c = o.sort().map((u) => `${u}=${s[u]}`).join("&"); return c === this._workspaceLastSearchedIdentitiesKey ? this._workspaceSearchInFlightPromise || Promise.resolve() : (this.userIdentifiedInWorkspace = !1, this._workspaceLastSearchedIdentitiesKey = c, new Promise((u) => { try { - i(e, s, (l) => { + n(t, s, (l) => { l?.httpCode === 200 && (this.userIdentifiedInWorkspace = !0), u(); }); } catch (l) { @@ -508,14 +711,14 @@ const p = class p { } })); } - onLoginComplete(t, e) { - return this.handleIdentityComplete(t, "onLoginComplete"); + onLoginComplete(e, t) { + return this.handleIdentityComplete(e, "onLoginComplete"); } - onLogoutComplete(t, e) { - return this.userIdentifiedInWorkspace = !1, this._workspaceSearchInFlightPromise = null, this._workspaceLastSearchedIdentitiesKey = void 0, this.handleIdentityComplete(t, "onLogoutComplete"); + onLogoutComplete(e, t) { + return this.userIdentifiedInWorkspace = !1, this._workspaceSearchInFlightPromise = null, this._workspaceLastSearchedIdentitiesKey = void 0, this.handleIdentityComplete(e, "onLogoutComplete"); } - onModifyComplete(t, e) { - return this.handleIdentityComplete(t, "onModifyComplete"); + onModifyComplete(e, t) { + return this.handleIdentityComplete(e, "onModifyComplete"); } /** * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options. @@ -540,80 +743,84 @@ const p = class p { * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`; * this wrapper just gates it on the in-flight search via `Promise.race`. */ - selectPlacements(t) { + selectPlacements(e) { if (this._workspaceSearchInFlightPromise) { - const e = this._workspaceSearchInFlightPromise; + const t = this._workspaceSearchInFlightPromise; return Promise.race([ - e, - new Promise((i) => setTimeout(i, nt)) - ]).then(() => this._dispatchPlacements(t)); + t, + new Promise((n) => setTimeout(n, Ye)) + ]).then(() => this._dispatchPlacements(e)); } - return this._dispatchPlacements(t); + return this._dispatchPlacements(e); } - _dispatchPlacements(t) { - const e = t && t.attributes || {}, r = { ...w(this.userAttributes), ...e }, s = this.filters || {}, o = s.userAttributeFilters || [], c = s.filteredUser || null, u = c ? c.getMPID() : null; + _dispatchPlacements(e) { + const t = e && e.attributes || {}, r = { ...b(this.userAttributes), ...t }, s = this.filters || {}, o = s.userAttributeFilters || [], c = s.filteredUser || null, u = c ? c.getMPID() : null; let l; - s ? s.filterUserAttributes ? l = s.filterUserAttributes(r, o) : l = r : (console.warn("Rokt Kit: No filters available, using user attributes"), l = r), this.userAttributes = w(l); - const h = this._onboardingExpProvider === "Optimizely" ? this.fetchOptimizely() : {}, v = this.returnUserIdentities(c), R = this.returnLocalSessionAttributes(), A = { - ...v, + s ? s.filterUserAttributes ? l = s.filterUserAttributes(r, o) : l = r : (console.warn("Rokt Kit: No filters available, using user attributes"), l = r), this.userAttributes = b(l); + const g = this._onboardingExpProvider === "Optimizely" ? this.fetchOptimizely() : {}, M = this.returnUserIdentities(c), v = this.returnLocalSessionAttributes(), w = Ae(z(this.loggingService)), f = Re(), A = this.readMpSessionId(), I = this.readMpDeviceId(), k = { + ...M, ...l, - ...h, - ...R, - ...this.userIdentifiedInWorkspace ? { [it]: !0 } : {}, + ...g, + ...v, + ...w.length ? { [Me]: JSON.stringify(w) } : {}, + ...f ? { [Ke]: f } : {}, + ...this.userIdentifiedInWorkspace ? { [Ne]: !0 } : {}, + ...A ? { [De]: A } : {}, + ...I ? { [Fe]: I } : {}, mpid: u - }, g = { ...t, attributes: A }, _ = this.launcher.selectPlacements(g), y = () => this.logSelectPlacementsEvent(A); - return Promise.resolve(_).then((S) => S?.context?.sessionId?.then((f) => this.setRoktSessionId(f))).catch(() => { - }).finally(y), _; + }, h = { ...e, attributes: k }, V = this.launcher.selectPlacements(h), fe = () => this.logSelectPlacementsEvent(k); + return Promise.resolve(V).then((me) => me?.context?.sessionId?.then((Ee) => this.setRoktSessionId(Ee))).catch(() => { + }).finally(fe), V; } /** * Passes attributes to the Rokt Web SDK for client-side hashing. */ - hashAttributes(t) { - return this.isKitReady() ? this.launcher.hashAttributes(t) : (console.error("Rokt Kit: Not initialized"), null); + hashAttributes(e) { + return this.isKitReady() ? this.launcher.hashAttributes(e) : (console.error("Rokt Kit: Not initialized"), null); } /** * Enables optional Integration Launcher extensions before selecting placements. * * @deprecated This functionality has been internalized and will be removed in a future release. */ - use(t) { - return this.isKitReady() ? !t || !m(t) ? Promise.reject(new Error("Rokt Kit: Invalid extension name")) : this.launcher.use(t) : (console.error("Rokt Kit: Not initialized"), Promise.reject(new Error("Rokt Kit: Not initialized"))); + use(e) { + return this.isKitReady() ? !e || !E(e) ? Promise.reject(new Error("Rokt Kit: Invalid extension name")) : this.launcher.use(e) : (console.error("Rokt Kit: Not initialized"), Promise.reject(new Error("Rokt Kit: Not initialized"))); } /** * Registers a callback to be invoked once rokt-thank-you-element.js becomes available. */ - onShoppableAdsReady(t) { - this._isThankYouElementLoaded ? t() : this._thankYouElementOnLoadCallback = t; + onShoppableAdsReady(e) { + this._isThankYouElementLoaded ? e() : this._thankYouElementOnLoadCallback = e; } }; -p._allowedOriginHashes = [-553112570, 549508659], p.PERFORMANCE_MARKS = { +m._allowedOriginHashes = [-553112570, 549508659], m.PERFORMANCE_MARKS = { RoktScriptAppended: "mp:RoktScriptAppended" -}, p.EMAIL_SHA256_KEY = "emailsha256"; -let E = p; -function pt() { - return b; +}, m.EMAIL_SHA256_KEY = "emailsha256"; +let y = m; +function Be() { + return L; } -function gt(n) { - if (!n) { +function Qe(i) { + if (!i) { window.console.log("You must pass a config object to register the kit " + d); return; } - if (!T(n)) { - window.console.log("'config' must be an object. You passed in a " + typeof n); + if (!_(i)) { + window.console.log("'config' must be an object. You passed in a " + typeof i); return; } - T(n.kits) ? n.kits[d] = { - constructor: E - } : (n.kits = {}, n.kits[d] = { - constructor: E + _(i.kits) ? i.kits[d] = { + constructor: y + } : (i.kits = {}, i.kits[d] = { + constructor: y }), window.console.log("Successfully registered " + d + " to your mParticle configuration"); } typeof window < "u" && window.mParticle && a().addForwarder && a().addForwarder({ name: d, - constructor: E, - getId: pt + constructor: y, + getId: Be }); export { - gt as register + Qe as register }; //# sourceMappingURL=Rokt-Kit.esm.js.map diff --git a/kits/rokt/dist/Rokt-Kit.esm.js.map b/kits/rokt/dist/Rokt-Kit.esm.js.map index e5995c8b1..524e8047a 100644 --- a/kits/rokt/dist/Rokt-Kit.esm.js.map +++ b/kits/rokt/dist/Rokt-Kit.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"Rokt-Kit.esm.js","sources":["../src/selectPlacementsAttributePersistence.ts","../src/Rokt-Kit.ts"],"sourcesContent":["const SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST = [\n 'billingaddress1',\n 'billingaddress2',\n 'billingcity',\n 'billingstate',\n 'billingzipcode',\n 'cartitems',\n 'ccbin',\n 'confirmationref',\n 'conversiontype',\n 'country',\n 'couponcode',\n 'currency',\n 'language',\n 'paymentserviceprovider',\n 'paymentserviceproviderattribute',\n 'paymenttype',\n 'shippingaddress1',\n 'shippingcity',\n 'shippingcountry',\n 'shippingmethod',\n 'shippingstate',\n 'shippingzipcode',\n 'totalprice',\n];\nconst SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET = new Set(SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST);\n\nexport function isSelectPlacementsAttributePersistenceDenied(key: string): boolean {\n return SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET.has(key.toLowerCase());\n}\n\nexport function removeSelectPlacementsAttributePersistenceDeniedAttributes(\n attributes: Record | null | undefined,\n): Record {\n const filteredAttributes: Record = {};\n const sourceAttributes = attributes || {};\n const attributeKeys = Object.keys(sourceAttributes);\n\n for (let i = 0; i < attributeKeys.length; i++) {\n const key = attributeKeys[i];\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n filteredAttributes[key] = sourceAttributes[key];\n }\n }\n\n return filteredAttributes;\n}\n","// Copyright 2025 mParticle, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// ============================================================\n// Types\n// ============================================================\n\nimport { KitInterface, IMParticleUser, SDKEvent } from '@mparticle/web-sdk/internal';\nimport type { IUserIdentities } from '@mparticle/web-sdk';\n\nimport {\n isSelectPlacementsAttributePersistenceDenied,\n removeSelectPlacementsAttributePersistenceDeniedAttributes,\n} from './selectPlacementsAttributePersistence';\n\ninterface RoktKitSettings {\n accountId: string;\n roktExtensions?: string;\n placementEventMapping?: string;\n placementEventAttributeMapping?: string;\n hashedEmailUserIdentityType?: string;\n onboardingExpProvider?: string;\n loggingUrl?: string;\n errorUrl?: string;\n workspaceIdSyncApiKey?: string;\n}\n\ninterface EventAttributeCondition {\n operator: string;\n attributeValue: string;\n}\n\ninterface PlacementEventRule {\n eventAttributeKey: string;\n conditions: EventAttributeCondition[];\n}\n\ninterface EventAttributeMapping {\n value: string;\n map: string;\n conditions?: EventAttributeCondition[];\n}\n\ninterface PlacementEventMappingEntry {\n jsmap: string;\n value: string;\n}\n\ninterface RoktExtensionEntry {\n value: string;\n}\n\ninterface RoktSelection {\n context?: {\n sessionId?: Promise;\n };\n then?: (callback: (sel: RoktSelection) => void) => Promise;\n catch?: (callback: () => void) => void;\n}\n\ninterface RoktLauncher {\n selectPlacements(options: Record): RoktSelection | Promise;\n hashAttributes(attributes: Record): Promise>;\n use(extensionName: string): Promise;\n}\n\ninterface RoktGlobal {\n createLauncher(options: Record): Promise;\n createLocalLauncher(options: Record): RoktLauncher;\n currentLauncher?: RoktLauncher;\n setExtensionData(data: Record): void;\n}\n\n// FilteredUser is the IMParticleUser shape we receive after kit filtering.\n// `getMPID` and `getUserIdentities` are inherited from the SDK's `User` base type.\ntype FilteredUser = IMParticleUser;\n\n// TODO: Replace with `IIdentitySearchResult` from `@mparticle/web-sdk` once\n// a version that exports it is published (currently on a feature branch in\n// mParticle/mparticle-web-sdk PR #1255). The shape below is intentionally\n// structurally identical so the swap is a one-line import change.\ninterface WorkspaceIdSyncResult {\n httpCode: number;\n body?: {\n context?: string | null;\n mpid?: string;\n matched_identities?: Record;\n is_ephemeral?: boolean;\n is_logged_in?: boolean;\n };\n}\n\n// TODO: Replace with `IdentitySearchCallback`-compatible reference from\n// `@mparticle/web-sdk` once published (mirrors `SDKIdentityApi.search`).\ntype WorkspaceIdSyncSearcher = (\n apiKey: string,\n knownIdentities: IUserIdentities,\n callback: (result: WorkspaceIdSyncResult) => void,\n) => void;\n\ninterface KitFilters {\n userAttributeFilters?: string[];\n filterUserAttributes?: (attributes: Record, filters?: string[]) => Record;\n filteredUser?: FilteredUser | null;\n}\n\ninterface RoktManager {\n attachKit(kit: RoktKit): void | Promise;\n flushOnShoppableAdsReadyMessageQueue?(kit: RoktKit): void;\n filters?: KitFilters;\n domain?: string;\n launcherOptions?: Record;\n getLocalSessionAttributes?(): Record;\n setLocalSessionAttribute?(key: string, value: unknown): void;\n}\n\ninterface MParticleInstance {\n setIntegrationAttribute(moduleId: number, attrs: Record): void;\n}\n\ninterface OptimizelyState {\n getActiveExperimentIds(): string[];\n getVariationMap(): Record;\n}\n\ninterface OptimizelyGlobal {\n get(key: 'state'): OptimizelyState;\n}\n\n// Our view of the mParticle global with Rokt-specific extensions.\n// We access window.mParticle via an explicit cast (see `mp()` helper below)\n// rather than augmenting Window to avoid conflicts with @mparticle/web-sdk declarations.\ninterface MParticleExtended {\n Rokt: RoktManager;\n addForwarder(config: ForwarderRegistration): void;\n getVersion(): string;\n generateHash(value: string): string | number;\n logEvent(name: string, type: number, attrs?: Record): void;\n EventType: { Other: number };\n getInstance(): MParticleInstance;\n sessionManager?: { getSession(): string };\n _getActiveForwarders(): Array<{ name: string }>;\n config?: { isLocalLauncherEnabled?: boolean; isLoggingEnabled?: boolean };\n captureTiming?(metricName: string): void;\n forwarder?: RoktKit;\n loggedEvents?: Array>;\n _registerErrorReportingService?(service: ErrorReportingService): void;\n _registerLoggingService?(service: LoggingService): void;\n Identity?: { search?: WorkspaceIdSyncSearcher };\n}\n\ninterface TestHelpers {\n generateLauncherScript: (domain: string | undefined, extensions: string[]) => string;\n generateThankYouElementScript: (domain: string | undefined) => string;\n extractRoktExtensionConfig: (settingsString?: string) => RoktExtensionConfig;\n hashEventMessage: (messageType: number, eventType: number, eventName: string) => string | number;\n parseSettingsString: (settingsString?: string) => T[];\n generateMappedEventLookup: (placementEventMapping: PlacementEventMappingEntry[]) => Record;\n generateMappedEventAttributeLookup: (mapping: EventAttributeMapping[]) => Record;\n sendAdBlockMeasurementSignals: (domain: string | undefined, version: string | null) => void;\n createAutoRemovedIframe: (src: string) => void;\n djb2: (str: string) => number;\n setAllowedOriginHashes: (hashes: number[]) => void;\n ReportingTransport: typeof ReportingTransport;\n ErrorReportingService: typeof ErrorReportingService;\n LoggingService: typeof LoggingService;\n RateLimiter: typeof RateLimiter;\n ErrorCodes: typeof ErrorCodes;\n WSDKErrorSeverity: typeof WSDKErrorSeverity;\n}\n\ninterface ForwarderRegistration {\n name: string;\n constructor: new () => RoktKit;\n getId: () => number;\n}\n\ninterface ReportingConfig {\n loggingUrl?: string;\n errorUrl?: string;\n integrationDomain?: string;\n isLoggingEnabled: boolean;\n}\n\ninterface ErrorReport {\n message: string;\n code?: string;\n severity?: string;\n stackTrace?: string;\n}\n\n// A log-delivery failure. statusCode is set when the request reached the server\n// and returned a non-2xx status (server-side); it is absent for network-level\n// failures such as ad-blockers, offline, or CORS rejections (client-side).\ninterface DeliveryError extends Error {\n statusCode?: number;\n}\n\ninterface LogEntry {\n message: string;\n code?: string;\n}\n\ninterface RoktExtensionConfig {\n roktExtensionsQueryParams: string[];\n legacyRoktExtensions: string[];\n loadThankYouElement: boolean;\n}\n\ndeclare global {\n interface Window {\n Rokt?: RoktGlobal;\n __rokt_li_guid__?: string;\n optimizely?: OptimizelyGlobal;\n // mParticle is declared as any to avoid conflicts with @mparticle/web-sdk type declarations.\n // We use the typed mp() accessor for all internal accesses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mParticle: any;\n }\n}\n\n// ============================================================\n// Module-level constants\n// ============================================================\n\nconst name = 'Rokt';\nconst moduleId = 181;\nconst EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements';\nconst ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com';\nconst INIT_LOG_SAMPLING_RATE = 0.1;\nconst ROKT_THANK_YOU_JOURNEY_EXTENSION = 'ThankYouPageJourney';\nconst ROKT_INTEGRATION_SCRIPT_ID = 'rokt-launcher';\nconst ROKT_THANK_YOU_ELEMENT_SCRIPT_ID = 'rokt-thank-you-element';\nconst USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace';\n\n// Bound on how long selectPlacements will wait for an in-flight Workspace\n// IDSync search before proceeding without the userIdentifiedInWorkspace flag.\n// Long enough to cover the typical /v1/search round-trip (~50ms); short enough that a\n// stalled search never blocks placement rendering on a thank-you page.\nconst WORKSPACE_SEARCH_SELECT_TIMEOUT_MS = 500;\n\n// ============================================================\n// Reporting service constants\n// ============================================================\n\nconst ErrorCodes = {\n UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION',\n IDENTITY_REQUEST: 'IDENTITY_REQUEST',\n LOG_DELIVERY_FAILURE: 'LOG_DELIVERY_FAILURE',\n} as const;\n\nconst WSDKErrorSeverity = {\n ERROR: 'ERROR',\n INFO: 'INFO',\n WARNING: 'WARNING',\n} as const;\n\nconst DEFAULT_ROKT_DOMAIN = 'apps.rokt-api.com';\nconst LOGGING_ENDPOINT = '/v1/log';\nconst ERROR_ENDPOINT = '/v1/errors';\nconst RATE_LIMIT_PER_SEVERITY = 10;\n\n// ============================================================\n// Helper: typed accessor for window.mParticle\n// We use an explicit cast here to avoid conflicts with @mparticle/web-sdk\n// type declarations while still providing full type safety for our usages.\n// ============================================================\n\nfunction mp(): MParticleExtended {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (window as any).mParticle as MParticleExtended;\n}\n\n// ============================================================\n// Module-level utility functions\n// ============================================================\n\nfunction generateLauncherScript(domain: string | undefined, extensions: string[]): string {\n const launcherPath = '/wsdk/integrations/launcher.js';\n const baseUrl = [generateBaseUrl(domain), launcherPath].join('');\n\n if (!extensions || extensions.length === 0) {\n return baseUrl;\n }\n return baseUrl + '?extensions=' + extensions.join(',');\n}\n\nfunction generateThankYouElementScript(domain: string | undefined) {\n const thankYouElementPath = '/rokt-elements/rokt-element-thank-you.js';\n return [generateBaseUrl(domain), thankYouElementPath].join('');\n}\n\nfunction generateBaseUrl(domain: string | undefined) {\n const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN;\n const protocol = 'https://';\n\n return [protocol, resolvedDomain].join('');\n}\n\nfunction generateReportingUrl(configuredUrl: string | undefined, domain: string | undefined, endpoint: string): string {\n if (configuredUrl) {\n if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://')) {\n return configuredUrl;\n }\n return 'https://' + configuredUrl;\n }\n\n return generateBaseUrl(domain) + endpoint;\n}\n\nfunction loadRoktScript(\n scriptId: string,\n source: string,\n handlers?: { onLoad?: () => void; onError?: (e: Event | string) => void },\n): void {\n if (document.getElementById(scriptId)) return; // resolves the preexisting script issue\n\n const target = document.head || document.body;\n const script = document.createElement('script');\n script.id = scriptId;\n script.type = 'text/javascript';\n script.src = source;\n script.async = true;\n script.crossOrigin = 'anonymous';\n (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high';\n if (handlers?.onLoad) script.onload = handlers.onLoad;\n if (handlers?.onError) script.onerror = handlers.onError;\n target.appendChild(script);\n}\n\nfunction isObject(val: unknown): val is Record {\n return val != null && typeof val === 'object' && Array.isArray(val) === false;\n}\n\nfunction parseSettingsString(settingsString?: string): T[] {\n if (!settingsString) {\n return [];\n }\n try {\n return JSON.parse(settingsString.replace(/"/g, '\"')) as T[];\n } catch (_error) {\n console.error('Settings string contains invalid JSON');\n }\n return [];\n}\n\nfunction extractRoktExtensionConfig(settingsString?: string): RoktExtensionConfig {\n const settings = settingsString ? parseSettingsString(settingsString) : [];\n const roktExtensionsQueryParams: string[] = [];\n const legacyRoktExtensions: string[] = [];\n let loadThankYouElement = false;\n\n for (let i = 0; i < settings.length; i++) {\n const extensionName = settings[i].value;\n if (extensionName === 'thank-you-journey') {\n loadThankYouElement = true;\n legacyRoktExtensions.push(ROKT_THANK_YOU_JOURNEY_EXTENSION);\n } else {\n roktExtensionsQueryParams.push(extensionName);\n }\n }\n\n return {\n roktExtensionsQueryParams,\n legacyRoktExtensions,\n loadThankYouElement,\n };\n}\n\nasync function registerLegacyExtensions(legacyExtensions: string[], launcher: RoktLauncher | null) {\n const extensions: Promise[] = [];\n if (launcher) {\n for (const extension of legacyExtensions) {\n extensions.push(launcher.use(extension));\n }\n }\n\n return Promise.all(extensions);\n}\n\nfunction generateMappedEventLookup(placementEventMapping: PlacementEventMappingEntry[]): Record {\n if (!placementEventMapping) {\n return {};\n }\n\n const mappedEvents: Record = {};\n for (let i = 0; i < placementEventMapping.length; i++) {\n const mapping = placementEventMapping[i];\n mappedEvents[mapping.jsmap] = mapping.value;\n }\n return mappedEvents;\n}\n\nfunction generateMappedEventAttributeLookup(\n placementEventAttributeMapping: EventAttributeMapping[],\n): Record {\n const mappedAttributeKeys: Record = {};\n if (!Array.isArray(placementEventAttributeMapping)) {\n return mappedAttributeKeys;\n }\n for (let i = 0; i < placementEventAttributeMapping.length; i++) {\n const mapping = placementEventAttributeMapping[i];\n if (!mapping || !isString(mapping.value) || !isString(mapping.map)) {\n continue;\n }\n\n const mappedAttributeKey = mapping.value;\n const eventAttributeKey = mapping.map;\n\n if (!mappedAttributeKeys[mappedAttributeKey]) {\n mappedAttributeKeys[mappedAttributeKey] = [];\n }\n\n mappedAttributeKeys[mappedAttributeKey].push({\n eventAttributeKey: eventAttributeKey,\n conditions: Array.isArray(mapping.conditions) ? mapping.conditions : [],\n });\n }\n return mappedAttributeKeys;\n}\n\nfunction hashEventMessage(messageType: number, eventType: number, eventName: string): string | number {\n return mp().generateHash([messageType, eventType, eventName].join(''));\n}\n\nfunction isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'object') {\n return Object.keys(value as object).length === 0;\n }\n if (Array.isArray(value)) {\n return (value as unknown[]).length === 0;\n }\n return false;\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nfunction generateIntegrationName(customIntegrationName?: string): string {\n const coreSdkVersion = mp().getVersion();\n const kitVersion = process.env.PACKAGE_VERSION;\n let integrationName = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion;\n\n if (customIntegrationName) {\n integrationName += '_' + customIntegrationName;\n }\n return integrationName;\n}\n\nfunction djb2(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return hash;\n}\n\nfunction createAutoRemovedIframe(src: string): void {\n const iframe = document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');\n iframe.src = src;\n iframe.onload = function () {\n iframe.onload = null;\n if (iframe.parentNode) {\n iframe.parentNode.removeChild(iframe);\n }\n };\n const target = document.body || document.head;\n if (target) {\n target.appendChild(iframe);\n }\n}\n\nfunction sendAdBlockMeasurementSignals(domain: string | undefined, version: string | null): void {\n const originHash = djb2(window.location.origin);\n const allowedOriginHashes = RoktKit._allowedOriginHashes;\n if (allowedOriginHashes.indexOf(originHash) === -1) {\n return;\n }\n\n if (Math.random() >= INIT_LOG_SAMPLING_RATE) {\n return;\n }\n\n const guid = window.__rokt_li_guid__;\n if (!guid) {\n return;\n }\n\n const pageUrl = window.location.href.split('?')[0].split('#')[0];\n const params =\n 'version=' +\n encodeURIComponent(version ?? '') +\n '&launcherInstanceGuid=' +\n encodeURIComponent(guid) +\n '&pageUrl=' +\n encodeURIComponent(pageUrl);\n\n const existingDomain = domain || 'apps.rokt.com';\n createAutoRemovedIframe('https://' + existingDomain + '/v1/wsdk-init/index.html?' + params);\n\n createAutoRemovedIframe(\n 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true',\n );\n}\n\n// ============================================================\n// Reporting helpers\n// ============================================================\n\nfunction _isDebugModeEnabled(): boolean {\n return typeof window !== 'undefined' && !!window.location?.search?.toLowerCase().includes('mp_enable_logging=true');\n}\n\nfunction _getReportingUrl(): string | undefined {\n return typeof window !== 'undefined' ? window.location?.href : undefined;\n}\n\nfunction _getUserAgent(): string | undefined {\n return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined;\n}\n\nclass RateLimiter {\n private _logCount: Record = {};\n\n incrementAndCheck(severity: string): boolean {\n const count = this._logCount[severity] || 0;\n const newCount = count + 1;\n this._logCount[severity] = newCount;\n return newCount > RATE_LIMIT_PER_SEVERITY;\n }\n}\n\nclass ReportingTransport {\n private _isEnabled: boolean;\n private _integrationName: string;\n private _launcherInstanceGuid: string | undefined;\n private _accountId: string | null;\n private _rateLimiter: RateLimiter;\n private readonly _reporter = 'mp-wsdk';\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid: string | undefined,\n accountId: string | null | undefined,\n rateLimiter?: RateLimiter,\n ) {\n const isLoggingEnabled = config.isLoggingEnabled;\n this._integrationName = integrationName || '';\n this._launcherInstanceGuid = launcherInstanceGuid;\n this._accountId = accountId || null;\n this._rateLimiter = rateLimiter || new RateLimiter();\n this._isEnabled = _isDebugModeEnabled() || isLoggingEnabled;\n }\n\n send(\n url: string,\n severity: string,\n msg: string,\n code?: string,\n stackTrace?: string,\n onError?: (error: DeliveryError) => void,\n ): void {\n if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) {\n return;\n }\n\n try {\n const logRequest = {\n additionalInformation: {\n message: msg,\n version: this._integrationName,\n },\n severity,\n code: code || ErrorCodes.UNKNOWN_ERROR,\n url: _getReportingUrl(),\n deviceInfo: _getUserAgent(),\n stackTrace,\n reporter: this._reporter,\n integration: this._integrationName,\n };\n\n const headers: Record = {\n Accept: 'text/plain;charset=UTF-8',\n 'Content-Type': 'application/json',\n 'rokt-launcher-version': this._integrationName,\n 'rokt-wsdk-version': 'joint',\n };\n\n if (this._launcherInstanceGuid) {\n headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid;\n }\n if (this._accountId) {\n headers['rokt-account-id'] = this._accountId;\n }\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(logRequest),\n })\n .then((response: Response) => {\n // fetch only rejects on network failures; an HTTP 5xx resolves with\n // ok === false. Surface server-side failures so they are not swallowed.\n if (!response.ok) {\n const serverError: DeliveryError = new Error('HTTP ' + response.status + ' from log endpoint');\n serverError.statusCode = response.status;\n throw serverError;\n }\n })\n .catch((error: DeliveryError) => {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error);\n });\n } catch (error) {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error as DeliveryError);\n }\n }\n}\n\nclass ErrorReportingService {\n private _transport: ReportingTransport;\n private _errorUrl: string;\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._errorUrl = generateReportingUrl(config?.errorUrl, config?.integrationDomain, ERROR_ENDPOINT);\n }\n\n report(error: ErrorReport | null | undefined): void {\n if (!error) return;\n const severity = error.severity || WSDKErrorSeverity.ERROR;\n this._transport.send(this._errorUrl, severity, error.message, error.code, error.stackTrace);\n }\n}\n\nclass LoggingService {\n private _transport: ReportingTransport;\n private _loggingUrl: string;\n private _errorReportingService: { report: (e: ErrorReport) => void };\n\n constructor(\n config: ReportingConfig,\n errorReportingService: { report: (e: ErrorReport) => void },\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._loggingUrl = generateReportingUrl(config?.loggingUrl, config?.integrationDomain, LOGGING_ENDPOINT);\n this._errorReportingService = errorReportingService;\n }\n\n log(entry: LogEntry | null | undefined): void {\n if (!entry) return;\n this._transport.send(\n this._loggingUrl,\n WSDKErrorSeverity.INFO,\n entry.message,\n entry.code,\n undefined,\n (error: DeliveryError) => {\n if (this._errorReportingService) {\n // A failed log POST is not itself an SDK error. Network-level failures\n // (ad-blockers, offline, CORS) are client-side noise and reported as a\n // WARNING; only a server-side non-2xx response stays at ERROR severity.\n const isServerSide = typeof error.statusCode === 'number';\n this._errorReportingService.report({\n message: 'LoggingService: Failed to send log: ' + error.message,\n code: ErrorCodes.LOG_DELIVERY_FAILURE,\n severity: isServerSide ? WSDKErrorSeverity.ERROR : WSDKErrorSeverity.WARNING,\n });\n }\n },\n );\n }\n}\n\n// ============================================================\n// RoktKit class\n// ============================================================\n\nclass RoktKit implements KitInterface {\n // Static field for allowed origin hashes (mutable by testHelpers)\n public static _allowedOriginHashes: number[] = [-553112570, 549508659];\n\n private static readonly PERFORMANCE_MARKS = {\n RoktScriptAppended: 'mp:RoktScriptAppended',\n };\n\n private static readonly EMAIL_SHA256_KEY = 'emailsha256';\n\n // Public fields (accessed by tests and the mParticle framework)\n public name = name;\n public id = moduleId;\n public moduleId = moduleId;\n public isInitialized = false;\n public launcher: RoktLauncher | null = null;\n public filters: KitFilters = {};\n public userAttributes: Record = {};\n // Flag set by the Workspace IDSync flow on a 200 response. Stored on the\n // kit instance and merged into placement attributes inside selectPlacements.\n public userIdentifiedInWorkspace = false;\n public testHelpers: TestHelpers | null = null;\n public placementEventMappingLookup: Record = {};\n public placementEventAttributeMappingLookup: Record = {};\n public integrationName: string | null = null;\n public domain?: string;\n public errorReportingService: ErrorReportingService | null = null;\n public loggingService: LoggingService | null = null;\n\n // Private fields\n private _mappedEmailSha256Key?: string;\n private _onboardingExpProvider?: string;\n private _thankYouElementOnLoadCallback: (() => void) | null = null;\n private _isThankYouElementLoaded = false;\n private _workspaceIdSyncApiKey?: string;\n\n // Held during a search dispatch so the next selectPlacements call;\n // can wait for the HTTP response before reading userIdentifiedInWorkspace;\n // — otherwise the first placement call ships without the flag.\n private _workspaceSearchInFlightPromise: Promise | null = null;\n // Stable serialization of the identifier set sent in the most recent\n // successful search dispatch. If a subsequent identification arrives with\n // an identical set, we skip the network call (the flag is still correct\n // from the prior search). Keyed over the full IUserIdentities map — not\n // just email — so partners passing hashed email through `other`/`other2-10`\n // or any other identifier benefit from the same dedupe. Cleared on logout\n // so a re-login re-evaluates fresh.\n private _workspaceLastSearchedIdentitiesKey?: string;\n\n // ---- Private helpers ----\n\n private getEventAttributeValue(event: SDKEvent, eventAttributeKey: string): unknown {\n const attributes = event && event.EventAttributes;\n if (!attributes) {\n return null;\n }\n\n if (typeof attributes[eventAttributeKey] === 'undefined') {\n return null;\n }\n\n return attributes[eventAttributeKey];\n }\n\n private doesEventAttributeConditionMatch(condition: EventAttributeCondition, actualValue: unknown): boolean {\n if (!condition || !isString(condition.operator)) {\n return false;\n }\n\n const operator = condition.operator.toLowerCase();\n const expectedValue = condition.attributeValue;\n\n if (operator === 'exists') {\n return actualValue !== null;\n }\n\n if (actualValue == null) {\n return false;\n }\n\n if (operator === 'equals') {\n return String(actualValue) === String(expectedValue);\n }\n\n if (operator === 'contains') {\n return String(actualValue).indexOf(String(expectedValue)) !== -1;\n }\n\n return false;\n }\n\n private doesEventMatchRule(event: SDKEvent, rule: PlacementEventRule): boolean {\n if (!rule || !isString(rule.eventAttributeKey)) {\n return false;\n }\n\n const conditions = rule.conditions;\n if (!Array.isArray(conditions)) {\n return false;\n }\n\n const actualValue = this.getEventAttributeValue(event, rule.eventAttributeKey);\n\n if (conditions.length === 0) {\n return actualValue !== null;\n }\n for (let i = 0; i < conditions.length; i++) {\n if (!this.doesEventAttributeConditionMatch(conditions[i], actualValue)) {\n return false;\n }\n }\n\n return true;\n }\n\n private applyPlacementEventAttributeMapping(event: SDKEvent): void {\n const mappedAttributeKeys = Object.keys(this.placementEventAttributeMappingLookup);\n for (let i = 0; i < mappedAttributeKeys.length; i++) {\n const mappedAttributeKey = mappedAttributeKeys[i];\n const rulesForMappedAttributeKey = this.placementEventAttributeMappingLookup[mappedAttributeKey];\n if (isEmpty(rulesForMappedAttributeKey)) {\n continue;\n }\n\n // Require ALL rules for the same key to match (AND).\n let allMatch = true;\n for (let j = 0; j < rulesForMappedAttributeKey.length; j++) {\n if (!this.doesEventMatchRule(event, rulesForMappedAttributeKey[j])) {\n allMatch = false;\n break;\n }\n }\n if (!allMatch) {\n continue;\n }\n\n mp().Rokt.setLocalSessionAttribute?.(mappedAttributeKey, true);\n }\n }\n\n private isLauncherReadyToAttach(): boolean {\n return !!window.Rokt && typeof window.Rokt.createLauncher === 'function';\n }\n\n /**\n * Returns the user identities from the filtered user, if any.\n */\n private returnUserIdentities(filteredUser: FilteredUser | null | undefined): Record {\n if (!filteredUser || !filteredUser.getUserIdentities) {\n return {};\n }\n\n const userIdentities: IUserIdentities = filteredUser.getUserIdentities().userIdentities;\n\n return this.replaceOtherIdentityWithEmailsha256(userIdentities);\n }\n\n private returnLocalSessionAttributes(): Record {\n if (!mp().Rokt || typeof mp().Rokt.getLocalSessionAttributes !== 'function') {\n return {};\n }\n if (isEmpty(this.placementEventMappingLookup) && isEmpty(this.placementEventAttributeMappingLookup)) {\n return {};\n }\n return mp().Rokt.getLocalSessionAttributes!();\n }\n\n private replaceOtherIdentityWithEmailsha256(userIdentities: IUserIdentities): Record {\n const newUserIdentities: Record = { ...(userIdentities || {}) };\n const key = this._mappedEmailSha256Key;\n if (key && userIdentities[key as keyof IUserIdentities]) {\n newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key as keyof IUserIdentities] as string;\n }\n if (key) {\n delete newUserIdentities[key];\n }\n\n return newUserIdentities;\n }\n\n private logSelectPlacementsEvent(attributes: unknown): void {\n if (!window.mParticle || typeof mp().logEvent !== 'function') {\n return;\n }\n\n if (!isObject(attributes)) {\n return;\n }\n\n const EVENT_TYPE_OTHER = mp().EventType.Other;\n\n mp().logEvent(EVENT_NAME_SELECT_PLACEMENTS, EVENT_TYPE_OTHER, attributes as Record);\n }\n\n private setRoktSessionId(sessionId: string): void {\n if (!sessionId || typeof sessionId !== 'string') {\n return;\n }\n try {\n const mpInstance = mp().getInstance();\n if (mpInstance && typeof mpInstance.setIntegrationAttribute === 'function') {\n mpInstance.setIntegrationAttribute(moduleId, {\n roktSessionId: sessionId,\n });\n }\n } catch (_e) {\n // Best effort — never let this break the partner page\n }\n }\n\n private attachLauncher(\n accountId: string,\n launcherOptions: Record,\n legacyRoktExtensions: string[] = [],\n ): void {\n const mpSessionId =\n mp() && mp().sessionManager && typeof mp().sessionManager!.getSession === 'function'\n ? mp().sessionManager!.getSession()\n : undefined;\n\n const options: Record = {\n accountId,\n ...(launcherOptions || {}),\n ...(mpSessionId ? { mpSessionId } : {}),\n };\n\n let launcherPromise: Promise;\n if (this.isPartnerInLocalLauncherTestGroup()) {\n launcherPromise = Promise.resolve(window.Rokt!.createLocalLauncher(options));\n } else {\n launcherPromise = window.Rokt!.createLauncher(options);\n }\n\n launcherPromise\n .then(async (launcher) => {\n await registerLegacyExtensions(legacyRoktExtensions, launcher);\n this.initRoktLauncher(launcher);\n })\n .catch((err: unknown) => {\n console.error('Error creating Rokt launcher:', err);\n });\n }\n\n private initRoktLauncher(launcher: RoktLauncher): void {\n // Assign the launcher to a global variable for later access\n if (window.Rokt) {\n window.Rokt.currentLauncher = launcher;\n }\n // Locally cache the launcher and filters\n this.launcher = launcher;\n\n const roktFilters = mp().Rokt?.filters;\n\n if (!roktFilters) {\n console.warn('Rokt Kit: No filters have been set.');\n } else {\n this.filters = roktFilters;\n if (!roktFilters.filteredUser) {\n console.warn('Rokt Kit: No filtered user has been set.');\n } else {\n this._workspaceSearchInFlightPromise = this.search(roktFilters.filteredUser);\n }\n }\n\n // Kit must be initialized before attaching to the Rokt manager\n this.isInitialized = true;\n\n sendAdBlockMeasurementSignals(this.domain, this.integrationName);\n\n // Attaches the kit to the Rokt manager\n mp().Rokt.attachKit(this);\n }\n\n private fetchOptimizely(): Record {\n const forwarders = mp()\n ._getActiveForwarders()\n .filter((forwarder) => forwarder.name === 'Optimizely');\n\n try {\n if (forwarders.length > 0 && window.optimizely) {\n const optimizelyState = window.optimizely.get('state');\n if (!optimizelyState || !optimizelyState.getActiveExperimentIds) {\n return {};\n }\n const activeExperimentIds = optimizelyState.getActiveExperimentIds();\n const activeExperiments = activeExperimentIds.reduce((acc: Record, expId: string) => {\n acc['rokt.custom.optimizely.experiment.' + expId + '.variationId'] =\n optimizelyState.getVariationMap()[expId].id;\n return acc;\n }, {});\n return activeExperiments;\n }\n } catch (error) {\n console.error('Error fetching Optimizely attributes:', error);\n }\n return {};\n }\n\n private isKitReady(): boolean {\n return !!(this.isInitialized && this.launcher);\n }\n\n private isPartnerInLocalLauncherTestGroup(): boolean {\n return !!(mp().config && mp().config!.isLocalLauncherEnabled && this.isAssignedToSampleGroup());\n }\n\n private isAssignedToSampleGroup(): boolean {\n const LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5;\n return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD;\n }\n\n private captureTiming(metricName: string): void {\n if (window && mp() && mp().captureTiming && metricName) {\n mp().captureTiming!(metricName);\n }\n }\n\n // ---- Public methods (mParticle Kit Callbacks) ----\n\n /**\n * Initializes the Rokt forwarder with settings from the mParticle server.\n */\n public init(\n settings: Record,\n _service: unknown,\n testMode: boolean,\n _trackerId: unknown,\n filteredUserAttributes?: Record,\n ): string {\n const kitSettings = settings as unknown as RoktKitSettings;\n const accountId = kitSettings.accountId;\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredUserAttributes);\n this._onboardingExpProvider = kitSettings.onboardingExpProvider;\n\n const placementEventMapping = parseSettingsString(kitSettings.placementEventMapping);\n this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping);\n\n const placementEventAttributeMapping = parseSettingsString(\n kitSettings.placementEventAttributeMapping,\n );\n this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping);\n\n // Set dynamic OTHER_IDENTITY based on server settings\n if (kitSettings.hashedEmailUserIdentityType) {\n this._mappedEmailSha256Key = kitSettings.hashedEmailUserIdentityType.toLowerCase();\n }\n\n this._workspaceIdSyncApiKey = isString(kitSettings.workspaceIdSyncApiKey)\n ? kitSettings.workspaceIdSyncApiKey\n : undefined;\n\n const domain = mp().Rokt?.domain;\n const { roktExtensionsQueryParams, legacyRoktExtensions, loadThankYouElement } = extractRoktExtensionConfig(\n kitSettings.roktExtensions,\n );\n const launcherOptions: Record = {\n ...((mp().Rokt?.launcherOptions as Record) || {}),\n };\n this.integrationName = generateIntegrationName(launcherOptions.integrationName as string | undefined);\n launcherOptions.integrationName = this.integrationName;\n\n this.domain = domain;\n\n const reportingConfig: ReportingConfig = {\n loggingUrl: kitSettings.loggingUrl,\n errorUrl: kitSettings.errorUrl,\n integrationDomain: domain,\n isLoggingEnabled: mp().config?.isLoggingEnabled === true,\n };\n const errorReportingService = new ErrorReportingService(\n reportingConfig,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n const loggingService = new LoggingService(\n reportingConfig,\n errorReportingService,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n\n this.errorReportingService = errorReportingService;\n this.loggingService = loggingService;\n\n if (mp()._registerErrorReportingService) {\n mp()._registerErrorReportingService!(errorReportingService);\n }\n if (mp()._registerLoggingService) {\n mp()._registerLoggingService!(loggingService);\n }\n\n if (testMode) {\n this.testHelpers = {\n generateLauncherScript: generateLauncherScript,\n generateThankYouElementScript: generateThankYouElementScript,\n extractRoktExtensionConfig: extractRoktExtensionConfig,\n hashEventMessage: hashEventMessage,\n parseSettingsString: parseSettingsString,\n generateMappedEventLookup: generateMappedEventLookup,\n generateMappedEventAttributeLookup: generateMappedEventAttributeLookup,\n sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals,\n createAutoRemovedIframe: createAutoRemovedIframe,\n djb2: djb2,\n setAllowedOriginHashes: (hashes: number[]) => {\n RoktKit._allowedOriginHashes = hashes;\n },\n ReportingTransport: ReportingTransport,\n ErrorReportingService: ErrorReportingService,\n LoggingService: LoggingService,\n RateLimiter: RateLimiter,\n ErrorCodes: ErrorCodes,\n WSDKErrorSeverity: WSDKErrorSeverity,\n };\n this.attachLauncher(accountId, launcherOptions);\n return 'Successfully initialized: ' + name;\n }\n\n if (loadThankYouElement) {\n mp().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this);\n loadRoktScript(ROKT_THANK_YOU_ELEMENT_SCRIPT_ID, generateThankYouElementScript(domain), {\n onLoad: () => {\n this._isThankYouElementLoaded = true;\n if (this._thankYouElementOnLoadCallback) {\n this._thankYouElementOnLoadCallback();\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt Thank You Element script:', error);\n },\n });\n }\n\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n loadRoktScript(ROKT_INTEGRATION_SCRIPT_ID, generateLauncherScript(domain, roktExtensionsQueryParams), {\n onLoad: () => {\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n console.error('Rokt object is not available after script load.');\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt launcher script:', error);\n },\n });\n\n this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended);\n }\n\n return 'Successfully initialized: ' + name;\n }\n\n public process(event: SDKEvent): string {\n if (!this.isKitReady()) {\n return 'Kit not ready for forwarder: ' + name;\n }\n if (typeof mp().Rokt?.setLocalSessionAttribute === 'function') {\n if (!isEmpty(this.placementEventAttributeMappingLookup)) {\n this.applyPlacementEventAttributeMapping(event);\n }\n\n if (!isEmpty(this.placementEventMappingLookup)) {\n const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? '');\n if (this.placementEventMappingLookup[String(hashedEvent)]) {\n mp().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(hashedEvent)], true);\n }\n }\n }\n\n return 'Successfully sent to forwarder: ' + name;\n }\n\n public setExtensionData(partnerExtensionData: Record): void {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return;\n }\n\n window.Rokt!.setExtensionData(partnerExtensionData);\n }\n\n public setUserAttribute(key: string, value: unknown): string {\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n this.userAttributes[key] = value;\n }\n return 'Successfully set user attribute for forwarder: ' + name;\n }\n\n public removeUserAttribute(key: string): string {\n delete this.userAttributes[key];\n return 'Successfully removed user attribute for forwarder: ' + name;\n }\n\n private handleIdentityComplete(user: IMParticleUser, callbackName: string): string {\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(user.getAllUserAttributes());\n return 'Successfully called ' + callbackName + ' for forwarder: ' + name;\n }\n\n public onUserIdentified(user: IMParticleUser): string {\n const filteredUser = user as FilteredUser;\n this.filters.filteredUser = filteredUser;\n this._workspaceSearchInFlightPromise = this.search(filteredUser);\n return this.handleIdentityComplete(user, 'onUserIdentified');\n }\n\n private search(filteredUser: FilteredUser): Promise {\n const apiKey = this._workspaceIdSyncApiKey;\n if (!apiKey) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n const search = mp().Identity?.search;\n if (typeof search !== 'function') {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n const userIdentities: IUserIdentities | null = filteredUser.getUserIdentities\n ? filteredUser.getUserIdentities().userIdentities\n : null;\n\n // Forward every non-empty string identifier the user has — email,\n // customerid, other/other2-10 (commonly used for hashed email),\n // mobile_number, facebook, etc. The host SDK's Identity.search accepts\n // the full IUserIdentities surface and the server validates it.\n const knownIdentities: Record = {};\n if (userIdentities) {\n for (const key of Object.keys(userIdentities) as Array) {\n const value = userIdentities[key];\n if (isString(value) && value.length > 0) {\n knownIdentities[key] = value;\n }\n }\n }\n\n const identityKeys = Object.keys(knownIdentities);\n if (identityKeys.length === 0) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n // Stable cache key: sort keys so insertion-order differences don't\n // cause false misses. The values are partner-supplied strings; no\n // hashing needed — equality on this serialization is sufficient.\n const identitiesKey = identityKeys\n .sort()\n .map((k) => `${k}=${knownIdentities[k]}`)\n .join('&');\n\n // Same identifier set as the last successful dispatch → skip the\n // network call. The current flag value still reflects the correct\n // match status.\n if (identitiesKey === this._workspaceLastSearchedIdentitiesKey) {\n return this._workspaceSearchInFlightPromise || Promise.resolve();\n }\n\n // New / different identifier set → reset and re-search. Cache the key\n // up front so a second concurrent invocation with the same set also\n // dedupes.\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = identitiesKey;\n\n return new Promise((resolve) => {\n try {\n search(apiKey, knownIdentities as IUserIdentities, (result: WorkspaceIdSyncResult) => {\n if (result?.httpCode === 200) {\n this.userIdentifiedInWorkspace = true;\n }\n resolve();\n });\n } catch (err) {\n console.error('Rokt Kit: Workspace IDSync search failed', err);\n // Dispatch failed — clear the cache so the same identifier set\n // can retry on the next identification rather than being stuck\n // behind a poisoned entry that short-circuits future searches.\n this._workspaceLastSearchedIdentitiesKey = undefined;\n resolve();\n }\n });\n }\n\n public onLoginComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onLoginComplete');\n }\n\n public onLogoutComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n // Anonymous sessions must not carry the previous user's match forward.\n // Clear the flag explicitly here. Also clear the identities cache so a\n // re-login (possibly with the same identifiers) dispatches a fresh\n // search rather than reusing a stale answer.\n this.userIdentifiedInWorkspace = false;\n this._workspaceSearchInFlightPromise = null;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return this.handleIdentityComplete(user, 'onLogoutComplete');\n }\n\n public onModifyComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onModifyComplete');\n }\n\n /**\n * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options.\n *\n * If a Workspace IDSync search is in flight from a recent onUserIdentified\n * call, this method waits up to `WORKSPACE_SEARCH_SELECT_TIMEOUT_MS` for it\n * to settle so the first placement call can include the\n * `userIdentifiedInWorkspace` flag without racing the network response.\n * The timeout protects against a stalled or slow search blocking placement\n * rendering — if it fires, selectPlacements proceeds without the flag.\n *\n * Implementation note: this method stays non-async deliberately. First,\n * the public return type is `RoktSelection | Promise |\n * undefined` — a superset of the `RoktSelection | Promise`\n * shape declared for `RoktLauncher.selectPlacements` above (line ~70).\n * Marking this `async` would narrow it to `Promise` and silently change the contract for callers that read\n * the result synchronously. Second, `RoktSelection` has an optional\n * `then?` member, so TS treats it as ambiguously promise-like and\n * rejects it as the awaited return of an async function (TS1058) —\n * working around that would require a cast or wrapping every return in\n * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`;\n * this wrapper just gates it on the in-flight search via `Promise.race`.\n */\n public selectPlacements(options: Record): RoktSelection | Promise | undefined {\n if (this._workspaceSearchInFlightPromise) {\n const inFlight = this._workspaceSearchInFlightPromise;\n return Promise.race([\n inFlight,\n new Promise((resolve) => setTimeout(resolve, WORKSPACE_SEARCH_SELECT_TIMEOUT_MS)),\n ]).then(() => this._dispatchPlacements(options)) as Promise;\n }\n return this._dispatchPlacements(options);\n }\n\n private _dispatchPlacements(options: Record): RoktSelection | Promise | undefined {\n const attributes = ((options && (options.attributes as Record)) || {}) as Record;\n const cachedUserAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(this.userAttributes);\n const placementAttributes: Record = { ...cachedUserAttributes, ...attributes };\n\n const filters = this.filters || {};\n const userAttributeFilters = (filters.userAttributeFilters as string[]) || [];\n const filteredUser = filters.filteredUser || null;\n const mpid = filteredUser ? filteredUser.getMPID() : null;\n\n let filteredAttributes: Record;\n\n if (!filters) {\n console.warn('Rokt Kit: No filters available, using user attributes');\n filteredAttributes = placementAttributes;\n } else if (filters.filterUserAttributes) {\n filteredAttributes = filters.filterUserAttributes(placementAttributes, userAttributeFilters);\n } else {\n filteredAttributes = placementAttributes;\n }\n\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredAttributes);\n\n const optimizelyAttributes = this._onboardingExpProvider === 'Optimizely' ? this.fetchOptimizely() : {};\n\n const filteredUserIdentities = this.returnUserIdentities(filteredUser);\n\n const localSessionAttributes = this.returnLocalSessionAttributes();\n\n const selectPlacementsAttributes: Record = {\n ...(filteredUserIdentities as Record),\n ...filteredAttributes,\n ...optimizelyAttributes,\n ...localSessionAttributes,\n ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}),\n mpid,\n };\n\n const selectPlacementsOptions: Record = { ...options, attributes: selectPlacementsAttributes };\n\n const selection = this.launcher!.selectPlacements(selectPlacementsOptions);\n\n // After selection resolves, sync the Rokt session ID back to mParticle, then log\n const logSelection = () => this.logSelectPlacementsEvent(selectPlacementsAttributes);\n\n void Promise.resolve(selection)\n .then((sel) => sel?.context?.sessionId?.then((sessionId) => this.setRoktSessionId(sessionId)))\n .catch(() => undefined)\n .finally(logSelection);\n\n return selection;\n }\n\n /**\n * Passes attributes to the Rokt Web SDK for client-side hashing.\n */\n public hashAttributes(attributes: Record): Promise> | null {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return null;\n }\n return this.launcher!.hashAttributes(attributes);\n }\n\n /**\n * Enables optional Integration Launcher extensions before selecting placements.\n *\n * @deprecated This functionality has been internalized and will be removed in a future release.\n */\n public use(extensionName: string): Promise {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return Promise.reject(new Error('Rokt Kit: Not initialized'));\n }\n if (!extensionName || !isString(extensionName)) {\n return Promise.reject(new Error('Rokt Kit: Invalid extension name'));\n }\n return this.launcher!.use(extensionName);\n }\n\n /**\n * Registers a callback to be invoked once rokt-thank-you-element.js becomes available.\n */\n public onShoppableAdsReady(callback: () => void) {\n if (this._isThankYouElementLoaded) {\n callback();\n } else {\n this._thankYouElementOnLoadCallback = callback;\n }\n }\n}\n\n// ============================================================\n// Kit registration\n// ============================================================\n\nfunction getId(): number {\n return moduleId;\n}\n\nfunction register(config: { kits?: Record }): void {\n if (!config) {\n window.console.log('You must pass a config object to register the kit ' + name);\n return;\n }\n if (!isObject(config)) {\n window.console.log(\"'config' must be an object. You passed in a \" + typeof config);\n return;\n }\n\n if (isObject(config.kits)) {\n (config.kits as Record)[name] = {\n constructor: RoktKit,\n };\n } else {\n config.kits = {};\n config.kits[name] = {\n constructor: RoktKit,\n };\n }\n window.console.log('Successfully registered ' + name + ' to your mParticle configuration');\n}\n\nif (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) {\n mp().addForwarder({\n name: name,\n constructor: RoktKit,\n getId: getId,\n });\n}\n\nexport { register };\n"],"names":["SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST","SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET","isSelectPlacementsAttributePersistenceDenied","key","removeSelectPlacementsAttributePersistenceDeniedAttributes","attributes","filteredAttributes","sourceAttributes","attributeKeys","i","name","moduleId","EVENT_NAME_SELECT_PLACEMENTS","ADBLOCK_CONTROL_DOMAIN","INIT_LOG_SAMPLING_RATE","ROKT_THANK_YOU_JOURNEY_EXTENSION","ROKT_INTEGRATION_SCRIPT_ID","ROKT_THANK_YOU_ELEMENT_SCRIPT_ID","USER_IDENTIFIED_IN_WORKSPACE_KEY","WORKSPACE_SEARCH_SELECT_TIMEOUT_MS","ErrorCodes","WSDKErrorSeverity","DEFAULT_ROKT_DOMAIN","LOGGING_ENDPOINT","ERROR_ENDPOINT","RATE_LIMIT_PER_SEVERITY","mp","generateLauncherScript","domain","extensions","baseUrl","generateBaseUrl","generateThankYouElementScript","generateReportingUrl","configuredUrl","endpoint","loadRoktScript","scriptId","source","handlers","target","script","isObject","val","parseSettingsString","settingsString","extractRoktExtensionConfig","settings","roktExtensionsQueryParams","legacyRoktExtensions","loadThankYouElement","extensionName","registerLegacyExtensions","legacyExtensions","launcher","extension","generateMappedEventLookup","placementEventMapping","mappedEvents","mapping","generateMappedEventAttributeLookup","placementEventAttributeMapping","mappedAttributeKeys","isString","mappedAttributeKey","eventAttributeKey","hashEventMessage","messageType","eventType","eventName","isEmpty","value","generateIntegrationName","customIntegrationName","integrationName","djb2","str","hash","createAutoRemovedIframe","src","iframe","sendAdBlockMeasurementSignals","version","originHash","RoktKit","guid","pageUrl","params","_isDebugModeEnabled","_getReportingUrl","_getUserAgent","RateLimiter","severity","newCount","ReportingTransport","config","launcherInstanceGuid","accountId","rateLimiter","isLoggingEnabled","url","msg","code","stackTrace","onError","logRequest","headers","response","serverError","error","ErrorReportingService","LoggingService","errorReportingService","entry","isServerSide","_RoktKit","event","condition","actualValue","operator","expectedValue","rule","conditions","rulesForMappedAttributeKey","allMatch","j","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","launcherOptions","mpSessionId","options","launcherPromise","err","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","loggingService","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","search","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","localSessionAttributes","selectPlacementsAttributes","selectPlacementsOptions","selection","logSelection","sel","callback","getId","register"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"Rokt-Kit.esm.js","sources":["../src/selectPlacementsAttributePersistence.ts","../src/utils.ts","../src/storage.ts","../src/pageViewStorage.ts","../src/Rokt-Kit.ts"],"sourcesContent":["const SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST = [\n 'active_time_on_site_ms',\n 'billingaddress1',\n 'billingaddress2',\n 'billingcity',\n 'billingstate',\n 'billingzipcode',\n 'cartitems',\n 'ccbin',\n 'confirmationref',\n 'conversiontype',\n 'country',\n 'couponcode',\n 'currency',\n 'language',\n 'paymentserviceprovider',\n 'paymentserviceproviderattribute',\n 'paymenttype',\n 'shippingaddress1',\n 'shippingcity',\n 'shippingcountry',\n 'shippingmethod',\n 'shippingstate',\n 'shippingzipcode',\n 'totalprice',\n];\nconst SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET = new Set(SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST);\n\nexport function isSelectPlacementsAttributePersistenceDenied(key: string): boolean {\n return SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET.has(key.toLowerCase());\n}\n\nexport function removeSelectPlacementsAttributePersistenceDeniedAttributes(\n attributes: Record | null | undefined,\n): Record {\n const filteredAttributes: Record = {};\n const sourceAttributes = attributes || {};\n const attributeKeys = Object.keys(sourceAttributes);\n\n for (let i = 0; i < attributeKeys.length; i++) {\n const key = attributeKeys[i];\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n filteredAttributes[key] = sourceAttributes[key];\n }\n }\n\n return filteredAttributes;\n}\n","export function isObject(value: unknown): value is Record {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nexport function isFunction(value: unknown): value is (...args: Array) => unknown {\n return typeof value === 'function';\n}\n\nexport function isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'object') {\n return Object.keys(value as object).length === 0;\n }\n return false;\n}\n\n// Strips the query string from a URL before it is persisted and sent to Rokt,\n// since query params commonly carry PII (emails, tokens, order refs).\n// Returns the input unchanged if it can't be parsed as a URL.\nexport function sanitizeUrl(href: string): string {\n try {\n const url = new URL(href);\n url.search = '';\n return url.toString();\n } catch {\n return href;\n }\n}\n","import { isObject } from './utils';\n\nconst LS_PROBE_KEY = '__rokt_ls_probe__';\n\nexport function isLocalStorageAvailable(): boolean {\n try {\n window.localStorage.setItem(LS_PROBE_KEY, '1');\n window.localStorage.removeItem(LS_PROBE_KEY);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function readJSON(key: string): unknown {\n try {\n const stored = window.localStorage.getItem(key);\n return stored === null ? null : JSON.parse(stored);\n } catch {\n return null;\n }\n}\n\nexport function writeJSON(key: string, value: unknown): boolean {\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n return true;\n } catch {\n return false;\n }\n}\n\nexport function removeKey(key: string): void {\n try {\n window.localStorage.removeItem(key);\n } catch {\n /* empty */\n }\n}\n\nexport function readNamespacedField(namespaceKey: string, field: string): unknown {\n const blob = readJSON(namespaceKey);\n return isObject(blob) ? blob[field] : undefined;\n}\n\nexport function writeNamespacedField(namespaceKey: string, field: string, value: unknown): boolean {\n const blob = readJSON(namespaceKey);\n const next = isObject(blob) ? { ...blob } : {};\n next[field] = value;\n return writeJSON(namespaceKey, next);\n}\n\nexport function removeNamespacedField(namespaceKey: string, field: string): void {\n const blob = readJSON(namespaceKey);\n if (!isObject(blob) || !(field in blob)) {\n return;\n }\n const next = { ...blob };\n delete next[field];\n if (Object.keys(next).length === 0) {\n removeKey(namespaceKey);\n } else {\n writeJSON(namespaceKey, next);\n }\n}\n","import type { LoggingService } from './Rokt-Kit';\nimport {\n readJSON,\n removeKey,\n readNamespacedField,\n writeNamespacedField,\n removeNamespacedField,\n isLocalStorageAvailable,\n} from './storage';\nimport { sanitizeUrl, isObject } from './utils';\n\nconst LS_NAMESPACE_KEY = 'mp-rokt-kit';\nconst LS_PAGE_VIEWS_FIELD = 'pageViews';\nconst LS_UTM_PARAMS_FIELD = 'utmParams';\nconst LEGACY_PAGE_VIEWS_KEY = 'mpPageViews';\nexport const PAGE_VIEWS_MAX_COUNT = 25;\n\nconst UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'] as const;\ntype UtmKey = (typeof UTM_KEYS)[number];\nexport type UtmParams = Partial>;\n\nexport interface PageEvent {\n pageUrl: string;\n sourceMessageId: string;\n timestamp: number;\n pageTitle?: string;\n canonicalUrl?: string;\n activeTimeOnSite?: number;\n activeTimeOnPage?: number;\n}\n\nfunction capPageViews(views: PageEvent[]): PageEvent[] {\n return views.slice(-PAGE_VIEWS_MAX_COUNT);\n}\n\nexport function migrateLegacyPageViewStorage(loggingService: LoggingService | null): void {\n const legacyViews = readJSON(LEGACY_PAGE_VIEWS_KEY);\n if (legacyViews === null) {\n return;\n }\n\n const alreadyMigrated = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD) !== undefined;\n const needsMigration = !alreadyMigrated && Array.isArray(legacyViews);\n\n if (needsMigration) {\n loggingService?.log({\n message: 'Rokt Kit: Migrating legacy page-view storage',\n code: 'PAGE_VIEW_LEGACY_MIGRATION',\n });\n const migrated = writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, legacyViews);\n if (!migrated) {\n loggingService?.log({\n message: 'Rokt Kit: Failed to migrate legacy page-view storage [reason: migration_retry]',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n removeKey(LEGACY_PAGE_VIEWS_KEY);\n}\n\nexport function loadPageViews(loggingService: LoggingService | null): PageEvent[] {\n migrateLegacyPageViewStorage(loggingService);\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n return Array.isArray(stored) ? (stored as PageEvent[]) : [];\n}\n\nexport function writePageViews(pageViews: PageEvent[]): number {\n const views = capPageViews(pageViews);\n for (let i = 0; i < views.length; i++) {\n const toWrite = views.slice(i);\n if (writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, toWrite)) {\n return toWrite.length;\n }\n }\n return 0;\n}\n\nexport function clearPageViews(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n}\n\nexport function buildPageEvents(pageViews: PageEvent[]): PageEvent[] {\n const views = capPageViews(pageViews);\n return views.map((pageView, index) => {\n const activeTimeOnSite = pageView.activeTimeOnSite;\n const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite);\n\n const next = views[index + 1];\n const nextActiveTimeOnSite = next?.activeTimeOnSite;\n const hasNextActiveTimeOnSite = nextActiveTimeOnSite !== undefined && Number.isFinite(nextActiveTimeOnSite);\n\n const diff = hasActiveTime && hasNextActiveTimeOnSite ? nextActiveTimeOnSite - activeTimeOnSite : undefined;\n\n return {\n pageUrl: pageView.pageUrl,\n sourceMessageId: pageView.sourceMessageId,\n timestamp: pageView.timestamp,\n ...(pageView.pageTitle !== undefined ? { pageTitle: pageView.pageTitle } : {}),\n ...(pageView.canonicalUrl !== undefined ? { canonicalUrl: pageView.canonicalUrl } : {}),\n ...(hasActiveTime ? { activeTimeOnSite } : {}),\n ...(diff !== undefined && diff >= 0 ? { activeTimeOnPage: diff } : {}),\n };\n });\n}\n\nexport function captureUtmParams(loggingService: LoggingService | null): void {\n if (readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD) !== undefined) {\n return;\n }\n const search = new URLSearchParams(window.location.search);\n const params: UtmParams = {};\n for (const key of UTM_KEYS) {\n const value = search.get(key);\n if (value) params[key] = value;\n }\n if (Object.keys(params).length === 0) {\n return;\n }\n const captured = Object.keys(params).join(', ');\n if (!writeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD, params)) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n loggingService?.log({\n message: `Rokt Kit: Failed to persist UTM params [reason: ${reason}]`,\n code: 'UTM_CAPTURE_FAILED',\n });\n return;\n }\n loggingService?.log({\n message: `Rokt Kit: Captured UTM params [${captured}]`,\n code: 'UTM_CAPTURE_SUCCESS',\n });\n}\n\nexport function loadUtmParams(): UtmParams | null {\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n return isObject(stored) ? (stored as UtmParams) : null;\n}\n\nexport function clearUtmParams(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n}\n\nexport function readCanonicalUrl(): string | undefined {\n const link = document.querySelector('link[rel=\"canonical\"]');\n const href = link?.href;\n if (!href) {\n return undefined;\n }\n return sanitizeUrl(href);\n}\n","// Copyright 2025 mParticle, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// ============================================================\n// Types\n// ============================================================\n\nimport { KitInterface, IMParticleUser, SDKEvent } from '@mparticle/web-sdk/internal';\nimport type { IUserIdentities } from '@mparticle/web-sdk';\n\nimport {\n isSelectPlacementsAttributePersistenceDenied,\n removeSelectPlacementsAttributePersistenceDeniedAttributes,\n} from './selectPlacementsAttributePersistence';\n\nimport {\n PageEvent,\n PAGE_VIEWS_MAX_COUNT,\n buildPageEvents,\n migrateLegacyPageViewStorage,\n loadPageViews,\n writePageViews,\n clearPageViews,\n readCanonicalUrl,\n captureUtmParams,\n loadUtmParams,\n clearUtmParams,\n} from './pageViewStorage';\nimport { isLocalStorageAvailable } from './storage';\n\nimport { isObject, isString, isEmpty, isFunction, sanitizeUrl } from './utils';\n\ninterface RoktKitSettings {\n accountId: string;\n roktExtensions?: string;\n placementEventMapping?: string;\n placementEventAttributeMapping?: string;\n hashedEmailUserIdentityType?: string;\n onboardingExpProvider?: string;\n loggingUrl?: string;\n errorUrl?: string;\n workspaceIdSyncApiKey?: string;\n}\n\ninterface EventAttributeCondition {\n operator: string;\n attributeValue: string;\n}\n\ninterface PlacementEventRule {\n eventAttributeKey: string;\n conditions: EventAttributeCondition[];\n}\n\ninterface EventAttributeMapping {\n value: string;\n map: string;\n conditions?: EventAttributeCondition[];\n}\n\ninterface PlacementEventMappingEntry {\n jsmap: string;\n value: string;\n}\n\ninterface RoktExtensionEntry {\n value: string;\n}\n\ninterface RoktSelection {\n context?: {\n sessionId?: Promise;\n };\n then?: (callback: (sel: RoktSelection) => void) => Promise;\n catch?: (callback: () => void) => void;\n}\n\ninterface RoktLauncher {\n selectPlacements(options: Record): RoktSelection | Promise;\n hashAttributes(attributes: Record): Promise>;\n use(extensionName: string): Promise;\n}\n\ninterface RoktGlobal {\n createLauncher(options: Record): Promise;\n createLocalLauncher(options: Record): RoktLauncher;\n currentLauncher?: RoktLauncher;\n setExtensionData(data: Record): void;\n}\n\n// FilteredUser is the IMParticleUser shape we receive after kit filtering.\n// `getMPID` and `getUserIdentities` are inherited from the SDK's `User` base type.\ntype FilteredUser = IMParticleUser;\n\n// TODO: Replace with `IIdentitySearchResult` from `@mparticle/web-sdk` once\n// a version that exports it is published (currently on a feature branch in\n// mParticle/mparticle-web-sdk PR #1255). The shape below is intentionally\n// structurally identical so the swap is a one-line import change.\ninterface WorkspaceIdSyncResult {\n httpCode: number;\n body?: {\n context?: string | null;\n mpid?: string;\n matched_identities?: Record;\n is_ephemeral?: boolean;\n is_logged_in?: boolean;\n };\n}\n\n// TODO: Replace with `IdentitySearchCallback`-compatible reference from\n// `@mparticle/web-sdk` once published (mirrors `SDKIdentityApi.search`).\ntype WorkspaceIdSyncSearcher = (\n apiKey: string,\n knownIdentities: IUserIdentities,\n callback: (result: WorkspaceIdSyncResult) => void,\n) => void;\n\ninterface KitFilters {\n userAttributeFilters?: string[];\n filterUserAttributes?: (attributes: Record, filters?: string[]) => Record;\n filteredUser?: FilteredUser | null;\n}\n\ninterface RoktManager {\n attachKit(kit: RoktKit): void | Promise;\n flushOnShoppableAdsReadyMessageQueue?(kit: RoktKit): void;\n filters?: KitFilters;\n domain?: string;\n launcherOptions?: Record;\n getLocalSessionAttributes?(): Record;\n setLocalSessionAttribute?(key: string, value: unknown): void;\n}\n\ninterface MParticleInstance {\n setIntegrationAttribute(moduleId: number, attrs: Record): void;\n}\n\ninterface OptimizelyState {\n getActiveExperimentIds(): string[];\n getVariationMap(): Record;\n}\n\ninterface OptimizelyGlobal {\n get(key: 'state'): OptimizelyState;\n}\n\n// Our view of the mParticle global with Rokt-specific extensions.\n// We access window.mParticle via an explicit cast (see `mp()` helper below)\n// rather than augmenting Window to avoid conflicts with @mparticle/web-sdk declarations.\ninterface MParticleExtended {\n Rokt: RoktManager;\n addForwarder(config: ForwarderRegistration): void;\n getVersion(): string;\n generateHash(value: string): string | number;\n logEvent(name: string, type: number, attrs?: Record): void;\n EventType: { Other: number };\n getInstance(): MParticleInstance;\n getDeviceId?(): string;\n sessionManager?: { getSession?(): string; getSessionId?(): string };\n _getActiveForwarders(): Array<{ name: string }>;\n config?: { isLocalLauncherEnabled?: boolean; isLoggingEnabled?: boolean };\n captureTiming?(metricName: string): void;\n forwarder?: RoktKit;\n loggedEvents?: Array>;\n _registerErrorReportingService?(service: ErrorReportingService): void;\n _registerLoggingService?(service: LoggingService): void;\n Identity?: { search?: WorkspaceIdSyncSearcher };\n}\n\ninterface TestHelpers {\n generateLauncherScript: (domain: string | undefined, extensions: string[]) => string;\n generateThankYouElementScript: (domain: string | undefined) => string;\n extractRoktExtensionConfig: (settingsString?: string) => RoktExtensionConfig;\n hashEventMessage: (messageType: number, eventType: number, eventName: string) => string | number;\n parseSettingsString: (settingsString?: string) => T[];\n generateMappedEventLookup: (placementEventMapping: PlacementEventMappingEntry[]) => Record;\n generateMappedEventAttributeLookup: (mapping: EventAttributeMapping[]) => Record;\n sendAdBlockMeasurementSignals: (domain: string | undefined, version: string | null) => void;\n createAutoRemovedIframe: (src: string) => void;\n djb2: (str: string) => number;\n setAllowedOriginHashes: (hashes: number[]) => void;\n ReportingTransport: typeof ReportingTransport;\n ErrorReportingService: typeof ErrorReportingService;\n LoggingService: typeof LoggingService;\n RateLimiter: typeof RateLimiter;\n ErrorCodes: typeof ErrorCodes;\n WSDKErrorSeverity: typeof WSDKErrorSeverity;\n}\n\ninterface ForwarderRegistration {\n name: string;\n constructor: new () => RoktKit;\n getId: () => number;\n}\n\ninterface ReportingConfig {\n loggingUrl?: string;\n errorUrl?: string;\n integrationDomain?: string;\n isLoggingEnabled: boolean;\n}\n\ninterface ErrorReport {\n message: string;\n code?: string;\n severity?: string;\n stackTrace?: string;\n}\n\n// A log-delivery failure. statusCode is set when the request reached the server\n// and returned a non-2xx status (server-side); it is absent for network-level\n// failures such as ad-blockers, offline, or CORS rejections (client-side).\ninterface DeliveryError extends Error {\n statusCode?: number;\n}\n\ninterface LogEntry {\n message: string;\n code?: string;\n}\n\ninterface RoktExtensionConfig {\n roktExtensionsQueryParams: string[];\n legacyRoktExtensions: string[];\n loadThankYouElement: boolean;\n}\n\ndeclare global {\n interface Window {\n Rokt?: RoktGlobal;\n __rokt_li_guid__?: string;\n optimizely?: OptimizelyGlobal;\n // mParticle is declared as any to avoid conflicts with @mparticle/web-sdk type declarations.\n // We use the typed mp() accessor for all internal accesses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mParticle: any;\n }\n}\n\n// ============================================================\n// Module-level constants\n// ============================================================\n\nconst name = 'Rokt';\nconst moduleId = 181;\nconst EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements';\nconst ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com';\nconst INIT_LOG_SAMPLING_RATE = 0.1;\nconst ROKT_THANK_YOU_JOURNEY_EXTENSION = 'ThankYouPageJourney';\nconst ROKT_INTEGRATION_SCRIPT_ID = 'rokt-launcher';\nconst ROKT_THANK_YOU_ELEMENT_SCRIPT_ID = 'rokt-thank-you-element';\nconst USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace';\n\nconst MESSAGE_TYPE_PAGE_VIEW = 3; // mParticle MessageType.PageView\nconst MESSAGE_TYPE_SESSION_END = 2; // mParticle MessageType.SessionEnd\nconst PAGE_EVENTS_KEY = 'page_events';\nconst PAGE_VIEW_ATTRIBUTES_KEY = 'page_view_attributes';\nconst MPARTICLE_SESSION_ID_KEY = 'mparticle_session_id';\nconst MPARTICLE_DEVICE_ID_KEY = 'mparticle_device_id';\n\n// Bound on how long selectPlacements will wait for an in-flight Workspace\n// IDSync search before proceeding without the userIdentifiedInWorkspace flag.\n// Long enough to cover the typical /v1/search round-trip (~50ms); short enough that a\n// stalled search never blocks placement rendering on a thank-you page.\nconst WORKSPACE_SEARCH_SELECT_TIMEOUT_MS = 500;\n\n// ============================================================\n// Reporting service constants\n// ============================================================\n\nconst ErrorCodes = {\n UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION',\n IDENTITY_REQUEST: 'IDENTITY_REQUEST',\n LOG_DELIVERY_FAILURE: 'LOG_DELIVERY_FAILURE',\n} as const;\n\nconst WSDKErrorSeverity = {\n ERROR: 'ERROR',\n INFO: 'INFO',\n WARNING: 'WARNING',\n} as const;\n\nconst DEFAULT_ROKT_DOMAIN = 'apps.rokt-api.com';\nconst LOGGING_ENDPOINT = '/v1/log';\nconst ERROR_ENDPOINT = '/v1/errors';\nconst RATE_LIMIT_PER_SEVERITY = 10;\n\n// ============================================================\n// Helper: typed accessor for window.mParticle\n// We use an explicit cast here to avoid conflicts with @mparticle/web-sdk\n// type declarations while still providing full type safety for our usages.\n// ============================================================\n\nfunction mp(): MParticleExtended {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (window as any).mParticle as MParticleExtended;\n}\n\n// ============================================================\n// Module-level utility functions\n// ============================================================\n\nfunction generateLauncherScript(domain: string | undefined, extensions: string[]): string {\n const launcherPath = '/wsdk/integrations/launcher.js';\n const baseUrl = [generateBaseUrl(domain), launcherPath].join('');\n\n if (!extensions || extensions.length === 0) {\n return baseUrl;\n }\n return baseUrl + '?extensions=' + extensions.join(',');\n}\n\nfunction generateThankYouElementScript(domain: string | undefined) {\n const thankYouElementPath = '/rokt-elements/rokt-element-thank-you.js';\n return [generateBaseUrl(domain), thankYouElementPath].join('');\n}\n\nfunction generateBaseUrl(domain: string | undefined) {\n const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN;\n\n if (resolvedDomain.includes('://')) {\n return resolvedDomain.replace(/\\/+$/, '');\n }\n\n const protocol = 'https://';\n\n return [protocol, resolvedDomain].join('');\n}\n\nfunction generateReportingUrl(configuredUrl: string | undefined, domain: string | undefined, endpoint: string): string {\n if (configuredUrl) {\n if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://')) {\n return configuredUrl;\n }\n return 'https://' + configuredUrl;\n }\n\n const hasNonHttpScheme = domain?.includes('://') && !/^https?:\\/\\//i.test(domain);\n const reportingDomain = hasNonHttpScheme ? undefined : domain;\n\n return generateBaseUrl(reportingDomain) + endpoint;\n}\n\nfunction loadRoktScript(\n scriptId: string,\n source: string,\n handlers?: { onLoad?: () => void; onError?: (e: Event | string) => void },\n): void {\n if (document.getElementById(scriptId)) return; // resolves the preexisting script issue\n\n const target = document.head || document.body;\n const script = document.createElement('script');\n script.id = scriptId;\n script.type = 'text/javascript';\n script.src = source;\n script.async = true;\n script.crossOrigin = 'anonymous';\n (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high';\n if (handlers?.onLoad) script.onload = handlers.onLoad;\n if (handlers?.onError) script.onerror = handlers.onError;\n target.appendChild(script);\n}\n\nfunction parseSettingsString(settingsString?: string): T[] {\n if (!settingsString) {\n return [];\n }\n try {\n return JSON.parse(settingsString.replace(/"/g, '\"')) as T[];\n } catch (_error) {\n console.error('Settings string contains invalid JSON');\n }\n return [];\n}\n\nfunction extractRoktExtensionConfig(settingsString?: string): RoktExtensionConfig {\n const settings = settingsString ? parseSettingsString(settingsString) : [];\n const roktExtensionsQueryParams: string[] = [];\n const legacyRoktExtensions: string[] = [];\n let loadThankYouElement = false;\n\n for (let i = 0; i < settings.length; i++) {\n const extensionName = settings[i].value;\n if (extensionName === 'thank-you-journey') {\n loadThankYouElement = true;\n legacyRoktExtensions.push(ROKT_THANK_YOU_JOURNEY_EXTENSION);\n } else {\n roktExtensionsQueryParams.push(extensionName);\n }\n }\n\n return {\n roktExtensionsQueryParams,\n legacyRoktExtensions,\n loadThankYouElement,\n };\n}\n\nasync function registerLegacyExtensions(legacyExtensions: string[], launcher: RoktLauncher | null) {\n const extensions: Promise[] = [];\n if (launcher) {\n for (const extension of legacyExtensions) {\n extensions.push(launcher.use(extension));\n }\n }\n\n return Promise.all(extensions);\n}\n\nfunction generateMappedEventLookup(placementEventMapping: PlacementEventMappingEntry[]): Record {\n if (!placementEventMapping) {\n return {};\n }\n\n const mappedEvents: Record = {};\n for (let i = 0; i < placementEventMapping.length; i++) {\n const mapping = placementEventMapping[i];\n mappedEvents[mapping.jsmap] = mapping.value;\n }\n return mappedEvents;\n}\n\nfunction generateMappedEventAttributeLookup(\n placementEventAttributeMapping: EventAttributeMapping[],\n): Record {\n const mappedAttributeKeys: Record = {};\n if (!Array.isArray(placementEventAttributeMapping)) {\n return mappedAttributeKeys;\n }\n for (let i = 0; i < placementEventAttributeMapping.length; i++) {\n const mapping = placementEventAttributeMapping[i];\n if (!mapping || !isString(mapping.value) || !isString(mapping.map)) {\n continue;\n }\n\n const mappedAttributeKey = mapping.value;\n const eventAttributeKey = mapping.map;\n\n if (!mappedAttributeKeys[mappedAttributeKey]) {\n mappedAttributeKeys[mappedAttributeKey] = [];\n }\n\n mappedAttributeKeys[mappedAttributeKey].push({\n eventAttributeKey: eventAttributeKey,\n conditions: Array.isArray(mapping.conditions) ? mapping.conditions : [],\n });\n }\n return mappedAttributeKeys;\n}\n\nfunction hashEventMessage(messageType: number, eventType: number, eventName: string): string | number {\n return mp().generateHash([messageType, eventType, eventName].join(''));\n}\n\nfunction generateIntegrationName(customIntegrationName?: string): string {\n const coreSdkVersion = mp().getVersion();\n const kitVersion = process.env.PACKAGE_VERSION;\n let integrationName = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion;\n\n if (customIntegrationName) {\n integrationName += '_' + customIntegrationName;\n }\n return integrationName;\n}\n\nfunction djb2(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return hash;\n}\n\nfunction createAutoRemovedIframe(src: string): void {\n const iframe = document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');\n iframe.src = src;\n iframe.onload = function () {\n iframe.onload = null;\n if (iframe.parentNode) {\n iframe.parentNode.removeChild(iframe);\n }\n };\n const target = document.body || document.head;\n if (target) {\n target.appendChild(iframe);\n }\n}\n\nfunction sendAdBlockMeasurementSignals(domain: string | undefined, version: string | null): void {\n const originHash = djb2(window.location.origin);\n const allowedOriginHashes = RoktKit._allowedOriginHashes;\n if (allowedOriginHashes.indexOf(originHash) === -1) {\n return;\n }\n\n if (Math.random() >= INIT_LOG_SAMPLING_RATE) {\n return;\n }\n\n const guid = window.__rokt_li_guid__;\n if (!guid) {\n return;\n }\n\n if (domain && domain.includes('://') && !/^https:\\/\\//i.test(domain)) {\n return;\n }\n\n const pageUrl = window.location.href.split('?')[0].split('#')[0];\n const params =\n 'version=' +\n encodeURIComponent(version ?? '') +\n '&launcherInstanceGuid=' +\n encodeURIComponent(guid) +\n '&pageUrl=' +\n encodeURIComponent(pageUrl);\n\n const existingBaseUrl = domain ? generateBaseUrl(domain) : 'https://apps.rokt.com';\n createAutoRemovedIframe(existingBaseUrl + '/v1/wsdk-init/index.html?' + params);\n\n createAutoRemovedIframe(\n 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true',\n );\n}\n\n// ============================================================\n// Reporting helpers\n// ============================================================\n\nfunction _isDebugModeEnabled(): boolean {\n return typeof window !== 'undefined' && !!window.location?.search?.toLowerCase().includes('mp_enable_logging=true');\n}\n\nfunction _getReportingUrl(): string | undefined {\n return typeof window !== 'undefined' ? window.location?.href : undefined;\n}\n\nfunction _getUserAgent(): string | undefined {\n return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined;\n}\n\nclass RateLimiter {\n private _logCount: Record = {};\n\n incrementAndCheck(severity: string): boolean {\n const count = this._logCount[severity] || 0;\n const newCount = count + 1;\n this._logCount[severity] = newCount;\n return newCount > RATE_LIMIT_PER_SEVERITY;\n }\n}\n\nclass ReportingTransport {\n private _isEnabled: boolean;\n private _integrationName: string;\n private _launcherInstanceGuid: string | undefined;\n private _accountId: string | null;\n private _rateLimiter: RateLimiter;\n private readonly _reporter = 'mp-wsdk';\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid: string | undefined,\n accountId: string | null | undefined,\n rateLimiter?: RateLimiter,\n ) {\n const isLoggingEnabled = config.isLoggingEnabled;\n this._integrationName = integrationName || '';\n this._launcherInstanceGuid = launcherInstanceGuid;\n this._accountId = accountId || null;\n this._rateLimiter = rateLimiter || new RateLimiter();\n this._isEnabled = _isDebugModeEnabled() || isLoggingEnabled;\n }\n\n send(\n url: string,\n severity: string,\n msg: string,\n code?: string,\n stackTrace?: string,\n onError?: (error: DeliveryError) => void,\n ): void {\n if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) {\n return;\n }\n\n try {\n const logRequest = {\n additionalInformation: {\n message: msg,\n version: this._integrationName,\n },\n severity,\n code: code || ErrorCodes.UNKNOWN_ERROR,\n url: _getReportingUrl(),\n deviceInfo: _getUserAgent(),\n stackTrace,\n reporter: this._reporter,\n integration: this._integrationName,\n };\n\n const headers: Record = {\n Accept: 'text/plain;charset=UTF-8',\n 'Content-Type': 'application/json',\n 'rokt-launcher-version': this._integrationName,\n 'rokt-wsdk-version': 'joint',\n };\n\n if (this._launcherInstanceGuid) {\n headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid;\n }\n if (this._accountId) {\n headers['rokt-account-id'] = this._accountId;\n }\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(logRequest),\n })\n .then((response: Response) => {\n // fetch only rejects on network failures; an HTTP 5xx resolves with\n // ok === false. Surface server-side failures so they are not swallowed.\n if (!response.ok) {\n const serverError: DeliveryError = new Error('HTTP ' + response.status + ' from log endpoint');\n serverError.statusCode = response.status;\n throw serverError;\n }\n })\n .catch((error: DeliveryError) => {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error);\n });\n } catch (error) {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error as DeliveryError);\n }\n }\n}\n\nclass ErrorReportingService {\n private _transport: ReportingTransport;\n private _errorUrl: string;\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._errorUrl = generateReportingUrl(config?.errorUrl, config?.integrationDomain, ERROR_ENDPOINT);\n }\n\n report(error: ErrorReport | null | undefined): void {\n if (!error) return;\n const severity = error.severity || WSDKErrorSeverity.ERROR;\n this._transport.send(this._errorUrl, severity, error.message, error.code, error.stackTrace);\n }\n}\n\nclass LoggingService {\n private _transport: ReportingTransport;\n private _loggingUrl: string;\n private _errorReportingService: { report: (e: ErrorReport) => void };\n\n constructor(\n config: ReportingConfig,\n errorReportingService: { report: (e: ErrorReport) => void },\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._loggingUrl = generateReportingUrl(config?.loggingUrl, config?.integrationDomain, LOGGING_ENDPOINT);\n this._errorReportingService = errorReportingService;\n }\n\n log(entry: LogEntry | null | undefined): void {\n if (!entry) return;\n this._transport.send(\n this._loggingUrl,\n WSDKErrorSeverity.INFO,\n entry.message,\n entry.code,\n undefined,\n (error: DeliveryError) => {\n if (this._errorReportingService) {\n // A failed log POST is not itself an SDK error. Network-level failures\n // (ad-blockers, offline, CORS) are client-side noise and reported as a\n // WARNING; only a server-side non-2xx response stays at ERROR severity.\n const isServerSide = typeof error.statusCode === 'number';\n this._errorReportingService.report({\n message: 'LoggingService: Failed to send log: ' + error.message,\n code: ErrorCodes.LOG_DELIVERY_FAILURE,\n severity: isServerSide ? WSDKErrorSeverity.ERROR : WSDKErrorSeverity.WARNING,\n });\n }\n },\n );\n }\n}\n\nfunction buildPageEvent(event: SDKEvent): PageEvent {\n const pageUrl = sanitizeUrl(window.location.href);\n const pageTitle = event.EventAttributes?.title || document.title;\n const canonicalUrl = readCanonicalUrl();\n const activeTimeOnSite = event.ActiveTimeOnSite;\n\n return {\n pageUrl,\n sourceMessageId: event.SourceMessageId,\n timestamp: event.Timestamp,\n ...(pageTitle ? { pageTitle } : {}),\n ...(canonicalUrl !== undefined ? { canonicalUrl } : {}),\n ...(Number.isFinite(activeTimeOnSite) ? { activeTimeOnSite } : {}),\n };\n}\n\n// ============================================================\n// RoktKit class\n// ============================================================\n\nclass RoktKit implements KitInterface {\n // Static field for allowed origin hashes (mutable by testHelpers)\n public static _allowedOriginHashes: number[] = [-553112570, 549508659];\n\n private static readonly PERFORMANCE_MARKS = {\n RoktScriptAppended: 'mp:RoktScriptAppended',\n };\n\n private static readonly EMAIL_SHA256_KEY = 'emailsha256';\n\n // Public fields (accessed by tests and the mParticle framework)\n public name = name;\n public id = moduleId;\n public moduleId = moduleId;\n public isInitialized = false;\n public launcher: RoktLauncher | null = null;\n public filters: KitFilters = {};\n public userAttributes: Record = {};\n // Flag set by the Workspace IDSync flow on a 200 response. Stored on the\n // kit instance and merged into placement attributes inside selectPlacements.\n public userIdentifiedInWorkspace = false;\n public testHelpers: TestHelpers | null = null;\n public placementEventMappingLookup: Record = {};\n public placementEventAttributeMappingLookup: Record = {};\n public integrationName: string | null = null;\n public domain?: string;\n public errorReportingService: ErrorReportingService | null = null;\n public loggingService: LoggingService | null = null;\n\n // Private fields\n private _mappedEmailSha256Key?: string;\n private _onboardingExpProvider?: string;\n private _thankYouElementOnLoadCallback: (() => void) | null = null;\n private _isThankYouElementLoaded = false;\n private _workspaceIdSyncApiKey?: string;\n\n // Held during a search dispatch so the next selectPlacements call;\n // can wait for the HTTP response before reading userIdentifiedInWorkspace;\n // — otherwise the first placement call ships without the flag.\n private _workspaceSearchInFlightPromise: Promise | null = null;\n // Stable serialization of the identifier set sent in the most recent\n // successful search dispatch. If a subsequent identification arrives with\n // an identical set, we skip the network call (the flag is still correct\n // from the prior search). Keyed over the full IUserIdentities map — not\n // just email — so partners passing hashed email through `other`/`other2-10`\n // or any other identifier benefit from the same dedupe. Cleared on logout\n // so a re-login re-evaluates fresh.\n private _workspaceLastSearchedIdentitiesKey?: string;\n\n // ---- Private helpers ----\n\n private getEventAttributeValue(event: SDKEvent, eventAttributeKey: string): unknown {\n const attributes = event && event.EventAttributes;\n if (!attributes) {\n return null;\n }\n\n if (typeof attributes[eventAttributeKey] === 'undefined') {\n return null;\n }\n\n return attributes[eventAttributeKey];\n }\n\n private doesEventAttributeConditionMatch(condition: EventAttributeCondition, actualValue: unknown): boolean {\n if (!condition || !isString(condition.operator)) {\n return false;\n }\n\n const operator = condition.operator.toLowerCase();\n const expectedValue = condition.attributeValue;\n\n if (operator === 'exists') {\n return actualValue !== null;\n }\n\n if (actualValue == null) {\n return false;\n }\n\n if (operator === 'equals') {\n return String(actualValue) === String(expectedValue);\n }\n\n if (operator === 'contains') {\n return String(actualValue).indexOf(String(expectedValue)) !== -1;\n }\n\n return false;\n }\n\n private doesEventMatchRule(event: SDKEvent, rule: PlacementEventRule): boolean {\n if (!rule || !isString(rule.eventAttributeKey)) {\n return false;\n }\n\n const conditions = rule.conditions;\n if (!Array.isArray(conditions)) {\n return false;\n }\n\n const actualValue = this.getEventAttributeValue(event, rule.eventAttributeKey);\n\n if (conditions.length === 0) {\n return actualValue !== null;\n }\n for (let i = 0; i < conditions.length; i++) {\n if (!this.doesEventAttributeConditionMatch(conditions[i], actualValue)) {\n return false;\n }\n }\n\n return true;\n }\n\n private applyPlacementEventAttributeMapping(event: SDKEvent): void {\n const mappedAttributeKeys = Object.keys(this.placementEventAttributeMappingLookup);\n for (let i = 0; i < mappedAttributeKeys.length; i++) {\n const mappedAttributeKey = mappedAttributeKeys[i];\n const rulesForMappedAttributeKey = this.placementEventAttributeMappingLookup[mappedAttributeKey];\n if (isEmpty(rulesForMappedAttributeKey)) {\n continue;\n }\n\n // Require ALL rules for the same key to match (AND).\n let allMatch = true;\n for (let j = 0; j < rulesForMappedAttributeKey.length; j++) {\n if (!this.doesEventMatchRule(event, rulesForMappedAttributeKey[j])) {\n allMatch = false;\n break;\n }\n }\n if (!allMatch) {\n continue;\n }\n\n mp().Rokt.setLocalSessionAttribute?.(mappedAttributeKey, true);\n }\n }\n\n private capturePageView(event: SDKEvent): void {\n let pageUrl: string | undefined;\n\n try {\n pageUrl = sanitizeUrl(window.location.href);\n\n const pageViews = loadPageViews(this.loggingService);\n const pageView = buildPageEvent(event);\n pageViews.push(pageView);\n\n const requested = Math.min(pageViews.length, PAGE_VIEWS_MAX_COUNT);\n const stored = writePageViews(pageViews);\n if (stored === 0) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n this.loggingService?.log({\n message: `Rokt Kit: Failed to persist page view for ${pageUrl} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n } else if (stored < requested) {\n this.loggingService?.log({\n message: `Rokt Kit: Page view storage reduced from ${requested} to ${stored} record(s) under quota pressure [reason: quota_eviction]`,\n code: 'PAGE_VIEW_QUOTA_EVICTION',\n });\n }\n } catch (err) {\n const reason = isLocalStorageAvailable() ? 'exception' : 'ls_unavailable';\n const errMessage = err instanceof Error ? err.message : String(err);\n this.loggingService?.log({\n message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${errMessage} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n private isLauncherReadyToAttach(): boolean {\n return !!window.Rokt && isFunction(window.Rokt.createLauncher);\n }\n\n /**\n * Returns the user identities from the filtered user, if any.\n */\n private returnUserIdentities(filteredUser: FilteredUser | null | undefined): Record {\n if (!filteredUser || !filteredUser.getUserIdentities) {\n return {};\n }\n\n const userIdentities: IUserIdentities = filteredUser.getUserIdentities().userIdentities;\n\n return this.replaceOtherIdentityWithEmailsha256(userIdentities);\n }\n\n private returnLocalSessionAttributes(): Record {\n if (!mp().Rokt || typeof mp().Rokt.getLocalSessionAttributes !== 'function') {\n return {};\n }\n return mp().Rokt.getLocalSessionAttributes!();\n }\n\n private replaceOtherIdentityWithEmailsha256(userIdentities: IUserIdentities): Record {\n const newUserIdentities: Record = { ...(userIdentities || {}) };\n const key = this._mappedEmailSha256Key;\n if (key && userIdentities[key as keyof IUserIdentities]) {\n newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key as keyof IUserIdentities] as string;\n }\n if (key) {\n delete newUserIdentities[key];\n }\n\n return newUserIdentities;\n }\n\n private logSelectPlacementsEvent(attributes: unknown): void {\n if (!window.mParticle || typeof mp().logEvent !== 'function') {\n return;\n }\n\n if (!isObject(attributes)) {\n return;\n }\n\n const EVENT_TYPE_OTHER = mp().EventType.Other;\n\n mp().logEvent(EVENT_NAME_SELECT_PLACEMENTS, EVENT_TYPE_OTHER, attributes as Record);\n }\n\n private setRoktSessionId(sessionId: string): void {\n if (!sessionId || typeof sessionId !== 'string') {\n return;\n }\n try {\n const mpInstance = mp().getInstance();\n if (mpInstance && isFunction(mpInstance.setIntegrationAttribute)) {\n mpInstance.setIntegrationAttribute(moduleId, {\n roktSessionId: sessionId,\n });\n }\n } catch (_e) {\n // Best effort — never let this break the partner page\n }\n }\n\n private readMpSessionId(): string | undefined {\n // The public mParticle.sessionManager facade exposes only getSession(), which already returns\n // the session id. getSessionId() lives on the internal _SessionManager and has never been\n // re-exported, so prefer it if a future core adds it and fall back to getSession() until then.\n const sessionManager = mp()?.sessionManager;\n const readSessionId = sessionManager?.getSessionId ?? sessionManager?.getSession;\n if (!isFunction(readSessionId)) {\n return undefined;\n }\n\n return readSessionId.call(sessionManager) || undefined;\n }\n\n private readMpDeviceId(): string | undefined {\n // The device application stamp (`das`) outlives the session id: core clears the session on\n // timeout, cross-tab rotation and endSession(), but never the device id, which lives in\n // localStorage/cookie for cookieExpiration days (365 by default) and survives login/logout.\n // Read it per call anyway — a partner can reassign it at any time via setDeviceId().\n return mp()?.getDeviceId?.() || undefined;\n }\n\n private attachLauncher(\n accountId: string,\n launcherOptions: Record,\n legacyRoktExtensions: string[] = [],\n ): void {\n const options: Record = {\n accountId,\n ...(launcherOptions || {}),\n };\n\n let launcherPromise: Promise;\n if (this.isPartnerInLocalLauncherTestGroup()) {\n launcherPromise = Promise.resolve(window.Rokt!.createLocalLauncher(options));\n } else {\n launcherPromise = window.Rokt!.createLauncher(options);\n }\n\n launcherPromise\n .then(async (launcher) => {\n await registerLegacyExtensions(legacyRoktExtensions, launcher);\n this.initRoktLauncher(launcher);\n })\n .catch((err: unknown) => {\n console.error('Error creating Rokt launcher:', err);\n });\n }\n\n private initRoktLauncher(launcher: RoktLauncher): void {\n // Assign the launcher to a global variable for later access\n if (window.Rokt) {\n window.Rokt.currentLauncher = launcher;\n }\n // Locally cache the launcher and filters\n this.launcher = launcher;\n\n const roktFilters = mp().Rokt?.filters;\n\n if (!roktFilters) {\n console.warn('Rokt Kit: No filters have been set.');\n } else {\n this.filters = roktFilters;\n if (!roktFilters.filteredUser) {\n console.warn('Rokt Kit: No filtered user has been set.');\n } else {\n this._workspaceSearchInFlightPromise = this.search(roktFilters.filteredUser);\n }\n }\n\n // Kit must be initialized before attaching to the Rokt manager\n this.isInitialized = true;\n\n sendAdBlockMeasurementSignals(this.domain, this.integrationName);\n\n // Attaches the kit to the Rokt manager\n mp().Rokt.attachKit(this);\n }\n\n private fetchOptimizely(): Record {\n const forwarders = mp()\n ._getActiveForwarders()\n .filter((forwarder) => forwarder.name === 'Optimizely');\n\n try {\n if (forwarders.length > 0 && window.optimizely) {\n const optimizelyState = window.optimizely.get('state');\n if (!optimizelyState || !optimizelyState.getActiveExperimentIds) {\n return {};\n }\n const activeExperimentIds = optimizelyState.getActiveExperimentIds();\n const activeExperiments = activeExperimentIds.reduce((acc: Record, expId: string) => {\n acc['rokt.custom.optimizely.experiment.' + expId + '.variationId'] =\n optimizelyState.getVariationMap()[expId].id;\n return acc;\n }, {});\n return activeExperiments;\n }\n } catch (error) {\n console.error('Error fetching Optimizely attributes:', error);\n }\n return {};\n }\n\n private isKitReady(): boolean {\n return !!(this.isInitialized && this.launcher);\n }\n\n // When the partner has opted out of targeting (noTargeting launcher option),\n // the kit must not collect behavioral targeting signals such as page views.\n private isTargetingDisabled(): boolean {\n return (mp().Rokt?.launcherOptions as Record | undefined)?.noTargeting === true;\n }\n\n private isPartnerInLocalLauncherTestGroup(): boolean {\n return !!(mp().config && mp().config!.isLocalLauncherEnabled && this.isAssignedToSampleGroup());\n }\n\n private isAssignedToSampleGroup(): boolean {\n const LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5;\n return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD;\n }\n\n private captureTiming(metricName: string): void {\n if (window && mp() && mp().captureTiming && metricName) {\n mp().captureTiming!(metricName);\n }\n }\n\n // ---- Public methods (mParticle Kit Callbacks) ----\n\n /**\n * Initializes the Rokt forwarder with settings from the mParticle server.\n */\n public init(\n settings: Record,\n _service: unknown,\n testMode: boolean,\n _trackerId: unknown,\n filteredUserAttributes?: Record,\n ): string {\n const kitSettings = settings as unknown as RoktKitSettings;\n const accountId = kitSettings.accountId;\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredUserAttributes);\n this._onboardingExpProvider = kitSettings.onboardingExpProvider;\n\n const placementEventMapping = parseSettingsString(kitSettings.placementEventMapping);\n this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping);\n\n const placementEventAttributeMapping = parseSettingsString(\n kitSettings.placementEventAttributeMapping,\n );\n this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping);\n\n // Set dynamic OTHER_IDENTITY based on server settings\n if (kitSettings.hashedEmailUserIdentityType) {\n this._mappedEmailSha256Key = kitSettings.hashedEmailUserIdentityType.toLowerCase();\n }\n\n this._workspaceIdSyncApiKey = isString(kitSettings.workspaceIdSyncApiKey)\n ? kitSettings.workspaceIdSyncApiKey\n : undefined;\n\n const domain = mp().Rokt?.domain;\n const { roktExtensionsQueryParams, legacyRoktExtensions, loadThankYouElement } = extractRoktExtensionConfig(\n kitSettings.roktExtensions,\n );\n const launcherOptions: Record = {\n ...((mp().Rokt?.launcherOptions as Record) || {}),\n };\n this.integrationName = generateIntegrationName(launcherOptions.integrationName as string | undefined);\n launcherOptions.integrationName = this.integrationName;\n\n this.domain = domain;\n\n const reportingConfig: ReportingConfig = {\n loggingUrl: kitSettings.loggingUrl,\n errorUrl: kitSettings.errorUrl,\n integrationDomain: domain,\n isLoggingEnabled: mp().config?.isLoggingEnabled === true,\n };\n const errorReportingService = new ErrorReportingService(\n reportingConfig,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n const loggingService = new LoggingService(\n reportingConfig,\n errorReportingService,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n\n this.errorReportingService = errorReportingService;\n this.loggingService = loggingService;\n\n if (this.isTargetingDisabled()) {\n try {\n clearPageViews();\n clearUtmParams();\n } catch (err) {\n this.errorReportingService?.report({\n message: 'Rokt Kit: Failed to clear page views when targeting is disabled',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n severity: WSDKErrorSeverity.INFO,\n stackTrace: err instanceof Error ? err.stack : undefined,\n });\n }\n }\n\n if (mp()._registerErrorReportingService) {\n mp()._registerErrorReportingService!(errorReportingService);\n }\n if (mp()._registerLoggingService) {\n mp()._registerLoggingService!(loggingService);\n }\n\n if (testMode) {\n this.testHelpers = {\n generateLauncherScript: generateLauncherScript,\n generateThankYouElementScript: generateThankYouElementScript,\n extractRoktExtensionConfig: extractRoktExtensionConfig,\n hashEventMessage: hashEventMessage,\n parseSettingsString: parseSettingsString,\n generateMappedEventLookup: generateMappedEventLookup,\n generateMappedEventAttributeLookup: generateMappedEventAttributeLookup,\n sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals,\n createAutoRemovedIframe: createAutoRemovedIframe,\n djb2: djb2,\n setAllowedOriginHashes: (hashes: number[]) => {\n RoktKit._allowedOriginHashes = hashes;\n },\n ReportingTransport: ReportingTransport,\n ErrorReportingService: ErrorReportingService,\n LoggingService: LoggingService,\n RateLimiter: RateLimiter,\n ErrorCodes: ErrorCodes,\n WSDKErrorSeverity: WSDKErrorSeverity,\n };\n this.attachLauncher(accountId, launcherOptions);\n return 'Successfully initialized: ' + name;\n }\n\n if (loadThankYouElement) {\n mp().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this);\n loadRoktScript(ROKT_THANK_YOU_ELEMENT_SCRIPT_ID, generateThankYouElementScript(domain), {\n onLoad: () => {\n this._isThankYouElementLoaded = true;\n if (this._thankYouElementOnLoadCallback) {\n this._thankYouElementOnLoadCallback();\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt Thank You Element script:', error);\n },\n });\n }\n\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n loadRoktScript(ROKT_INTEGRATION_SCRIPT_ID, generateLauncherScript(domain, roktExtensionsQueryParams), {\n onLoad: () => {\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n console.error('Rokt object is not available after script load.');\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt launcher script:', error);\n },\n });\n\n this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended);\n }\n\n return 'Successfully initialized: ' + name;\n }\n\n public process(event: SDKEvent): string {\n if (!this.isTargetingDisabled()) {\n if (event.EventDataType === MESSAGE_TYPE_PAGE_VIEW) {\n captureUtmParams(this.loggingService);\n this.capturePageView(event);\n }\n\n if (event.EventDataType === MESSAGE_TYPE_SESSION_END) {\n migrateLegacyPageViewStorage(this.loggingService);\n clearPageViews();\n clearUtmParams();\n }\n }\n\n // The forwarding work below (LSA mapping) depends on the launcher, so guard\n // it here and surface the not-ready signal to the core SDK.\n if (!this.isKitReady()) {\n return 'Kit not ready for forwarder: ' + name;\n }\n\n if (isFunction(mp().Rokt?.setLocalSessionAttribute)) {\n if (!isEmpty(this.placementEventAttributeMappingLookup)) {\n this.applyPlacementEventAttributeMapping(event);\n }\n\n if (!isEmpty(this.placementEventMappingLookup)) {\n const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? '');\n if (this.placementEventMappingLookup[String(hashedEvent)]) {\n mp().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(hashedEvent)], true);\n }\n }\n }\n\n return 'Successfully sent to forwarder: ' + name;\n }\n\n public setExtensionData(partnerExtensionData: Record): void {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return;\n }\n\n window.Rokt!.setExtensionData(partnerExtensionData);\n }\n\n public setUserAttribute(key: string, value: unknown): string {\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n this.userAttributes[key] = value;\n }\n return 'Successfully set user attribute for forwarder: ' + name;\n }\n\n public removeUserAttribute(key: string): string {\n delete this.userAttributes[key];\n return 'Successfully removed user attribute for forwarder: ' + name;\n }\n\n private handleIdentityComplete(user: IMParticleUser, callbackName: string): string {\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(user.getAllUserAttributes());\n return 'Successfully called ' + callbackName + ' for forwarder: ' + name;\n }\n\n public onUserIdentified(user: IMParticleUser): string {\n const filteredUser = user as FilteredUser;\n this.filters.filteredUser = filteredUser;\n this._workspaceSearchInFlightPromise = this.search(filteredUser);\n return this.handleIdentityComplete(user, 'onUserIdentified');\n }\n\n private search(filteredUser: FilteredUser): Promise {\n const apiKey = this._workspaceIdSyncApiKey;\n if (!apiKey) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n const search = mp().Identity?.search;\n if (typeof search !== 'function') {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n const userIdentities: IUserIdentities | null = filteredUser.getUserIdentities\n ? filteredUser.getUserIdentities().userIdentities\n : null;\n\n // Forward every non-empty string identifier the user has — email,\n // customerid, other/other2-10 (commonly used for hashed email),\n // mobile_number, facebook, etc. The host SDK's Identity.search accepts\n // the full IUserIdentities surface and the server validates it.\n const knownIdentities: Record = {};\n if (userIdentities) {\n for (const key of Object.keys(userIdentities) as Array) {\n const value = userIdentities[key];\n if (isString(value) && value.length > 0) {\n knownIdentities[key] = value;\n }\n }\n }\n\n const identityKeys = Object.keys(knownIdentities);\n if (identityKeys.length === 0) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n // Stable cache key: sort keys so insertion-order differences don't\n // cause false misses. The values are partner-supplied strings; no\n // hashing needed — equality on this serialization is sufficient.\n const identitiesKey = identityKeys\n .sort()\n .map((k) => `${k}=${knownIdentities[k]}`)\n .join('&');\n\n // Same identifier set as the last successful dispatch → skip the\n // network call. The current flag value still reflects the correct\n // match status.\n if (identitiesKey === this._workspaceLastSearchedIdentitiesKey) {\n return this._workspaceSearchInFlightPromise || Promise.resolve();\n }\n\n // New / different identifier set → reset and re-search. Cache the key\n // up front so a second concurrent invocation with the same set also\n // dedupes.\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = identitiesKey;\n\n return new Promise((resolve) => {\n try {\n search(apiKey, knownIdentities as IUserIdentities, (result: WorkspaceIdSyncResult) => {\n if (result?.httpCode === 200) {\n this.userIdentifiedInWorkspace = true;\n }\n resolve();\n });\n } catch (err) {\n console.error('Rokt Kit: Workspace IDSync search failed', err);\n // Dispatch failed — clear the cache so the same identifier set\n // can retry on the next identification rather than being stuck\n // behind a poisoned entry that short-circuits future searches.\n this._workspaceLastSearchedIdentitiesKey = undefined;\n resolve();\n }\n });\n }\n\n public onLoginComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onLoginComplete');\n }\n\n public onLogoutComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n // Anonymous sessions must not carry the previous user's match forward.\n // Clear the flag explicitly here. Also clear the identities cache so a\n // re-login (possibly with the same identifiers) dispatches a fresh\n // search rather than reusing a stale answer.\n this.userIdentifiedInWorkspace = false;\n this._workspaceSearchInFlightPromise = null;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return this.handleIdentityComplete(user, 'onLogoutComplete');\n }\n\n public onModifyComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onModifyComplete');\n }\n\n /**\n * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options.\n *\n * If a Workspace IDSync search is in flight from a recent onUserIdentified\n * call, this method waits up to `WORKSPACE_SEARCH_SELECT_TIMEOUT_MS` for it\n * to settle so the first placement call can include the\n * `userIdentifiedInWorkspace` flag without racing the network response.\n * The timeout protects against a stalled or slow search blocking placement\n * rendering — if it fires, selectPlacements proceeds without the flag.\n *\n * Implementation note: this method stays non-async deliberately. First,\n * the public return type is `RoktSelection | Promise |\n * undefined` — a superset of the `RoktSelection | Promise`\n * shape declared for `RoktLauncher.selectPlacements` above (line ~70).\n * Marking this `async` would narrow it to `Promise` and silently change the contract for callers that read\n * the result synchronously. Second, `RoktSelection` has an optional\n * `then?` member, so TS treats it as ambiguously promise-like and\n * rejects it as the awaited return of an async function (TS1058) —\n * working around that would require a cast or wrapping every return in\n * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`;\n * this wrapper just gates it on the in-flight search via `Promise.race`.\n */\n public selectPlacements(options: Record): RoktSelection | Promise | undefined {\n if (this._workspaceSearchInFlightPromise) {\n const inFlight = this._workspaceSearchInFlightPromise;\n return Promise.race([\n inFlight,\n new Promise((resolve) => setTimeout(resolve, WORKSPACE_SEARCH_SELECT_TIMEOUT_MS)),\n ]).then(() => this._dispatchPlacements(options)) as Promise;\n }\n return this._dispatchPlacements(options);\n }\n\n private _dispatchPlacements(options: Record): RoktSelection | Promise | undefined {\n const attributes = ((options && (options.attributes as Record)) || {}) as Record;\n const cachedUserAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(this.userAttributes);\n const placementAttributes: Record = { ...cachedUserAttributes, ...attributes };\n\n const filters = this.filters || {};\n const userAttributeFilters = (filters.userAttributeFilters as string[]) || [];\n const filteredUser = filters.filteredUser || null;\n const mpid = filteredUser ? filteredUser.getMPID() : null;\n\n let filteredAttributes: Record;\n\n if (!filters) {\n console.warn('Rokt Kit: No filters available, using user attributes');\n filteredAttributes = placementAttributes;\n } else if (filters.filterUserAttributes) {\n filteredAttributes = filters.filterUserAttributes(placementAttributes, userAttributeFilters);\n } else {\n filteredAttributes = placementAttributes;\n }\n\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredAttributes);\n\n const optimizelyAttributes = this._onboardingExpProvider === 'Optimizely' ? this.fetchOptimizely() : {};\n\n const filteredUserIdentities = this.returnUserIdentities(filteredUser);\n\n const sessionAttributes = this.returnLocalSessionAttributes();\n const pageEvents = buildPageEvents(loadPageViews(this.loggingService));\n const utmParams = loadUtmParams();\n const mpSessionId = this.readMpSessionId();\n const mpDeviceId = this.readMpDeviceId();\n\n const selectPlacementsAttributes: Record = {\n ...(filteredUserIdentities as Record),\n ...filteredAttributes,\n ...optimizelyAttributes,\n ...sessionAttributes,\n ...(pageEvents.length ? { [PAGE_EVENTS_KEY]: JSON.stringify(pageEvents) } : {}),\n ...(utmParams ? { [PAGE_VIEW_ATTRIBUTES_KEY]: utmParams } : {}),\n ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}),\n ...(mpSessionId ? { [MPARTICLE_SESSION_ID_KEY]: mpSessionId } : {}),\n ...(mpDeviceId ? { [MPARTICLE_DEVICE_ID_KEY]: mpDeviceId } : {}),\n mpid,\n };\n\n const selectPlacementsOptions: Record = { ...options, attributes: selectPlacementsAttributes };\n\n const selection = this.launcher!.selectPlacements(selectPlacementsOptions);\n\n // After selection resolves, sync the Rokt session ID back to mParticle, then log\n const logSelection = () => this.logSelectPlacementsEvent(selectPlacementsAttributes);\n\n void Promise.resolve(selection)\n .then((sel) => sel?.context?.sessionId?.then((sessionId) => this.setRoktSessionId(sessionId)))\n .catch(() => undefined)\n .finally(logSelection);\n\n return selection;\n }\n\n /**\n * Passes attributes to the Rokt Web SDK for client-side hashing.\n */\n public hashAttributes(attributes: Record): Promise> | null {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return null;\n }\n return this.launcher!.hashAttributes(attributes);\n }\n\n /**\n * Enables optional Integration Launcher extensions before selecting placements.\n *\n * @deprecated This functionality has been internalized and will be removed in a future release.\n */\n public use(extensionName: string): Promise {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return Promise.reject(new Error('Rokt Kit: Not initialized'));\n }\n if (!extensionName || !isString(extensionName)) {\n return Promise.reject(new Error('Rokt Kit: Invalid extension name'));\n }\n return this.launcher!.use(extensionName);\n }\n\n /**\n * Registers a callback to be invoked once rokt-thank-you-element.js becomes available.\n */\n public onShoppableAdsReady(callback: () => void) {\n if (this._isThankYouElementLoaded) {\n callback();\n } else {\n this._thankYouElementOnLoadCallback = callback;\n }\n }\n}\n\n// ============================================================\n// Kit registration\n// ============================================================\n\nfunction getId(): number {\n return moduleId;\n}\n\nfunction register(config: { kits?: Record }): void {\n if (!config) {\n window.console.log('You must pass a config object to register the kit ' + name);\n return;\n }\n if (!isObject(config)) {\n window.console.log(\"'config' must be an object. You passed in a \" + typeof config);\n return;\n }\n\n if (isObject(config.kits)) {\n (config.kits as Record)[name] = {\n constructor: RoktKit,\n };\n } else {\n config.kits = {};\n config.kits[name] = {\n constructor: RoktKit,\n };\n }\n window.console.log('Successfully registered ' + name + ' to your mParticle configuration');\n}\n\nif (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) {\n mp().addForwarder({\n name: name,\n constructor: RoktKit,\n getId: getId,\n });\n}\n\nexport { register };\nexport type { LoggingService };\n"],"names":["SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST","SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET","isSelectPlacementsAttributePersistenceDenied","key","removeSelectPlacementsAttributePersistenceDeniedAttributes","attributes","filteredAttributes","sourceAttributes","attributeKeys","i","isObject","value","isString","isFunction","isEmpty","sanitizeUrl","href","url","LS_PROBE_KEY","isLocalStorageAvailable","readJSON","stored","writeJSON","removeKey","readNamespacedField","namespaceKey","field","blob","writeNamespacedField","next","removeNamespacedField","LS_NAMESPACE_KEY","LS_PAGE_VIEWS_FIELD","LS_UTM_PARAMS_FIELD","LEGACY_PAGE_VIEWS_KEY","PAGE_VIEWS_MAX_COUNT","UTM_KEYS","capPageViews","views","migrateLegacyPageViewStorage","loggingService","legacyViews","loadPageViews","writePageViews","pageViews","toWrite","clearPageViews","buildPageEvents","pageView","index","activeTimeOnSite","hasActiveTime","nextActiveTimeOnSite","hasNextActiveTimeOnSite","diff","captureUtmParams","search","params","captured","reason","loadUtmParams","clearUtmParams","readCanonicalUrl","name","moduleId","EVENT_NAME_SELECT_PLACEMENTS","ADBLOCK_CONTROL_DOMAIN","INIT_LOG_SAMPLING_RATE","ROKT_THANK_YOU_JOURNEY_EXTENSION","ROKT_INTEGRATION_SCRIPT_ID","ROKT_THANK_YOU_ELEMENT_SCRIPT_ID","USER_IDENTIFIED_IN_WORKSPACE_KEY","MESSAGE_TYPE_PAGE_VIEW","MESSAGE_TYPE_SESSION_END","PAGE_EVENTS_KEY","PAGE_VIEW_ATTRIBUTES_KEY","MPARTICLE_SESSION_ID_KEY","MPARTICLE_DEVICE_ID_KEY","WORKSPACE_SEARCH_SELECT_TIMEOUT_MS","ErrorCodes","WSDKErrorSeverity","DEFAULT_ROKT_DOMAIN","LOGGING_ENDPOINT","ERROR_ENDPOINT","RATE_LIMIT_PER_SEVERITY","mp","generateLauncherScript","domain","extensions","baseUrl","generateBaseUrl","generateThankYouElementScript","resolvedDomain","generateReportingUrl","configuredUrl","endpoint","reportingDomain","loadRoktScript","scriptId","source","handlers","target","script","parseSettingsString","settingsString","extractRoktExtensionConfig","settings","roktExtensionsQueryParams","legacyRoktExtensions","loadThankYouElement","extensionName","registerLegacyExtensions","legacyExtensions","launcher","extension","generateMappedEventLookup","placementEventMapping","mappedEvents","mapping","generateMappedEventAttributeLookup","placementEventAttributeMapping","mappedAttributeKeys","mappedAttributeKey","eventAttributeKey","hashEventMessage","messageType","eventType","eventName","generateIntegrationName","customIntegrationName","integrationName","djb2","str","hash","createAutoRemovedIframe","src","iframe","sendAdBlockMeasurementSignals","version","originHash","RoktKit","guid","pageUrl","existingBaseUrl","_isDebugModeEnabled","_getReportingUrl","_getUserAgent","RateLimiter","severity","newCount","ReportingTransport","config","launcherInstanceGuid","accountId","rateLimiter","isLoggingEnabled","msg","code","stackTrace","onError","logRequest","headers","response","serverError","error","ErrorReportingService","LoggingService","errorReportingService","entry","isServerSide","buildPageEvent","event","pageTitle","canonicalUrl","_RoktKit","condition","actualValue","operator","expectedValue","rule","conditions","rulesForMappedAttributeKey","allMatch","j","requested","err","errMessage","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","sessionManager","readSessionId","launcherOptions","options","launcherPromise","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","sessionAttributes","pageEvents","utmParams","mpSessionId","mpDeviceId","selectPlacementsAttributes","selectPlacementsOptions","selection","logSelection","sel","callback","getId","register"],"mappings":"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"} \ No newline at end of file diff --git a/kits/rokt/dist/Rokt-Kit.iife.js b/kits/rokt/dist/Rokt-Kit.iife.js index fbe239f74..374d5a999 100644 --- a/kits/rokt/dist/Rokt-Kit.iife.js +++ b/kits/rokt/dist/Rokt-Kit.iife.js @@ -1,3 +1,2 @@ -console.info('[mParticle QA kit path smoke] Loaded kits/rokt/dist/Rokt-Kit.iife.js from monorepo GitHub path'); -var RoktKit=(function(v){"use strict";const J=["billingaddress1","billingaddress2","billingcity","billingstate","billingzipcode","cartitems","ccbin","confirmationref","conversiontype","country","couponcode","currency","language","paymentserviceprovider","paymentserviceproviderattribute","paymenttype","shippingaddress1","shippingcity","shippingcountry","shippingmethod","shippingstate","shippingzipcode","totalprice"],Q=new Set(J);function K(n){return Q.has(n.toLowerCase())}function R(n){const t={},e=n||{},i=Object.keys(e);for(let r=0;r=Z)return;const r=window.__rokt_li_guid__;if(!r)return;const s=window.location.href.split("?")[0].split("#")[0],o="version="+encodeURIComponent(t??"")+"&launcherInstanceGuid="+encodeURIComponent(r)+"&pageUrl="+encodeURIComponent(s);P("https://"+(n||"apps.rokt.com")+"/v1/wsdk-init/index.html?"+o),P("https://"+$+"/v1/wsdk-init/index.html?"+o+"&isControl=true")}function dt(){return typeof window<"u"&&!!window.location?.search?.toLowerCase().includes("mp_enable_logging=true")}function ht(){return typeof window<"u"?window.location?.href:void 0}function pt(){return typeof window<"u"?window.navigator?.userAgent:void 0}class V{constructor(){this._logCount={}}incrementAndCheck(t){const i=(this._logCount[t]||0)+1;return this._logCount[t]=i,i>ct}}class C{constructor(t,e,i,r,s){this._reporter="mp-wsdk";const o=t.isLoggingEnabled;this._integrationName=e||"",this._launcherInstanceGuid=i,this._accountId=r||null,this._rateLimiter=s||new V,this._isEnabled=dt()||o}send(t,e,i,r,s,o){if(!(!this._isEnabled||this._rateLimiter.incrementAndCheck(e)))try{const c={additionalInformation:{message:i,version:this._integrationName},severity:e,code:r||T.UNKNOWN_ERROR,url:ht(),deviceInfo:pt(),stackTrace:s,reporter:this._reporter,integration:this._integrationName},u={Accept:"text/plain;charset=UTF-8","Content-Type":"application/json","rokt-launcher-version":this._integrationName,"rokt-wsdk-version":"joint"};this._launcherInstanceGuid&&(u["rokt-launcher-instance-guid"]=this._launcherInstanceGuid),this._accountId&&(u["rokt-account-id"]=this._accountId),fetch(t,{method:"POST",headers:u,body:JSON.stringify(c)}).then(l=>{if(!l.ok){const h=new Error("HTTP "+l.status+" from log endpoint");throw h.statusCode=l.status,h}}).catch(l=>{console.error("ReportingTransport: Failed to send log",l),o&&o(l)})}catch(c){console.error("ReportingTransport: Failed to send log",c),o&&o(c)}}}class q{constructor(t,e,i,r,s){this._transport=new C(t,e,i,r,s),this._errorUrl=Y(t?.errorUrl,t?.integrationDomain,at)}report(t){if(!t)return;const e=t.severity||_.ERROR;this._transport.send(this._errorUrl,e,t.message,t.code,t.stackTrace)}}class B{constructor(t,e,i,r,s,o){this._transport=new C(t,i,r,s,o),this._loggingUrl=Y(t?.loggingUrl,t?.integrationDomain,ot),this._errorReportingService=e}log(t){t&&this._transport.send(this._loggingUrl,_.INFO,t.message,t.code,void 0,e=>{if(this._errorReportingService){const i=typeof e.statusCode=="number";this._errorReportingService.report({message:"LoggingService: Failed to send log: "+e.message,code:T.LOG_DELIVERY_FAILURE,severity:i?_.ERROR:_.WARNING})}})}}const p=class p{constructor(){this.name=d,this.id=A,this.moduleId=A,this.isInitialized=!1,this.launcher=null,this.filters={},this.userAttributes={},this.userIdentifiedInWorkspace=!1,this.testHelpers=null,this.placementEventMappingLookup={},this.placementEventAttributeMappingLookup={},this.integrationName=null,this.errorReportingService=null,this.loggingService=null,this._thankYouElementOnLoadCallback=null,this._isThankYouElementLoaded=!1,this._workspaceSearchInFlightPromise=null}getEventAttributeValue(t,e){const i=t&&t.EventAttributes;return!i||typeof i[e]>"u"?null:i[e]}doesEventAttributeConditionMatch(t,e){if(!t||!g(t.operator))return!1;const i=t.operator.toLowerCase(),r=t.attributeValue;return i==="exists"?e!==null:e==null?!1:i==="equals"?String(e)===String(r):i==="contains"?String(e).indexOf(String(r))!==-1:!1}doesEventMatchRule(t,e){if(!e||!g(e.eventAttributeKey))return!1;const i=e.conditions;if(!Array.isArray(i))return!1;const r=this.getEventAttributeValue(t,e.eventAttributeKey);if(i.length===0)return r!==null;for(let s=0;s{await lt(i,c),this.initRoktLauncher(c)}).catch(c=>{console.error("Error creating Rokt launcher:",c)})}initRoktLauncher(t){window.Rokt&&(window.Rokt.currentLauncher=t),this.launcher=t;const e=a().Rokt?.filters;e?(this.filters=e,e.filteredUser?this._workspaceSearchInFlightPromise=this.search(e.filteredUser):console.warn("Rokt Kit: No filtered user has been set.")):console.warn("Rokt Kit: No filters have been set."),this.isInitialized=!0,z(this.domain,this.integrationName),a().Rokt.attachKit(this)}fetchOptimizely(){const t=a()._getActiveForwarders().filter(e=>e.name==="Optimizely");try{if(t.length>0&&window.optimizely){const e=window.optimizely.get("state");return!e||!e.getActiveExperimentIds?{}:e.getActiveExperimentIds().reduce((s,o)=>(s["rokt.custom.optimizely.experiment."+o+".variationId"]=e.getVariationMap()[o].id,s),{})}}catch(e){console.error("Error fetching Optimizely attributes:",e)}return{}}isKitReady(){return!!(this.isInitialized&&this.launcher)}isPartnerInLocalLauncherTestGroup(){return!!(a().config&&a().config.isLocalLauncherEnabled&&this.isAssignedToSampleGroup())}isAssignedToSampleGroup(){return Math.random()>.5}captureTiming(t){window&&a()&&a().captureTiming&&t&&a().captureTiming(t)}init(t,e,i,r,s){const o=t,c=o.accountId;this.userAttributes=R(s),this._onboardingExpProvider=o.onboardingExpProvider;const u=S(o.placementEventMapping);this.placementEventMappingLookup=F(u);const l=S(o.placementEventAttributeMapping);this.placementEventAttributeMappingLookup=H(l),o.hashedEmailUserIdentityType&&(this._mappedEmailSha256Key=o.hashedEmailUserIdentityType.toLowerCase()),this._workspaceIdSyncApiKey=g(o.workspaceIdSyncApiKey)?o.workspaceIdSyncApiKey:void 0;const h=a().Rokt?.domain,{roktExtensionsQueryParams:U,legacyRoktExtensions:w,loadThankYouElement:b}=j(o.roktExtensions),f={...a().Rokt?.launcherOptions||{}};this.integrationName=ut(f.integrationName),f.integrationName=this.integrationName,this.domain=h;const k={loggingUrl:o.loggingUrl,errorUrl:o.errorUrl,integrationDomain:h,isLoggingEnabled:a().config?.isLoggingEnabled===!0},I=new q(k,this.integrationName,window.__rokt_li_guid__,o.accountId),L=new B(k,I,this.integrationName,window.__rokt_li_guid__,o.accountId);return this.errorReportingService=I,this.loggingService=L,a()._registerErrorReportingService&&a()._registerErrorReportingService(I),a()._registerLoggingService&&a()._registerLoggingService(L),i?(this.testHelpers={generateLauncherScript:M,generateThankYouElementScript:D,extractRoktExtensionConfig:j,hashEventMessage:W,parseSettingsString:S,generateMappedEventLookup:F,generateMappedEventAttributeLookup:H,sendAdBlockMeasurementSignals:z,createAutoRemovedIframe:P,djb2:G,setAllowedOriginHashes:m=>{p._allowedOriginHashes=m},ReportingTransport:C,ErrorReportingService:q,LoggingService:B,RateLimiter:V,ErrorCodes:T,WSDKErrorSeverity:_},this.attachLauncher(c,f),"Successfully initialized: "+d):(b&&(a().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this),x(it,D(h),{onLoad:()=>{this._isThankYouElementLoaded=!0,this._thankYouElementOnLoadCallback&&this._thankYouElementOnLoadCallback()},onError:m=>{console.error("Error loading Rokt Thank You Element script:",m)}})),this.isLauncherReadyToAttach()?this.attachLauncher(c,f,w):(x(et,M(h,U),{onLoad:()=>{this.isLauncherReadyToAttach()?this.attachLauncher(c,f,w):console.error("Rokt object is not available after script load.")},onError:m=>{console.error("Error loading Rokt launcher script:",m)}}),this.captureTiming(p.PERFORMANCE_MARKS.RoktScriptAppended)),"Successfully initialized: "+d)}process(t){if(!this.isKitReady())return"Kit not ready for forwarder: "+d;if(typeof a().Rokt?.setLocalSessionAttribute=="function"&&(y(this.placementEventAttributeMappingLookup)||this.applyPlacementEventAttributeMapping(t),!y(this.placementEventMappingLookup))){const e=W(t.EventDataType,t.EventCategory,t.EventName??"");this.placementEventMappingLookup[String(e)]&&a().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(e)],!0)}return"Successfully sent to forwarder: "+d}setExtensionData(t){if(!this.isKitReady()){console.error("Rokt Kit: Not initialized");return}window.Rokt.setExtensionData(t)}setUserAttribute(t,e){return K(t)||(this.userAttributes[t]=e),"Successfully set user attribute for forwarder: "+d}removeUserAttribute(t){return delete this.userAttributes[t],"Successfully removed user attribute for forwarder: "+d}handleIdentityComplete(t,e){return this.userAttributes=R(t.getAllUserAttributes()),"Successfully called "+e+" for forwarder: "+d}onUserIdentified(t){const e=t;return this.filters.filteredUser=e,this._workspaceSearchInFlightPromise=this.search(e),this.handleIdentityComplete(t,"onUserIdentified")}search(t){const e=this._workspaceIdSyncApiKey;if(!e)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const i=a().Identity?.search;if(typeof i!="function")return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const r=t.getUserIdentities?t.getUserIdentities().userIdentities:null,s={};if(r)for(const u of Object.keys(r)){const l=r[u];g(l)&&l.length>0&&(s[u]=l)}const o=Object.keys(s);if(o.length===0)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const c=o.sort().map(u=>`${u}=${s[u]}`).join("&");return c===this._workspaceLastSearchedIdentitiesKey?this._workspaceSearchInFlightPromise||Promise.resolve():(this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=c,new Promise(u=>{try{i(e,s,l=>{l?.httpCode===200&&(this.userIdentifiedInWorkspace=!0),u()})}catch(l){console.error("Rokt Kit: Workspace IDSync search failed",l),this._workspaceLastSearchedIdentitiesKey=void 0,u()}}))}onLoginComplete(t,e){return this.handleIdentityComplete(t,"onLoginComplete")}onLogoutComplete(t,e){return this.userIdentifiedInWorkspace=!1,this._workspaceSearchInFlightPromise=null,this._workspaceLastSearchedIdentitiesKey=void 0,this.handleIdentityComplete(t,"onLogoutComplete")}onModifyComplete(t,e){return this.handleIdentityComplete(t,"onModifyComplete")}selectPlacements(t){if(this._workspaceSearchInFlightPromise){const e=this._workspaceSearchInFlightPromise;return Promise.race([e,new Promise(i=>setTimeout(i,rt))]).then(()=>this._dispatchPlacements(t))}return this._dispatchPlacements(t)}_dispatchPlacements(t){const e=t&&t.attributes||{},r={...R(this.userAttributes),...e},s=this.filters||{},o=s.userAttributeFilters||[],c=s.filteredUser||null,u=c?c.getMPID():null;let l;s?s.filterUserAttributes?l=s.filterUserAttributes(r,o):l=r:(console.warn("Rokt Kit: No filters available, using user attributes"),l=r),this.userAttributes=R(l);const h=this._onboardingExpProvider==="Optimizely"?this.fetchOptimizely():{},U=this.returnUserIdentities(c),w=this.returnLocalSessionAttributes(),b={...U,...l,...h,...w,...this.userIdentifiedInWorkspace?{[nt]:!0}:{},mpid:u},f={...t,attributes:b},k=this.launcher.selectPlacements(f),I=()=>this.logSelectPlacementsEvent(b);return Promise.resolve(k).then(L=>L?.context?.sessionId?.then(m=>this.setRoktSessionId(m))).catch(()=>{}).finally(I),k}hashAttributes(t){return this.isKitReady()?this.launcher.hashAttributes(t):(console.error("Rokt Kit: Not initialized"),null)}use(t){return this.isKitReady()?!t||!g(t)?Promise.reject(new Error("Rokt Kit: Invalid extension name")):this.launcher.use(t):(console.error("Rokt Kit: Not initialized"),Promise.reject(new Error("Rokt Kit: Not initialized")))}onShoppableAdsReady(t){this._isThankYouElementLoaded?t():this._thankYouElementOnLoadCallback=t}};p._allowedOriginHashes=[-553112570,549508659],p.PERFORMANCE_MARKS={RoktScriptAppended:"mp:RoktScriptAppended"},p.EMAIL_SHA256_KEY="emailsha256";let E=p;function gt(){return A}function ft(n){if(!n){window.console.log("You must pass a config object to register the kit "+d);return}if(!N(n)){window.console.log("'config' must be an object. You passed in a "+typeof n);return}N(n.kits)?n.kits[d]={constructor:E}:(n.kits={},n.kits[d]={constructor:E}),window.console.log("Successfully registered "+d+" to your mParticle configuration")}return typeof window<"u"&&window.mParticle&&a().addForwarder&&a().addForwarder({name:d,constructor:E,getId:gt}),v.register=ft,Object.defineProperty(v,Symbol.toStringTag,{value:"Module"}),v})({}); +var RoktKit=(function(M){"use strict";const me=["active_time_on_site_ms","billingaddress1","billingaddress2","billingcity","billingstate","billingzipcode","cartitems","ccbin","confirmationref","conversiontype","country","couponcode","currency","language","paymentserviceprovider","paymentserviceproviderattribute","paymenttype","shippingaddress1","shippingcity","shippingcountry","shippingmethod","shippingstate","shippingzipcode","totalprice"],Ee=new Set(me);function V(i){return Ee.has(i.toLowerCase())}function R(i){const e={},t=i||{},n=Object.keys(t);for(let r=0;r{const r=t.activeTimeOnSite,s=r!==void 0&&Number.isFinite(r),c=e[n+1]?.activeTimeOnSite,u=c!==void 0&&Number.isFinite(c),l=s&&u?c-r:void 0;return{pageUrl:t.pageUrl,sourceMessageId:t.sourceMessageId,timestamp:t.timestamp,...t.pageTitle!==void 0?{pageTitle:t.pageTitle}:{},...t.canonicalUrl!==void 0?{canonicalUrl:t.canonicalUrl}:{},...s?{activeTimeOnSite:r}:{},...l!==void 0&&l>=0?{activeTimeOnPage:l}:{}}})}function ye(i){if(T(g,L)!==void 0)return;const e=new URLSearchParams(window.location.search),t={};for(const r of _e){const s=e.get(r);s&&(t[r]=s)}if(Object.keys(t).length===0)return;const n=Object.keys(t).join(", ");if(!Y(g,L,t)){const r=F()?"quota":"ls_unavailable";i?.log({message:`Rokt Kit: Failed to persist UTM params [reason: ${r}]`,code:"UTM_CAPTURE_FAILED"});return}i?.log({message:`Rokt Kit: Captured UTM params [${n}]`,code:"UTM_CAPTURE_SUCCESS"})}function Ae(){const i=T(g,L);return E(i)?i:null}function te(){$(g,L)}function ke(){const e=document.querySelector('link[rel="canonical"]')?.href;if(e)return D(e)}const d="Rokt",P=181,ve="selectPlacements",Re="apps.roktecommerce.com",we=.1,be="ThankYouPageJourney",Te="rokt-launcher",Le="rokt-thank-you-element",Pe="userIdentifiedInWorkspace",Oe=3,Ne=2,Ue="page_events",Ce="page_view_attributes",Me="mparticle_session_id",Ke="mparticle_device_id",De=500,G={UNKNOWN_ERROR:"UNKNOWN_ERROR",UNHANDLED_EXCEPTION:"UNHANDLED_EXCEPTION",IDENTITY_REQUEST:"IDENTITY_REQUEST",LOG_DELIVERY_FAILURE:"LOG_DELIVERY_FAILURE"},I={ERROR:"ERROR",INFO:"INFO",WARNING:"WARNING"},Fe="apps.rokt-api.com",Ye="/v1/log",Ge="/v1/errors",xe=10;function a(){return window.mParticle}function ie(i,e){const n=[O(i),"/wsdk/integrations/launcher.js"].join("");return!e||e.length===0?n:n+"?extensions="+e.join(",")}function ne(i){return[O(i),"/rokt-elements/rokt-element-thank-you.js"].join("")}function O(i){const e=typeof i<"u"?i:Fe;return e.includes("://")?e.replace(/\/+$/,""):["https://",e].join("")}function re(i,e,t){if(i)return i.startsWith("http://")||i.startsWith("https://")?i:"https://"+i;const r=e?.includes("://")&&!/^https?:\/\//i.test(e)?void 0:e;return O(r)+t}function se(i,e,t){if(document.getElementById(i))return;const n=document.head||document.body,r=document.createElement("script");r.id=i,r.type="text/javascript",r.src=e,r.async=!0,r.crossOrigin="anonymous",r.fetchPriority="high",t?.onLoad&&(r.onload=t.onLoad),t?.onError&&(r.onerror=t.onError),n.appendChild(r)}function N(i){if(!i)return[];try{return JSON.parse(i.replace(/"/g,'"'))}catch{console.error("Settings string contains invalid JSON")}return[]}function oe(i){const e=i?N(i):[],t=[],n=[];let r=!1;for(let s=0;s=we)return;const r=window.__rokt_li_guid__;if(!r||i&&i.includes("://")&&!/^https:\/\//i.test(i))return;const s=window.location.href.split("?")[0].split("#")[0],o="version="+encodeURIComponent(e??"")+"&launcherInstanceGuid="+encodeURIComponent(r)+"&pageUrl="+encodeURIComponent(s),c=i?O(i):"https://apps.rokt.com";x(c+"/v1/wsdk-init/index.html?"+o),x("https://"+Re+"/v1/wsdk-init/index.html?"+o+"&isControl=true")}function Ve(){return typeof window<"u"&&!!window.location?.search?.toLowerCase().includes("mp_enable_logging=true")}function He(){return typeof window<"u"?window.location?.href:void 0}function ze(){return typeof window<"u"?window.navigator?.userAgent:void 0}class he{constructor(){this._logCount={}}incrementAndCheck(e){const n=(this._logCount[e]||0)+1;return this._logCount[e]=n,n>xe}}class W{constructor(e,t,n,r,s){this._reporter="mp-wsdk";const o=e.isLoggingEnabled;this._integrationName=t||"",this._launcherInstanceGuid=n,this._accountId=r||null,this._rateLimiter=s||new he,this._isEnabled=Ve()||o}send(e,t,n,r,s,o){if(!(!this._isEnabled||this._rateLimiter.incrementAndCheck(t)))try{const c={additionalInformation:{message:n,version:this._integrationName},severity:t,code:r||G.UNKNOWN_ERROR,url:He(),deviceInfo:ze(),stackTrace:s,reporter:this._reporter,integration:this._integrationName},u={Accept:"text/plain;charset=UTF-8","Content-Type":"application/json","rokt-launcher-version":this._integrationName,"rokt-wsdk-version":"joint"};this._launcherInstanceGuid&&(u["rokt-launcher-instance-guid"]=this._launcherInstanceGuid),this._accountId&&(u["rokt-account-id"]=this._accountId),fetch(e,{method:"POST",headers:u,body:JSON.stringify(c)}).then(l=>{if(!l.ok){const p=new Error("HTTP "+l.status+" from log endpoint");throw p.statusCode=l.status,p}}).catch(l=>{console.error("ReportingTransport: Failed to send log",l),o&&o(l)})}catch(c){console.error("ReportingTransport: Failed to send log",c),o&&o(c)}}}class ge{constructor(e,t,n,r,s){this._transport=new W(e,t,n,r,s),this._errorUrl=re(e?.errorUrl,e?.integrationDomain,Ge)}report(e){if(!e)return;const t=e.severity||I.ERROR;this._transport.send(this._errorUrl,t,e.message,e.code,e.stackTrace)}}class pe{constructor(e,t,n,r,s,o){this._transport=new W(e,n,r,s,o),this._loggingUrl=re(e?.loggingUrl,e?.integrationDomain,Ye),this._errorReportingService=t}log(e){e&&this._transport.send(this._loggingUrl,I.INFO,e.message,e.code,void 0,t=>{if(this._errorReportingService){const n=typeof t.statusCode=="number";this._errorReportingService.report({message:"LoggingService: Failed to send log: "+t.message,code:G.LOG_DELIVERY_FAILURE,severity:n?I.ERROR:I.WARNING})}})}}function qe(i){const e=D(window.location.href),t=i.EventAttributes?.title||document.title,n=ke(),r=i.ActiveTimeOnSite;return{pageUrl:e,sourceMessageId:i.SourceMessageId,timestamp:i.Timestamp,...t?{pageTitle:t}:{},...n!==void 0?{canonicalUrl:n}:{},...Number.isFinite(r)?{activeTimeOnSite:r}:{}}}const f=class f{constructor(){this.name=d,this.id=P,this.moduleId=P,this.isInitialized=!1,this.launcher=null,this.filters={},this.userAttributes={},this.userIdentifiedInWorkspace=!1,this.testHelpers=null,this.placementEventMappingLookup={},this.placementEventAttributeMappingLookup={},this.integrationName=null,this.errorReportingService=null,this.loggingService=null,this._thankYouElementOnLoadCallback=null,this._isThankYouElementLoaded=!1,this._workspaceSearchInFlightPromise=null}getEventAttributeValue(e,t){const n=e&&e.EventAttributes;return!n||typeof n[t]>"u"?null:n[t]}doesEventAttributeConditionMatch(e,t){if(!e||!_(e.operator))return!1;const n=e.operator.toLowerCase(),r=e.attributeValue;return n==="exists"?t!==null:t==null?!1:n==="equals"?String(t)===String(r):n==="contains"?String(t).indexOf(String(r))!==-1:!1}doesEventMatchRule(e,t){if(!t||!_(t.eventAttributeKey))return!1;const n=t.conditions;if(!Array.isArray(n))return!1;const r=this.getEventAttributeValue(e,t.eventAttributeKey);if(n.length===0)return r!==null;for(let s=0;s{await We(n,o),this.initRoktLauncher(o)}).catch(o=>{console.error("Error creating Rokt launcher:",o)})}initRoktLauncher(e){window.Rokt&&(window.Rokt.currentLauncher=e),this.launcher=e;const t=a().Rokt?.filters;t?(this.filters=t,t.filteredUser?this._workspaceSearchInFlightPromise=this.search(t.filteredUser):console.warn("Rokt Kit: No filtered user has been set.")):console.warn("Rokt Kit: No filters have been set."),this.isInitialized=!0,de(this.domain,this.integrationName),a().Rokt.attachKit(this)}fetchOptimizely(){const e=a()._getActiveForwarders().filter(t=>t.name==="Optimizely");try{if(e.length>0&&window.optimizely){const t=window.optimizely.get("state");return!t||!t.getActiveExperimentIds?{}:t.getActiveExperimentIds().reduce((s,o)=>(s["rokt.custom.optimizely.experiment."+o+".variationId"]=t.getVariationMap()[o].id,s),{})}}catch(t){console.error("Error fetching Optimizely attributes:",t)}return{}}isKitReady(){return!!(this.isInitialized&&this.launcher)}isTargetingDisabled(){return a().Rokt?.launcherOptions?.noTargeting===!0}isPartnerInLocalLauncherTestGroup(){return!!(a().config&&a().config.isLocalLauncherEnabled&&this.isAssignedToSampleGroup())}isAssignedToSampleGroup(){return Math.random()>.5}captureTiming(e){window&&a()&&a().captureTiming&&e&&a().captureTiming(e)}init(e,t,n,r,s){const o=e,c=o.accountId;this.userAttributes=R(s),this._onboardingExpProvider=o.onboardingExpProvider;const u=N(o.placementEventMapping);this.placementEventMappingLookup=ae(u);const l=N(o.placementEventAttributeMapping);this.placementEventAttributeMappingLookup=ce(l),o.hashedEmailUserIdentityType&&(this._mappedEmailSha256Key=o.hashedEmailUserIdentityType.toLowerCase()),this._workspaceIdSyncApiKey=_(o.workspaceIdSyncApiKey)?o.workspaceIdSyncApiKey:void 0;const p=a().Rokt?.domain,{roktExtensionsQueryParams:j,legacyRoktExtensions:U,loadThankYouElement:C}=oe(o.roktExtensions),m={...a().Rokt?.launcherOptions||{}};this.integrationName=je(m.integrationName),m.integrationName=this.integrationName,this.domain=p;const k={loggingUrl:o.loggingUrl,errorUrl:o.errorUrl,integrationDomain:p,isLoggingEnabled:a().config?.isLoggingEnabled===!0},y=new ge(k,this.integrationName,window.__rokt_li_guid__,o.accountId),v=new pe(k,y,this.integrationName,window.__rokt_li_guid__,o.accountId);if(this.errorReportingService=y,this.loggingService=v,this.isTargetingDisabled())try{ee(),te()}catch(h){this.errorReportingService?.report({message:"Rokt Kit: Failed to clear page views when targeting is disabled",code:"PAGE_VIEW_CAPTURE_FAILED",severity:I.INFO,stackTrace:h instanceof Error?h.stack:void 0})}return a()._registerErrorReportingService&&a()._registerErrorReportingService(y),a()._registerLoggingService&&a()._registerLoggingService(v),n?(this.testHelpers={generateLauncherScript:ie,generateThankYouElementScript:ne,extractRoktExtensionConfig:oe,hashEventMessage:le,parseSettingsString:N,generateMappedEventLookup:ae,generateMappedEventAttributeLookup:ce,sendAdBlockMeasurementSignals:de,createAutoRemovedIframe:x,djb2:ue,setAllowedOriginHashes:h=>{f._allowedOriginHashes=h},ReportingTransport:W,ErrorReportingService:ge,LoggingService:pe,RateLimiter:he,ErrorCodes:G,WSDKErrorSeverity:I},this.attachLauncher(c,m),"Successfully initialized: "+d):(C&&(a().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this),se(Le,ne(p),{onLoad:()=>{this._isThankYouElementLoaded=!0,this._thankYouElementOnLoadCallback&&this._thankYouElementOnLoadCallback()},onError:h=>{console.error("Error loading Rokt Thank You Element script:",h)}})),this.isLauncherReadyToAttach()?this.attachLauncher(c,m,U):(se(Te,ie(p,j),{onLoad:()=>{this.isLauncherReadyToAttach()?this.attachLauncher(c,m,U):console.error("Rokt object is not available after script load.")},onError:h=>{console.error("Error loading Rokt launcher script:",h)}}),this.captureTiming(f.PERFORMANCE_MARKS.RoktScriptAppended)),"Successfully initialized: "+d)}process(e){if(this.isTargetingDisabled()||(e.EventDataType===Oe&&(ye(this.loggingService),this.capturePageView(e)),e.EventDataType===Ne&&(X(this.loggingService),ee(),te())),!this.isKitReady())return"Kit not ready for forwarder: "+d;if(w(a().Rokt?.setLocalSessionAttribute)&&(K(this.placementEventAttributeMappingLookup)||this.applyPlacementEventAttributeMapping(e),!K(this.placementEventMappingLookup))){const t=le(e.EventDataType,e.EventCategory,e.EventName??"");this.placementEventMappingLookup[String(t)]&&a().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(t)],!0)}return"Successfully sent to forwarder: "+d}setExtensionData(e){if(!this.isKitReady()){console.error("Rokt Kit: Not initialized");return}window.Rokt.setExtensionData(e)}setUserAttribute(e,t){return V(e)||(this.userAttributes[e]=t),"Successfully set user attribute for forwarder: "+d}removeUserAttribute(e){return delete this.userAttributes[e],"Successfully removed user attribute for forwarder: "+d}handleIdentityComplete(e,t){return this.userAttributes=R(e.getAllUserAttributes()),"Successfully called "+t+" for forwarder: "+d}onUserIdentified(e){const t=e;return this.filters.filteredUser=t,this._workspaceSearchInFlightPromise=this.search(t),this.handleIdentityComplete(e,"onUserIdentified")}search(e){const t=this._workspaceIdSyncApiKey;if(!t)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const n=a().Identity?.search;if(typeof n!="function")return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const r=e.getUserIdentities?e.getUserIdentities().userIdentities:null,s={};if(r)for(const u of Object.keys(r)){const l=r[u];_(l)&&l.length>0&&(s[u]=l)}const o=Object.keys(s);if(o.length===0)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const c=o.sort().map(u=>`${u}=${s[u]}`).join("&");return c===this._workspaceLastSearchedIdentitiesKey?this._workspaceSearchInFlightPromise||Promise.resolve():(this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=c,new Promise(u=>{try{n(t,s,l=>{l?.httpCode===200&&(this.userIdentifiedInWorkspace=!0),u()})}catch(l){console.error("Rokt Kit: Workspace IDSync search failed",l),this._workspaceLastSearchedIdentitiesKey=void 0,u()}}))}onLoginComplete(e,t){return this.handleIdentityComplete(e,"onLoginComplete")}onLogoutComplete(e,t){return this.userIdentifiedInWorkspace=!1,this._workspaceSearchInFlightPromise=null,this._workspaceLastSearchedIdentitiesKey=void 0,this.handleIdentityComplete(e,"onLogoutComplete")}onModifyComplete(e,t){return this.handleIdentityComplete(e,"onModifyComplete")}selectPlacements(e){if(this._workspaceSearchInFlightPromise){const t=this._workspaceSearchInFlightPromise;return Promise.race([t,new Promise(n=>setTimeout(n,De))]).then(()=>this._dispatchPlacements(e))}return this._dispatchPlacements(e)}_dispatchPlacements(e){const t=e&&e.attributes||{},r={...R(this.userAttributes),...t},s=this.filters||{},o=s.userAttributeFilters||[],c=s.filteredUser||null,u=c?c.getMPID():null;let l;s?s.filterUserAttributes?l=s.filterUserAttributes(r,o):l=r:(console.warn("Rokt Kit: No filters available, using user attributes"),l=r),this.userAttributes=R(l);const p=this._onboardingExpProvider==="Optimizely"?this.fetchOptimizely():{},j=this.returnUserIdentities(c),U=this.returnLocalSessionAttributes(),C=Se(Z(this.loggingService)),m=Ae(),k=this.readMpSessionId(),y=this.readMpDeviceId(),v={...j,...l,...p,...U,...C.length?{[Ue]:JSON.stringify(C)}:{},...m?{[Ce]:m}:{},...this.userIdentifiedInWorkspace?{[Pe]:!0}:{},...k?{[Me]:k}:{},...y?{[Ke]:y}:{},mpid:u},h={...e,attributes:v},fe=this.launcher.selectPlacements(h),Be=()=>this.logSelectPlacementsEvent(v);return Promise.resolve(fe).then(Qe=>Qe?.context?.sessionId?.then(Xe=>this.setRoktSessionId(Xe))).catch(()=>{}).finally(Be),fe}hashAttributes(e){return this.isKitReady()?this.launcher.hashAttributes(e):(console.error("Rokt Kit: Not initialized"),null)}use(e){return this.isKitReady()?!e||!_(e)?Promise.reject(new Error("Rokt Kit: Invalid extension name")):this.launcher.use(e):(console.error("Rokt Kit: Not initialized"),Promise.reject(new Error("Rokt Kit: Not initialized")))}onShoppableAdsReady(e){this._isThankYouElementLoaded?e():this._thankYouElementOnLoadCallback=e}};f._allowedOriginHashes=[-553112570,549508659],f.PERFORMANCE_MARKS={RoktScriptAppended:"mp:RoktScriptAppended"},f.EMAIL_SHA256_KEY="emailsha256";let S=f;function $e(){return P}function Je(i){if(!i){window.console.log("You must pass a config object to register the kit "+d);return}if(!E(i)){window.console.log("'config' must be an object. You passed in a "+typeof i);return}E(i.kits)?i.kits[d]={constructor:S}:(i.kits={},i.kits[d]={constructor:S}),window.console.log("Successfully registered "+d+" to your mParticle configuration")}return typeof window<"u"&&window.mParticle&&a().addForwarder&&a().addForwarder({name:d,constructor:S,getId:$e}),M.register=Je,Object.defineProperty(M,Symbol.toStringTag,{value:"Module"}),M})({}); //# sourceMappingURL=Rokt-Kit.iife.js.map diff --git a/kits/rokt/dist/Rokt-Kit.iife.js.map b/kits/rokt/dist/Rokt-Kit.iife.js.map index 616a6bf33..6e82cf887 100644 --- a/kits/rokt/dist/Rokt-Kit.iife.js.map +++ b/kits/rokt/dist/Rokt-Kit.iife.js.map @@ -1 +1 @@ -{"version":3,"file":"Rokt-Kit.iife.js","sources":["../src/selectPlacementsAttributePersistence.ts","../src/Rokt-Kit.ts"],"sourcesContent":["const SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST = [\n 'billingaddress1',\n 'billingaddress2',\n 'billingcity',\n 'billingstate',\n 'billingzipcode',\n 'cartitems',\n 'ccbin',\n 'confirmationref',\n 'conversiontype',\n 'country',\n 'couponcode',\n 'currency',\n 'language',\n 'paymentserviceprovider',\n 'paymentserviceproviderattribute',\n 'paymenttype',\n 'shippingaddress1',\n 'shippingcity',\n 'shippingcountry',\n 'shippingmethod',\n 'shippingstate',\n 'shippingzipcode',\n 'totalprice',\n];\nconst SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET = new Set(SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST);\n\nexport function isSelectPlacementsAttributePersistenceDenied(key: string): boolean {\n return SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET.has(key.toLowerCase());\n}\n\nexport function removeSelectPlacementsAttributePersistenceDeniedAttributes(\n attributes: Record | null | undefined,\n): Record {\n const filteredAttributes: Record = {};\n const sourceAttributes = attributes || {};\n const attributeKeys = Object.keys(sourceAttributes);\n\n for (let i = 0; i < attributeKeys.length; i++) {\n const key = attributeKeys[i];\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n filteredAttributes[key] = sourceAttributes[key];\n }\n }\n\n return filteredAttributes;\n}\n","// Copyright 2025 mParticle, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// ============================================================\n// Types\n// ============================================================\n\nimport { KitInterface, IMParticleUser, SDKEvent } from '@mparticle/web-sdk/internal';\nimport type { IUserIdentities } from '@mparticle/web-sdk';\n\nimport {\n isSelectPlacementsAttributePersistenceDenied,\n removeSelectPlacementsAttributePersistenceDeniedAttributes,\n} from './selectPlacementsAttributePersistence';\n\ninterface RoktKitSettings {\n accountId: string;\n roktExtensions?: string;\n placementEventMapping?: string;\n placementEventAttributeMapping?: string;\n hashedEmailUserIdentityType?: string;\n onboardingExpProvider?: string;\n loggingUrl?: string;\n errorUrl?: string;\n workspaceIdSyncApiKey?: string;\n}\n\ninterface EventAttributeCondition {\n operator: string;\n attributeValue: string;\n}\n\ninterface PlacementEventRule {\n eventAttributeKey: string;\n conditions: EventAttributeCondition[];\n}\n\ninterface EventAttributeMapping {\n value: string;\n map: string;\n conditions?: EventAttributeCondition[];\n}\n\ninterface PlacementEventMappingEntry {\n jsmap: string;\n value: string;\n}\n\ninterface RoktExtensionEntry {\n value: string;\n}\n\ninterface RoktSelection {\n context?: {\n sessionId?: Promise;\n };\n then?: (callback: (sel: RoktSelection) => void) => Promise;\n catch?: (callback: () => void) => void;\n}\n\ninterface RoktLauncher {\n selectPlacements(options: Record): RoktSelection | Promise;\n hashAttributes(attributes: Record): Promise>;\n use(extensionName: string): Promise;\n}\n\ninterface RoktGlobal {\n createLauncher(options: Record): Promise;\n createLocalLauncher(options: Record): RoktLauncher;\n currentLauncher?: RoktLauncher;\n setExtensionData(data: Record): void;\n}\n\n// FilteredUser is the IMParticleUser shape we receive after kit filtering.\n// `getMPID` and `getUserIdentities` are inherited from the SDK's `User` base type.\ntype FilteredUser = IMParticleUser;\n\n// TODO: Replace with `IIdentitySearchResult` from `@mparticle/web-sdk` once\n// a version that exports it is published (currently on a feature branch in\n// mParticle/mparticle-web-sdk PR #1255). The shape below is intentionally\n// structurally identical so the swap is a one-line import change.\ninterface WorkspaceIdSyncResult {\n httpCode: number;\n body?: {\n context?: string | null;\n mpid?: string;\n matched_identities?: Record;\n is_ephemeral?: boolean;\n is_logged_in?: boolean;\n };\n}\n\n// TODO: Replace with `IdentitySearchCallback`-compatible reference from\n// `@mparticle/web-sdk` once published (mirrors `SDKIdentityApi.search`).\ntype WorkspaceIdSyncSearcher = (\n apiKey: string,\n knownIdentities: IUserIdentities,\n callback: (result: WorkspaceIdSyncResult) => void,\n) => void;\n\ninterface KitFilters {\n userAttributeFilters?: string[];\n filterUserAttributes?: (attributes: Record, filters?: string[]) => Record;\n filteredUser?: FilteredUser | null;\n}\n\ninterface RoktManager {\n attachKit(kit: RoktKit): void | Promise;\n flushOnShoppableAdsReadyMessageQueue?(kit: RoktKit): void;\n filters?: KitFilters;\n domain?: string;\n launcherOptions?: Record;\n getLocalSessionAttributes?(): Record;\n setLocalSessionAttribute?(key: string, value: unknown): void;\n}\n\ninterface MParticleInstance {\n setIntegrationAttribute(moduleId: number, attrs: Record): void;\n}\n\ninterface OptimizelyState {\n getActiveExperimentIds(): string[];\n getVariationMap(): Record;\n}\n\ninterface OptimizelyGlobal {\n get(key: 'state'): OptimizelyState;\n}\n\n// Our view of the mParticle global with Rokt-specific extensions.\n// We access window.mParticle via an explicit cast (see `mp()` helper below)\n// rather than augmenting Window to avoid conflicts with @mparticle/web-sdk declarations.\ninterface MParticleExtended {\n Rokt: RoktManager;\n addForwarder(config: ForwarderRegistration): void;\n getVersion(): string;\n generateHash(value: string): string | number;\n logEvent(name: string, type: number, attrs?: Record): void;\n EventType: { Other: number };\n getInstance(): MParticleInstance;\n sessionManager?: { getSession(): string };\n _getActiveForwarders(): Array<{ name: string }>;\n config?: { isLocalLauncherEnabled?: boolean; isLoggingEnabled?: boolean };\n captureTiming?(metricName: string): void;\n forwarder?: RoktKit;\n loggedEvents?: Array>;\n _registerErrorReportingService?(service: ErrorReportingService): void;\n _registerLoggingService?(service: LoggingService): void;\n Identity?: { search?: WorkspaceIdSyncSearcher };\n}\n\ninterface TestHelpers {\n generateLauncherScript: (domain: string | undefined, extensions: string[]) => string;\n generateThankYouElementScript: (domain: string | undefined) => string;\n extractRoktExtensionConfig: (settingsString?: string) => RoktExtensionConfig;\n hashEventMessage: (messageType: number, eventType: number, eventName: string) => string | number;\n parseSettingsString: (settingsString?: string) => T[];\n generateMappedEventLookup: (placementEventMapping: PlacementEventMappingEntry[]) => Record;\n generateMappedEventAttributeLookup: (mapping: EventAttributeMapping[]) => Record;\n sendAdBlockMeasurementSignals: (domain: string | undefined, version: string | null) => void;\n createAutoRemovedIframe: (src: string) => void;\n djb2: (str: string) => number;\n setAllowedOriginHashes: (hashes: number[]) => void;\n ReportingTransport: typeof ReportingTransport;\n ErrorReportingService: typeof ErrorReportingService;\n LoggingService: typeof LoggingService;\n RateLimiter: typeof RateLimiter;\n ErrorCodes: typeof ErrorCodes;\n WSDKErrorSeverity: typeof WSDKErrorSeverity;\n}\n\ninterface ForwarderRegistration {\n name: string;\n constructor: new () => RoktKit;\n getId: () => number;\n}\n\ninterface ReportingConfig {\n loggingUrl?: string;\n errorUrl?: string;\n integrationDomain?: string;\n isLoggingEnabled: boolean;\n}\n\ninterface ErrorReport {\n message: string;\n code?: string;\n severity?: string;\n stackTrace?: string;\n}\n\n// A log-delivery failure. statusCode is set when the request reached the server\n// and returned a non-2xx status (server-side); it is absent for network-level\n// failures such as ad-blockers, offline, or CORS rejections (client-side).\ninterface DeliveryError extends Error {\n statusCode?: number;\n}\n\ninterface LogEntry {\n message: string;\n code?: string;\n}\n\ninterface RoktExtensionConfig {\n roktExtensionsQueryParams: string[];\n legacyRoktExtensions: string[];\n loadThankYouElement: boolean;\n}\n\ndeclare global {\n interface Window {\n Rokt?: RoktGlobal;\n __rokt_li_guid__?: string;\n optimizely?: OptimizelyGlobal;\n // mParticle is declared as any to avoid conflicts with @mparticle/web-sdk type declarations.\n // We use the typed mp() accessor for all internal accesses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mParticle: any;\n }\n}\n\n// ============================================================\n// Module-level constants\n// ============================================================\n\nconst name = 'Rokt';\nconst moduleId = 181;\nconst EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements';\nconst ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com';\nconst INIT_LOG_SAMPLING_RATE = 0.1;\nconst ROKT_THANK_YOU_JOURNEY_EXTENSION = 'ThankYouPageJourney';\nconst ROKT_INTEGRATION_SCRIPT_ID = 'rokt-launcher';\nconst ROKT_THANK_YOU_ELEMENT_SCRIPT_ID = 'rokt-thank-you-element';\nconst USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace';\n\n// Bound on how long selectPlacements will wait for an in-flight Workspace\n// IDSync search before proceeding without the userIdentifiedInWorkspace flag.\n// Long enough to cover the typical /v1/search round-trip (~50ms); short enough that a\n// stalled search never blocks placement rendering on a thank-you page.\nconst WORKSPACE_SEARCH_SELECT_TIMEOUT_MS = 500;\n\n// ============================================================\n// Reporting service constants\n// ============================================================\n\nconst ErrorCodes = {\n UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION',\n IDENTITY_REQUEST: 'IDENTITY_REQUEST',\n LOG_DELIVERY_FAILURE: 'LOG_DELIVERY_FAILURE',\n} as const;\n\nconst WSDKErrorSeverity = {\n ERROR: 'ERROR',\n INFO: 'INFO',\n WARNING: 'WARNING',\n} as const;\n\nconst DEFAULT_ROKT_DOMAIN = 'apps.rokt-api.com';\nconst LOGGING_ENDPOINT = '/v1/log';\nconst ERROR_ENDPOINT = '/v1/errors';\nconst RATE_LIMIT_PER_SEVERITY = 10;\n\n// ============================================================\n// Helper: typed accessor for window.mParticle\n// We use an explicit cast here to avoid conflicts with @mparticle/web-sdk\n// type declarations while still providing full type safety for our usages.\n// ============================================================\n\nfunction mp(): MParticleExtended {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (window as any).mParticle as MParticleExtended;\n}\n\n// ============================================================\n// Module-level utility functions\n// ============================================================\n\nfunction generateLauncherScript(domain: string | undefined, extensions: string[]): string {\n const launcherPath = '/wsdk/integrations/launcher.js';\n const baseUrl = [generateBaseUrl(domain), launcherPath].join('');\n\n if (!extensions || extensions.length === 0) {\n return baseUrl;\n }\n return baseUrl + '?extensions=' + extensions.join(',');\n}\n\nfunction generateThankYouElementScript(domain: string | undefined) {\n const thankYouElementPath = '/rokt-elements/rokt-element-thank-you.js';\n return [generateBaseUrl(domain), thankYouElementPath].join('');\n}\n\nfunction generateBaseUrl(domain: string | undefined) {\n const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN;\n const protocol = 'https://';\n\n return [protocol, resolvedDomain].join('');\n}\n\nfunction generateReportingUrl(configuredUrl: string | undefined, domain: string | undefined, endpoint: string): string {\n if (configuredUrl) {\n if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://')) {\n return configuredUrl;\n }\n return 'https://' + configuredUrl;\n }\n\n return generateBaseUrl(domain) + endpoint;\n}\n\nfunction loadRoktScript(\n scriptId: string,\n source: string,\n handlers?: { onLoad?: () => void; onError?: (e: Event | string) => void },\n): void {\n if (document.getElementById(scriptId)) return; // resolves the preexisting script issue\n\n const target = document.head || document.body;\n const script = document.createElement('script');\n script.id = scriptId;\n script.type = 'text/javascript';\n script.src = source;\n script.async = true;\n script.crossOrigin = 'anonymous';\n (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high';\n if (handlers?.onLoad) script.onload = handlers.onLoad;\n if (handlers?.onError) script.onerror = handlers.onError;\n target.appendChild(script);\n}\n\nfunction isObject(val: unknown): val is Record {\n return val != null && typeof val === 'object' && Array.isArray(val) === false;\n}\n\nfunction parseSettingsString(settingsString?: string): T[] {\n if (!settingsString) {\n return [];\n }\n try {\n return JSON.parse(settingsString.replace(/"/g, '\"')) as T[];\n } catch (_error) {\n console.error('Settings string contains invalid JSON');\n }\n return [];\n}\n\nfunction extractRoktExtensionConfig(settingsString?: string): RoktExtensionConfig {\n const settings = settingsString ? parseSettingsString(settingsString) : [];\n const roktExtensionsQueryParams: string[] = [];\n const legacyRoktExtensions: string[] = [];\n let loadThankYouElement = false;\n\n for (let i = 0; i < settings.length; i++) {\n const extensionName = settings[i].value;\n if (extensionName === 'thank-you-journey') {\n loadThankYouElement = true;\n legacyRoktExtensions.push(ROKT_THANK_YOU_JOURNEY_EXTENSION);\n } else {\n roktExtensionsQueryParams.push(extensionName);\n }\n }\n\n return {\n roktExtensionsQueryParams,\n legacyRoktExtensions,\n loadThankYouElement,\n };\n}\n\nasync function registerLegacyExtensions(legacyExtensions: string[], launcher: RoktLauncher | null) {\n const extensions: Promise[] = [];\n if (launcher) {\n for (const extension of legacyExtensions) {\n extensions.push(launcher.use(extension));\n }\n }\n\n return Promise.all(extensions);\n}\n\nfunction generateMappedEventLookup(placementEventMapping: PlacementEventMappingEntry[]): Record {\n if (!placementEventMapping) {\n return {};\n }\n\n const mappedEvents: Record = {};\n for (let i = 0; i < placementEventMapping.length; i++) {\n const mapping = placementEventMapping[i];\n mappedEvents[mapping.jsmap] = mapping.value;\n }\n return mappedEvents;\n}\n\nfunction generateMappedEventAttributeLookup(\n placementEventAttributeMapping: EventAttributeMapping[],\n): Record {\n const mappedAttributeKeys: Record = {};\n if (!Array.isArray(placementEventAttributeMapping)) {\n return mappedAttributeKeys;\n }\n for (let i = 0; i < placementEventAttributeMapping.length; i++) {\n const mapping = placementEventAttributeMapping[i];\n if (!mapping || !isString(mapping.value) || !isString(mapping.map)) {\n continue;\n }\n\n const mappedAttributeKey = mapping.value;\n const eventAttributeKey = mapping.map;\n\n if (!mappedAttributeKeys[mappedAttributeKey]) {\n mappedAttributeKeys[mappedAttributeKey] = [];\n }\n\n mappedAttributeKeys[mappedAttributeKey].push({\n eventAttributeKey: eventAttributeKey,\n conditions: Array.isArray(mapping.conditions) ? mapping.conditions : [],\n });\n }\n return mappedAttributeKeys;\n}\n\nfunction hashEventMessage(messageType: number, eventType: number, eventName: string): string | number {\n return mp().generateHash([messageType, eventType, eventName].join(''));\n}\n\nfunction isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'object') {\n return Object.keys(value as object).length === 0;\n }\n if (Array.isArray(value)) {\n return (value as unknown[]).length === 0;\n }\n return false;\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nfunction generateIntegrationName(customIntegrationName?: string): string {\n const coreSdkVersion = mp().getVersion();\n const kitVersion = process.env.PACKAGE_VERSION;\n let integrationName = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion;\n\n if (customIntegrationName) {\n integrationName += '_' + customIntegrationName;\n }\n return integrationName;\n}\n\nfunction djb2(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return hash;\n}\n\nfunction createAutoRemovedIframe(src: string): void {\n const iframe = document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');\n iframe.src = src;\n iframe.onload = function () {\n iframe.onload = null;\n if (iframe.parentNode) {\n iframe.parentNode.removeChild(iframe);\n }\n };\n const target = document.body || document.head;\n if (target) {\n target.appendChild(iframe);\n }\n}\n\nfunction sendAdBlockMeasurementSignals(domain: string | undefined, version: string | null): void {\n const originHash = djb2(window.location.origin);\n const allowedOriginHashes = RoktKit._allowedOriginHashes;\n if (allowedOriginHashes.indexOf(originHash) === -1) {\n return;\n }\n\n if (Math.random() >= INIT_LOG_SAMPLING_RATE) {\n return;\n }\n\n const guid = window.__rokt_li_guid__;\n if (!guid) {\n return;\n }\n\n const pageUrl = window.location.href.split('?')[0].split('#')[0];\n const params =\n 'version=' +\n encodeURIComponent(version ?? '') +\n '&launcherInstanceGuid=' +\n encodeURIComponent(guid) +\n '&pageUrl=' +\n encodeURIComponent(pageUrl);\n\n const existingDomain = domain || 'apps.rokt.com';\n createAutoRemovedIframe('https://' + existingDomain + '/v1/wsdk-init/index.html?' + params);\n\n createAutoRemovedIframe(\n 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true',\n );\n}\n\n// ============================================================\n// Reporting helpers\n// ============================================================\n\nfunction _isDebugModeEnabled(): boolean {\n return typeof window !== 'undefined' && !!window.location?.search?.toLowerCase().includes('mp_enable_logging=true');\n}\n\nfunction _getReportingUrl(): string | undefined {\n return typeof window !== 'undefined' ? window.location?.href : undefined;\n}\n\nfunction _getUserAgent(): string | undefined {\n return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined;\n}\n\nclass RateLimiter {\n private _logCount: Record = {};\n\n incrementAndCheck(severity: string): boolean {\n const count = this._logCount[severity] || 0;\n const newCount = count + 1;\n this._logCount[severity] = newCount;\n return newCount > RATE_LIMIT_PER_SEVERITY;\n }\n}\n\nclass ReportingTransport {\n private _isEnabled: boolean;\n private _integrationName: string;\n private _launcherInstanceGuid: string | undefined;\n private _accountId: string | null;\n private _rateLimiter: RateLimiter;\n private readonly _reporter = 'mp-wsdk';\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid: string | undefined,\n accountId: string | null | undefined,\n rateLimiter?: RateLimiter,\n ) {\n const isLoggingEnabled = config.isLoggingEnabled;\n this._integrationName = integrationName || '';\n this._launcherInstanceGuid = launcherInstanceGuid;\n this._accountId = accountId || null;\n this._rateLimiter = rateLimiter || new RateLimiter();\n this._isEnabled = _isDebugModeEnabled() || isLoggingEnabled;\n }\n\n send(\n url: string,\n severity: string,\n msg: string,\n code?: string,\n stackTrace?: string,\n onError?: (error: DeliveryError) => void,\n ): void {\n if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) {\n return;\n }\n\n try {\n const logRequest = {\n additionalInformation: {\n message: msg,\n version: this._integrationName,\n },\n severity,\n code: code || ErrorCodes.UNKNOWN_ERROR,\n url: _getReportingUrl(),\n deviceInfo: _getUserAgent(),\n stackTrace,\n reporter: this._reporter,\n integration: this._integrationName,\n };\n\n const headers: Record = {\n Accept: 'text/plain;charset=UTF-8',\n 'Content-Type': 'application/json',\n 'rokt-launcher-version': this._integrationName,\n 'rokt-wsdk-version': 'joint',\n };\n\n if (this._launcherInstanceGuid) {\n headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid;\n }\n if (this._accountId) {\n headers['rokt-account-id'] = this._accountId;\n }\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(logRequest),\n })\n .then((response: Response) => {\n // fetch only rejects on network failures; an HTTP 5xx resolves with\n // ok === false. Surface server-side failures so they are not swallowed.\n if (!response.ok) {\n const serverError: DeliveryError = new Error('HTTP ' + response.status + ' from log endpoint');\n serverError.statusCode = response.status;\n throw serverError;\n }\n })\n .catch((error: DeliveryError) => {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error);\n });\n } catch (error) {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error as DeliveryError);\n }\n }\n}\n\nclass ErrorReportingService {\n private _transport: ReportingTransport;\n private _errorUrl: string;\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._errorUrl = generateReportingUrl(config?.errorUrl, config?.integrationDomain, ERROR_ENDPOINT);\n }\n\n report(error: ErrorReport | null | undefined): void {\n if (!error) return;\n const severity = error.severity || WSDKErrorSeverity.ERROR;\n this._transport.send(this._errorUrl, severity, error.message, error.code, error.stackTrace);\n }\n}\n\nclass LoggingService {\n private _transport: ReportingTransport;\n private _loggingUrl: string;\n private _errorReportingService: { report: (e: ErrorReport) => void };\n\n constructor(\n config: ReportingConfig,\n errorReportingService: { report: (e: ErrorReport) => void },\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._loggingUrl = generateReportingUrl(config?.loggingUrl, config?.integrationDomain, LOGGING_ENDPOINT);\n this._errorReportingService = errorReportingService;\n }\n\n log(entry: LogEntry | null | undefined): void {\n if (!entry) return;\n this._transport.send(\n this._loggingUrl,\n WSDKErrorSeverity.INFO,\n entry.message,\n entry.code,\n undefined,\n (error: DeliveryError) => {\n if (this._errorReportingService) {\n // A failed log POST is not itself an SDK error. Network-level failures\n // (ad-blockers, offline, CORS) are client-side noise and reported as a\n // WARNING; only a server-side non-2xx response stays at ERROR severity.\n const isServerSide = typeof error.statusCode === 'number';\n this._errorReportingService.report({\n message: 'LoggingService: Failed to send log: ' + error.message,\n code: ErrorCodes.LOG_DELIVERY_FAILURE,\n severity: isServerSide ? WSDKErrorSeverity.ERROR : WSDKErrorSeverity.WARNING,\n });\n }\n },\n );\n }\n}\n\n// ============================================================\n// RoktKit class\n// ============================================================\n\nclass RoktKit implements KitInterface {\n // Static field for allowed origin hashes (mutable by testHelpers)\n public static _allowedOriginHashes: number[] = [-553112570, 549508659];\n\n private static readonly PERFORMANCE_MARKS = {\n RoktScriptAppended: 'mp:RoktScriptAppended',\n };\n\n private static readonly EMAIL_SHA256_KEY = 'emailsha256';\n\n // Public fields (accessed by tests and the mParticle framework)\n public name = name;\n public id = moduleId;\n public moduleId = moduleId;\n public isInitialized = false;\n public launcher: RoktLauncher | null = null;\n public filters: KitFilters = {};\n public userAttributes: Record = {};\n // Flag set by the Workspace IDSync flow on a 200 response. Stored on the\n // kit instance and merged into placement attributes inside selectPlacements.\n public userIdentifiedInWorkspace = false;\n public testHelpers: TestHelpers | null = null;\n public placementEventMappingLookup: Record = {};\n public placementEventAttributeMappingLookup: Record = {};\n public integrationName: string | null = null;\n public domain?: string;\n public errorReportingService: ErrorReportingService | null = null;\n public loggingService: LoggingService | null = null;\n\n // Private fields\n private _mappedEmailSha256Key?: string;\n private _onboardingExpProvider?: string;\n private _thankYouElementOnLoadCallback: (() => void) | null = null;\n private _isThankYouElementLoaded = false;\n private _workspaceIdSyncApiKey?: string;\n\n // Held during a search dispatch so the next selectPlacements call;\n // can wait for the HTTP response before reading userIdentifiedInWorkspace;\n // — otherwise the first placement call ships without the flag.\n private _workspaceSearchInFlightPromise: Promise | null = null;\n // Stable serialization of the identifier set sent in the most recent\n // successful search dispatch. If a subsequent identification arrives with\n // an identical set, we skip the network call (the flag is still correct\n // from the prior search). Keyed over the full IUserIdentities map — not\n // just email — so partners passing hashed email through `other`/`other2-10`\n // or any other identifier benefit from the same dedupe. Cleared on logout\n // so a re-login re-evaluates fresh.\n private _workspaceLastSearchedIdentitiesKey?: string;\n\n // ---- Private helpers ----\n\n private getEventAttributeValue(event: SDKEvent, eventAttributeKey: string): unknown {\n const attributes = event && event.EventAttributes;\n if (!attributes) {\n return null;\n }\n\n if (typeof attributes[eventAttributeKey] === 'undefined') {\n return null;\n }\n\n return attributes[eventAttributeKey];\n }\n\n private doesEventAttributeConditionMatch(condition: EventAttributeCondition, actualValue: unknown): boolean {\n if (!condition || !isString(condition.operator)) {\n return false;\n }\n\n const operator = condition.operator.toLowerCase();\n const expectedValue = condition.attributeValue;\n\n if (operator === 'exists') {\n return actualValue !== null;\n }\n\n if (actualValue == null) {\n return false;\n }\n\n if (operator === 'equals') {\n return String(actualValue) === String(expectedValue);\n }\n\n if (operator === 'contains') {\n return String(actualValue).indexOf(String(expectedValue)) !== -1;\n }\n\n return false;\n }\n\n private doesEventMatchRule(event: SDKEvent, rule: PlacementEventRule): boolean {\n if (!rule || !isString(rule.eventAttributeKey)) {\n return false;\n }\n\n const conditions = rule.conditions;\n if (!Array.isArray(conditions)) {\n return false;\n }\n\n const actualValue = this.getEventAttributeValue(event, rule.eventAttributeKey);\n\n if (conditions.length === 0) {\n return actualValue !== null;\n }\n for (let i = 0; i < conditions.length; i++) {\n if (!this.doesEventAttributeConditionMatch(conditions[i], actualValue)) {\n return false;\n }\n }\n\n return true;\n }\n\n private applyPlacementEventAttributeMapping(event: SDKEvent): void {\n const mappedAttributeKeys = Object.keys(this.placementEventAttributeMappingLookup);\n for (let i = 0; i < mappedAttributeKeys.length; i++) {\n const mappedAttributeKey = mappedAttributeKeys[i];\n const rulesForMappedAttributeKey = this.placementEventAttributeMappingLookup[mappedAttributeKey];\n if (isEmpty(rulesForMappedAttributeKey)) {\n continue;\n }\n\n // Require ALL rules for the same key to match (AND).\n let allMatch = true;\n for (let j = 0; j < rulesForMappedAttributeKey.length; j++) {\n if (!this.doesEventMatchRule(event, rulesForMappedAttributeKey[j])) {\n allMatch = false;\n break;\n }\n }\n if (!allMatch) {\n continue;\n }\n\n mp().Rokt.setLocalSessionAttribute?.(mappedAttributeKey, true);\n }\n }\n\n private isLauncherReadyToAttach(): boolean {\n return !!window.Rokt && typeof window.Rokt.createLauncher === 'function';\n }\n\n /**\n * Returns the user identities from the filtered user, if any.\n */\n private returnUserIdentities(filteredUser: FilteredUser | null | undefined): Record {\n if (!filteredUser || !filteredUser.getUserIdentities) {\n return {};\n }\n\n const userIdentities: IUserIdentities = filteredUser.getUserIdentities().userIdentities;\n\n return this.replaceOtherIdentityWithEmailsha256(userIdentities);\n }\n\n private returnLocalSessionAttributes(): Record {\n if (!mp().Rokt || typeof mp().Rokt.getLocalSessionAttributes !== 'function') {\n return {};\n }\n if (isEmpty(this.placementEventMappingLookup) && isEmpty(this.placementEventAttributeMappingLookup)) {\n return {};\n }\n return mp().Rokt.getLocalSessionAttributes!();\n }\n\n private replaceOtherIdentityWithEmailsha256(userIdentities: IUserIdentities): Record {\n const newUserIdentities: Record = { ...(userIdentities || {}) };\n const key = this._mappedEmailSha256Key;\n if (key && userIdentities[key as keyof IUserIdentities]) {\n newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key as keyof IUserIdentities] as string;\n }\n if (key) {\n delete newUserIdentities[key];\n }\n\n return newUserIdentities;\n }\n\n private logSelectPlacementsEvent(attributes: unknown): void {\n if (!window.mParticle || typeof mp().logEvent !== 'function') {\n return;\n }\n\n if (!isObject(attributes)) {\n return;\n }\n\n const EVENT_TYPE_OTHER = mp().EventType.Other;\n\n mp().logEvent(EVENT_NAME_SELECT_PLACEMENTS, EVENT_TYPE_OTHER, attributes as Record);\n }\n\n private setRoktSessionId(sessionId: string): void {\n if (!sessionId || typeof sessionId !== 'string') {\n return;\n }\n try {\n const mpInstance = mp().getInstance();\n if (mpInstance && typeof mpInstance.setIntegrationAttribute === 'function') {\n mpInstance.setIntegrationAttribute(moduleId, {\n roktSessionId: sessionId,\n });\n }\n } catch (_e) {\n // Best effort — never let this break the partner page\n }\n }\n\n private attachLauncher(\n accountId: string,\n launcherOptions: Record,\n legacyRoktExtensions: string[] = [],\n ): void {\n const mpSessionId =\n mp() && mp().sessionManager && typeof mp().sessionManager!.getSession === 'function'\n ? mp().sessionManager!.getSession()\n : undefined;\n\n const options: Record = {\n accountId,\n ...(launcherOptions || {}),\n ...(mpSessionId ? { mpSessionId } : {}),\n };\n\n let launcherPromise: Promise;\n if (this.isPartnerInLocalLauncherTestGroup()) {\n launcherPromise = Promise.resolve(window.Rokt!.createLocalLauncher(options));\n } else {\n launcherPromise = window.Rokt!.createLauncher(options);\n }\n\n launcherPromise\n .then(async (launcher) => {\n await registerLegacyExtensions(legacyRoktExtensions, launcher);\n this.initRoktLauncher(launcher);\n })\n .catch((err: unknown) => {\n console.error('Error creating Rokt launcher:', err);\n });\n }\n\n private initRoktLauncher(launcher: RoktLauncher): void {\n // Assign the launcher to a global variable for later access\n if (window.Rokt) {\n window.Rokt.currentLauncher = launcher;\n }\n // Locally cache the launcher and filters\n this.launcher = launcher;\n\n const roktFilters = mp().Rokt?.filters;\n\n if (!roktFilters) {\n console.warn('Rokt Kit: No filters have been set.');\n } else {\n this.filters = roktFilters;\n if (!roktFilters.filteredUser) {\n console.warn('Rokt Kit: No filtered user has been set.');\n } else {\n this._workspaceSearchInFlightPromise = this.search(roktFilters.filteredUser);\n }\n }\n\n // Kit must be initialized before attaching to the Rokt manager\n this.isInitialized = true;\n\n sendAdBlockMeasurementSignals(this.domain, this.integrationName);\n\n // Attaches the kit to the Rokt manager\n mp().Rokt.attachKit(this);\n }\n\n private fetchOptimizely(): Record {\n const forwarders = mp()\n ._getActiveForwarders()\n .filter((forwarder) => forwarder.name === 'Optimizely');\n\n try {\n if (forwarders.length > 0 && window.optimizely) {\n const optimizelyState = window.optimizely.get('state');\n if (!optimizelyState || !optimizelyState.getActiveExperimentIds) {\n return {};\n }\n const activeExperimentIds = optimizelyState.getActiveExperimentIds();\n const activeExperiments = activeExperimentIds.reduce((acc: Record, expId: string) => {\n acc['rokt.custom.optimizely.experiment.' + expId + '.variationId'] =\n optimizelyState.getVariationMap()[expId].id;\n return acc;\n }, {});\n return activeExperiments;\n }\n } catch (error) {\n console.error('Error fetching Optimizely attributes:', error);\n }\n return {};\n }\n\n private isKitReady(): boolean {\n return !!(this.isInitialized && this.launcher);\n }\n\n private isPartnerInLocalLauncherTestGroup(): boolean {\n return !!(mp().config && mp().config!.isLocalLauncherEnabled && this.isAssignedToSampleGroup());\n }\n\n private isAssignedToSampleGroup(): boolean {\n const LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5;\n return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD;\n }\n\n private captureTiming(metricName: string): void {\n if (window && mp() && mp().captureTiming && metricName) {\n mp().captureTiming!(metricName);\n }\n }\n\n // ---- Public methods (mParticle Kit Callbacks) ----\n\n /**\n * Initializes the Rokt forwarder with settings from the mParticle server.\n */\n public init(\n settings: Record,\n _service: unknown,\n testMode: boolean,\n _trackerId: unknown,\n filteredUserAttributes?: Record,\n ): string {\n const kitSettings = settings as unknown as RoktKitSettings;\n const accountId = kitSettings.accountId;\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredUserAttributes);\n this._onboardingExpProvider = kitSettings.onboardingExpProvider;\n\n const placementEventMapping = parseSettingsString(kitSettings.placementEventMapping);\n this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping);\n\n const placementEventAttributeMapping = parseSettingsString(\n kitSettings.placementEventAttributeMapping,\n );\n this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping);\n\n // Set dynamic OTHER_IDENTITY based on server settings\n if (kitSettings.hashedEmailUserIdentityType) {\n this._mappedEmailSha256Key = kitSettings.hashedEmailUserIdentityType.toLowerCase();\n }\n\n this._workspaceIdSyncApiKey = isString(kitSettings.workspaceIdSyncApiKey)\n ? kitSettings.workspaceIdSyncApiKey\n : undefined;\n\n const domain = mp().Rokt?.domain;\n const { roktExtensionsQueryParams, legacyRoktExtensions, loadThankYouElement } = extractRoktExtensionConfig(\n kitSettings.roktExtensions,\n );\n const launcherOptions: Record = {\n ...((mp().Rokt?.launcherOptions as Record) || {}),\n };\n this.integrationName = generateIntegrationName(launcherOptions.integrationName as string | undefined);\n launcherOptions.integrationName = this.integrationName;\n\n this.domain = domain;\n\n const reportingConfig: ReportingConfig = {\n loggingUrl: kitSettings.loggingUrl,\n errorUrl: kitSettings.errorUrl,\n integrationDomain: domain,\n isLoggingEnabled: mp().config?.isLoggingEnabled === true,\n };\n const errorReportingService = new ErrorReportingService(\n reportingConfig,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n const loggingService = new LoggingService(\n reportingConfig,\n errorReportingService,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n\n this.errorReportingService = errorReportingService;\n this.loggingService = loggingService;\n\n if (mp()._registerErrorReportingService) {\n mp()._registerErrorReportingService!(errorReportingService);\n }\n if (mp()._registerLoggingService) {\n mp()._registerLoggingService!(loggingService);\n }\n\n if (testMode) {\n this.testHelpers = {\n generateLauncherScript: generateLauncherScript,\n generateThankYouElementScript: generateThankYouElementScript,\n extractRoktExtensionConfig: extractRoktExtensionConfig,\n hashEventMessage: hashEventMessage,\n parseSettingsString: parseSettingsString,\n generateMappedEventLookup: generateMappedEventLookup,\n generateMappedEventAttributeLookup: generateMappedEventAttributeLookup,\n sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals,\n createAutoRemovedIframe: createAutoRemovedIframe,\n djb2: djb2,\n setAllowedOriginHashes: (hashes: number[]) => {\n RoktKit._allowedOriginHashes = hashes;\n },\n ReportingTransport: ReportingTransport,\n ErrorReportingService: ErrorReportingService,\n LoggingService: LoggingService,\n RateLimiter: RateLimiter,\n ErrorCodes: ErrorCodes,\n WSDKErrorSeverity: WSDKErrorSeverity,\n };\n this.attachLauncher(accountId, launcherOptions);\n return 'Successfully initialized: ' + name;\n }\n\n if (loadThankYouElement) {\n mp().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this);\n loadRoktScript(ROKT_THANK_YOU_ELEMENT_SCRIPT_ID, generateThankYouElementScript(domain), {\n onLoad: () => {\n this._isThankYouElementLoaded = true;\n if (this._thankYouElementOnLoadCallback) {\n this._thankYouElementOnLoadCallback();\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt Thank You Element script:', error);\n },\n });\n }\n\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n loadRoktScript(ROKT_INTEGRATION_SCRIPT_ID, generateLauncherScript(domain, roktExtensionsQueryParams), {\n onLoad: () => {\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n console.error('Rokt object is not available after script load.');\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt launcher script:', error);\n },\n });\n\n this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended);\n }\n\n return 'Successfully initialized: ' + name;\n }\n\n public process(event: SDKEvent): string {\n if (!this.isKitReady()) {\n return 'Kit not ready for forwarder: ' + name;\n }\n if (typeof mp().Rokt?.setLocalSessionAttribute === 'function') {\n if (!isEmpty(this.placementEventAttributeMappingLookup)) {\n this.applyPlacementEventAttributeMapping(event);\n }\n\n if (!isEmpty(this.placementEventMappingLookup)) {\n const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? '');\n if (this.placementEventMappingLookup[String(hashedEvent)]) {\n mp().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(hashedEvent)], true);\n }\n }\n }\n\n return 'Successfully sent to forwarder: ' + name;\n }\n\n public setExtensionData(partnerExtensionData: Record): void {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return;\n }\n\n window.Rokt!.setExtensionData(partnerExtensionData);\n }\n\n public setUserAttribute(key: string, value: unknown): string {\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n this.userAttributes[key] = value;\n }\n return 'Successfully set user attribute for forwarder: ' + name;\n }\n\n public removeUserAttribute(key: string): string {\n delete this.userAttributes[key];\n return 'Successfully removed user attribute for forwarder: ' + name;\n }\n\n private handleIdentityComplete(user: IMParticleUser, callbackName: string): string {\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(user.getAllUserAttributes());\n return 'Successfully called ' + callbackName + ' for forwarder: ' + name;\n }\n\n public onUserIdentified(user: IMParticleUser): string {\n const filteredUser = user as FilteredUser;\n this.filters.filteredUser = filteredUser;\n this._workspaceSearchInFlightPromise = this.search(filteredUser);\n return this.handleIdentityComplete(user, 'onUserIdentified');\n }\n\n private search(filteredUser: FilteredUser): Promise {\n const apiKey = this._workspaceIdSyncApiKey;\n if (!apiKey) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n const search = mp().Identity?.search;\n if (typeof search !== 'function') {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n const userIdentities: IUserIdentities | null = filteredUser.getUserIdentities\n ? filteredUser.getUserIdentities().userIdentities\n : null;\n\n // Forward every non-empty string identifier the user has — email,\n // customerid, other/other2-10 (commonly used for hashed email),\n // mobile_number, facebook, etc. The host SDK's Identity.search accepts\n // the full IUserIdentities surface and the server validates it.\n const knownIdentities: Record = {};\n if (userIdentities) {\n for (const key of Object.keys(userIdentities) as Array) {\n const value = userIdentities[key];\n if (isString(value) && value.length > 0) {\n knownIdentities[key] = value;\n }\n }\n }\n\n const identityKeys = Object.keys(knownIdentities);\n if (identityKeys.length === 0) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n // Stable cache key: sort keys so insertion-order differences don't\n // cause false misses. The values are partner-supplied strings; no\n // hashing needed — equality on this serialization is sufficient.\n const identitiesKey = identityKeys\n .sort()\n .map((k) => `${k}=${knownIdentities[k]}`)\n .join('&');\n\n // Same identifier set as the last successful dispatch → skip the\n // network call. The current flag value still reflects the correct\n // match status.\n if (identitiesKey === this._workspaceLastSearchedIdentitiesKey) {\n return this._workspaceSearchInFlightPromise || Promise.resolve();\n }\n\n // New / different identifier set → reset and re-search. Cache the key\n // up front so a second concurrent invocation with the same set also\n // dedupes.\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = identitiesKey;\n\n return new Promise((resolve) => {\n try {\n search(apiKey, knownIdentities as IUserIdentities, (result: WorkspaceIdSyncResult) => {\n if (result?.httpCode === 200) {\n this.userIdentifiedInWorkspace = true;\n }\n resolve();\n });\n } catch (err) {\n console.error('Rokt Kit: Workspace IDSync search failed', err);\n // Dispatch failed — clear the cache so the same identifier set\n // can retry on the next identification rather than being stuck\n // behind a poisoned entry that short-circuits future searches.\n this._workspaceLastSearchedIdentitiesKey = undefined;\n resolve();\n }\n });\n }\n\n public onLoginComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onLoginComplete');\n }\n\n public onLogoutComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n // Anonymous sessions must not carry the previous user's match forward.\n // Clear the flag explicitly here. Also clear the identities cache so a\n // re-login (possibly with the same identifiers) dispatches a fresh\n // search rather than reusing a stale answer.\n this.userIdentifiedInWorkspace = false;\n this._workspaceSearchInFlightPromise = null;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return this.handleIdentityComplete(user, 'onLogoutComplete');\n }\n\n public onModifyComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onModifyComplete');\n }\n\n /**\n * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options.\n *\n * If a Workspace IDSync search is in flight from a recent onUserIdentified\n * call, this method waits up to `WORKSPACE_SEARCH_SELECT_TIMEOUT_MS` for it\n * to settle so the first placement call can include the\n * `userIdentifiedInWorkspace` flag without racing the network response.\n * The timeout protects against a stalled or slow search blocking placement\n * rendering — if it fires, selectPlacements proceeds without the flag.\n *\n * Implementation note: this method stays non-async deliberately. First,\n * the public return type is `RoktSelection | Promise |\n * undefined` — a superset of the `RoktSelection | Promise`\n * shape declared for `RoktLauncher.selectPlacements` above (line ~70).\n * Marking this `async` would narrow it to `Promise` and silently change the contract for callers that read\n * the result synchronously. Second, `RoktSelection` has an optional\n * `then?` member, so TS treats it as ambiguously promise-like and\n * rejects it as the awaited return of an async function (TS1058) —\n * working around that would require a cast or wrapping every return in\n * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`;\n * this wrapper just gates it on the in-flight search via `Promise.race`.\n */\n public selectPlacements(options: Record): RoktSelection | Promise | undefined {\n if (this._workspaceSearchInFlightPromise) {\n const inFlight = this._workspaceSearchInFlightPromise;\n return Promise.race([\n inFlight,\n new Promise((resolve) => setTimeout(resolve, WORKSPACE_SEARCH_SELECT_TIMEOUT_MS)),\n ]).then(() => this._dispatchPlacements(options)) as Promise;\n }\n return this._dispatchPlacements(options);\n }\n\n private _dispatchPlacements(options: Record): RoktSelection | Promise | undefined {\n const attributes = ((options && (options.attributes as Record)) || {}) as Record;\n const cachedUserAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(this.userAttributes);\n const placementAttributes: Record = { ...cachedUserAttributes, ...attributes };\n\n const filters = this.filters || {};\n const userAttributeFilters = (filters.userAttributeFilters as string[]) || [];\n const filteredUser = filters.filteredUser || null;\n const mpid = filteredUser ? filteredUser.getMPID() : null;\n\n let filteredAttributes: Record;\n\n if (!filters) {\n console.warn('Rokt Kit: No filters available, using user attributes');\n filteredAttributes = placementAttributes;\n } else if (filters.filterUserAttributes) {\n filteredAttributes = filters.filterUserAttributes(placementAttributes, userAttributeFilters);\n } else {\n filteredAttributes = placementAttributes;\n }\n\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredAttributes);\n\n const optimizelyAttributes = this._onboardingExpProvider === 'Optimizely' ? this.fetchOptimizely() : {};\n\n const filteredUserIdentities = this.returnUserIdentities(filteredUser);\n\n const localSessionAttributes = this.returnLocalSessionAttributes();\n\n const selectPlacementsAttributes: Record = {\n ...(filteredUserIdentities as Record),\n ...filteredAttributes,\n ...optimizelyAttributes,\n ...localSessionAttributes,\n ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}),\n mpid,\n };\n\n const selectPlacementsOptions: Record = { ...options, attributes: selectPlacementsAttributes };\n\n const selection = this.launcher!.selectPlacements(selectPlacementsOptions);\n\n // After selection resolves, sync the Rokt session ID back to mParticle, then log\n const logSelection = () => this.logSelectPlacementsEvent(selectPlacementsAttributes);\n\n void Promise.resolve(selection)\n .then((sel) => sel?.context?.sessionId?.then((sessionId) => this.setRoktSessionId(sessionId)))\n .catch(() => undefined)\n .finally(logSelection);\n\n return selection;\n }\n\n /**\n * Passes attributes to the Rokt Web SDK for client-side hashing.\n */\n public hashAttributes(attributes: Record): Promise> | null {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return null;\n }\n return this.launcher!.hashAttributes(attributes);\n }\n\n /**\n * Enables optional Integration Launcher extensions before selecting placements.\n *\n * @deprecated This functionality has been internalized and will be removed in a future release.\n */\n public use(extensionName: string): Promise {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return Promise.reject(new Error('Rokt Kit: Not initialized'));\n }\n if (!extensionName || !isString(extensionName)) {\n return Promise.reject(new Error('Rokt Kit: Invalid extension name'));\n }\n return this.launcher!.use(extensionName);\n }\n\n /**\n * Registers a callback to be invoked once rokt-thank-you-element.js becomes available.\n */\n public onShoppableAdsReady(callback: () => void) {\n if (this._isThankYouElementLoaded) {\n callback();\n } else {\n this._thankYouElementOnLoadCallback = callback;\n }\n }\n}\n\n// ============================================================\n// Kit registration\n// ============================================================\n\nfunction getId(): number {\n return moduleId;\n}\n\nfunction register(config: { kits?: Record }): void {\n if (!config) {\n window.console.log('You must pass a config object to register the kit ' + name);\n return;\n }\n if (!isObject(config)) {\n window.console.log(\"'config' must be an object. You passed in a \" + typeof config);\n return;\n }\n\n if (isObject(config.kits)) {\n (config.kits as Record)[name] = {\n constructor: RoktKit,\n };\n } else {\n config.kits = {};\n config.kits[name] = {\n constructor: RoktKit,\n };\n }\n window.console.log('Successfully registered ' + name + ' to your mParticle configuration');\n}\n\nif (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) {\n mp().addForwarder({\n name: name,\n constructor: RoktKit,\n getId: getId,\n });\n}\n\nexport { register };\n"],"names":["SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST","SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET","isSelectPlacementsAttributePersistenceDenied","key","removeSelectPlacementsAttributePersistenceDeniedAttributes","attributes","filteredAttributes","sourceAttributes","attributeKeys","i","name","moduleId","EVENT_NAME_SELECT_PLACEMENTS","ADBLOCK_CONTROL_DOMAIN","INIT_LOG_SAMPLING_RATE","ROKT_THANK_YOU_JOURNEY_EXTENSION","ROKT_INTEGRATION_SCRIPT_ID","ROKT_THANK_YOU_ELEMENT_SCRIPT_ID","USER_IDENTIFIED_IN_WORKSPACE_KEY","WORKSPACE_SEARCH_SELECT_TIMEOUT_MS","ErrorCodes","WSDKErrorSeverity","DEFAULT_ROKT_DOMAIN","LOGGING_ENDPOINT","ERROR_ENDPOINT","RATE_LIMIT_PER_SEVERITY","mp","generateLauncherScript","domain","extensions","baseUrl","generateBaseUrl","generateThankYouElementScript","generateReportingUrl","configuredUrl","endpoint","loadRoktScript","scriptId","source","handlers","target","script","isObject","val","parseSettingsString","settingsString","extractRoktExtensionConfig","settings","roktExtensionsQueryParams","legacyRoktExtensions","loadThankYouElement","extensionName","registerLegacyExtensions","legacyExtensions","launcher","extension","generateMappedEventLookup","placementEventMapping","mappedEvents","mapping","generateMappedEventAttributeLookup","placementEventAttributeMapping","mappedAttributeKeys","isString","mappedAttributeKey","eventAttributeKey","hashEventMessage","messageType","eventType","eventName","isEmpty","value","generateIntegrationName","customIntegrationName","integrationName","djb2","str","hash","createAutoRemovedIframe","src","iframe","sendAdBlockMeasurementSignals","version","originHash","RoktKit","guid","pageUrl","params","_isDebugModeEnabled","_getReportingUrl","_getUserAgent","RateLimiter","severity","newCount","ReportingTransport","config","launcherInstanceGuid","accountId","rateLimiter","isLoggingEnabled","url","msg","code","stackTrace","onError","logRequest","headers","response","serverError","error","ErrorReportingService","LoggingService","errorReportingService","entry","isServerSide","_RoktKit","event","condition","actualValue","operator","expectedValue","rule","conditions","rulesForMappedAttributeKey","allMatch","j","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","launcherOptions","mpSessionId","options","launcherPromise","err","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","loggingService","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","search","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","localSessionAttributes","selectPlacementsAttributes","selectPlacementsOptions","selection","logSelection","sel","callback","getId","register"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"Rokt-Kit.iife.js","sources":["../src/selectPlacementsAttributePersistence.ts","../src/utils.ts","../src/storage.ts","../src/pageViewStorage.ts","../src/Rokt-Kit.ts"],"sourcesContent":["const SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST = [\n 'active_time_on_site_ms',\n 'billingaddress1',\n 'billingaddress2',\n 'billingcity',\n 'billingstate',\n 'billingzipcode',\n 'cartitems',\n 'ccbin',\n 'confirmationref',\n 'conversiontype',\n 'country',\n 'couponcode',\n 'currency',\n 'language',\n 'paymentserviceprovider',\n 'paymentserviceproviderattribute',\n 'paymenttype',\n 'shippingaddress1',\n 'shippingcity',\n 'shippingcountry',\n 'shippingmethod',\n 'shippingstate',\n 'shippingzipcode',\n 'totalprice',\n];\nconst SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET = new Set(SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST);\n\nexport function isSelectPlacementsAttributePersistenceDenied(key: string): boolean {\n return SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET.has(key.toLowerCase());\n}\n\nexport function removeSelectPlacementsAttributePersistenceDeniedAttributes(\n attributes: Record | null | undefined,\n): Record {\n const filteredAttributes: Record = {};\n const sourceAttributes = attributes || {};\n const attributeKeys = Object.keys(sourceAttributes);\n\n for (let i = 0; i < attributeKeys.length; i++) {\n const key = attributeKeys[i];\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n filteredAttributes[key] = sourceAttributes[key];\n }\n }\n\n return filteredAttributes;\n}\n","export function isObject(value: unknown): value is Record {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nexport function isFunction(value: unknown): value is (...args: Array) => unknown {\n return typeof value === 'function';\n}\n\nexport function isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'object') {\n return Object.keys(value as object).length === 0;\n }\n return false;\n}\n\n// Strips the query string from a URL before it is persisted and sent to Rokt,\n// since query params commonly carry PII (emails, tokens, order refs).\n// Returns the input unchanged if it can't be parsed as a URL.\nexport function sanitizeUrl(href: string): string {\n try {\n const url = new URL(href);\n url.search = '';\n return url.toString();\n } catch {\n return href;\n }\n}\n","import { isObject } from './utils';\n\nconst LS_PROBE_KEY = '__rokt_ls_probe__';\n\nexport function isLocalStorageAvailable(): boolean {\n try {\n window.localStorage.setItem(LS_PROBE_KEY, '1');\n window.localStorage.removeItem(LS_PROBE_KEY);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function readJSON(key: string): unknown {\n try {\n const stored = window.localStorage.getItem(key);\n return stored === null ? null : JSON.parse(stored);\n } catch {\n return null;\n }\n}\n\nexport function writeJSON(key: string, value: unknown): boolean {\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n return true;\n } catch {\n return false;\n }\n}\n\nexport function removeKey(key: string): void {\n try {\n window.localStorage.removeItem(key);\n } catch {\n /* empty */\n }\n}\n\nexport function readNamespacedField(namespaceKey: string, field: string): unknown {\n const blob = readJSON(namespaceKey);\n return isObject(blob) ? blob[field] : undefined;\n}\n\nexport function writeNamespacedField(namespaceKey: string, field: string, value: unknown): boolean {\n const blob = readJSON(namespaceKey);\n const next = isObject(blob) ? { ...blob } : {};\n next[field] = value;\n return writeJSON(namespaceKey, next);\n}\n\nexport function removeNamespacedField(namespaceKey: string, field: string): void {\n const blob = readJSON(namespaceKey);\n if (!isObject(blob) || !(field in blob)) {\n return;\n }\n const next = { ...blob };\n delete next[field];\n if (Object.keys(next).length === 0) {\n removeKey(namespaceKey);\n } else {\n writeJSON(namespaceKey, next);\n }\n}\n","import type { LoggingService } from './Rokt-Kit';\nimport {\n readJSON,\n removeKey,\n readNamespacedField,\n writeNamespacedField,\n removeNamespacedField,\n isLocalStorageAvailable,\n} from './storage';\nimport { sanitizeUrl, isObject } from './utils';\n\nconst LS_NAMESPACE_KEY = 'mp-rokt-kit';\nconst LS_PAGE_VIEWS_FIELD = 'pageViews';\nconst LS_UTM_PARAMS_FIELD = 'utmParams';\nconst LEGACY_PAGE_VIEWS_KEY = 'mpPageViews';\nexport const PAGE_VIEWS_MAX_COUNT = 25;\n\nconst UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'] as const;\ntype UtmKey = (typeof UTM_KEYS)[number];\nexport type UtmParams = Partial>;\n\nexport interface PageEvent {\n pageUrl: string;\n sourceMessageId: string;\n timestamp: number;\n pageTitle?: string;\n canonicalUrl?: string;\n activeTimeOnSite?: number;\n activeTimeOnPage?: number;\n}\n\nfunction capPageViews(views: PageEvent[]): PageEvent[] {\n return views.slice(-PAGE_VIEWS_MAX_COUNT);\n}\n\nexport function migrateLegacyPageViewStorage(loggingService: LoggingService | null): void {\n const legacyViews = readJSON(LEGACY_PAGE_VIEWS_KEY);\n if (legacyViews === null) {\n return;\n }\n\n const alreadyMigrated = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD) !== undefined;\n const needsMigration = !alreadyMigrated && Array.isArray(legacyViews);\n\n if (needsMigration) {\n loggingService?.log({\n message: 'Rokt Kit: Migrating legacy page-view storage',\n code: 'PAGE_VIEW_LEGACY_MIGRATION',\n });\n const migrated = writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, legacyViews);\n if (!migrated) {\n loggingService?.log({\n message: 'Rokt Kit: Failed to migrate legacy page-view storage [reason: migration_retry]',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n removeKey(LEGACY_PAGE_VIEWS_KEY);\n}\n\nexport function loadPageViews(loggingService: LoggingService | null): PageEvent[] {\n migrateLegacyPageViewStorage(loggingService);\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n return Array.isArray(stored) ? (stored as PageEvent[]) : [];\n}\n\nexport function writePageViews(pageViews: PageEvent[]): number {\n const views = capPageViews(pageViews);\n for (let i = 0; i < views.length; i++) {\n const toWrite = views.slice(i);\n if (writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, toWrite)) {\n return toWrite.length;\n }\n }\n return 0;\n}\n\nexport function clearPageViews(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n}\n\nexport function buildPageEvents(pageViews: PageEvent[]): PageEvent[] {\n const views = capPageViews(pageViews);\n return views.map((pageView, index) => {\n const activeTimeOnSite = pageView.activeTimeOnSite;\n const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite);\n\n const next = views[index + 1];\n const nextActiveTimeOnSite = next?.activeTimeOnSite;\n const hasNextActiveTimeOnSite = nextActiveTimeOnSite !== undefined && Number.isFinite(nextActiveTimeOnSite);\n\n const diff = hasActiveTime && hasNextActiveTimeOnSite ? nextActiveTimeOnSite - activeTimeOnSite : undefined;\n\n return {\n pageUrl: pageView.pageUrl,\n sourceMessageId: pageView.sourceMessageId,\n timestamp: pageView.timestamp,\n ...(pageView.pageTitle !== undefined ? { pageTitle: pageView.pageTitle } : {}),\n ...(pageView.canonicalUrl !== undefined ? { canonicalUrl: pageView.canonicalUrl } : {}),\n ...(hasActiveTime ? { activeTimeOnSite } : {}),\n ...(diff !== undefined && diff >= 0 ? { activeTimeOnPage: diff } : {}),\n };\n });\n}\n\nexport function captureUtmParams(loggingService: LoggingService | null): void {\n if (readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD) !== undefined) {\n return;\n }\n const search = new URLSearchParams(window.location.search);\n const params: UtmParams = {};\n for (const key of UTM_KEYS) {\n const value = search.get(key);\n if (value) params[key] = value;\n }\n if (Object.keys(params).length === 0) {\n return;\n }\n const captured = Object.keys(params).join(', ');\n if (!writeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD, params)) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n loggingService?.log({\n message: `Rokt Kit: Failed to persist UTM params [reason: ${reason}]`,\n code: 'UTM_CAPTURE_FAILED',\n });\n return;\n }\n loggingService?.log({\n message: `Rokt Kit: Captured UTM params [${captured}]`,\n code: 'UTM_CAPTURE_SUCCESS',\n });\n}\n\nexport function loadUtmParams(): UtmParams | null {\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n return isObject(stored) ? (stored as UtmParams) : null;\n}\n\nexport function clearUtmParams(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n}\n\nexport function readCanonicalUrl(): string | undefined {\n const link = document.querySelector('link[rel=\"canonical\"]');\n const href = link?.href;\n if (!href) {\n return undefined;\n }\n return sanitizeUrl(href);\n}\n","// Copyright 2025 mParticle, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// ============================================================\n// Types\n// ============================================================\n\nimport { KitInterface, IMParticleUser, SDKEvent } from '@mparticle/web-sdk/internal';\nimport type { IUserIdentities } from '@mparticle/web-sdk';\n\nimport {\n isSelectPlacementsAttributePersistenceDenied,\n removeSelectPlacementsAttributePersistenceDeniedAttributes,\n} from './selectPlacementsAttributePersistence';\n\nimport {\n PageEvent,\n PAGE_VIEWS_MAX_COUNT,\n buildPageEvents,\n migrateLegacyPageViewStorage,\n loadPageViews,\n writePageViews,\n clearPageViews,\n readCanonicalUrl,\n captureUtmParams,\n loadUtmParams,\n clearUtmParams,\n} from './pageViewStorage';\nimport { isLocalStorageAvailable } from './storage';\n\nimport { isObject, isString, isEmpty, isFunction, sanitizeUrl } from './utils';\n\ninterface RoktKitSettings {\n accountId: string;\n roktExtensions?: string;\n placementEventMapping?: string;\n placementEventAttributeMapping?: string;\n hashedEmailUserIdentityType?: string;\n onboardingExpProvider?: string;\n loggingUrl?: string;\n errorUrl?: string;\n workspaceIdSyncApiKey?: string;\n}\n\ninterface EventAttributeCondition {\n operator: string;\n attributeValue: string;\n}\n\ninterface PlacementEventRule {\n eventAttributeKey: string;\n conditions: EventAttributeCondition[];\n}\n\ninterface EventAttributeMapping {\n value: string;\n map: string;\n conditions?: EventAttributeCondition[];\n}\n\ninterface PlacementEventMappingEntry {\n jsmap: string;\n value: string;\n}\n\ninterface RoktExtensionEntry {\n value: string;\n}\n\ninterface RoktSelection {\n context?: {\n sessionId?: Promise;\n };\n then?: (callback: (sel: RoktSelection) => void) => Promise;\n catch?: (callback: () => void) => void;\n}\n\ninterface RoktLauncher {\n selectPlacements(options: Record): RoktSelection | Promise;\n hashAttributes(attributes: Record): Promise>;\n use(extensionName: string): Promise;\n}\n\ninterface RoktGlobal {\n createLauncher(options: Record): Promise;\n createLocalLauncher(options: Record): RoktLauncher;\n currentLauncher?: RoktLauncher;\n setExtensionData(data: Record): void;\n}\n\n// FilteredUser is the IMParticleUser shape we receive after kit filtering.\n// `getMPID` and `getUserIdentities` are inherited from the SDK's `User` base type.\ntype FilteredUser = IMParticleUser;\n\n// TODO: Replace with `IIdentitySearchResult` from `@mparticle/web-sdk` once\n// a version that exports it is published (currently on a feature branch in\n// mParticle/mparticle-web-sdk PR #1255). The shape below is intentionally\n// structurally identical so the swap is a one-line import change.\ninterface WorkspaceIdSyncResult {\n httpCode: number;\n body?: {\n context?: string | null;\n mpid?: string;\n matched_identities?: Record;\n is_ephemeral?: boolean;\n is_logged_in?: boolean;\n };\n}\n\n// TODO: Replace with `IdentitySearchCallback`-compatible reference from\n// `@mparticle/web-sdk` once published (mirrors `SDKIdentityApi.search`).\ntype WorkspaceIdSyncSearcher = (\n apiKey: string,\n knownIdentities: IUserIdentities,\n callback: (result: WorkspaceIdSyncResult) => void,\n) => void;\n\ninterface KitFilters {\n userAttributeFilters?: string[];\n filterUserAttributes?: (attributes: Record, filters?: string[]) => Record;\n filteredUser?: FilteredUser | null;\n}\n\ninterface RoktManager {\n attachKit(kit: RoktKit): void | Promise;\n flushOnShoppableAdsReadyMessageQueue?(kit: RoktKit): void;\n filters?: KitFilters;\n domain?: string;\n launcherOptions?: Record;\n getLocalSessionAttributes?(): Record;\n setLocalSessionAttribute?(key: string, value: unknown): void;\n}\n\ninterface MParticleInstance {\n setIntegrationAttribute(moduleId: number, attrs: Record): void;\n}\n\ninterface OptimizelyState {\n getActiveExperimentIds(): string[];\n getVariationMap(): Record;\n}\n\ninterface OptimizelyGlobal {\n get(key: 'state'): OptimizelyState;\n}\n\n// Our view of the mParticle global with Rokt-specific extensions.\n// We access window.mParticle via an explicit cast (see `mp()` helper below)\n// rather than augmenting Window to avoid conflicts with @mparticle/web-sdk declarations.\ninterface MParticleExtended {\n Rokt: RoktManager;\n addForwarder(config: ForwarderRegistration): void;\n getVersion(): string;\n generateHash(value: string): string | number;\n logEvent(name: string, type: number, attrs?: Record): void;\n EventType: { Other: number };\n getInstance(): MParticleInstance;\n getDeviceId?(): string;\n sessionManager?: { getSession?(): string; getSessionId?(): string };\n _getActiveForwarders(): Array<{ name: string }>;\n config?: { isLocalLauncherEnabled?: boolean; isLoggingEnabled?: boolean };\n captureTiming?(metricName: string): void;\n forwarder?: RoktKit;\n loggedEvents?: Array>;\n _registerErrorReportingService?(service: ErrorReportingService): void;\n _registerLoggingService?(service: LoggingService): void;\n Identity?: { search?: WorkspaceIdSyncSearcher };\n}\n\ninterface TestHelpers {\n generateLauncherScript: (domain: string | undefined, extensions: string[]) => string;\n generateThankYouElementScript: (domain: string | undefined) => string;\n extractRoktExtensionConfig: (settingsString?: string) => RoktExtensionConfig;\n hashEventMessage: (messageType: number, eventType: number, eventName: string) => string | number;\n parseSettingsString: (settingsString?: string) => T[];\n generateMappedEventLookup: (placementEventMapping: PlacementEventMappingEntry[]) => Record;\n generateMappedEventAttributeLookup: (mapping: EventAttributeMapping[]) => Record;\n sendAdBlockMeasurementSignals: (domain: string | undefined, version: string | null) => void;\n createAutoRemovedIframe: (src: string) => void;\n djb2: (str: string) => number;\n setAllowedOriginHashes: (hashes: number[]) => void;\n ReportingTransport: typeof ReportingTransport;\n ErrorReportingService: typeof ErrorReportingService;\n LoggingService: typeof LoggingService;\n RateLimiter: typeof RateLimiter;\n ErrorCodes: typeof ErrorCodes;\n WSDKErrorSeverity: typeof WSDKErrorSeverity;\n}\n\ninterface ForwarderRegistration {\n name: string;\n constructor: new () => RoktKit;\n getId: () => number;\n}\n\ninterface ReportingConfig {\n loggingUrl?: string;\n errorUrl?: string;\n integrationDomain?: string;\n isLoggingEnabled: boolean;\n}\n\ninterface ErrorReport {\n message: string;\n code?: string;\n severity?: string;\n stackTrace?: string;\n}\n\n// A log-delivery failure. statusCode is set when the request reached the server\n// and returned a non-2xx status (server-side); it is absent for network-level\n// failures such as ad-blockers, offline, or CORS rejections (client-side).\ninterface DeliveryError extends Error {\n statusCode?: number;\n}\n\ninterface LogEntry {\n message: string;\n code?: string;\n}\n\ninterface RoktExtensionConfig {\n roktExtensionsQueryParams: string[];\n legacyRoktExtensions: string[];\n loadThankYouElement: boolean;\n}\n\ndeclare global {\n interface Window {\n Rokt?: RoktGlobal;\n __rokt_li_guid__?: string;\n optimizely?: OptimizelyGlobal;\n // mParticle is declared as any to avoid conflicts with @mparticle/web-sdk type declarations.\n // We use the typed mp() accessor for all internal accesses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mParticle: any;\n }\n}\n\n// ============================================================\n// Module-level constants\n// ============================================================\n\nconst name = 'Rokt';\nconst moduleId = 181;\nconst EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements';\nconst ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com';\nconst INIT_LOG_SAMPLING_RATE = 0.1;\nconst ROKT_THANK_YOU_JOURNEY_EXTENSION = 'ThankYouPageJourney';\nconst ROKT_INTEGRATION_SCRIPT_ID = 'rokt-launcher';\nconst ROKT_THANK_YOU_ELEMENT_SCRIPT_ID = 'rokt-thank-you-element';\nconst USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace';\n\nconst MESSAGE_TYPE_PAGE_VIEW = 3; // mParticle MessageType.PageView\nconst MESSAGE_TYPE_SESSION_END = 2; // mParticle MessageType.SessionEnd\nconst PAGE_EVENTS_KEY = 'page_events';\nconst PAGE_VIEW_ATTRIBUTES_KEY = 'page_view_attributes';\nconst MPARTICLE_SESSION_ID_KEY = 'mparticle_session_id';\nconst MPARTICLE_DEVICE_ID_KEY = 'mparticle_device_id';\n\n// Bound on how long selectPlacements will wait for an in-flight Workspace\n// IDSync search before proceeding without the userIdentifiedInWorkspace flag.\n// Long enough to cover the typical /v1/search round-trip (~50ms); short enough that a\n// stalled search never blocks placement rendering on a thank-you page.\nconst WORKSPACE_SEARCH_SELECT_TIMEOUT_MS = 500;\n\n// ============================================================\n// Reporting service constants\n// ============================================================\n\nconst ErrorCodes = {\n UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION',\n IDENTITY_REQUEST: 'IDENTITY_REQUEST',\n LOG_DELIVERY_FAILURE: 'LOG_DELIVERY_FAILURE',\n} as const;\n\nconst WSDKErrorSeverity = {\n ERROR: 'ERROR',\n INFO: 'INFO',\n WARNING: 'WARNING',\n} as const;\n\nconst DEFAULT_ROKT_DOMAIN = 'apps.rokt-api.com';\nconst LOGGING_ENDPOINT = '/v1/log';\nconst ERROR_ENDPOINT = '/v1/errors';\nconst RATE_LIMIT_PER_SEVERITY = 10;\n\n// ============================================================\n// Helper: typed accessor for window.mParticle\n// We use an explicit cast here to avoid conflicts with @mparticle/web-sdk\n// type declarations while still providing full type safety for our usages.\n// ============================================================\n\nfunction mp(): MParticleExtended {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (window as any).mParticle as MParticleExtended;\n}\n\n// ============================================================\n// Module-level utility functions\n// ============================================================\n\nfunction generateLauncherScript(domain: string | undefined, extensions: string[]): string {\n const launcherPath = '/wsdk/integrations/launcher.js';\n const baseUrl = [generateBaseUrl(domain), launcherPath].join('');\n\n if (!extensions || extensions.length === 0) {\n return baseUrl;\n }\n return baseUrl + '?extensions=' + extensions.join(',');\n}\n\nfunction generateThankYouElementScript(domain: string | undefined) {\n const thankYouElementPath = '/rokt-elements/rokt-element-thank-you.js';\n return [generateBaseUrl(domain), thankYouElementPath].join('');\n}\n\nfunction generateBaseUrl(domain: string | undefined) {\n const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN;\n\n if (resolvedDomain.includes('://')) {\n return resolvedDomain.replace(/\\/+$/, '');\n }\n\n const protocol = 'https://';\n\n return [protocol, resolvedDomain].join('');\n}\n\nfunction generateReportingUrl(configuredUrl: string | undefined, domain: string | undefined, endpoint: string): string {\n if (configuredUrl) {\n if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://')) {\n return configuredUrl;\n }\n return 'https://' + configuredUrl;\n }\n\n const hasNonHttpScheme = domain?.includes('://') && !/^https?:\\/\\//i.test(domain);\n const reportingDomain = hasNonHttpScheme ? undefined : domain;\n\n return generateBaseUrl(reportingDomain) + endpoint;\n}\n\nfunction loadRoktScript(\n scriptId: string,\n source: string,\n handlers?: { onLoad?: () => void; onError?: (e: Event | string) => void },\n): void {\n if (document.getElementById(scriptId)) return; // resolves the preexisting script issue\n\n const target = document.head || document.body;\n const script = document.createElement('script');\n script.id = scriptId;\n script.type = 'text/javascript';\n script.src = source;\n script.async = true;\n script.crossOrigin = 'anonymous';\n (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high';\n if (handlers?.onLoad) script.onload = handlers.onLoad;\n if (handlers?.onError) script.onerror = handlers.onError;\n target.appendChild(script);\n}\n\nfunction parseSettingsString(settingsString?: string): T[] {\n if (!settingsString) {\n return [];\n }\n try {\n return JSON.parse(settingsString.replace(/"/g, '\"')) as T[];\n } catch (_error) {\n console.error('Settings string contains invalid JSON');\n }\n return [];\n}\n\nfunction extractRoktExtensionConfig(settingsString?: string): RoktExtensionConfig {\n const settings = settingsString ? parseSettingsString(settingsString) : [];\n const roktExtensionsQueryParams: string[] = [];\n const legacyRoktExtensions: string[] = [];\n let loadThankYouElement = false;\n\n for (let i = 0; i < settings.length; i++) {\n const extensionName = settings[i].value;\n if (extensionName === 'thank-you-journey') {\n loadThankYouElement = true;\n legacyRoktExtensions.push(ROKT_THANK_YOU_JOURNEY_EXTENSION);\n } else {\n roktExtensionsQueryParams.push(extensionName);\n }\n }\n\n return {\n roktExtensionsQueryParams,\n legacyRoktExtensions,\n loadThankYouElement,\n };\n}\n\nasync function registerLegacyExtensions(legacyExtensions: string[], launcher: RoktLauncher | null) {\n const extensions: Promise[] = [];\n if (launcher) {\n for (const extension of legacyExtensions) {\n extensions.push(launcher.use(extension));\n }\n }\n\n return Promise.all(extensions);\n}\n\nfunction generateMappedEventLookup(placementEventMapping: PlacementEventMappingEntry[]): Record {\n if (!placementEventMapping) {\n return {};\n }\n\n const mappedEvents: Record = {};\n for (let i = 0; i < placementEventMapping.length; i++) {\n const mapping = placementEventMapping[i];\n mappedEvents[mapping.jsmap] = mapping.value;\n }\n return mappedEvents;\n}\n\nfunction generateMappedEventAttributeLookup(\n placementEventAttributeMapping: EventAttributeMapping[],\n): Record {\n const mappedAttributeKeys: Record = {};\n if (!Array.isArray(placementEventAttributeMapping)) {\n return mappedAttributeKeys;\n }\n for (let i = 0; i < placementEventAttributeMapping.length; i++) {\n const mapping = placementEventAttributeMapping[i];\n if (!mapping || !isString(mapping.value) || !isString(mapping.map)) {\n continue;\n }\n\n const mappedAttributeKey = mapping.value;\n const eventAttributeKey = mapping.map;\n\n if (!mappedAttributeKeys[mappedAttributeKey]) {\n mappedAttributeKeys[mappedAttributeKey] = [];\n }\n\n mappedAttributeKeys[mappedAttributeKey].push({\n eventAttributeKey: eventAttributeKey,\n conditions: Array.isArray(mapping.conditions) ? mapping.conditions : [],\n });\n }\n return mappedAttributeKeys;\n}\n\nfunction hashEventMessage(messageType: number, eventType: number, eventName: string): string | number {\n return mp().generateHash([messageType, eventType, eventName].join(''));\n}\n\nfunction generateIntegrationName(customIntegrationName?: string): string {\n const coreSdkVersion = mp().getVersion();\n const kitVersion = process.env.PACKAGE_VERSION;\n let integrationName = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion;\n\n if (customIntegrationName) {\n integrationName += '_' + customIntegrationName;\n }\n return integrationName;\n}\n\nfunction djb2(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return hash;\n}\n\nfunction createAutoRemovedIframe(src: string): void {\n const iframe = document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');\n iframe.src = src;\n iframe.onload = function () {\n iframe.onload = null;\n if (iframe.parentNode) {\n iframe.parentNode.removeChild(iframe);\n }\n };\n const target = document.body || document.head;\n if (target) {\n target.appendChild(iframe);\n }\n}\n\nfunction sendAdBlockMeasurementSignals(domain: string | undefined, version: string | null): void {\n const originHash = djb2(window.location.origin);\n const allowedOriginHashes = RoktKit._allowedOriginHashes;\n if (allowedOriginHashes.indexOf(originHash) === -1) {\n return;\n }\n\n if (Math.random() >= INIT_LOG_SAMPLING_RATE) {\n return;\n }\n\n const guid = window.__rokt_li_guid__;\n if (!guid) {\n return;\n }\n\n if (domain && domain.includes('://') && !/^https:\\/\\//i.test(domain)) {\n return;\n }\n\n const pageUrl = window.location.href.split('?')[0].split('#')[0];\n const params =\n 'version=' +\n encodeURIComponent(version ?? '') +\n '&launcherInstanceGuid=' +\n encodeURIComponent(guid) +\n '&pageUrl=' +\n encodeURIComponent(pageUrl);\n\n const existingBaseUrl = domain ? generateBaseUrl(domain) : 'https://apps.rokt.com';\n createAutoRemovedIframe(existingBaseUrl + '/v1/wsdk-init/index.html?' + params);\n\n createAutoRemovedIframe(\n 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true',\n );\n}\n\n// ============================================================\n// Reporting helpers\n// ============================================================\n\nfunction _isDebugModeEnabled(): boolean {\n return typeof window !== 'undefined' && !!window.location?.search?.toLowerCase().includes('mp_enable_logging=true');\n}\n\nfunction _getReportingUrl(): string | undefined {\n return typeof window !== 'undefined' ? window.location?.href : undefined;\n}\n\nfunction _getUserAgent(): string | undefined {\n return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined;\n}\n\nclass RateLimiter {\n private _logCount: Record = {};\n\n incrementAndCheck(severity: string): boolean {\n const count = this._logCount[severity] || 0;\n const newCount = count + 1;\n this._logCount[severity] = newCount;\n return newCount > RATE_LIMIT_PER_SEVERITY;\n }\n}\n\nclass ReportingTransport {\n private _isEnabled: boolean;\n private _integrationName: string;\n private _launcherInstanceGuid: string | undefined;\n private _accountId: string | null;\n private _rateLimiter: RateLimiter;\n private readonly _reporter = 'mp-wsdk';\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid: string | undefined,\n accountId: string | null | undefined,\n rateLimiter?: RateLimiter,\n ) {\n const isLoggingEnabled = config.isLoggingEnabled;\n this._integrationName = integrationName || '';\n this._launcherInstanceGuid = launcherInstanceGuid;\n this._accountId = accountId || null;\n this._rateLimiter = rateLimiter || new RateLimiter();\n this._isEnabled = _isDebugModeEnabled() || isLoggingEnabled;\n }\n\n send(\n url: string,\n severity: string,\n msg: string,\n code?: string,\n stackTrace?: string,\n onError?: (error: DeliveryError) => void,\n ): void {\n if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) {\n return;\n }\n\n try {\n const logRequest = {\n additionalInformation: {\n message: msg,\n version: this._integrationName,\n },\n severity,\n code: code || ErrorCodes.UNKNOWN_ERROR,\n url: _getReportingUrl(),\n deviceInfo: _getUserAgent(),\n stackTrace,\n reporter: this._reporter,\n integration: this._integrationName,\n };\n\n const headers: Record = {\n Accept: 'text/plain;charset=UTF-8',\n 'Content-Type': 'application/json',\n 'rokt-launcher-version': this._integrationName,\n 'rokt-wsdk-version': 'joint',\n };\n\n if (this._launcherInstanceGuid) {\n headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid;\n }\n if (this._accountId) {\n headers['rokt-account-id'] = this._accountId;\n }\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(logRequest),\n })\n .then((response: Response) => {\n // fetch only rejects on network failures; an HTTP 5xx resolves with\n // ok === false. Surface server-side failures so they are not swallowed.\n if (!response.ok) {\n const serverError: DeliveryError = new Error('HTTP ' + response.status + ' from log endpoint');\n serverError.statusCode = response.status;\n throw serverError;\n }\n })\n .catch((error: DeliveryError) => {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error);\n });\n } catch (error) {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error as DeliveryError);\n }\n }\n}\n\nclass ErrorReportingService {\n private _transport: ReportingTransport;\n private _errorUrl: string;\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._errorUrl = generateReportingUrl(config?.errorUrl, config?.integrationDomain, ERROR_ENDPOINT);\n }\n\n report(error: ErrorReport | null | undefined): void {\n if (!error) return;\n const severity = error.severity || WSDKErrorSeverity.ERROR;\n this._transport.send(this._errorUrl, severity, error.message, error.code, error.stackTrace);\n }\n}\n\nclass LoggingService {\n private _transport: ReportingTransport;\n private _loggingUrl: string;\n private _errorReportingService: { report: (e: ErrorReport) => void };\n\n constructor(\n config: ReportingConfig,\n errorReportingService: { report: (e: ErrorReport) => void },\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._loggingUrl = generateReportingUrl(config?.loggingUrl, config?.integrationDomain, LOGGING_ENDPOINT);\n this._errorReportingService = errorReportingService;\n }\n\n log(entry: LogEntry | null | undefined): void {\n if (!entry) return;\n this._transport.send(\n this._loggingUrl,\n WSDKErrorSeverity.INFO,\n entry.message,\n entry.code,\n undefined,\n (error: DeliveryError) => {\n if (this._errorReportingService) {\n // A failed log POST is not itself an SDK error. Network-level failures\n // (ad-blockers, offline, CORS) are client-side noise and reported as a\n // WARNING; only a server-side non-2xx response stays at ERROR severity.\n const isServerSide = typeof error.statusCode === 'number';\n this._errorReportingService.report({\n message: 'LoggingService: Failed to send log: ' + error.message,\n code: ErrorCodes.LOG_DELIVERY_FAILURE,\n severity: isServerSide ? WSDKErrorSeverity.ERROR : WSDKErrorSeverity.WARNING,\n });\n }\n },\n );\n }\n}\n\nfunction buildPageEvent(event: SDKEvent): PageEvent {\n const pageUrl = sanitizeUrl(window.location.href);\n const pageTitle = event.EventAttributes?.title || document.title;\n const canonicalUrl = readCanonicalUrl();\n const activeTimeOnSite = event.ActiveTimeOnSite;\n\n return {\n pageUrl,\n sourceMessageId: event.SourceMessageId,\n timestamp: event.Timestamp,\n ...(pageTitle ? { pageTitle } : {}),\n ...(canonicalUrl !== undefined ? { canonicalUrl } : {}),\n ...(Number.isFinite(activeTimeOnSite) ? { activeTimeOnSite } : {}),\n };\n}\n\n// ============================================================\n// RoktKit class\n// ============================================================\n\nclass RoktKit implements KitInterface {\n // Static field for allowed origin hashes (mutable by testHelpers)\n public static _allowedOriginHashes: number[] = [-553112570, 549508659];\n\n private static readonly PERFORMANCE_MARKS = {\n RoktScriptAppended: 'mp:RoktScriptAppended',\n };\n\n private static readonly EMAIL_SHA256_KEY = 'emailsha256';\n\n // Public fields (accessed by tests and the mParticle framework)\n public name = name;\n public id = moduleId;\n public moduleId = moduleId;\n public isInitialized = false;\n public launcher: RoktLauncher | null = null;\n public filters: KitFilters = {};\n public userAttributes: Record = {};\n // Flag set by the Workspace IDSync flow on a 200 response. Stored on the\n // kit instance and merged into placement attributes inside selectPlacements.\n public userIdentifiedInWorkspace = false;\n public testHelpers: TestHelpers | null = null;\n public placementEventMappingLookup: Record = {};\n public placementEventAttributeMappingLookup: Record = {};\n public integrationName: string | null = null;\n public domain?: string;\n public errorReportingService: ErrorReportingService | null = null;\n public loggingService: LoggingService | null = null;\n\n // Private fields\n private _mappedEmailSha256Key?: string;\n private _onboardingExpProvider?: string;\n private _thankYouElementOnLoadCallback: (() => void) | null = null;\n private _isThankYouElementLoaded = false;\n private _workspaceIdSyncApiKey?: string;\n\n // Held during a search dispatch so the next selectPlacements call;\n // can wait for the HTTP response before reading userIdentifiedInWorkspace;\n // — otherwise the first placement call ships without the flag.\n private _workspaceSearchInFlightPromise: Promise | null = null;\n // Stable serialization of the identifier set sent in the most recent\n // successful search dispatch. If a subsequent identification arrives with\n // an identical set, we skip the network call (the flag is still correct\n // from the prior search). Keyed over the full IUserIdentities map — not\n // just email — so partners passing hashed email through `other`/`other2-10`\n // or any other identifier benefit from the same dedupe. Cleared on logout\n // so a re-login re-evaluates fresh.\n private _workspaceLastSearchedIdentitiesKey?: string;\n\n // ---- Private helpers ----\n\n private getEventAttributeValue(event: SDKEvent, eventAttributeKey: string): unknown {\n const attributes = event && event.EventAttributes;\n if (!attributes) {\n return null;\n }\n\n if (typeof attributes[eventAttributeKey] === 'undefined') {\n return null;\n }\n\n return attributes[eventAttributeKey];\n }\n\n private doesEventAttributeConditionMatch(condition: EventAttributeCondition, actualValue: unknown): boolean {\n if (!condition || !isString(condition.operator)) {\n return false;\n }\n\n const operator = condition.operator.toLowerCase();\n const expectedValue = condition.attributeValue;\n\n if (operator === 'exists') {\n return actualValue !== null;\n }\n\n if (actualValue == null) {\n return false;\n }\n\n if (operator === 'equals') {\n return String(actualValue) === String(expectedValue);\n }\n\n if (operator === 'contains') {\n return String(actualValue).indexOf(String(expectedValue)) !== -1;\n }\n\n return false;\n }\n\n private doesEventMatchRule(event: SDKEvent, rule: PlacementEventRule): boolean {\n if (!rule || !isString(rule.eventAttributeKey)) {\n return false;\n }\n\n const conditions = rule.conditions;\n if (!Array.isArray(conditions)) {\n return false;\n }\n\n const actualValue = this.getEventAttributeValue(event, rule.eventAttributeKey);\n\n if (conditions.length === 0) {\n return actualValue !== null;\n }\n for (let i = 0; i < conditions.length; i++) {\n if (!this.doesEventAttributeConditionMatch(conditions[i], actualValue)) {\n return false;\n }\n }\n\n return true;\n }\n\n private applyPlacementEventAttributeMapping(event: SDKEvent): void {\n const mappedAttributeKeys = Object.keys(this.placementEventAttributeMappingLookup);\n for (let i = 0; i < mappedAttributeKeys.length; i++) {\n const mappedAttributeKey = mappedAttributeKeys[i];\n const rulesForMappedAttributeKey = this.placementEventAttributeMappingLookup[mappedAttributeKey];\n if (isEmpty(rulesForMappedAttributeKey)) {\n continue;\n }\n\n // Require ALL rules for the same key to match (AND).\n let allMatch = true;\n for (let j = 0; j < rulesForMappedAttributeKey.length; j++) {\n if (!this.doesEventMatchRule(event, rulesForMappedAttributeKey[j])) {\n allMatch = false;\n break;\n }\n }\n if (!allMatch) {\n continue;\n }\n\n mp().Rokt.setLocalSessionAttribute?.(mappedAttributeKey, true);\n }\n }\n\n private capturePageView(event: SDKEvent): void {\n let pageUrl: string | undefined;\n\n try {\n pageUrl = sanitizeUrl(window.location.href);\n\n const pageViews = loadPageViews(this.loggingService);\n const pageView = buildPageEvent(event);\n pageViews.push(pageView);\n\n const requested = Math.min(pageViews.length, PAGE_VIEWS_MAX_COUNT);\n const stored = writePageViews(pageViews);\n if (stored === 0) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n this.loggingService?.log({\n message: `Rokt Kit: Failed to persist page view for ${pageUrl} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n } else if (stored < requested) {\n this.loggingService?.log({\n message: `Rokt Kit: Page view storage reduced from ${requested} to ${stored} record(s) under quota pressure [reason: quota_eviction]`,\n code: 'PAGE_VIEW_QUOTA_EVICTION',\n });\n }\n } catch (err) {\n const reason = isLocalStorageAvailable() ? 'exception' : 'ls_unavailable';\n const errMessage = err instanceof Error ? err.message : String(err);\n this.loggingService?.log({\n message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${errMessage} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n private isLauncherReadyToAttach(): boolean {\n return !!window.Rokt && isFunction(window.Rokt.createLauncher);\n }\n\n /**\n * Returns the user identities from the filtered user, if any.\n */\n private returnUserIdentities(filteredUser: FilteredUser | null | undefined): Record {\n if (!filteredUser || !filteredUser.getUserIdentities) {\n return {};\n }\n\n const userIdentities: IUserIdentities = filteredUser.getUserIdentities().userIdentities;\n\n return this.replaceOtherIdentityWithEmailsha256(userIdentities);\n }\n\n private returnLocalSessionAttributes(): Record {\n if (!mp().Rokt || typeof mp().Rokt.getLocalSessionAttributes !== 'function') {\n return {};\n }\n return mp().Rokt.getLocalSessionAttributes!();\n }\n\n private replaceOtherIdentityWithEmailsha256(userIdentities: IUserIdentities): Record {\n const newUserIdentities: Record = { ...(userIdentities || {}) };\n const key = this._mappedEmailSha256Key;\n if (key && userIdentities[key as keyof IUserIdentities]) {\n newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key as keyof IUserIdentities] as string;\n }\n if (key) {\n delete newUserIdentities[key];\n }\n\n return newUserIdentities;\n }\n\n private logSelectPlacementsEvent(attributes: unknown): void {\n if (!window.mParticle || typeof mp().logEvent !== 'function') {\n return;\n }\n\n if (!isObject(attributes)) {\n return;\n }\n\n const EVENT_TYPE_OTHER = mp().EventType.Other;\n\n mp().logEvent(EVENT_NAME_SELECT_PLACEMENTS, EVENT_TYPE_OTHER, attributes as Record);\n }\n\n private setRoktSessionId(sessionId: string): void {\n if (!sessionId || typeof sessionId !== 'string') {\n return;\n }\n try {\n const mpInstance = mp().getInstance();\n if (mpInstance && isFunction(mpInstance.setIntegrationAttribute)) {\n mpInstance.setIntegrationAttribute(moduleId, {\n roktSessionId: sessionId,\n });\n }\n } catch (_e) {\n // Best effort — never let this break the partner page\n }\n }\n\n private readMpSessionId(): string | undefined {\n // The public mParticle.sessionManager facade exposes only getSession(), which already returns\n // the session id. getSessionId() lives on the internal _SessionManager and has never been\n // re-exported, so prefer it if a future core adds it and fall back to getSession() until then.\n const sessionManager = mp()?.sessionManager;\n const readSessionId = sessionManager?.getSessionId ?? sessionManager?.getSession;\n if (!isFunction(readSessionId)) {\n return undefined;\n }\n\n return readSessionId.call(sessionManager) || undefined;\n }\n\n private readMpDeviceId(): string | undefined {\n // The device application stamp (`das`) outlives the session id: core clears the session on\n // timeout, cross-tab rotation and endSession(), but never the device id, which lives in\n // localStorage/cookie for cookieExpiration days (365 by default) and survives login/logout.\n // Read it per call anyway — a partner can reassign it at any time via setDeviceId().\n return mp()?.getDeviceId?.() || undefined;\n }\n\n private attachLauncher(\n accountId: string,\n launcherOptions: Record,\n legacyRoktExtensions: string[] = [],\n ): void {\n const options: Record = {\n accountId,\n ...(launcherOptions || {}),\n };\n\n let launcherPromise: Promise;\n if (this.isPartnerInLocalLauncherTestGroup()) {\n launcherPromise = Promise.resolve(window.Rokt!.createLocalLauncher(options));\n } else {\n launcherPromise = window.Rokt!.createLauncher(options);\n }\n\n launcherPromise\n .then(async (launcher) => {\n await registerLegacyExtensions(legacyRoktExtensions, launcher);\n this.initRoktLauncher(launcher);\n })\n .catch((err: unknown) => {\n console.error('Error creating Rokt launcher:', err);\n });\n }\n\n private initRoktLauncher(launcher: RoktLauncher): void {\n // Assign the launcher to a global variable for later access\n if (window.Rokt) {\n window.Rokt.currentLauncher = launcher;\n }\n // Locally cache the launcher and filters\n this.launcher = launcher;\n\n const roktFilters = mp().Rokt?.filters;\n\n if (!roktFilters) {\n console.warn('Rokt Kit: No filters have been set.');\n } else {\n this.filters = roktFilters;\n if (!roktFilters.filteredUser) {\n console.warn('Rokt Kit: No filtered user has been set.');\n } else {\n this._workspaceSearchInFlightPromise = this.search(roktFilters.filteredUser);\n }\n }\n\n // Kit must be initialized before attaching to the Rokt manager\n this.isInitialized = true;\n\n sendAdBlockMeasurementSignals(this.domain, this.integrationName);\n\n // Attaches the kit to the Rokt manager\n mp().Rokt.attachKit(this);\n }\n\n private fetchOptimizely(): Record {\n const forwarders = mp()\n ._getActiveForwarders()\n .filter((forwarder) => forwarder.name === 'Optimizely');\n\n try {\n if (forwarders.length > 0 && window.optimizely) {\n const optimizelyState = window.optimizely.get('state');\n if (!optimizelyState || !optimizelyState.getActiveExperimentIds) {\n return {};\n }\n const activeExperimentIds = optimizelyState.getActiveExperimentIds();\n const activeExperiments = activeExperimentIds.reduce((acc: Record, expId: string) => {\n acc['rokt.custom.optimizely.experiment.' + expId + '.variationId'] =\n optimizelyState.getVariationMap()[expId].id;\n return acc;\n }, {});\n return activeExperiments;\n }\n } catch (error) {\n console.error('Error fetching Optimizely attributes:', error);\n }\n return {};\n }\n\n private isKitReady(): boolean {\n return !!(this.isInitialized && this.launcher);\n }\n\n // When the partner has opted out of targeting (noTargeting launcher option),\n // the kit must not collect behavioral targeting signals such as page views.\n private isTargetingDisabled(): boolean {\n return (mp().Rokt?.launcherOptions as Record | undefined)?.noTargeting === true;\n }\n\n private isPartnerInLocalLauncherTestGroup(): boolean {\n return !!(mp().config && mp().config!.isLocalLauncherEnabled && this.isAssignedToSampleGroup());\n }\n\n private isAssignedToSampleGroup(): boolean {\n const LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5;\n return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD;\n }\n\n private captureTiming(metricName: string): void {\n if (window && mp() && mp().captureTiming && metricName) {\n mp().captureTiming!(metricName);\n }\n }\n\n // ---- Public methods (mParticle Kit Callbacks) ----\n\n /**\n * Initializes the Rokt forwarder with settings from the mParticle server.\n */\n public init(\n settings: Record,\n _service: unknown,\n testMode: boolean,\n _trackerId: unknown,\n filteredUserAttributes?: Record,\n ): string {\n const kitSettings = settings as unknown as RoktKitSettings;\n const accountId = kitSettings.accountId;\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredUserAttributes);\n this._onboardingExpProvider = kitSettings.onboardingExpProvider;\n\n const placementEventMapping = parseSettingsString(kitSettings.placementEventMapping);\n this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping);\n\n const placementEventAttributeMapping = parseSettingsString(\n kitSettings.placementEventAttributeMapping,\n );\n this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping);\n\n // Set dynamic OTHER_IDENTITY based on server settings\n if (kitSettings.hashedEmailUserIdentityType) {\n this._mappedEmailSha256Key = kitSettings.hashedEmailUserIdentityType.toLowerCase();\n }\n\n this._workspaceIdSyncApiKey = isString(kitSettings.workspaceIdSyncApiKey)\n ? kitSettings.workspaceIdSyncApiKey\n : undefined;\n\n const domain = mp().Rokt?.domain;\n const { roktExtensionsQueryParams, legacyRoktExtensions, loadThankYouElement } = extractRoktExtensionConfig(\n kitSettings.roktExtensions,\n );\n const launcherOptions: Record = {\n ...((mp().Rokt?.launcherOptions as Record) || {}),\n };\n this.integrationName = generateIntegrationName(launcherOptions.integrationName as string | undefined);\n launcherOptions.integrationName = this.integrationName;\n\n this.domain = domain;\n\n const reportingConfig: ReportingConfig = {\n loggingUrl: kitSettings.loggingUrl,\n errorUrl: kitSettings.errorUrl,\n integrationDomain: domain,\n isLoggingEnabled: mp().config?.isLoggingEnabled === true,\n };\n const errorReportingService = new ErrorReportingService(\n reportingConfig,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n const loggingService = new LoggingService(\n reportingConfig,\n errorReportingService,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n\n this.errorReportingService = errorReportingService;\n this.loggingService = loggingService;\n\n if (this.isTargetingDisabled()) {\n try {\n clearPageViews();\n clearUtmParams();\n } catch (err) {\n this.errorReportingService?.report({\n message: 'Rokt Kit: Failed to clear page views when targeting is disabled',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n severity: WSDKErrorSeverity.INFO,\n stackTrace: err instanceof Error ? err.stack : undefined,\n });\n }\n }\n\n if (mp()._registerErrorReportingService) {\n mp()._registerErrorReportingService!(errorReportingService);\n }\n if (mp()._registerLoggingService) {\n mp()._registerLoggingService!(loggingService);\n }\n\n if (testMode) {\n this.testHelpers = {\n generateLauncherScript: generateLauncherScript,\n generateThankYouElementScript: generateThankYouElementScript,\n extractRoktExtensionConfig: extractRoktExtensionConfig,\n hashEventMessage: hashEventMessage,\n parseSettingsString: parseSettingsString,\n generateMappedEventLookup: generateMappedEventLookup,\n generateMappedEventAttributeLookup: generateMappedEventAttributeLookup,\n sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals,\n createAutoRemovedIframe: createAutoRemovedIframe,\n djb2: djb2,\n setAllowedOriginHashes: (hashes: number[]) => {\n RoktKit._allowedOriginHashes = hashes;\n },\n ReportingTransport: ReportingTransport,\n ErrorReportingService: ErrorReportingService,\n LoggingService: LoggingService,\n RateLimiter: RateLimiter,\n ErrorCodes: ErrorCodes,\n WSDKErrorSeverity: WSDKErrorSeverity,\n };\n this.attachLauncher(accountId, launcherOptions);\n return 'Successfully initialized: ' + name;\n }\n\n if (loadThankYouElement) {\n mp().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this);\n loadRoktScript(ROKT_THANK_YOU_ELEMENT_SCRIPT_ID, generateThankYouElementScript(domain), {\n onLoad: () => {\n this._isThankYouElementLoaded = true;\n if (this._thankYouElementOnLoadCallback) {\n this._thankYouElementOnLoadCallback();\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt Thank You Element script:', error);\n },\n });\n }\n\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n loadRoktScript(ROKT_INTEGRATION_SCRIPT_ID, generateLauncherScript(domain, roktExtensionsQueryParams), {\n onLoad: () => {\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n console.error('Rokt object is not available after script load.');\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt launcher script:', error);\n },\n });\n\n this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended);\n }\n\n return 'Successfully initialized: ' + name;\n }\n\n public process(event: SDKEvent): string {\n if (!this.isTargetingDisabled()) {\n if (event.EventDataType === MESSAGE_TYPE_PAGE_VIEW) {\n captureUtmParams(this.loggingService);\n this.capturePageView(event);\n }\n\n if (event.EventDataType === MESSAGE_TYPE_SESSION_END) {\n migrateLegacyPageViewStorage(this.loggingService);\n clearPageViews();\n clearUtmParams();\n }\n }\n\n // The forwarding work below (LSA mapping) depends on the launcher, so guard\n // it here and surface the not-ready signal to the core SDK.\n if (!this.isKitReady()) {\n return 'Kit not ready for forwarder: ' + name;\n }\n\n if (isFunction(mp().Rokt?.setLocalSessionAttribute)) {\n if (!isEmpty(this.placementEventAttributeMappingLookup)) {\n this.applyPlacementEventAttributeMapping(event);\n }\n\n if (!isEmpty(this.placementEventMappingLookup)) {\n const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? '');\n if (this.placementEventMappingLookup[String(hashedEvent)]) {\n mp().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(hashedEvent)], true);\n }\n }\n }\n\n return 'Successfully sent to forwarder: ' + name;\n }\n\n public setExtensionData(partnerExtensionData: Record): void {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return;\n }\n\n window.Rokt!.setExtensionData(partnerExtensionData);\n }\n\n public setUserAttribute(key: string, value: unknown): string {\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n this.userAttributes[key] = value;\n }\n return 'Successfully set user attribute for forwarder: ' + name;\n }\n\n public removeUserAttribute(key: string): string {\n delete this.userAttributes[key];\n return 'Successfully removed user attribute for forwarder: ' + name;\n }\n\n private handleIdentityComplete(user: IMParticleUser, callbackName: string): string {\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(user.getAllUserAttributes());\n return 'Successfully called ' + callbackName + ' for forwarder: ' + name;\n }\n\n public onUserIdentified(user: IMParticleUser): string {\n const filteredUser = user as FilteredUser;\n this.filters.filteredUser = filteredUser;\n this._workspaceSearchInFlightPromise = this.search(filteredUser);\n return this.handleIdentityComplete(user, 'onUserIdentified');\n }\n\n private search(filteredUser: FilteredUser): Promise {\n const apiKey = this._workspaceIdSyncApiKey;\n if (!apiKey) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n const search = mp().Identity?.search;\n if (typeof search !== 'function') {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n const userIdentities: IUserIdentities | null = filteredUser.getUserIdentities\n ? filteredUser.getUserIdentities().userIdentities\n : null;\n\n // Forward every non-empty string identifier the user has — email,\n // customerid, other/other2-10 (commonly used for hashed email),\n // mobile_number, facebook, etc. The host SDK's Identity.search accepts\n // the full IUserIdentities surface and the server validates it.\n const knownIdentities: Record = {};\n if (userIdentities) {\n for (const key of Object.keys(userIdentities) as Array) {\n const value = userIdentities[key];\n if (isString(value) && value.length > 0) {\n knownIdentities[key] = value;\n }\n }\n }\n\n const identityKeys = Object.keys(knownIdentities);\n if (identityKeys.length === 0) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n // Stable cache key: sort keys so insertion-order differences don't\n // cause false misses. The values are partner-supplied strings; no\n // hashing needed — equality on this serialization is sufficient.\n const identitiesKey = identityKeys\n .sort()\n .map((k) => `${k}=${knownIdentities[k]}`)\n .join('&');\n\n // Same identifier set as the last successful dispatch → skip the\n // network call. The current flag value still reflects the correct\n // match status.\n if (identitiesKey === this._workspaceLastSearchedIdentitiesKey) {\n return this._workspaceSearchInFlightPromise || Promise.resolve();\n }\n\n // New / different identifier set → reset and re-search. Cache the key\n // up front so a second concurrent invocation with the same set also\n // dedupes.\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = identitiesKey;\n\n return new Promise((resolve) => {\n try {\n search(apiKey, knownIdentities as IUserIdentities, (result: WorkspaceIdSyncResult) => {\n if (result?.httpCode === 200) {\n this.userIdentifiedInWorkspace = true;\n }\n resolve();\n });\n } catch (err) {\n console.error('Rokt Kit: Workspace IDSync search failed', err);\n // Dispatch failed — clear the cache so the same identifier set\n // can retry on the next identification rather than being stuck\n // behind a poisoned entry that short-circuits future searches.\n this._workspaceLastSearchedIdentitiesKey = undefined;\n resolve();\n }\n });\n }\n\n public onLoginComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onLoginComplete');\n }\n\n public onLogoutComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n // Anonymous sessions must not carry the previous user's match forward.\n // Clear the flag explicitly here. Also clear the identities cache so a\n // re-login (possibly with the same identifiers) dispatches a fresh\n // search rather than reusing a stale answer.\n this.userIdentifiedInWorkspace = false;\n this._workspaceSearchInFlightPromise = null;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return this.handleIdentityComplete(user, 'onLogoutComplete');\n }\n\n public onModifyComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onModifyComplete');\n }\n\n /**\n * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options.\n *\n * If a Workspace IDSync search is in flight from a recent onUserIdentified\n * call, this method waits up to `WORKSPACE_SEARCH_SELECT_TIMEOUT_MS` for it\n * to settle so the first placement call can include the\n * `userIdentifiedInWorkspace` flag without racing the network response.\n * The timeout protects against a stalled or slow search blocking placement\n * rendering — if it fires, selectPlacements proceeds without the flag.\n *\n * Implementation note: this method stays non-async deliberately. First,\n * the public return type is `RoktSelection | Promise |\n * undefined` — a superset of the `RoktSelection | Promise`\n * shape declared for `RoktLauncher.selectPlacements` above (line ~70).\n * Marking this `async` would narrow it to `Promise` and silently change the contract for callers that read\n * the result synchronously. Second, `RoktSelection` has an optional\n * `then?` member, so TS treats it as ambiguously promise-like and\n * rejects it as the awaited return of an async function (TS1058) —\n * working around that would require a cast or wrapping every return in\n * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`;\n * this wrapper just gates it on the in-flight search via `Promise.race`.\n */\n public selectPlacements(options: Record): RoktSelection | Promise | undefined {\n if (this._workspaceSearchInFlightPromise) {\n const inFlight = this._workspaceSearchInFlightPromise;\n return Promise.race([\n inFlight,\n new Promise((resolve) => setTimeout(resolve, WORKSPACE_SEARCH_SELECT_TIMEOUT_MS)),\n ]).then(() => this._dispatchPlacements(options)) as Promise;\n }\n return this._dispatchPlacements(options);\n }\n\n private _dispatchPlacements(options: Record): RoktSelection | Promise | undefined {\n const attributes = ((options && (options.attributes as Record)) || {}) as Record;\n const cachedUserAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(this.userAttributes);\n const placementAttributes: Record = { ...cachedUserAttributes, ...attributes };\n\n const filters = this.filters || {};\n const userAttributeFilters = (filters.userAttributeFilters as string[]) || [];\n const filteredUser = filters.filteredUser || null;\n const mpid = filteredUser ? filteredUser.getMPID() : null;\n\n let filteredAttributes: Record;\n\n if (!filters) {\n console.warn('Rokt Kit: No filters available, using user attributes');\n filteredAttributes = placementAttributes;\n } else if (filters.filterUserAttributes) {\n filteredAttributes = filters.filterUserAttributes(placementAttributes, userAttributeFilters);\n } else {\n filteredAttributes = placementAttributes;\n }\n\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredAttributes);\n\n const optimizelyAttributes = this._onboardingExpProvider === 'Optimizely' ? this.fetchOptimizely() : {};\n\n const filteredUserIdentities = this.returnUserIdentities(filteredUser);\n\n const sessionAttributes = this.returnLocalSessionAttributes();\n const pageEvents = buildPageEvents(loadPageViews(this.loggingService));\n const utmParams = loadUtmParams();\n const mpSessionId = this.readMpSessionId();\n const mpDeviceId = this.readMpDeviceId();\n\n const selectPlacementsAttributes: Record = {\n ...(filteredUserIdentities as Record),\n ...filteredAttributes,\n ...optimizelyAttributes,\n ...sessionAttributes,\n ...(pageEvents.length ? { [PAGE_EVENTS_KEY]: JSON.stringify(pageEvents) } : {}),\n ...(utmParams ? { [PAGE_VIEW_ATTRIBUTES_KEY]: utmParams } : {}),\n ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}),\n ...(mpSessionId ? { [MPARTICLE_SESSION_ID_KEY]: mpSessionId } : {}),\n ...(mpDeviceId ? { [MPARTICLE_DEVICE_ID_KEY]: mpDeviceId } : {}),\n mpid,\n };\n\n const selectPlacementsOptions: Record = { ...options, attributes: selectPlacementsAttributes };\n\n const selection = this.launcher!.selectPlacements(selectPlacementsOptions);\n\n // After selection resolves, sync the Rokt session ID back to mParticle, then log\n const logSelection = () => this.logSelectPlacementsEvent(selectPlacementsAttributes);\n\n void Promise.resolve(selection)\n .then((sel) => sel?.context?.sessionId?.then((sessionId) => this.setRoktSessionId(sessionId)))\n .catch(() => undefined)\n .finally(logSelection);\n\n return selection;\n }\n\n /**\n * Passes attributes to the Rokt Web SDK for client-side hashing.\n */\n public hashAttributes(attributes: Record): Promise> | null {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return null;\n }\n return this.launcher!.hashAttributes(attributes);\n }\n\n /**\n * Enables optional Integration Launcher extensions before selecting placements.\n *\n * @deprecated This functionality has been internalized and will be removed in a future release.\n */\n public use(extensionName: string): Promise {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return Promise.reject(new Error('Rokt Kit: Not initialized'));\n }\n if (!extensionName || !isString(extensionName)) {\n return Promise.reject(new Error('Rokt Kit: Invalid extension name'));\n }\n return this.launcher!.use(extensionName);\n }\n\n /**\n * Registers a callback to be invoked once rokt-thank-you-element.js becomes available.\n */\n public onShoppableAdsReady(callback: () => void) {\n if (this._isThankYouElementLoaded) {\n callback();\n } else {\n this._thankYouElementOnLoadCallback = callback;\n }\n }\n}\n\n// ============================================================\n// Kit registration\n// ============================================================\n\nfunction getId(): number {\n return moduleId;\n}\n\nfunction register(config: { kits?: Record }): void {\n if (!config) {\n window.console.log('You must pass a config object to register the kit ' + name);\n return;\n }\n if (!isObject(config)) {\n window.console.log(\"'config' must be an object. You passed in a \" + typeof config);\n return;\n }\n\n if (isObject(config.kits)) {\n (config.kits as Record)[name] = {\n constructor: RoktKit,\n };\n } else {\n config.kits = {};\n config.kits[name] = {\n constructor: RoktKit,\n };\n }\n window.console.log('Successfully registered ' + name + ' to your mParticle configuration');\n}\n\nif (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) {\n mp().addForwarder({\n name: name,\n constructor: RoktKit,\n getId: getId,\n });\n}\n\nexport { register };\nexport type { LoggingService };\n"],"names":["SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST","SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET","isSelectPlacementsAttributePersistenceDenied","key","removeSelectPlacementsAttributePersistenceDeniedAttributes","attributes","filteredAttributes","sourceAttributes","attributeKeys","i","isObject","value","isString","isFunction","isEmpty","sanitizeUrl","href","url","LS_PROBE_KEY","isLocalStorageAvailable","readJSON","stored","writeJSON","removeKey","readNamespacedField","namespaceKey","field","blob","writeNamespacedField","next","removeNamespacedField","LS_NAMESPACE_KEY","LS_PAGE_VIEWS_FIELD","LS_UTM_PARAMS_FIELD","LEGACY_PAGE_VIEWS_KEY","PAGE_VIEWS_MAX_COUNT","UTM_KEYS","capPageViews","views","migrateLegacyPageViewStorage","loggingService","legacyViews","loadPageViews","writePageViews","pageViews","toWrite","clearPageViews","buildPageEvents","pageView","index","activeTimeOnSite","hasActiveTime","nextActiveTimeOnSite","hasNextActiveTimeOnSite","diff","captureUtmParams","search","params","captured","reason","loadUtmParams","clearUtmParams","readCanonicalUrl","name","moduleId","EVENT_NAME_SELECT_PLACEMENTS","ADBLOCK_CONTROL_DOMAIN","INIT_LOG_SAMPLING_RATE","ROKT_THANK_YOU_JOURNEY_EXTENSION","ROKT_INTEGRATION_SCRIPT_ID","ROKT_THANK_YOU_ELEMENT_SCRIPT_ID","USER_IDENTIFIED_IN_WORKSPACE_KEY","MESSAGE_TYPE_PAGE_VIEW","MESSAGE_TYPE_SESSION_END","PAGE_EVENTS_KEY","PAGE_VIEW_ATTRIBUTES_KEY","MPARTICLE_SESSION_ID_KEY","MPARTICLE_DEVICE_ID_KEY","WORKSPACE_SEARCH_SELECT_TIMEOUT_MS","ErrorCodes","WSDKErrorSeverity","DEFAULT_ROKT_DOMAIN","LOGGING_ENDPOINT","ERROR_ENDPOINT","RATE_LIMIT_PER_SEVERITY","mp","generateLauncherScript","domain","extensions","baseUrl","generateBaseUrl","generateThankYouElementScript","resolvedDomain","generateReportingUrl","configuredUrl","endpoint","reportingDomain","loadRoktScript","scriptId","source","handlers","target","script","parseSettingsString","settingsString","extractRoktExtensionConfig","settings","roktExtensionsQueryParams","legacyRoktExtensions","loadThankYouElement","extensionName","registerLegacyExtensions","legacyExtensions","launcher","extension","generateMappedEventLookup","placementEventMapping","mappedEvents","mapping","generateMappedEventAttributeLookup","placementEventAttributeMapping","mappedAttributeKeys","mappedAttributeKey","eventAttributeKey","hashEventMessage","messageType","eventType","eventName","generateIntegrationName","customIntegrationName","integrationName","djb2","str","hash","createAutoRemovedIframe","src","iframe","sendAdBlockMeasurementSignals","version","originHash","RoktKit","guid","pageUrl","existingBaseUrl","_isDebugModeEnabled","_getReportingUrl","_getUserAgent","RateLimiter","severity","newCount","ReportingTransport","config","launcherInstanceGuid","accountId","rateLimiter","isLoggingEnabled","msg","code","stackTrace","onError","logRequest","headers","response","serverError","error","ErrorReportingService","LoggingService","errorReportingService","entry","isServerSide","buildPageEvent","event","pageTitle","canonicalUrl","_RoktKit","condition","actualValue","operator","expectedValue","rule","conditions","rulesForMappedAttributeKey","allMatch","j","requested","err","errMessage","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","sessionManager","readSessionId","launcherOptions","options","launcherPromise","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","sessionAttributes","pageEvents","utmParams","mpSessionId","mpDeviceId","selectPlacementsAttributes","selectPlacementsOptions","selection","logSelection","sel","callback","getId","register"],"mappings":"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"} \ No newline at end of file diff --git a/kits/rokt/package-lock.json b/kits/rokt/package-lock.json index c47632f10..eeded3dbf 100644 --- a/kits/rokt/package-lock.json +++ b/kits/rokt/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mparticle/web-rokt-kit", - "version": "1.30.2", + "version": "1.35.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mparticle/web-rokt-kit", - "version": "1.30.2", + "version": "1.35.0", "license": "Apache-2.0", "devDependencies": { "@eslint/eslintrc": "^3.3.1", diff --git a/kits/rokt/package.json b/kits/rokt/package.json index 4d28fa149..13c5a83dc 100644 --- a/kits/rokt/package.json +++ b/kits/rokt/package.json @@ -1,6 +1,6 @@ { "name": "@mparticle/web-rokt-kit", - "version": "1.30.2", + "version": "1.35.0", "description": "mParticle integration kit for Rokt", "main": "dist/Rokt-Kit.common.js", "module": "dist/Rokt-Kit.esm.js", diff --git a/kits/rokt/src/Rokt-Kit.ts b/kits/rokt/src/Rokt-Kit.ts index 3246b2fe7..afef3243d 100644 --- a/kits/rokt/src/Rokt-Kit.ts +++ b/kits/rokt/src/Rokt-Kit.ts @@ -24,6 +24,23 @@ import { removeSelectPlacementsAttributePersistenceDeniedAttributes, } from './selectPlacementsAttributePersistence'; +import { + PageEvent, + PAGE_VIEWS_MAX_COUNT, + buildPageEvents, + migrateLegacyPageViewStorage, + loadPageViews, + writePageViews, + clearPageViews, + readCanonicalUrl, + captureUtmParams, + loadUtmParams, + clearUtmParams, +} from './pageViewStorage'; +import { isLocalStorageAvailable } from './storage'; + +import { isObject, isString, isEmpty, isFunction, sanitizeUrl } from './utils'; + interface RoktKitSettings { accountId: string; roktExtensions?: string; @@ -61,17 +78,6 @@ interface RoktExtensionEntry { value: string; } -interface PageEvent { - pageUrl: string; - sourceMessageId: string; - timestamp: number; - activeTimeOnSite?: number; - // Derived at transmission not at capture based - // on the next page view's activeTimeOnSite, - // so it is absent on stored records. - activeTimeOnPage?: number; -} - interface RoktSelection { context?: { sessionId?: Promise; @@ -160,7 +166,8 @@ interface MParticleExtended { logEvent(name: string, type: number, attrs?: Record): void; EventType: { Other: number }; getInstance(): MParticleInstance; - sessionManager?: { getSession(): string }; + getDeviceId?(): string; + sessionManager?: { getSession?(): string; getSessionId?(): string }; _getActiveForwarders(): Array<{ name: string }>; config?: { isLocalLauncherEnabled?: boolean; isLoggingEnabled?: boolean }; captureTiming?(metricName: string): void; @@ -257,16 +264,10 @@ const USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace'; const MESSAGE_TYPE_PAGE_VIEW = 3; // mParticle MessageType.PageView const MESSAGE_TYPE_SESSION_END = 2; // mParticle MessageType.SessionEnd -// localStorage key under which captured page views are persisted (as a JSON -// string). The kit owns this storage directly — separate from mParticle's -// cookie/localStorage — so page-view capture does not affect mParticle -// persistence or cookie sync. Distinct from PAGE_EVENTS_KEY, which is the -// flattened wire shape sent to Rokt on selectPlacements. -const LS_PAGE_VIEWS_KEY = 'mpPageViews'; -// Fixed cap on the number of persisted page views (oldest evicted first). Code -// constant, not a kit setting — change it here. -const PAGE_VIEWS_MAX_COUNT = 25; const PAGE_EVENTS_KEY = 'page_events'; +const PAGE_VIEW_ATTRIBUTES_KEY = 'page_view_attributes'; +const MPARTICLE_SESSION_ID_KEY = 'mparticle_session_id'; +const MPARTICLE_DEVICE_ID_KEY = 'mparticle_device_id'; // Bound on how long selectPlacements will wait for an in-flight Workspace // IDSync search before proceeding without the userIdentifiedInWorkspace flag. @@ -311,27 +312,6 @@ function mp(): MParticleExtended { // Module-level utility functions // ============================================================ -function readPageViewsStorage(): PageEvent[] { - try { - const stored = window.localStorage.getItem(LS_PAGE_VIEWS_KEY); - if (stored === null) { - return []; - } - const parsed = JSON.parse(stored); - return Array.isArray(parsed) ? (parsed as PageEvent[]) : []; - } catch { - return []; - } -} - -function writePageViewsStorage(pageViews: PageEvent[]): void { - window.localStorage.setItem(LS_PAGE_VIEWS_KEY, JSON.stringify(pageViews)); -} - -function clearPageViewsStorage(): void { - window.localStorage.removeItem(LS_PAGE_VIEWS_KEY); -} - function generateLauncherScript(domain: string | undefined, extensions: string[]): string { const launcherPath = '/wsdk/integrations/launcher.js'; const baseUrl = [generateBaseUrl(domain), launcherPath].join(''); @@ -349,6 +329,11 @@ function generateThankYouElementScript(domain: string | undefined) { function generateBaseUrl(domain: string | undefined) { const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN; + + if (resolvedDomain.includes('://')) { + return resolvedDomain.replace(/\/+$/, ''); + } + const protocol = 'https://'; return [protocol, resolvedDomain].join(''); @@ -362,7 +347,10 @@ function generateReportingUrl(configuredUrl: string | undefined, domain: string return 'https://' + configuredUrl; } - return generateBaseUrl(domain) + endpoint; + const hasNonHttpScheme = domain?.includes('://') && !/^https?:\/\//i.test(domain); + const reportingDomain = hasNonHttpScheme ? undefined : domain; + + return generateBaseUrl(reportingDomain) + endpoint; } function loadRoktScript( @@ -385,10 +373,6 @@ function loadRoktScript( target.appendChild(script); } -function isObject(val: unknown): val is Record { - return val != null && typeof val === 'object' && Array.isArray(val) === false; -} - function parseSettingsString(settingsString?: string): T[] { if (!settingsString) { return []; @@ -480,34 +464,6 @@ function hashEventMessage(messageType: number, eventType: number, eventName: str return mp().generateHash([messageType, eventType, eventName].join('')); } -function isEmpty(value: unknown): boolean { - if (value == null) return true; - if (typeof value === 'object') { - return Object.keys(value as object).length === 0; - } - if (Array.isArray(value)) { - return (value as unknown[]).length === 0; - } - return false; -} - -function isString(value: unknown): value is string { - return typeof value === 'string'; -} - -// Strips the query string from a page-view URL before it is persisted and sent -// to Rokt, since query params commonly carry PII (emails, tokens, order refs). -// Returns the input unchanged if it can't be parsed as a URL. -function sanitizeUrl(href: string): string { - try { - const url = new URL(href); - url.search = ''; - return url.toString(); - } catch { - return href; - } -} - function generateIntegrationName(customIntegrationName?: string): string { const coreSdkVersion = mp().getVersion(); const kitVersion = process.env.PACKAGE_VERSION; @@ -561,6 +517,10 @@ function sendAdBlockMeasurementSignals(domain: string | undefined, version: stri return; } + if (domain && domain.includes('://') && !/^https:\/\//i.test(domain)) { + return; + } + const pageUrl = window.location.href.split('?')[0].split('#')[0]; const params = 'version=' + @@ -570,8 +530,8 @@ function sendAdBlockMeasurementSignals(domain: string | undefined, version: stri '&pageUrl=' + encodeURIComponent(pageUrl); - const existingDomain = domain || 'apps.rokt.com'; - createAutoRemovedIframe('https://' + existingDomain + '/v1/wsdk-init/index.html?' + params); + const existingBaseUrl = domain ? generateBaseUrl(domain) : 'https://apps.rokt.com'; + createAutoRemovedIframe(existingBaseUrl + '/v1/wsdk-init/index.html?' + params); createAutoRemovedIframe( 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true', @@ -759,6 +719,22 @@ class LoggingService { } } +function buildPageEvent(event: SDKEvent): PageEvent { + const pageUrl = sanitizeUrl(window.location.href); + const pageTitle = event.EventAttributes?.title || document.title; + const canonicalUrl = readCanonicalUrl(); + const activeTimeOnSite = event.ActiveTimeOnSite; + + return { + pageUrl, + sourceMessageId: event.SourceMessageId, + timestamp: event.Timestamp, + ...(pageTitle ? { pageTitle } : {}), + ...(canonicalUrl !== undefined ? { canonicalUrl } : {}), + ...(Number.isFinite(activeTimeOnSite) ? { activeTimeOnSite } : {}), + }; +} + // ============================================================ // RoktKit class // ============================================================ @@ -909,37 +885,36 @@ class RoktKit implements KitInterface { try { pageUrl = sanitizeUrl(window.location.href); - const pageViews = readPageViewsStorage(); - - const pageView: PageEvent = { - pageUrl, - sourceMessageId: event.SourceMessageId, - timestamp: event.Timestamp, - }; - - if (Number.isFinite(event.ActiveTimeOnSite)) { - pageView.activeTimeOnSite = event.ActiveTimeOnSite; - } - + const pageViews = loadPageViews(this.loggingService); + const pageView = buildPageEvent(event); pageViews.push(pageView); - while (pageViews.length > PAGE_VIEWS_MAX_COUNT) { - pageViews.shift(); + const requested = Math.min(pageViews.length, PAGE_VIEWS_MAX_COUNT); + const stored = writePageViews(pageViews); + if (stored === 0) { + const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable'; + this.loggingService?.log({ + message: `Rokt Kit: Failed to persist page view for ${pageUrl} [reason: ${reason}]`, + code: 'PAGE_VIEW_CAPTURE_FAILED', + }); + } else if (stored < requested) { + this.loggingService?.log({ + message: `Rokt Kit: Page view storage reduced from ${requested} to ${stored} record(s) under quota pressure [reason: quota_eviction]`, + code: 'PAGE_VIEW_QUOTA_EVICTION', + }); } - - writePageViewsStorage(pageViews); } catch (err) { - this.errorReportingService?.report({ - message: `Rokt Kit: Failed to capture page view for ${pageUrl}`, + const reason = isLocalStorageAvailable() ? 'exception' : 'ls_unavailable'; + const errMessage = err instanceof Error ? err.message : String(err); + this.loggingService?.log({ + message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${errMessage} [reason: ${reason}]`, code: 'PAGE_VIEW_CAPTURE_FAILED', - severity: WSDKErrorSeverity.INFO, - stackTrace: err instanceof Error ? err.stack : undefined, }); } } private isLauncherReadyToAttach(): boolean { - return !!window.Rokt && typeof window.Rokt.createLauncher === 'function'; + return !!window.Rokt && isFunction(window.Rokt.createLauncher); } /** @@ -962,34 +937,6 @@ class RoktKit implements KitInterface { return mp().Rokt.getLocalSessionAttributes!(); } - private buildPageEvents(pageViews: PageEvent[]): PageEvent[] { - return pageViews.map((pageView, index) => { - const pageEvent: PageEvent = { - pageUrl: pageView.pageUrl, - sourceMessageId: pageView.sourceMessageId, - timestamp: pageView.timestamp, - }; - - const activeTimeOnSite = pageView.activeTimeOnSite; - const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite); - if (hasActiveTime) { - pageEvent.activeTimeOnSite = activeTimeOnSite; - } - - const next = pageViews[index + 1]; - const nextActiveTimeOnSite = next?.activeTimeOnSite; - const hasNextActiveTimeOnSite = nextActiveTimeOnSite !== undefined && Number.isFinite(nextActiveTimeOnSite); - - if (hasActiveTime && hasNextActiveTimeOnSite) { - const diff = nextActiveTimeOnSite - activeTimeOnSite; - if (diff >= 0) { - pageEvent.activeTimeOnPage = diff; - } - } - return pageEvent; - }); - } - private replaceOtherIdentityWithEmailsha256(userIdentities: IUserIdentities): Record { const newUserIdentities: Record = { ...(userIdentities || {}) }; const key = this._mappedEmailSha256Key; @@ -1023,7 +970,7 @@ class RoktKit implements KitInterface { } try { const mpInstance = mp().getInstance(); - if (mpInstance && typeof mpInstance.setIntegrationAttribute === 'function') { + if (mpInstance && isFunction(mpInstance.setIntegrationAttribute)) { mpInstance.setIntegrationAttribute(moduleId, { roktSessionId: sessionId, }); @@ -1033,20 +980,35 @@ class RoktKit implements KitInterface { } } + private readMpSessionId(): string | undefined { + // The public mParticle.sessionManager facade exposes only getSession(), which already returns + // the session id. getSessionId() lives on the internal _SessionManager and has never been + // re-exported, so prefer it if a future core adds it and fall back to getSession() until then. + const sessionManager = mp()?.sessionManager; + const readSessionId = sessionManager?.getSessionId ?? sessionManager?.getSession; + if (!isFunction(readSessionId)) { + return undefined; + } + + return readSessionId.call(sessionManager) || undefined; + } + + private readMpDeviceId(): string | undefined { + // The device application stamp (`das`) outlives the session id: core clears the session on + // timeout, cross-tab rotation and endSession(), but never the device id, which lives in + // localStorage/cookie for cookieExpiration days (365 by default) and survives login/logout. + // Read it per call anyway — a partner can reassign it at any time via setDeviceId(). + return mp()?.getDeviceId?.() || undefined; + } + private attachLauncher( accountId: string, launcherOptions: Record, legacyRoktExtensions: string[] = [], ): void { - const mpSessionId = - mp() && mp().sessionManager && typeof mp().sessionManager!.getSession === 'function' - ? mp().sessionManager!.getSession() - : undefined; - const options: Record = { accountId, ...(launcherOptions || {}), - ...(mpSessionId ? { mpSessionId } : {}), }; let launcherPromise: Promise; @@ -1217,7 +1179,8 @@ class RoktKit implements KitInterface { if (this.isTargetingDisabled()) { try { - clearPageViewsStorage(); + clearPageViews(); + clearUtmParams(); } catch (err) { this.errorReportingService?.report({ message: 'Rokt Kit: Failed to clear page views when targeting is disabled', @@ -1301,20 +1264,14 @@ class RoktKit implements KitInterface { public process(event: SDKEvent): string { if (!this.isTargetingDisabled()) { if (event.EventDataType === MESSAGE_TYPE_PAGE_VIEW) { + captureUtmParams(this.loggingService); this.capturePageView(event); } if (event.EventDataType === MESSAGE_TYPE_SESSION_END) { - try { - clearPageViewsStorage(); - } catch (err) { - this.errorReportingService?.report({ - message: 'Rokt Kit: Failed to clear page views on session end', - code: 'PAGE_VIEW_CAPTURE_FAILED', - severity: WSDKErrorSeverity.INFO, - stackTrace: err instanceof Error ? err.stack : undefined, - }); - } + migrateLegacyPageViewStorage(this.loggingService); + clearPageViews(); + clearUtmParams(); } } @@ -1324,7 +1281,7 @@ class RoktKit implements KitInterface { return 'Kit not ready for forwarder: ' + name; } - if (typeof mp().Rokt?.setLocalSessionAttribute === 'function') { + if (isFunction(mp().Rokt?.setLocalSessionAttribute)) { if (!isEmpty(this.placementEventAttributeMappingLookup)) { this.applyPlacementEventAttributeMapping(event); } @@ -1533,7 +1490,10 @@ class RoktKit implements KitInterface { const filteredUserIdentities = this.returnUserIdentities(filteredUser); const sessionAttributes = this.returnLocalSessionAttributes(); - const pageEvents = this.buildPageEvents(readPageViewsStorage()); + const pageEvents = buildPageEvents(loadPageViews(this.loggingService)); + const utmParams = loadUtmParams(); + const mpSessionId = this.readMpSessionId(); + const mpDeviceId = this.readMpDeviceId(); const selectPlacementsAttributes: Record = { ...(filteredUserIdentities as Record), @@ -1541,7 +1501,10 @@ class RoktKit implements KitInterface { ...optimizelyAttributes, ...sessionAttributes, ...(pageEvents.length ? { [PAGE_EVENTS_KEY]: JSON.stringify(pageEvents) } : {}), + ...(utmParams ? { [PAGE_VIEW_ATTRIBUTES_KEY]: utmParams } : {}), ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}), + ...(mpSessionId ? { [MPARTICLE_SESSION_ID_KEY]: mpSessionId } : {}), + ...(mpDeviceId ? { [MPARTICLE_DEVICE_ID_KEY]: mpDeviceId } : {}), mpid, }; @@ -1639,3 +1602,4 @@ if (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) { } export { register }; +export type { LoggingService }; diff --git a/kits/rokt/src/pageViewStorage.ts b/kits/rokt/src/pageViewStorage.ts new file mode 100644 index 000000000..7295bdcce --- /dev/null +++ b/kits/rokt/src/pageViewStorage.ts @@ -0,0 +1,151 @@ +import type { LoggingService } from './Rokt-Kit'; +import { + readJSON, + removeKey, + readNamespacedField, + writeNamespacedField, + removeNamespacedField, + isLocalStorageAvailable, +} from './storage'; +import { sanitizeUrl, isObject } from './utils'; + +const LS_NAMESPACE_KEY = 'mp-rokt-kit'; +const LS_PAGE_VIEWS_FIELD = 'pageViews'; +const LS_UTM_PARAMS_FIELD = 'utmParams'; +const LEGACY_PAGE_VIEWS_KEY = 'mpPageViews'; +export const PAGE_VIEWS_MAX_COUNT = 25; + +const UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'] as const; +type UtmKey = (typeof UTM_KEYS)[number]; +export type UtmParams = Partial>; + +export interface PageEvent { + pageUrl: string; + sourceMessageId: string; + timestamp: number; + pageTitle?: string; + canonicalUrl?: string; + activeTimeOnSite?: number; + activeTimeOnPage?: number; +} + +function capPageViews(views: PageEvent[]): PageEvent[] { + return views.slice(-PAGE_VIEWS_MAX_COUNT); +} + +export function migrateLegacyPageViewStorage(loggingService: LoggingService | null): void { + const legacyViews = readJSON(LEGACY_PAGE_VIEWS_KEY); + if (legacyViews === null) { + return; + } + + const alreadyMigrated = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD) !== undefined; + const needsMigration = !alreadyMigrated && Array.isArray(legacyViews); + + if (needsMigration) { + loggingService?.log({ + message: 'Rokt Kit: Migrating legacy page-view storage', + code: 'PAGE_VIEW_LEGACY_MIGRATION', + }); + const migrated = writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, legacyViews); + if (!migrated) { + loggingService?.log({ + message: 'Rokt Kit: Failed to migrate legacy page-view storage [reason: migration_retry]', + code: 'PAGE_VIEW_CAPTURE_FAILED', + }); + } + } + + removeKey(LEGACY_PAGE_VIEWS_KEY); +} + +export function loadPageViews(loggingService: LoggingService | null): PageEvent[] { + migrateLegacyPageViewStorage(loggingService); + const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD); + return Array.isArray(stored) ? (stored as PageEvent[]) : []; +} + +export function writePageViews(pageViews: PageEvent[]): number { + const views = capPageViews(pageViews); + for (let i = 0; i < views.length; i++) { + const toWrite = views.slice(i); + if (writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, toWrite)) { + return toWrite.length; + } + } + return 0; +} + +export function clearPageViews(): void { + removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD); +} + +export function buildPageEvents(pageViews: PageEvent[]): PageEvent[] { + const views = capPageViews(pageViews); + return views.map((pageView, index) => { + const activeTimeOnSite = pageView.activeTimeOnSite; + const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite); + + const next = views[index + 1]; + const nextActiveTimeOnSite = next?.activeTimeOnSite; + const hasNextActiveTimeOnSite = nextActiveTimeOnSite !== undefined && Number.isFinite(nextActiveTimeOnSite); + + const diff = hasActiveTime && hasNextActiveTimeOnSite ? nextActiveTimeOnSite - activeTimeOnSite : undefined; + + return { + pageUrl: pageView.pageUrl, + sourceMessageId: pageView.sourceMessageId, + timestamp: pageView.timestamp, + ...(pageView.pageTitle !== undefined ? { pageTitle: pageView.pageTitle } : {}), + ...(pageView.canonicalUrl !== undefined ? { canonicalUrl: pageView.canonicalUrl } : {}), + ...(hasActiveTime ? { activeTimeOnSite } : {}), + ...(diff !== undefined && diff >= 0 ? { activeTimeOnPage: diff } : {}), + }; + }); +} + +export function captureUtmParams(loggingService: LoggingService | null): void { + if (readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD) !== undefined) { + return; + } + const search = new URLSearchParams(window.location.search); + const params: UtmParams = {}; + for (const key of UTM_KEYS) { + const value = search.get(key); + if (value) params[key] = value; + } + if (Object.keys(params).length === 0) { + return; + } + const captured = Object.keys(params).join(', '); + if (!writeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD, params)) { + const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable'; + loggingService?.log({ + message: `Rokt Kit: Failed to persist UTM params [reason: ${reason}]`, + code: 'UTM_CAPTURE_FAILED', + }); + return; + } + loggingService?.log({ + message: `Rokt Kit: Captured UTM params [${captured}]`, + code: 'UTM_CAPTURE_SUCCESS', + }); +} + +export function loadUtmParams(): UtmParams | null { + const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD); + return isObject(stored) ? (stored as UtmParams) : null; +} + +export function clearUtmParams(): void { + removeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD); +} + +export function readCanonicalUrl(): string | undefined { + const link = document.querySelector('link[rel="canonical"]'); + const href = link?.href; + if (!href) { + return undefined; + } + return sanitizeUrl(href); +} diff --git a/kits/rokt/src/storage.ts b/kits/rokt/src/storage.ts new file mode 100644 index 000000000..10b60d496 --- /dev/null +++ b/kits/rokt/src/storage.ts @@ -0,0 +1,65 @@ +import { isObject } from './utils'; + +const LS_PROBE_KEY = '__rokt_ls_probe__'; + +export function isLocalStorageAvailable(): boolean { + try { + window.localStorage.setItem(LS_PROBE_KEY, '1'); + window.localStorage.removeItem(LS_PROBE_KEY); + return true; + } catch { + return false; + } +} + +export function readJSON(key: string): unknown { + try { + const stored = window.localStorage.getItem(key); + return stored === null ? null : JSON.parse(stored); + } catch { + return null; + } +} + +export function writeJSON(key: string, value: unknown): boolean { + try { + window.localStorage.setItem(key, JSON.stringify(value)); + return true; + } catch { + return false; + } +} + +export function removeKey(key: string): void { + try { + window.localStorage.removeItem(key); + } catch { + /* empty */ + } +} + +export function readNamespacedField(namespaceKey: string, field: string): unknown { + const blob = readJSON(namespaceKey); + return isObject(blob) ? blob[field] : undefined; +} + +export function writeNamespacedField(namespaceKey: string, field: string, value: unknown): boolean { + const blob = readJSON(namespaceKey); + const next = isObject(blob) ? { ...blob } : {}; + next[field] = value; + return writeJSON(namespaceKey, next); +} + +export function removeNamespacedField(namespaceKey: string, field: string): void { + const blob = readJSON(namespaceKey); + if (!isObject(blob) || !(field in blob)) { + return; + } + const next = { ...blob }; + delete next[field]; + if (Object.keys(next).length === 0) { + removeKey(namespaceKey); + } else { + writeJSON(namespaceKey, next); + } +} diff --git a/kits/rokt/src/utils.ts b/kits/rokt/src/utils.ts new file mode 100644 index 000000000..be905f58e --- /dev/null +++ b/kits/rokt/src/utils.ts @@ -0,0 +1,32 @@ +export function isObject(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +export function isString(value: unknown): value is string { + return typeof value === 'string'; +} + +export function isFunction(value: unknown): value is (...args: Array) => unknown { + return typeof value === 'function'; +} + +export function isEmpty(value: unknown): boolean { + if (value == null) return true; + if (typeof value === 'object') { + return Object.keys(value as object).length === 0; + } + return false; +} + +// Strips the query string from a URL before it is persisted and sent to Rokt, +// since query params commonly carry PII (emails, tokens, order refs). +// Returns the input unchanged if it can't be parsed as a URL. +export function sanitizeUrl(href: string): string { + try { + const url = new URL(href); + url.search = ''; + return url.toString(); + } catch { + return href; + } +} diff --git a/kits/rokt/test/src/pageViewStorage.spec.ts b/kits/rokt/test/src/pageViewStorage.spec.ts new file mode 100644 index 000000000..e297f5df3 --- /dev/null +++ b/kits/rokt/test/src/pageViewStorage.spec.ts @@ -0,0 +1,311 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { readJSON, writeNamespacedField } from '../../src/storage'; +import { + migrateLegacyPageViewStorage, + loadPageViews, + writePageViews, + clearPageViews, + buildPageEvents, + captureUtmParams, + loadUtmParams, + clearUtmParams, +} from '../../src/pageViewStorage'; +import type { LoggingService } from '../../src/Rokt-Kit'; + +const NAMESPACE_KEY = 'mp-rokt-kit'; +const PAGE_VIEWS_FIELD = 'pageViews'; +const UTM_PARAMS_FIELD = 'utmParams'; +const LEGACY_PAGE_VIEWS_KEY = 'mpPageViews'; + +function stubSearch(search: string): void { + vi.stubGlobal('location', { ...window.location, search }); +} + +const pageView = (id: string) => ({ pageUrl: 'https://example.com/' + id, sourceMessageId: id, timestamp: 1 }); + +describe('pageViewStorage', () => { + beforeEach(() => { + window.localStorage.clear(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + window.localStorage.clear(); + }); + + describe('migrateLegacyPageViewStorage', () => { + it('is a no-op when the legacy key is absent', () => { + migrateLegacyPageViewStorage(null); + expect(readJSON(NAMESPACE_KEY)).toBeNull(); + }); + + it('moves a legacy array into the namespaced field and removes the legacy key', () => { + window.localStorage.setItem(LEGACY_PAGE_VIEWS_KEY, JSON.stringify([pageView('home')])); + migrateLegacyPageViewStorage(null); + + expect(readJSON(NAMESPACE_KEY)).toEqual({ [PAGE_VIEWS_FIELD]: [pageView('home')] }); + expect(window.localStorage.getItem(LEGACY_PAGE_VIEWS_KEY)).toBeNull(); + }); + + it('does not overwrite an already-migrated field, but still clears the legacy key', () => { + writeNamespacedField(NAMESPACE_KEY, PAGE_VIEWS_FIELD, [pageView('current')]); + window.localStorage.setItem(LEGACY_PAGE_VIEWS_KEY, JSON.stringify([pageView('stale')])); + + migrateLegacyPageViewStorage(null); + + expect(readJSON(NAMESPACE_KEY)).toEqual({ [PAGE_VIEWS_FIELD]: [pageView('current')] }); + expect(window.localStorage.getItem(LEGACY_PAGE_VIEWS_KEY)).toBeNull(); + }); + + it('logs PAGE_VIEW_LEGACY_MIGRATION when the migration path is taken', () => { + window.localStorage.setItem(LEGACY_PAGE_VIEWS_KEY, JSON.stringify([pageView('home')])); + const logger = { log: vi.fn() } as unknown as LoggingService; + + migrateLegacyPageViewStorage(logger); + + expect(logger.log).toHaveBeenCalledWith(expect.objectContaining({ code: 'PAGE_VIEW_LEGACY_MIGRATION' })); + }); + + it('removes the legacy key and logs when the migrating write fails', () => { + window.localStorage.setItem(LEGACY_PAGE_VIEWS_KEY, JSON.stringify([pageView('home')])); + const logger = { log: vi.fn() } as unknown as LoggingService; + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { + throw new DOMException('quota', 'QuotaExceededError'); + }); + + migrateLegacyPageViewStorage(logger); + + // Legacy key is removed even on failure — prevents the infinite retry loop. + expect(window.localStorage.getItem(LEGACY_PAGE_VIEWS_KEY)).toBeNull(); + expect(logger.log).toHaveBeenCalledWith(expect.objectContaining({ code: 'PAGE_VIEW_CAPTURE_FAILED' })); + }); + + it('does not log PAGE_VIEW_CAPTURE_FAILED on a second call after a failed migration', () => { + window.localStorage.setItem(LEGACY_PAGE_VIEWS_KEY, JSON.stringify([pageView('home')])); + const logger = { log: vi.fn() } as unknown as LoggingService; + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { + throw new DOMException('quota', 'QuotaExceededError'); + }); + + migrateLegacyPageViewStorage(logger); // first call: fails, legacy key removed + vi.restoreAllMocks(); + logger.log.mockClear(); + + migrateLegacyPageViewStorage(logger); // second call: legacy key gone, no-op + + expect(logger.log).not.toHaveBeenCalled(); + }); + }); + + describe('loadPageViews', () => { + it('returns an empty array when nothing is stored', () => { + expect(loadPageViews(null)).toEqual([]); + }); + + it('returns the stored page views', () => { + writeNamespacedField(NAMESPACE_KEY, PAGE_VIEWS_FIELD, [pageView('home'), pageView('about')]); + expect(loadPageViews(null)).toEqual([pageView('home'), pageView('about')]); + }); + + it('returns an empty array when the stored value is not an array', () => { + writeNamespacedField(NAMESPACE_KEY, PAGE_VIEWS_FIELD, { not: 'an array' }); + expect(loadPageViews(null)).toEqual([]); + }); + + it('migrates the legacy key before reading', () => { + window.localStorage.setItem(LEGACY_PAGE_VIEWS_KEY, JSON.stringify([pageView('legacy')])); + expect(loadPageViews(null)).toEqual([pageView('legacy')]); + expect(window.localStorage.getItem(LEGACY_PAGE_VIEWS_KEY)).toBeNull(); + }); + }); + + describe('writePageViews', () => { + it('persists the page views and returns the stored count', () => { + expect(writePageViews([pageView('home')])).toBe(1); + expect(loadPageViews(null)).toEqual([pageView('home')]); + }); + + it('keeps only the 25 most-recent views when given more than 25', () => { + const views = Array.from({ length: 40 }, (_, i) => pageView('page-' + i)); + expect(writePageViews(views)).toBe(25); + const stored = loadPageViews(null); + expect(stored).toHaveLength(25); + expect(stored[0].sourceMessageId).toBe('page-15'); + expect(stored[24].sourceMessageId).toBe('page-39'); + }); + + it('evicts oldest records and retries when the initial write fails due to quota', () => { + const views = Array.from({ length: 5 }, (_, i) => pageView('page-' + i)); + const original = Storage.prototype.setItem; + let calls = 0; + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(function (this: Storage, key: string, value: string) { + if (++calls === 1) throw new DOMException('quota', 'QuotaExceededError'); + original.call(this, key, value); + }); + + expect(writePageViews(views)).toBe(4); + const stored = loadPageViews(null); + expect(stored).toHaveLength(4); + expect(stored[0].sourceMessageId).toBe('page-1'); + expect(stored[3].sourceMessageId).toBe('page-4'); + }); + + it('evicts oldest records across multiple failed writes until one succeeds', () => { + const views = Array.from({ length: 5 }, (_, i) => pageView('page-' + i)); + const original = Storage.prototype.setItem; + let calls = 0; + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(function (this: Storage, key: string, value: string) { + if (++calls <= 3) throw new DOMException('quota', 'QuotaExceededError'); + original.call(this, key, value); + }); + + expect(writePageViews(views)).toBe(2); + const stored = loadPageViews(null); + expect(stored).toHaveLength(2); + expect(stored[0].sourceMessageId).toBe('page-3'); + expect(stored[1].sourceMessageId).toBe('page-4'); + }); + + it('evicts the oldest record from pre-existing storage when quota is tight on the next write', () => { + const existing = Array.from({ length: 5 }, (_, i) => pageView('existing-' + i)); + writePageViews(existing); // seed storage + + const updated = [...existing, pageView('new')]; + const original = Storage.prototype.setItem; + let calls = 0; + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(function (this: Storage, key: string, value: string) { + if (++calls === 1) throw new DOMException('quota', 'QuotaExceededError'); + original.call(this, key, value); + }); + + expect(writePageViews(updated)).toBe(5); + const stored = loadPageViews(null); + expect(stored).toHaveLength(5); + expect(stored[0].sourceMessageId).toBe('existing-1'); + expect(stored[4].sourceMessageId).toBe('new'); + }); + + it('returns 0 when every write attempt fails', () => { + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { + throw new DOMException('quota', 'QuotaExceededError'); + }); + expect(writePageViews([pageView('home')])).toBe(0); + }); + }); + + describe('buildPageEvents', () => { + it('returns all views when count is within the send limit', () => { + const views = Array.from({ length: 10 }, (_, i) => pageView('page-' + i)); + expect(buildPageEvents(views)).toHaveLength(10); + }); + + it('caps output at 25 most-recent views when storage exceeds the send limit', () => { + const views = Array.from({ length: 40 }, (_, i) => ({ + pageUrl: 'https://example.com/page-' + i, + sourceMessageId: 'id-' + i, + timestamp: i, + })); + const result = buildPageEvents(views); + expect(result).toHaveLength(25); + expect(result[0].sourceMessageId).toBe('id-15'); + expect(result[24].sourceMessageId).toBe('id-39'); + }); + + it('computes activeTimeOnPage correctly within the capped window', () => { + const views = Array.from({ length: 30 }, (_, i) => ({ + pageUrl: 'https://example.com/page-' + i, + sourceMessageId: 'id-' + i, + timestamp: i, + activeTimeOnSite: i * 1000, + })); + const result = buildPageEvents(views); + expect(result).toHaveLength(25); + expect(result[0].activeTimeOnPage).toBe(1000); + expect(result[24].activeTimeOnPage).toBeUndefined(); + }); + }); + + describe('clearPageViews', () => { + it('removes the page-view field', () => { + writeNamespacedField(NAMESPACE_KEY, PAGE_VIEWS_FIELD, [pageView('home')]); + writeNamespacedField(NAMESPACE_KEY, 'unrelatedField', 'keep-me'); + clearPageViews(); + + const blob = readJSON(NAMESPACE_KEY); + expect(blob).not.toHaveProperty(PAGE_VIEWS_FIELD); + expect(blob).toHaveProperty('unrelatedField', 'keep-me'); + }); + }); + + describe('captureUtmParams', () => { + afterEach(() => { + vi.unstubAllGlobals(); + }); + + it('stores present UTM params on first call', () => { + stubSearch('?utm_source=google&utm_medium=cpc&utm_campaign=spring'); + captureUtmParams(null); + expect(readJSON(NAMESPACE_KEY)).toHaveProperty(UTM_PARAMS_FIELD, { + utm_source: 'google', + utm_medium: 'cpc', + utm_campaign: 'spring', + }); + }); + + it('only stores the keys that are present', () => { + stubSearch('?utm_source=email'); + captureUtmParams(null); + const stored = readJSON(NAMESPACE_KEY) as Record; + expect(stored[UTM_PARAMS_FIELD]).toEqual({ utm_source: 'email' }); + }); + + it('does nothing when no UTM params are in the URL', () => { + stubSearch('?unrelated=value'); + captureUtmParams(null); + expect(readJSON(NAMESPACE_KEY)).toBeNull(); + }); + + it('does nothing when the URL has no query string', () => { + stubSearch(''); + captureUtmParams(null); + expect(readJSON(NAMESPACE_KEY)).toBeNull(); + }); + + it('first touch wins — does not overwrite when UTMs are already stored', () => { + stubSearch('?utm_source=google'); + captureUtmParams(null); + stubSearch('?utm_source=facebook&utm_medium=paid'); + captureUtmParams(null); + const stored = readJSON(NAMESPACE_KEY) as Record; + expect(stored[UTM_PARAMS_FIELD]).toEqual({ utm_source: 'google' }); + }); + }); + + describe('loadUtmParams', () => { + it('returns null when nothing is stored', () => { + expect(loadUtmParams()).toBeNull(); + }); + + it('returns the stored UTM params', () => { + writeNamespacedField(NAMESPACE_KEY, UTM_PARAMS_FIELD, { utm_source: 'google', utm_medium: 'cpc' }); + expect(loadUtmParams()).toEqual({ utm_source: 'google', utm_medium: 'cpc' }); + }); + + it('returns null when the stored value is not an object', () => { + writeNamespacedField(NAMESPACE_KEY, UTM_PARAMS_FIELD, 'invalid'); + expect(loadUtmParams()).toBeNull(); + }); + }); + + describe('clearUtmParams', () => { + it('removes the utmParams field without affecting other fields', () => { + writeNamespacedField(NAMESPACE_KEY, UTM_PARAMS_FIELD, { utm_source: 'google' }); + writeNamespacedField(NAMESPACE_KEY, PAGE_VIEWS_FIELD, [pageView('home')]); + clearUtmParams(); + + const blob = readJSON(NAMESPACE_KEY); + expect(blob).not.toHaveProperty(UTM_PARAMS_FIELD); + expect(blob).toHaveProperty(PAGE_VIEWS_FIELD); + }); + }); +}); diff --git a/kits/rokt/test/src/storage.spec.ts b/kits/rokt/test/src/storage.spec.ts new file mode 100644 index 000000000..821333e96 --- /dev/null +++ b/kits/rokt/test/src/storage.spec.ts @@ -0,0 +1,175 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { + isLocalStorageAvailable, + readJSON, + writeJSON, + removeKey, + readNamespacedField, + writeNamespacedField, + removeNamespacedField, +} from '../../src/storage'; + +describe('storage: key-agnostic localStorage helpers', () => { + beforeEach(() => { + window.localStorage.clear(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + window.localStorage.clear(); + }); + + describe('readJSON', () => { + it('returns the parsed value for a stored JSON string', () => { + window.localStorage.setItem('k', JSON.stringify({ a: 1, b: [2, 3] })); + expect(readJSON('k')).toEqual({ a: 1, b: [2, 3] }); + }); + + it('round-trips values written by writeJSON', () => { + writeJSON('k', ['x', 'y']); + expect(readJSON('k')).toEqual(['x', 'y']); + }); + + it('returns null when the key is absent', () => { + expect(readJSON('missing')).toBeNull(); + }); + + it('returns null for malformed JSON (does not throw)', () => { + window.localStorage.setItem('k', '{not valid json'); + expect(readJSON('k')).toBeNull(); + }); + + it('returns null when getItem throws (access denied)', () => { + vi.spyOn(Storage.prototype, 'getItem').mockImplementation(() => { + throw new Error('SecurityError'); + }); + expect(readJSON('k')).toBeNull(); + }); + }); + + describe('writeJSON', () => { + it('persists the value as a JSON string and returns true', () => { + expect(writeJSON('k', { hello: 'world' })).toBe(true); + expect(window.localStorage.getItem('k')).toBe(JSON.stringify({ hello: 'world' })); + }); + + it('returns false when setItem throws (quota exceeded / private mode)', () => { + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { + throw new Error('QuotaExceededError'); + }); + expect(writeJSON('k', { hello: 'world' })).toBe(false); + }); + + it('overwrites an existing value', () => { + writeJSON('k', 1); + writeJSON('k', 2); + expect(readJSON('k')).toBe(2); + }); + }); + + describe('removeKey', () => { + it('removes the stored key', () => { + window.localStorage.setItem('k', '1'); + removeKey('k'); + expect(window.localStorage.getItem('k')).toBeNull(); + }); + + it('does not throw when removeItem throws', () => { + vi.spyOn(Storage.prototype, 'removeItem').mockImplementation(() => { + throw new Error('SecurityError'); + }); + expect(() => removeKey('k')).not.toThrow(); + }); + + it('is a no-op for an absent key', () => { + expect(() => removeKey('missing')).not.toThrow(); + }); + }); + + describe('namespaced fields', () => { + const NAMESPACE_KEY = 'mp-rokt-kit'; + + it('writeNamespacedField stores the value under a field of the namespace object', () => { + expect(writeNamespacedField(NAMESPACE_KEY, 'pageViews', [1, 2])).toBe(true); + expect(readJSON(NAMESPACE_KEY)).toEqual({ pageViews: [1, 2] }); + }); + + it('readNamespacedField returns the stored field value', () => { + writeNamespacedField(NAMESPACE_KEY, 'pageViews', ['a']); + expect(readNamespacedField(NAMESPACE_KEY, 'pageViews')).toEqual(['a']); + }); + + it('preserves sibling fields on write (read-modify-write)', () => { + writeNamespacedField(NAMESPACE_KEY, 'pageViews', ['a']); + writeNamespacedField(NAMESPACE_KEY, 'other', { x: 1 }); + expect(readJSON(NAMESPACE_KEY)).toEqual({ pageViews: ['a'], other: { x: 1 } }); + }); + + it('overwrites only the targeted field', () => { + writeNamespacedField(NAMESPACE_KEY, 'pageViews', ['a']); + writeNamespacedField(NAMESPACE_KEY, 'other', 1); + writeNamespacedField(NAMESPACE_KEY, 'pageViews', ['b']); + expect(readNamespacedField(NAMESPACE_KEY, 'pageViews')).toEqual(['b']); + expect(readNamespacedField(NAMESPACE_KEY, 'other')).toBe(1); + }); + + it('readNamespacedField returns undefined when the key is absent', () => { + expect(readNamespacedField(NAMESPACE_KEY, 'pageViews')).toBeUndefined(); + }); + + it('readNamespacedField returns undefined when the field is absent', () => { + writeNamespacedField(NAMESPACE_KEY, 'other', 1); + expect(readNamespacedField(NAMESPACE_KEY, 'pageViews')).toBeUndefined(); + }); + + it('readNamespacedField returns undefined when the stored value is not a plain object', () => { + writeJSON(NAMESPACE_KEY, [1, 2, 3]); + expect(readNamespacedField(NAMESPACE_KEY, 'pageViews')).toBeUndefined(); + }); + + it('writeNamespacedField returns false when the write throws', () => { + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { + throw new Error('QuotaExceededError'); + }); + expect(writeNamespacedField(NAMESPACE_KEY, 'pageViews', ['a'])).toBe(false); + }); + + it('removeNamespacedField clears the field but keeps other fields', () => { + writeNamespacedField(NAMESPACE_KEY, 'pageViews', ['a']); + writeNamespacedField(NAMESPACE_KEY, 'other', 1); + removeNamespacedField(NAMESPACE_KEY, 'pageViews'); + expect(readNamespacedField(NAMESPACE_KEY, 'pageViews')).toBeUndefined(); + expect(readJSON(NAMESPACE_KEY)).toEqual({ other: 1 }); + }); + + it('removeNamespacedField drops the namespace key once its last field is gone', () => { + writeNamespacedField(NAMESPACE_KEY, 'pageViews', ['a']); + removeNamespacedField(NAMESPACE_KEY, 'pageViews'); + expect(window.localStorage.getItem(NAMESPACE_KEY)).toBeNull(); + }); + + it('removeNamespacedField is a no-op for an absent key or field', () => { + expect(() => removeNamespacedField(NAMESPACE_KEY, 'pageViews')).not.toThrow(); + writeNamespacedField(NAMESPACE_KEY, 'other', 1); + removeNamespacedField(NAMESPACE_KEY, 'pageViews'); + expect(readJSON(NAMESPACE_KEY)).toEqual({ other: 1 }); + }); + }); +}); + +describe('isLocalStorageAvailable', () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('returns true when localStorage is accessible', () => { + expect(isLocalStorageAvailable()).toBe(true); + }); + + it('returns false when setItem throws', () => { + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { + throw new DOMException('SecurityError'); + }); + expect(isLocalStorageAvailable()).toBe(false); + }); +}); diff --git a/kits/rokt/test/src/tests.spec.ts b/kits/rokt/test/src/tests.spec.ts index dc18813c7..b3aba2975 100644 --- a/kits/rokt/test/src/tests.spec.ts +++ b/kits/rokt/test/src/tests.spec.ts @@ -5,6 +5,7 @@ import { isSelectPlacementsAttributePersistenceDenied, removeSelectPlacementsAttributePersistenceDeniedAttributes, } from '../../src/selectPlacementsAttributePersistence'; +import { readJSON, readNamespacedField, writeNamespacedField } from '../../src/storage'; /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -103,6 +104,9 @@ describe('Rokt Forwarder', () => { return 'test-mp-session-id'; }, }; + mParticle.getDeviceId = function () { + return 'test-mp-device-id'; + }; mParticle._getActiveForwarders = function () { return []; }; @@ -136,6 +140,8 @@ describe('Rokt Forwarder', () => { self.noFunctional = options.noFunctional; self.noTargeting = options.noTargeting; self.mpSessionId = options.mpSessionId; + self.sessionId = options.sessionId; + self.sessionToken = options.sessionToken; self.createLauncherCalled = true; self.isInitialized = true; self.sandbox = options.sandbox; @@ -161,6 +167,8 @@ describe('Rokt Forwarder', () => { self.noFunctional = options.noFunctional; self.noTargeting = options.noTargeting; self.mpSessionId = options.mpSessionId; + self.sessionId = options.sessionId; + self.sessionToken = options.sessionToken; self.createLocalLauncherCalled = true; self.isInitialized = true; self.sandbox = options.sandbox; @@ -320,6 +328,32 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.noTargeting).toBe(true); }); + it('should forward sessionId and sessionToken from launcherOptions to createLauncher', async () => { + const sessionId = '0198c1a2-3b4c-7d5e-8f90-1a2b3c4d5e6f'; + const sessionToken = 'header.payload.signature'; + (window as any).mParticle.Rokt.launcherOptions = { + sessionId, + sessionToken, + }; + + await mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + null, + null, + null, + ); + + expect((window as any).Rokt.createLauncherCalled).toBe(true); + expect((window as any).Rokt.sessionId).toBe(sessionId); + expect((window as any).Rokt.sessionToken).toBe(sessionToken); + }); + it('should set the filters on the forwarder', async () => { await mParticle.forwarder.init( { @@ -820,7 +854,7 @@ describe('Rokt Forwarder', () => { expect((window as any).mParticle.Rokt.createLauncherCalled).toBe(true); }); - it('should pass mpSessionId from mParticle sessionManager to createLauncher', async () => { + it('should not pass mpSessionId to createLauncher', async () => { (window as any).mParticle.sessionManager = { getSession: function () { return 'my-mp-session-123'; @@ -829,14 +863,6 @@ describe('Rokt Forwarder', () => { await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); - expect((window as any).mParticle.Rokt.mpSessionId).toBe('my-mp-session-123'); - }); - - it('should not pass mpSessionId when sessionManager is unavailable', async () => { - delete (window as any).mParticle.sessionManager; - - await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); - expect((window as any).mParticle.Rokt.mpSessionId).toBeUndefined(); }); }); @@ -850,6 +876,14 @@ describe('Rokt Forwarder', () => { return Promise.resolve(); }; mParticle.loggedEvents = []; + (window as any).mParticle.sessionManager = { + getSession: function () { + return 'test-mp-session-id'; + }, + }; + (window as any).mParticle.getDeviceId = function () { + return 'test-mp-device-id'; + }; (window as any).mParticle.Rokt.setLocalSessionAttribute = function (key: any, value: any) { mParticle._Store.localSessionAttributes[key] = value; }; @@ -901,11 +935,155 @@ describe('Rokt Forwarder', () => { identifier: 'test-placement', attributes: { test: 'test', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', }, }); }); + it('should send the mParticle session id current at the time of each call', async () => { + let currentSessionId = 'first-mp-session'; + (window as any).mParticle.sessionManager = { + getSession: function () { + return currentSessionId; + }, + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes.mparticle_session_id).toBe('first-mp-session'); + + currentSessionId = 'second-mp-session'; + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes.mparticle_session_id).toBe('second-mp-session'); + }); + + it('should omit the mParticle session id when sessionManager is unavailable', async () => { + delete (window as any).mParticle.sessionManager; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).not.toHaveProperty('mparticle_session_id'); + }); + + // Every published core exposes getSession() and nothing else on the public facade, so this + // is the shape that has to keep working. + it('should read the mParticle session id from a facade exposing only getSession', async () => { + (window as any).mParticle.sessionManager = { + getSession: function () { + return 'public-facade-session'; + }, + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes.mparticle_session_id).toBe( + 'public-facade-session', + ); + }); + + it('should prefer getSessionId when a future core exposes it on the facade', async () => { + (window as any).mParticle.sessionManager = { + getSession: function () { + return 'legacy-accessor-session'; + }, + getSessionId: function () { + return 'preferred-accessor-session'; + }, + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes.mparticle_session_id).toBe( + 'preferred-accessor-session', + ); + }); + + it('should omit the mParticle session id when the facade exposes neither accessor', async () => { + (window as any).mParticle.sessionManager = {}; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).not.toHaveProperty('mparticle_session_id'); + }); + + it('should keep sending the same device id after the session id rotates', async () => { + let currentSessionId = 'first-mp-session'; + (window as any).mParticle.sessionManager = { + getSession: function () { + return currentSessionId; + }, + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes.mparticle_session_id).toBe('first-mp-session'); + expect((window as any).Rokt.selectPlacementsOptions.attributes.mparticle_device_id).toBe('test-mp-device-id'); + + currentSessionId = 'second-mp-session'; + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes.mparticle_session_id).toBe('second-mp-session'); + expect((window as any).Rokt.selectPlacementsOptions.attributes.mparticle_device_id).toBe('test-mp-device-id'); + }); + + it('should send the device id current at the time of each call', async () => { + let currentDeviceId = 'first-mp-device'; + (window as any).mParticle.getDeviceId = function () { + return currentDeviceId; + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes.mparticle_device_id).toBe('first-mp-device'); + + currentDeviceId = 'second-mp-device'; + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes.mparticle_device_id).toBe('second-mp-device'); + }); + + it('should omit the device id when getDeviceId is unavailable', async () => { + delete (window as any).mParticle.getDeviceId; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).not.toHaveProperty('mparticle_device_id'); + }); + + it('should omit the device id when getDeviceId returns nothing', async () => { + (window as any).mParticle.getDeviceId = function () { + return undefined; + }; + + await (window as any).mParticle.forwarder.init({ accountId: '123456' }, reportService.cb, true, null, {}); + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + expect((window as any).Rokt.selectPlacementsOptions.attributes).not.toHaveProperty('mparticle_device_id'); + }); + it('should collect mpid and send to launcher.selectPlacements', async () => { await (window as any).mParticle.forwarder.init( { @@ -931,6 +1109,8 @@ describe('Rokt Forwarder', () => { identifier: 'test-placement', attributes: { 'user-attribute': 'user-attribute-value', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', }, }); @@ -969,6 +1149,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions).toEqual({ identifier: 'test-placement', attributes: { + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', 'test-attribute': 'test-value', 'custom-local-attribute': true, @@ -1043,6 +1225,8 @@ describe('Rokt Forwarder', () => { attributes: { 'user-attribute': 'user-attribute-value', 'unfiltered-attribute': 'unfiltered-value', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', }, }); @@ -1097,6 +1281,8 @@ describe('Rokt Forwarder', () => { 'user-attribute': 'user-attribute-value', 'unfiltered-attribute': 'unfiltered-value', 'changed-attribute': 'new-value', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', }, }); @@ -1134,6 +1320,8 @@ describe('Rokt Forwarder', () => { attributes: { loyaltyTier: 'gold', page: 'checkout', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', }, }); @@ -1181,6 +1369,8 @@ describe('Rokt Forwarder', () => { couponCode: 'SAVE10', shippingMethod: 'ground', page: 'checkout', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', }, }); @@ -1218,6 +1408,8 @@ describe('Rokt Forwarder', () => { loyaltyTier: 'gold', active_time_on_site_ms: 12345, page: 'checkout', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', }, }); @@ -1256,6 +1448,8 @@ describe('Rokt Forwarder', () => { identifier: 'test-placement', attributes: { active_time_on_site_ms: 67890, + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', }, }); @@ -1286,6 +1480,8 @@ describe('Rokt Forwarder', () => { identifier: 'test-placement', attributes: { favoriteStore: 'test-store', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', }, }); @@ -1367,6 +1563,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ 'test-attribute': 'test-value', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: 'abc', }); }); @@ -1421,6 +1619,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ customerid: 'customer123', email: 'test@example.com', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '234', }); }); @@ -1480,6 +1680,8 @@ describe('Rokt Forwarder', () => { 'test-attribute': 'test-value', customerid: 'customer123', email: 'test@example.com', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', }); }); @@ -1525,6 +1727,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ 'test-attribute': 'test-value', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: null, }); }); @@ -1574,6 +1778,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ 'test-attribute': 'test-value', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', }); }); @@ -1629,6 +1835,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ customerid: 'customer123', emailsha256: 'sha256-test@gmail.com', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '234', }); }); @@ -1685,6 +1893,8 @@ describe('Rokt Forwarder', () => { const attrs = (window as any).Rokt.selectPlacementsOptions.attributes; expect(attrs).toEqual({ customerid: 'customer123', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '234', }); expect(attrs).not.toHaveProperty('emailsha256'); @@ -1747,6 +1957,8 @@ describe('Rokt Forwarder', () => { 'test-attribute': 'test-value', customerid: 'customer123', other: 'other-attribute', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', }); }); @@ -1809,6 +2021,8 @@ describe('Rokt Forwarder', () => { customerid: 'customer123', other: 'continues-to-exist', emailsha256: 'other-id', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '123', }); }); @@ -1869,6 +2083,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ 'test-attribute': 'test-value', emailsha256: 'hashed-customer-id-value', // mapped from customerid in userIdentities + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '789', }); }); @@ -1929,6 +2145,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ 'test-attr': 'test-value', other: 'hashed-custom-identity-value', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '999', }); }); @@ -1987,6 +2205,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ email: 'test@example.com', emailsha256: 'hashed-email-value', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '456', }); }); @@ -2046,6 +2266,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ email: 'developer-email@example.com', emailsha256: 'hashed-email-value', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '789', }); }); @@ -2106,6 +2328,8 @@ describe('Rokt Forwarder', () => { email: 'identity-email@example.com', customerid: 'customer456', someAttribute: 'someValue', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '901', }); }); @@ -2166,6 +2390,8 @@ describe('Rokt Forwarder', () => { email: 'identity-email@example.com', emailsha256: 'hashed-from-other', customerid: 'customer789', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '912', }); }); @@ -2224,6 +2450,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ email: 'developer-email@example.com', customerid: 'customer202', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '934', }); }); @@ -2279,6 +2507,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ emailsha256: 'developer-hashed-email', customerid: 'customer303', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '945', }); }); @@ -2331,6 +2561,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ customerid: 'customer505', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '967', }); }); @@ -2386,6 +2618,8 @@ describe('Rokt Forwarder', () => { expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ emailsha256: 'hashed-from-useridentities', customerid: 'customer606', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '978', }); }); @@ -2447,6 +2681,8 @@ describe('Rokt Forwarder', () => { email: 'developer-email@example.com', emailsha256: 'developer-hashed-email', customerid: 'customer909', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '992', }); }); @@ -2502,6 +2738,8 @@ describe('Rokt Forwarder', () => { // Should NOT include emailsha256 since the other identity value was empty expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ email: 'test@gmail.com', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '234', }); }); @@ -2557,6 +2795,8 @@ describe('Rokt Forwarder', () => { // Should NOT include emailsha256 since the other identity value was null expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ email: 'test@gmail.com', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '345', }); }); @@ -2612,6 +2852,8 @@ describe('Rokt Forwarder', () => { // Should NOT include emailsha256 since the other identity value was undefined expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ email: 'test@gmail.com', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '456', }); }); @@ -2667,6 +2909,8 @@ describe('Rokt Forwarder', () => { // Should NOT include emailsha256 since the other identity value was 0 expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ email: 'test@gmail.com', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '567', }); }); @@ -2722,6 +2966,8 @@ describe('Rokt Forwarder', () => { // Should NOT include emailsha256 since the other identity value was false expect((window as any).Rokt.selectPlacementsOptions.attributes).toEqual({ email: 'test@gmail.com', + mparticle_session_id: 'test-mp-session-id', + mparticle_device_id: 'test-mp-device-id', mpid: '678', }); }); @@ -4116,6 +4362,24 @@ describe('Rokt Forwarder', () => { ); }); + it('should use a chrome-extension origin verbatim so the launcher loads from the bundled extension', () => { + expect( + (window as any).mParticle.forwarder.testHelpers.generateLauncherScript('chrome-extension://abcdef123/rokt'), + ).toBe('chrome-extension://abcdef123/rokt/wsdk/integrations/launcher.js'); + }); + + it('should trim a trailing slash from a full origin so the path join stays clean', () => { + expect( + (window as any).mParticle.forwarder.testHelpers.generateLauncherScript('chrome-extension://abcdef123/rokt/'), + ).toBe('chrome-extension://abcdef123/rokt/wsdk/integrations/launcher.js'); + }); + + it('should preserve an http origin for local development', () => { + expect((window as any).mParticle.forwarder.testHelpers.generateLauncherScript('http://localhost:8001')).toBe( + 'http://localhost:8001/wsdk/integrations/launcher.js', + ); + }); + it('should return base URL when no extensions are provided', () => { const url = (window as any).mParticle.forwarder.testHelpers.generateLauncherScript(); expect(url).toBe(baseUrl); @@ -4164,6 +4428,13 @@ describe('Rokt Forwarder', () => { const url = (window as any).mParticle.forwarder.testHelpers.generateThankYouElementScript('cname.rokt.com'); expect(url).toBe('https://cname.rokt.com/rokt-elements/rokt-element-thank-you.js'); }); + + it('should use a full custom origin verbatim', () => { + const url = (window as any).mParticle.forwarder.testHelpers.generateThankYouElementScript( + 'chrome-extension://abcdef123/rokt', + ); + expect(url).toBe('chrome-extension://abcdef123/rokt/rokt-elements/rokt-element-thank-you.js'); + }); }); describe('#roktExtensions', () => { @@ -5638,10 +5909,13 @@ describe('Rokt Forwarder', () => { }); describe('page view capture', () => { - const readStoredPageViews = () => { - const raw = window.localStorage.getItem('mpPageViews'); - return raw === null ? null : JSON.parse(raw); - }; + const NS_KEY = 'mp-rokt-kit'; + const PAGE_VIEWS_FIELD = 'pageViews'; + const LEGACY_KEY = 'mpPageViews'; + + const readStoredPageViews = () => readNamespacedField(NS_KEY, PAGE_VIEWS_FIELD) ?? null; + const seedStoredPageViews = (views: unknown) => writeNamespacedField(NS_KEY, PAGE_VIEWS_FIELD, views); + const seedLegacyPageViews = (views: unknown) => window.localStorage.setItem(LEGACY_KEY, JSON.stringify(views)); beforeEach(() => { window.localStorage.clear(); @@ -5682,11 +5956,125 @@ describe('Rokt Forwarder', () => { pageUrl: window.location.href, sourceMessageId: 'source-message-id-1', timestamp: 1712345678000, + pageTitle: 'Home', activeTimeOnSite: 4200, }, ]); }); + it('captures the page title and canonical URL when present', async () => { + document.title = 'Home Page Title'; + const canonical = document.createElement('link'); + canonical.setAttribute('rel', 'canonical'); + canonical.setAttribute('href', 'https://example.com/canonical?tracking=abc#section'); + document.head.appendChild(canonical); + + try { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle.forwarder.process({ + EventName: 'Home Page', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + SourceMessageId: 'source-message-id-title', + Timestamp: 1712345678000, + }); + + expect(readStoredPageViews()).toEqual([ + { + pageUrl: window.location.href, + sourceMessageId: 'source-message-id-title', + timestamp: 1712345678000, + pageTitle: 'Home Page Title', + canonicalUrl: 'https://example.com/canonical#section', + }, + ]); + } finally { + document.title = ''; + document.head.removeChild(canonical); + } + }); + + it('prefers the event title over document.title when both are present', async () => { + document.title = 'Document Title'; + + try { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle.forwarder.process({ + EventName: 'Home Page', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + SourceMessageId: 'source-message-id-event-title', + Timestamp: 1712345678000, + EventAttributes: { + title: 'Event Title', + }, + }); + + expect(readStoredPageViews()).toEqual([ + { + pageUrl: window.location.href, + sourceMessageId: 'source-message-id-event-title', + timestamp: 1712345678000, + pageTitle: 'Event Title', + }, + ]); + } finally { + document.title = ''; + } + }); + + it('omits pageTitle and canonicalUrl when neither is available', async () => { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle.forwarder.process({ + EventName: 'Home Page', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + SourceMessageId: 'source-message-id-bare', + Timestamp: 1712345678000, + }); + + expect(readStoredPageViews()).toEqual([ + { + pageUrl: window.location.href, + sourceMessageId: 'source-message-id-bare', + timestamp: 1712345678000, + }, + ]); + }); + it('omits activeTimeOnSite when the source value is non-finite', async () => { await (window as any).mParticle.forwarder.init( { @@ -5748,7 +6136,7 @@ describe('Rokt Forwarder', () => { expect(readStoredPageViews()).toBeNull(); }); - it('caps the stored history at 25 records, evicting oldest first', async () => { + it('keeps only the 25 most-recent views when more than 25 are written', async () => { await (window as any).mParticle.forwarder.init( { accountId: '123456', @@ -5761,22 +6149,64 @@ describe('Rokt Forwarder', () => { await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + const seed = []; for (let i = 0; i < 30; i++) { - (window as any).mParticle.forwarder.process({ - EventName: 'Page ' + i, - EventCategory: EventType.Unknown, - EventDataType: MessageType.PageView, - SourceMessageId: 'source-message-id-' + i, - Timestamp: 1712345678000 + i, - ActiveTimeOnSite: i, + seed.push({ + pageUrl: 'https://example.com/page-' + i, + sourceMessageId: 'seed-' + i, + timestamp: 1712345678000 + i, }); } + seedStoredPageViews(seed); + + (window as any).mParticle.forwarder.process({ + EventName: 'Newest', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + SourceMessageId: 'newest', + Timestamp: 1712345678999, + ActiveTimeOnSite: 1, + }); const stored = readStoredPageViews(); - // 30 written, capped at 25 — the 5 oldest evicted, newest always retained. expect(stored.length).toBe(25); - expect(stored[0].sourceMessageId).toBe('source-message-id-5'); - expect(stored[stored.length - 1].sourceMessageId).toBe('source-message-id-29'); + expect(stored[stored.length - 1].sourceMessageId).toBe('newest'); + expect(stored[0].sourceMessageId).toBe('seed-6'); + }); + + it('stores both old and new record regardless of individual record size', async () => { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + seedStoredPageViews([ + { + pageUrl: 'https://example.com/' + 'a'.repeat(50000), + sourceMessageId: 'seed-huge', + timestamp: 1712345678000, + }, + ]); + + (window as any).mParticle.forwarder.process({ + EventName: 'Newest', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + SourceMessageId: 'newest', + Timestamp: 1712345678999, + ActiveTimeOnSite: 1, + }); + + const stored = readStoredPageViews(); + expect(stored.length).toBe(2); + expect(stored[stored.length - 1].sourceMessageId).toBe('newest'); }); it('clears the stored page-view history on a SessionEnd event', async () => { @@ -5815,6 +6245,150 @@ describe('Rokt Forwarder', () => { expect(readStoredPageViews()).toBeNull(); }); + describe('legacy storage migration', () => { + const initKit = async () => { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + }; + + const runSelectPlacements = async () => { + (window as any).mParticle._Store.localSessionAttributes = {}; + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + return (window as any).mParticle.Rokt.selectPlacementsOptions.attributes; + }; + + it('adopts legacy history into the new key and sweeps the legacy key on read', async () => { + const seeded = [ + { + pageUrl: 'https://example.com/legacy', + sourceMessageId: 'legacy-1', + timestamp: 1712345678000, + }, + ]; + seedLegacyPageViews(seeded); + + await initKit(); + const attributes = await runSelectPlacements(); + + // Legacy history surfaces on read (adopted into the namespaced field). + expect(JSON.parse(attributes.page_events)).toEqual(seeded); + expect(readStoredPageViews()).toEqual(seeded); + // Legacy key is always swept. + expect(readJSON(LEGACY_KEY)).toBeNull(); + }); + + it('keeps the new key and sweeps the legacy key when both exist', async () => { + const legacy = [ + { + pageUrl: 'https://example.com/legacy', + sourceMessageId: 'legacy-1', + timestamp: 1712345678000, + }, + ]; + const current = [ + { + pageUrl: 'https://example.com/current', + sourceMessageId: 'current-1', + timestamp: 1712345679000, + }, + ]; + seedLegacyPageViews(legacy); + seedStoredPageViews(current); + + await initKit(); + const attributes = await runSelectPlacements(); + + // Namespaced field wins — legacy value is discarded, not merged. + expect(JSON.parse(attributes.page_events)).toEqual(current); + expect(readStoredPageViews()).toEqual(current); + expect(readJSON(LEGACY_KEY)).toBeNull(); + }); + + it('leaves the new key untouched when there is no legacy key', async () => { + const current = [ + { + pageUrl: 'https://example.com/current', + sourceMessageId: 'current-1', + timestamp: 1712345679000, + }, + ]; + seedStoredPageViews(current); + + await initKit(); + const attributes = await runSelectPlacements(); + + expect(JSON.parse(attributes.page_events)).toEqual(current); + expect(readStoredPageViews()).toEqual(current); + expect(readJSON(LEGACY_KEY)).toBeNull(); + }); + + it('sweeps the legacy key on SessionEnd before clearing the new key', async () => { + seedLegacyPageViews([ + { + pageUrl: 'https://example.com/legacy', + sourceMessageId: 'legacy-1', + timestamp: 1712345678000, + }, + ]); + + await initKit(); + + (window as any).mParticle.forwarder.process({ + EventName: 'Session End', + EventCategory: EventType.Unknown, + EventDataType: MessageType.SessionEnd, + SourceMessageId: 'source-message-id-session-end', + Timestamp: 1712345679000, + }); + + expect(readJSON(LEGACY_KEY)).toBeNull(); + expect(readStoredPageViews()).toBeNull(); + }); + + it('does not throw out of selectPlacements when the migration hits a storage error', async () => { + // Legacy present + namespaced field absent → migration attempts the adopt + // write, which throws here. The read path must swallow it (best-effort) so + // placement selection still proceeds without page events. + seedLegacyPageViews([ + { + pageUrl: 'https://example.com/legacy', + sourceMessageId: 'legacy-1', + timestamp: 1712345678000, + }, + ]); + + await initKit(); + + // A read/migration failure is surfaced as a diagnostic INFO log + // (loggingService.log), not an error report. + const logSpy = vi.spyOn((window as any).mParticle.forwarder.loggingService, 'log'); + const setItemSpy = vi.spyOn(Storage.prototype, 'setItem').mockImplementation((key: string) => { + if (key === NS_KEY) { + throw new Error('QuotaExceededError'); + } + }); + + try { + const attributes = await runSelectPlacements(); + // Selection proceeds; page events are simply omitted. + expect(attributes.page_events).toBeUndefined(); + } finally { + setItemSpy.mockRestore(); + } + + expect(logSpy).toHaveBeenCalledWith(expect.objectContaining({ code: 'PAGE_VIEW_CAPTURE_FAILED' })); + logSpy.mockRestore(); + }); + }); + it('captures the page view but returns the not-ready signal when the kit is not ready', () => { // Force a not-ready state: capture must still run (kit-owned storage), // but process() must tell the core SDK the forwarder is not ready. @@ -5870,7 +6444,7 @@ describe('Rokt Forwarder', () => { expect(readStoredPageViews()).toBeNull(); }); - it('does not throw and reports a warning when localStorage writes throw', async () => { + it('does not throw and logs a diagnostic when localStorage writes throw', async () => { await (window as any).mParticle.forwarder.init( { accountId: '123456', @@ -5884,6 +6458,7 @@ describe('Rokt Forwarder', () => { await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); const reportSpy = vi.spyOn((window as any).mParticle.forwarder.errorReportingService, 'report'); + const logSpy = vi.spyOn((window as any).mParticle.forwarder.loggingService, 'log'); const setItemSpy = vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { throw new Error('QuotaExceededError'); }); @@ -5905,13 +6480,56 @@ describe('Rokt Forwarder', () => { // Nothing is persisted, but the forwarder keeps running. expect(readStoredPageViews()).toBeNull(); - // The write failure is surfaced as an INFO (rate-limited per severity). - expect(reportSpy).toHaveBeenCalledWith( - expect.objectContaining({ code: 'PAGE_VIEW_CAPTURE_FAILED', severity: 'INFO' }), - ); + // The failed write is best-effort: surfaced as a diagnostic INFO log + // (loggingService.log), never an error report. + expect(logSpy).toHaveBeenCalledWith(expect.objectContaining({ code: 'PAGE_VIEW_CAPTURE_FAILED' })); + expect(reportSpy).not.toHaveBeenCalledWith(expect.objectContaining({ code: 'PAGE_VIEW_CAPTURE_FAILED' })); + logSpy.mockRestore(); reportSpy.mockRestore(); }); + it('fails gracefully and preserves existing data when localStorage quota is exceeded', async () => { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + const seed = []; + for (let i = 0; i < 5; i++) { + seed.push({ pageUrl: 'https://example.com/', sourceMessageId: 'seed-' + i, timestamp: 1712345678000 + i }); + } + seedStoredPageViews(seed); + + const setItemSpy = vi.spyOn(Storage.prototype, 'setItem').mockImplementation(function () { + throw new DOMException('quota', 'QuotaExceededError'); + }); + + try { + (window as any).mParticle.forwarder.process({ + EventName: 'Newest', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + SourceMessageId: 'newest', + Timestamp: 1712345678999, + ActiveTimeOnSite: 1, + }); + } finally { + setItemSpy.mockRestore(); + } + + // Write failed silently — existing seed data is unchanged. + const stored = readStoredPageViews(); + expect(stored.length).toBe(5); + expect(stored[stored.length - 1].sourceMessageId).toBe('seed-4'); + }); + it('captures page views independently of setLocalSessionAttribute availability', async () => { await (window as any).mParticle.forwarder.init( { @@ -5989,6 +6607,43 @@ describe('Rokt Forwarder', () => { ]); }); + it('carries pageTitle and canonicalUrl through selectPlacements when stored', async () => { + seedStoredPageViews([ + { + pageUrl: 'https://example.com/a', + sourceMessageId: 'source-message-id-a', + timestamp: 1712345678000, + pageTitle: 'Page A', + canonicalUrl: 'https://example.com/canonical-a', + }, + ]); + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + const forwardedAttributes = (window as any).mParticle.Rokt.selectPlacementsOptions.attributes; + expect(JSON.parse(forwardedAttributes.page_events)).toEqual([ + { + pageUrl: 'https://example.com/a', + sourceMessageId: 'source-message-id-a', + timestamp: 1712345678000, + pageTitle: 'Page A', + canonicalUrl: 'https://example.com/canonical-a', + }, + ]); + }); + it('does not add a page_events attribute when no page views are stored', async () => { await (window as any).mParticle.forwarder.init( { @@ -6157,22 +6812,19 @@ describe('Rokt Forwarder', () => { // followed by one that has it. A coerced-to-0 first record would diff // against the next (300000 - 0) and invent a 5-minute dwell that never // happened; "unknown" must stay distinguishable from a genuine zero. - window.localStorage.setItem( - 'mpPageViews', - JSON.stringify([ - { - pageUrl: 'https://example.com/a', - sourceMessageId: 'missing-ats', - timestamp: 1712345678000, - }, - { - pageUrl: 'https://example.com/b', - sourceMessageId: 'has-ats', - timestamp: 1712345679000, - activeTimeOnSite: 300000, - }, - ]), - ); + seedStoredPageViews([ + { + pageUrl: 'https://example.com/a', + sourceMessageId: 'missing-ats', + timestamp: 1712345678000, + }, + { + pageUrl: 'https://example.com/b', + sourceMessageId: 'has-ats', + timestamp: 1712345679000, + activeTimeOnSite: 300000, + }, + ]); await (window as any).mParticle.forwarder.init( { @@ -6201,17 +6853,14 @@ describe('Rokt Forwarder', () => { it('clears stored page views on init when targeting is disabled', async () => { // Seed a stored page view from a period when targeting was permitted. - window.localStorage.setItem( - 'mpPageViews', - JSON.stringify([ - { - pageUrl: 'https://example.com/', - sourceMessageId: 'seeded', - timestamp: 1712345678000, - activeTimeOnSite: 4200, - }, - ]), - ); + seedStoredPageViews([ + { + pageUrl: 'https://example.com/', + sourceMessageId: 'seeded', + timestamp: 1712345678000, + activeTimeOnSite: 4200, + }, + ]); (window as any).mParticle.Rokt.launcherOptions = { noTargeting: true, @@ -6240,6 +6889,48 @@ describe('Rokt Forwarder', () => { expect(forwardedAttributes.page_events).toBeUndefined(); }); + it('does not sweep the legacy key on init when targeting is disabled', async () => { + // The targeting-disabled clear path (initForwarder) intentionally only + // clears the kit-owned new key; it does not run the legacy migration. + // A user with targeting off keeps an orphaned legacy `mpPageViews` until + // the shim's removal date — benign, and swept the moment targeting is + // re-enabled (loadPageViews) or a SessionEnd fires. + seedLegacyPageViews([ + { + pageUrl: 'https://example.com/legacy', + sourceMessageId: 'legacy-seeded', + timestamp: 1712345678000, + }, + ]); + seedStoredPageViews([ + { + pageUrl: 'https://example.com/', + sourceMessageId: 'seeded', + timestamp: 1712345678000, + }, + ]); + + (window as any).mParticle.Rokt.launcherOptions = { + noTargeting: true, + }; + + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + // New key is cleared; legacy key is left untouched (not swept on this path). + expect(readStoredPageViews()).toBeNull(); + expect(readJSON(LEGACY_KEY)).not.toBeNull(); + }); + it('strips query params from the captured pageUrl', async () => { const originalLocation = window.location; // Query params commonly carry PII (emails, tokens); they must not be captured. @@ -6688,6 +7379,42 @@ describe('Rokt Forwarder', () => { expect(defaultDomainIframe).toBeTruthy(); }); + it('should still create the probe for a full https origin', () => { + Math.random = () => 0.05; + (window as any).__rokt_li_guid__ = 'test-guid-123'; + + (window as any).mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals( + 'https://custom.rokt.com', + 'test-version', + ); + + const iframes = document.querySelectorAll('iframe'); + const srcs = Array.prototype.map.call(iframes, (iframe: any) => iframe.src) as string[]; + + const httpsDomainIframe = srcs.find( + (src) => src.indexOf('https://custom.rokt.com/v1/wsdk-init/index.html') !== -1, + ); + + expect(httpsDomainIframe).toBeTruthy(); + }); + + it('should not create the probe for a chrome-extension origin', () => { + Math.random = () => 0.05; + (window as any).__rokt_li_guid__ = 'test-guid-123'; + + (window as any).mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals( + 'chrome-extension://abcdef123/rokt', + 'test-version', + ); + + const iframes = document.querySelectorAll('iframe'); + const srcs = Array.prototype.map.call(iframes, (iframe: any) => iframe.src) as string[]; + + const anyProbe = srcs.find((src) => src.indexOf('/v1/wsdk-init/index.html') !== -1); + + expect(anyProbe).toBeUndefined(); + }); + it('should not create iframes when sampled out', () => { Math.random = () => 0.5; // Above 0.1 threshold (window as any).__rokt_li_guid__ = 'test-guid-123'; @@ -6977,6 +7704,26 @@ describe('Rokt Forwarder', () => { expect(fetchCalls[0].url).toBe('https://apps.rokt-api.com/v1/errors'); }); + it('should use a full https integration domain for the error URL', () => { + const service = new ErrorReportingServiceClass( + { isLoggingEnabled: true, integrationDomain: 'https://custom.rokt.com' }, + '1.0.0', + 'test-guid', + ); + service.report({ message: 'test error', severity: WSDKErrorSeverityConst.ERROR }); + expect(fetchCalls[0].url).toBe('https://custom.rokt.com/v1/errors'); + }); + + it('should fall back to the default error URL for a chrome-extension integration domain', () => { + const service = new ErrorReportingServiceClass( + { isLoggingEnabled: true, integrationDomain: 'chrome-extension://abcdef123/rokt' }, + '1.0.0', + 'test-guid', + ); + service.report({ message: 'test error', severity: WSDKErrorSeverityConst.ERROR }); + expect(fetchCalls[0].url).toBe('https://apps.rokt-api.com/v1/errors'); + }); + it('should include all required fields in the log request body', () => { const service = new ErrorReportingServiceClass({ isLoggingEnabled: true }, 'test-integration', 'test-guid'); service.report({ diff --git a/kits/rokt/test/src/utils.spec.ts b/kits/rokt/test/src/utils.spec.ts new file mode 100644 index 000000000..09d3d855c --- /dev/null +++ b/kits/rokt/test/src/utils.spec.ts @@ -0,0 +1,96 @@ +import { describe, it, expect } from 'vitest'; +import { isObject, isString, isEmpty, isFunction } from '../../src/utils'; + +describe('utils: type guards', () => { + describe('isObject', () => { + it('is true for plain objects', () => { + expect(isObject({})).toBe(true); + expect(isObject({ a: 1 })).toBe(true); + }); + + it('is false for arrays', () => { + expect(isObject([])).toBe(false); + expect(isObject([1, 2])).toBe(false); + }); + + it('is false for null and undefined', () => { + expect(isObject(null)).toBe(false); + expect(isObject(undefined)).toBe(false); + }); + + it('is false for primitives', () => { + expect(isObject('s')).toBe(false); + expect(isObject(1)).toBe(false); + expect(isObject(true)).toBe(false); + }); + }); + + describe('isString', () => { + it('is true for strings', () => { + expect(isString('')).toBe(true); + expect(isString('abc')).toBe(true); + }); + + it('is false for non-strings', () => { + expect(isString(1)).toBe(false); + expect(isString(null)).toBe(false); + expect(isString(undefined)).toBe(false); + expect(isString({})).toBe(false); + expect(isString(['a'])).toBe(false); + }); + }); + + describe('isFunction', () => { + it('is true for function declarations and expressions', () => { + expect(isFunction(function named() {})).toBe(true); + expect(isFunction(() => undefined)).toBe(true); + expect(isFunction(async () => undefined)).toBe(true); + }); + + it('is true for methods read off an object', () => { + const sessionManager = { getSessionId: () => 'session-id' }; + expect(isFunction(sessionManager.getSessionId)).toBe(true); + }); + + it('is false for a missing method', () => { + const sessionManager = {} as { getSessionId?: () => string }; + expect(isFunction(sessionManager.getSessionId)).toBe(false); + }); + + it('is false for null and undefined', () => { + expect(isFunction(null)).toBe(false); + expect(isFunction(undefined)).toBe(false); + }); + + it('is false for non-callable values', () => { + expect(isFunction({})).toBe(false); + expect(isFunction([])).toBe(false); + expect(isFunction('getSessionId')).toBe(false); + expect(isFunction(1)).toBe(false); + expect(isFunction(true)).toBe(false); + }); + }); + + describe('isEmpty', () => { + it('is true for null and undefined', () => { + expect(isEmpty(null)).toBe(true); + expect(isEmpty(undefined)).toBe(true); + }); + + it('is true for empty objects and arrays', () => { + expect(isEmpty({})).toBe(true); + expect(isEmpty([])).toBe(true); + }); + + it('is false for non-empty objects and arrays', () => { + expect(isEmpty({ a: 1 })).toBe(false); + expect(isEmpty([1])).toBe(false); + }); + + it('is false for non-empty primitives', () => { + expect(isEmpty('abc')).toBe(false); + expect(isEmpty(0)).toBe(false); + expect(isEmpty(false)).toBe(false); + }); + }); +}); diff --git a/kits/rokt/test/vitest.setup.ts b/kits/rokt/test/vitest.setup.ts index 162c5ded6..84511df24 100644 --- a/kits/rokt/test/vitest.setup.ts +++ b/kits/rokt/test/vitest.setup.ts @@ -26,6 +26,7 @@ sessionManager: { getSession: () => 'test-mp-session-id', }, + getDeviceId: () => 'test-mp-device-id', _getActiveForwarders: () => [], generateHash: (input: string) => 'hashed-<' + input + '>-value', loggedEvents: [] as unknown[], From 0be01384ca15b8eac8670433c5f60cdfbad29792 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 26 Aug 2026 13:33:31 +0000 Subject: [PATCH 2/2] fix(rokt): stringify UTM selectPlacements attributes Co-authored-by: Cris Ryan Tan --- kits/rokt/dist/Rokt-Kit.common.js | 2 +- kits/rokt/dist/Rokt-Kit.common.js.map | 2 +- kits/rokt/dist/Rokt-Kit.esm.js | 2 +- kits/rokt/dist/Rokt-Kit.esm.js.map | 2 +- kits/rokt/dist/Rokt-Kit.iife.js | 2 +- kits/rokt/dist/Rokt-Kit.iife.js.map | 2 +- kits/rokt/src/Rokt-Kit.ts | 2 +- kits/rokt/test/src/tests.spec.ts | 50 +++++++++++++++++++++++++++ 8 files changed, 57 insertions(+), 7 deletions(-) diff --git a/kits/rokt/dist/Rokt-Kit.common.js b/kits/rokt/dist/Rokt-Kit.common.js index a4f463950..f1147e052 100644 --- a/kits/rokt/dist/Rokt-Kit.common.js +++ b/kits/rokt/dist/Rokt-Kit.common.js @@ -1,2 +1,2 @@ -"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _e=["active_time_on_site_ms","billingaddress1","billingaddress2","billingcity","billingstate","billingzipcode","cartitems","ccbin","confirmationref","conversiontype","country","couponcode","currency","language","paymentserviceprovider","paymentserviceproviderattribute","paymenttype","shippingaddress1","shippingcity","shippingcountry","shippingmethod","shippingstate","shippingzipcode","totalprice"],Ie=new Set(_e);function se(i){return Ie.has(i.toLowerCase())}function b(i){const e={},t=i||{},n=Object.keys(t);for(let r=0;r{const r=t.activeTimeOnSite,s=r!==void 0&&Number.isFinite(r),c=e[n+1]?.activeTimeOnSite,u=c!==void 0&&Number.isFinite(c),l=s&&u?c-r:void 0;return{pageUrl:t.pageUrl,sourceMessageId:t.sourceMessageId,timestamp:t.timestamp,...t.pageTitle!==void 0?{pageTitle:t.pageTitle}:{},...t.canonicalUrl!==void 0?{canonicalUrl:t.canonicalUrl}:{},...s?{activeTimeOnSite:r}:{},...l!==void 0&&l>=0?{activeTimeOnPage:l}:{}}})}function ke(i){if(U(p,O)!==void 0)return;const e=new URLSearchParams(window.location.search),t={};for(const r of Se){const s=e.get(r);s&&(t[r]=s)}if(Object.keys(t).length===0)return;const n=Object.keys(t).join(", ");if(!G(p,O,t)){const r=D()?"quota":"ls_unavailable";i?.log({message:`Rokt Kit: Failed to persist UTM params [reason: ${r}]`,code:"UTM_CAPTURE_FAILED"});return}i?.log({message:`Rokt Kit: Captured UTM params [${n}]`,code:"UTM_CAPTURE_SUCCESS"})}function ve(){const i=U(p,O);return _(i)?i:null}function $(){ce(p,O)}function Re(){const e=document.querySelector('link[rel="canonical"]')?.href;if(e)return Y(e)}const d="Rokt",L=181,we="selectPlacements",be="apps.roktecommerce.com",Te=.1,Le="ThankYouPageJourney",Pe="rokt-launcher",Oe="rokt-thank-you-element",Ne="userIdentifiedInWorkspace",Ue=3,Ce=2,Me="page_events",Ke="page_view_attributes",De="mparticle_session_id",Fe="mparticle_device_id",Ye=500,x={UNKNOWN_ERROR:"UNKNOWN_ERROR",UNHANDLED_EXCEPTION:"UNHANDLED_EXCEPTION",IDENTITY_REQUEST:"IDENTITY_REQUEST",LOG_DELIVERY_FAILURE:"LOG_DELIVERY_FAILURE"},S={ERROR:"ERROR",INFO:"INFO",WARNING:"WARNING"},Ge="apps.rokt-api.com",xe="/v1/log",We="/v1/errors",je=10;function a(){return window.mParticle}function J(i,e){const n=[C(i),"/wsdk/integrations/launcher.js"].join("");return!e||e.length===0?n:n+"?extensions="+e.join(",")}function B(i){return[C(i),"/rokt-elements/rokt-element-thank-you.js"].join("")}function C(i){const e=typeof i<"u"?i:Ge;return e.includes("://")?e.replace(/\/+$/,""):["https://",e].join("")}function he(i,e,t){if(i)return i.startsWith("http://")||i.startsWith("https://")?i:"https://"+i;const r=e?.includes("://")&&!/^https?:\/\//i.test(e)?void 0:e;return C(r)+t}function Q(i,e,t){if(document.getElementById(i))return;const n=document.head||document.body,r=document.createElement("script");r.id=i,r.type="text/javascript",r.src=e,r.async=!0,r.crossOrigin="anonymous",r.fetchPriority="high",t?.onLoad&&(r.onload=t.onLoad),t?.onError&&(r.onerror=t.onError),n.appendChild(r)}function P(i){if(!i)return[];try{return JSON.parse(i.replace(/"/g,'"'))}catch{console.error("Settings string contains invalid JSON")}return[]}function X(i){const e=i?P(i):[],t=[],n=[];let r=!1;for(let s=0;s=Te)return;const r=window.__rokt_li_guid__;if(!r||i&&i.includes("://")&&!/^https:\/\//i.test(i))return;const s=window.location.href.split("?")[0].split("#")[0],o="version="+encodeURIComponent(e??"")+"&launcherInstanceGuid="+encodeURIComponent(r)+"&pageUrl="+encodeURIComponent(s),c=i?C(i):"https://apps.rokt.com";F(c+"/v1/wsdk-init/index.html?"+o),F("https://"+be+"/v1/wsdk-init/index.html?"+o+"&isControl=true")}function ze(){return typeof window<"u"&&!!window.location?.search?.toLowerCase().includes("mp_enable_logging=true")}function qe(){return typeof window<"u"?window.location?.href:void 0}function $e(){return typeof window<"u"?window.navigator?.userAgent:void 0}class pe{constructor(){this._logCount={}}incrementAndCheck(e){const n=(this._logCount[e]||0)+1;return this._logCount[e]=n,n>je}}class W{constructor(e,t,n,r,s){this._reporter="mp-wsdk";const o=e.isLoggingEnabled;this._integrationName=t||"",this._launcherInstanceGuid=n,this._accountId=r||null,this._rateLimiter=s||new pe,this._isEnabled=ze()||o}send(e,t,n,r,s,o){if(!(!this._isEnabled||this._rateLimiter.incrementAndCheck(t)))try{const c={additionalInformation:{message:n,version:this._integrationName},severity:t,code:r||x.UNKNOWN_ERROR,url:qe(),deviceInfo:$e(),stackTrace:s,reporter:this._reporter,integration:this._integrationName},u={Accept:"text/plain;charset=UTF-8","Content-Type":"application/json","rokt-launcher-version":this._integrationName,"rokt-wsdk-version":"joint"};this._launcherInstanceGuid&&(u["rokt-launcher-instance-guid"]=this._launcherInstanceGuid),this._accountId&&(u["rokt-account-id"]=this._accountId),fetch(e,{method:"POST",headers:u,body:JSON.stringify(c)}).then(l=>{if(!l.ok){const g=new Error("HTTP "+l.status+" from log endpoint");throw g.statusCode=l.status,g}}).catch(l=>{console.error("ReportingTransport: Failed to send log",l),o&&o(l)})}catch(c){console.error("ReportingTransport: Failed to send log",c),o&&o(c)}}}class ne{constructor(e,t,n,r,s){this._transport=new W(e,t,n,r,s),this._errorUrl=he(e?.errorUrl,e?.integrationDomain,We)}report(e){if(!e)return;const t=e.severity||S.ERROR;this._transport.send(this._errorUrl,t,e.message,e.code,e.stackTrace)}}class re{constructor(e,t,n,r,s,o){this._transport=new W(e,n,r,s,o),this._loggingUrl=he(e?.loggingUrl,e?.integrationDomain,xe),this._errorReportingService=t}log(e){e&&this._transport.send(this._loggingUrl,S.INFO,e.message,e.code,void 0,t=>{if(this._errorReportingService){const n=typeof t.statusCode=="number";this._errorReportingService.report({message:"LoggingService: Failed to send log: "+t.message,code:x.LOG_DELIVERY_FAILURE,severity:n?S.ERROR:S.WARNING})}})}}function Je(i){const e=Y(window.location.href),t=i.EventAttributes?.title||document.title,n=Re(),r=i.ActiveTimeOnSite;return{pageUrl:e,sourceMessageId:i.SourceMessageId,timestamp:i.Timestamp,...t?{pageTitle:t}:{},...n!==void 0?{canonicalUrl:n}:{},...Number.isFinite(r)?{activeTimeOnSite:r}:{}}}const m=class m{constructor(){this.name=d,this.id=L,this.moduleId=L,this.isInitialized=!1,this.launcher=null,this.filters={},this.userAttributes={},this.userIdentifiedInWorkspace=!1,this.testHelpers=null,this.placementEventMappingLookup={},this.placementEventAttributeMappingLookup={},this.integrationName=null,this.errorReportingService=null,this.loggingService=null,this._thankYouElementOnLoadCallback=null,this._isThankYouElementLoaded=!1,this._workspaceSearchInFlightPromise=null}getEventAttributeValue(e,t){const n=e&&e.EventAttributes;return!n||typeof n[t]>"u"?null:n[t]}doesEventAttributeConditionMatch(e,t){if(!e||!E(e.operator))return!1;const n=e.operator.toLowerCase(),r=e.attributeValue;return n==="exists"?t!==null:t==null?!1:n==="equals"?String(t)===String(r):n==="contains"?String(t).indexOf(String(r))!==-1:!1}doesEventMatchRule(e,t){if(!t||!E(t.eventAttributeKey))return!1;const n=t.conditions;if(!Array.isArray(n))return!1;const r=this.getEventAttributeValue(e,t.eventAttributeKey);if(n.length===0)return r!==null;for(let s=0;s{await Ve(n,o),this.initRoktLauncher(o)}).catch(o=>{console.error("Error creating Rokt launcher:",o)})}initRoktLauncher(e){window.Rokt&&(window.Rokt.currentLauncher=e),this.launcher=e;const t=a().Rokt?.filters;t?(this.filters=t,t.filteredUser?this._workspaceSearchInFlightPromise=this.search(t.filteredUser):console.warn("Rokt Kit: No filtered user has been set.")):console.warn("Rokt Kit: No filters have been set."),this.isInitialized=!0,ie(this.domain,this.integrationName),a().Rokt.attachKit(this)}fetchOptimizely(){const e=a()._getActiveForwarders().filter(t=>t.name==="Optimizely");try{if(e.length>0&&window.optimizely){const t=window.optimizely.get("state");return!t||!t.getActiveExperimentIds?{}:t.getActiveExperimentIds().reduce((s,o)=>(s["rokt.custom.optimizely.experiment."+o+".variationId"]=t.getVariationMap()[o].id,s),{})}}catch(t){console.error("Error fetching Optimizely attributes:",t)}return{}}isKitReady(){return!!(this.isInitialized&&this.launcher)}isTargetingDisabled(){return a().Rokt?.launcherOptions?.noTargeting===!0}isPartnerInLocalLauncherTestGroup(){return!!(a().config&&a().config.isLocalLauncherEnabled&&this.isAssignedToSampleGroup())}isAssignedToSampleGroup(){return Math.random()>.5}captureTiming(e){window&&a()&&a().captureTiming&&e&&a().captureTiming(e)}init(e,t,n,r,s){const o=e,c=o.accountId;this.userAttributes=b(s),this._onboardingExpProvider=o.onboardingExpProvider;const u=P(o.placementEventMapping);this.placementEventMappingLookup=Z(u);const l=P(o.placementEventAttributeMapping);this.placementEventAttributeMappingLookup=ee(l),o.hashedEmailUserIdentityType&&(this._mappedEmailSha256Key=o.hashedEmailUserIdentityType.toLowerCase()),this._workspaceIdSyncApiKey=E(o.workspaceIdSyncApiKey)?o.workspaceIdSyncApiKey:void 0;const g=a().Rokt?.domain,{roktExtensionsQueryParams:M,legacyRoktExtensions:R,loadThankYouElement:w}=X(o.roktExtensions),f={...a().Rokt?.launcherOptions||{}};this.integrationName=He(f.integrationName),f.integrationName=this.integrationName,this.domain=g;const A={loggingUrl:o.loggingUrl,errorUrl:o.errorUrl,integrationDomain:g,isLoggingEnabled:a().config?.isLoggingEnabled===!0},I=new ne(A,this.integrationName,window.__rokt_li_guid__,o.accountId),k=new re(A,I,this.integrationName,window.__rokt_li_guid__,o.accountId);if(this.errorReportingService=I,this.loggingService=k,this.isTargetingDisabled())try{q(),$()}catch(h){this.errorReportingService?.report({message:"Rokt Kit: Failed to clear page views when targeting is disabled",code:"PAGE_VIEW_CAPTURE_FAILED",severity:S.INFO,stackTrace:h instanceof Error?h.stack:void 0})}return a()._registerErrorReportingService&&a()._registerErrorReportingService(I),a()._registerLoggingService&&a()._registerLoggingService(k),n?(this.testHelpers={generateLauncherScript:J,generateThankYouElementScript:B,extractRoktExtensionConfig:X,hashEventMessage:te,parseSettingsString:P,generateMappedEventLookup:Z,generateMappedEventAttributeLookup:ee,sendAdBlockMeasurementSignals:ie,createAutoRemovedIframe:F,djb2:ge,setAllowedOriginHashes:h=>{m._allowedOriginHashes=h},ReportingTransport:W,ErrorReportingService:ne,LoggingService:re,RateLimiter:pe,ErrorCodes:x,WSDKErrorSeverity:S},this.attachLauncher(c,f),"Successfully initialized: "+d):(w&&(a().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this),Q(Oe,B(g),{onLoad:()=>{this._isThankYouElementLoaded=!0,this._thankYouElementOnLoadCallback&&this._thankYouElementOnLoadCallback()},onError:h=>{console.error("Error loading Rokt Thank You Element script:",h)}})),this.isLauncherReadyToAttach()?this.attachLauncher(c,f,R):(Q(Pe,J(g,M),{onLoad:()=>{this.isLauncherReadyToAttach()?this.attachLauncher(c,f,R):console.error("Rokt object is not available after script load.")},onError:h=>{console.error("Error loading Rokt launcher script:",h)}}),this.captureTiming(m.PERFORMANCE_MARKS.RoktScriptAppended)),"Successfully initialized: "+d)}process(e){if(this.isTargetingDisabled()||(e.EventDataType===Ue&&(ke(this.loggingService),this.capturePageView(e)),e.EventDataType===Ce&&(de(this.loggingService),q(),$())),!this.isKitReady())return"Kit not ready for forwarder: "+d;if(T(a().Rokt?.setLocalSessionAttribute)&&(K(this.placementEventAttributeMappingLookup)||this.applyPlacementEventAttributeMapping(e),!K(this.placementEventMappingLookup))){const t=te(e.EventDataType,e.EventCategory,e.EventName??"");this.placementEventMappingLookup[String(t)]&&a().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(t)],!0)}return"Successfully sent to forwarder: "+d}setExtensionData(e){if(!this.isKitReady()){console.error("Rokt Kit: Not initialized");return}window.Rokt.setExtensionData(e)}setUserAttribute(e,t){return se(e)||(this.userAttributes[e]=t),"Successfully set user attribute for forwarder: "+d}removeUserAttribute(e){return delete this.userAttributes[e],"Successfully removed user attribute for forwarder: "+d}handleIdentityComplete(e,t){return this.userAttributes=b(e.getAllUserAttributes()),"Successfully called "+t+" for forwarder: "+d}onUserIdentified(e){const t=e;return this.filters.filteredUser=t,this._workspaceSearchInFlightPromise=this.search(t),this.handleIdentityComplete(e,"onUserIdentified")}search(e){const t=this._workspaceIdSyncApiKey;if(!t)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const n=a().Identity?.search;if(typeof n!="function")return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const r=e.getUserIdentities?e.getUserIdentities().userIdentities:null,s={};if(r)for(const u of Object.keys(r)){const l=r[u];E(l)&&l.length>0&&(s[u]=l)}const o=Object.keys(s);if(o.length===0)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const c=o.sort().map(u=>`${u}=${s[u]}`).join("&");return c===this._workspaceLastSearchedIdentitiesKey?this._workspaceSearchInFlightPromise||Promise.resolve():(this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=c,new Promise(u=>{try{n(t,s,l=>{l?.httpCode===200&&(this.userIdentifiedInWorkspace=!0),u()})}catch(l){console.error("Rokt Kit: Workspace IDSync search failed",l),this._workspaceLastSearchedIdentitiesKey=void 0,u()}}))}onLoginComplete(e,t){return this.handleIdentityComplete(e,"onLoginComplete")}onLogoutComplete(e,t){return this.userIdentifiedInWorkspace=!1,this._workspaceSearchInFlightPromise=null,this._workspaceLastSearchedIdentitiesKey=void 0,this.handleIdentityComplete(e,"onLogoutComplete")}onModifyComplete(e,t){return this.handleIdentityComplete(e,"onModifyComplete")}selectPlacements(e){if(this._workspaceSearchInFlightPromise){const t=this._workspaceSearchInFlightPromise;return Promise.race([t,new Promise(n=>setTimeout(n,Ye))]).then(()=>this._dispatchPlacements(e))}return this._dispatchPlacements(e)}_dispatchPlacements(e){const t=e&&e.attributes||{},r={...b(this.userAttributes),...t},s=this.filters||{},o=s.userAttributeFilters||[],c=s.filteredUser||null,u=c?c.getMPID():null;let l;s?s.filterUserAttributes?l=s.filterUserAttributes(r,o):l=r:(console.warn("Rokt Kit: No filters available, using user attributes"),l=r),this.userAttributes=b(l);const g=this._onboardingExpProvider==="Optimizely"?this.fetchOptimizely():{},M=this.returnUserIdentities(c),R=this.returnLocalSessionAttributes(),w=Ae(z(this.loggingService)),f=ve(),A=this.readMpSessionId(),I=this.readMpDeviceId(),k={...M,...l,...g,...R,...w.length?{[Me]:JSON.stringify(w)}:{},...f?{[Ke]:f}:{},...this.userIdentifiedInWorkspace?{[Ne]:!0}:{},...A?{[De]:A}:{},...I?{[Fe]:I}:{},mpid:u},h={...e,attributes:k},j=this.launcher.selectPlacements(h),fe=()=>this.logSelectPlacementsEvent(k);return Promise.resolve(j).then(me=>me?.context?.sessionId?.then(Ee=>this.setRoktSessionId(Ee))).catch(()=>{}).finally(fe),j}hashAttributes(e){return this.isKitReady()?this.launcher.hashAttributes(e):(console.error("Rokt Kit: Not initialized"),null)}use(e){return this.isKitReady()?!e||!E(e)?Promise.reject(new Error("Rokt Kit: Invalid extension name")):this.launcher.use(e):(console.error("Rokt Kit: Not initialized"),Promise.reject(new Error("Rokt Kit: Not initialized")))}onShoppableAdsReady(e){this._isThankYouElementLoaded?e():this._thankYouElementOnLoadCallback=e}};m._allowedOriginHashes=[-553112570,549508659],m.PERFORMANCE_MARKS={RoktScriptAppended:"mp:RoktScriptAppended"},m.EMAIL_SHA256_KEY="emailsha256";let y=m;function Be(){return L}function Qe(i){if(!i){window.console.log("You must pass a config object to register the kit "+d);return}if(!_(i)){window.console.log("'config' must be an object. You passed in a "+typeof i);return}_(i.kits)?i.kits[d]={constructor:y}:(i.kits={},i.kits[d]={constructor:y}),window.console.log("Successfully registered "+d+" to your mParticle configuration")}typeof window<"u"&&window.mParticle&&a().addForwarder&&a().addForwarder({name:d,constructor:y,getId:Be});exports.register=Qe; +"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _e=["active_time_on_site_ms","billingaddress1","billingaddress2","billingcity","billingstate","billingzipcode","cartitems","ccbin","confirmationref","conversiontype","country","couponcode","currency","language","paymentserviceprovider","paymentserviceproviderattribute","paymenttype","shippingaddress1","shippingcity","shippingcountry","shippingmethod","shippingstate","shippingzipcode","totalprice"],Ie=new Set(_e);function se(i){return Ie.has(i.toLowerCase())}function b(i){const e={},t=i||{},n=Object.keys(t);for(let r=0;r{const r=t.activeTimeOnSite,s=r!==void 0&&Number.isFinite(r),c=e[n+1]?.activeTimeOnSite,u=c!==void 0&&Number.isFinite(c),l=s&&u?c-r:void 0;return{pageUrl:t.pageUrl,sourceMessageId:t.sourceMessageId,timestamp:t.timestamp,...t.pageTitle!==void 0?{pageTitle:t.pageTitle}:{},...t.canonicalUrl!==void 0?{canonicalUrl:t.canonicalUrl}:{},...s?{activeTimeOnSite:r}:{},...l!==void 0&&l>=0?{activeTimeOnPage:l}:{}}})}function ke(i){if(U(p,O)!==void 0)return;const e=new URLSearchParams(window.location.search),t={};for(const r of Se){const s=e.get(r);s&&(t[r]=s)}if(Object.keys(t).length===0)return;const n=Object.keys(t).join(", ");if(!G(p,O,t)){const r=D()?"quota":"ls_unavailable";i?.log({message:`Rokt Kit: Failed to persist UTM params [reason: ${r}]`,code:"UTM_CAPTURE_FAILED"});return}i?.log({message:`Rokt Kit: Captured UTM params [${n}]`,code:"UTM_CAPTURE_SUCCESS"})}function ve(){const i=U(p,O);return _(i)?i:null}function $(){ce(p,O)}function Re(){const e=document.querySelector('link[rel="canonical"]')?.href;if(e)return Y(e)}const d="Rokt",L=181,we="selectPlacements",be="apps.roktecommerce.com",Te=.1,Le="ThankYouPageJourney",Pe="rokt-launcher",Oe="rokt-thank-you-element",Ne="userIdentifiedInWorkspace",Ue=3,Ce=2,Me="page_events",Ke="page_view_attributes",De="mparticle_session_id",Fe="mparticle_device_id",Ye=500,x={UNKNOWN_ERROR:"UNKNOWN_ERROR",UNHANDLED_EXCEPTION:"UNHANDLED_EXCEPTION",IDENTITY_REQUEST:"IDENTITY_REQUEST",LOG_DELIVERY_FAILURE:"LOG_DELIVERY_FAILURE"},S={ERROR:"ERROR",INFO:"INFO",WARNING:"WARNING"},Ge="apps.rokt-api.com",xe="/v1/log",We="/v1/errors",je=10;function a(){return window.mParticle}function J(i,e){const n=[C(i),"/wsdk/integrations/launcher.js"].join("");return!e||e.length===0?n:n+"?extensions="+e.join(",")}function B(i){return[C(i),"/rokt-elements/rokt-element-thank-you.js"].join("")}function C(i){const e=typeof i<"u"?i:Ge;return e.includes("://")?e.replace(/\/+$/,""):["https://",e].join("")}function he(i,e,t){if(i)return i.startsWith("http://")||i.startsWith("https://")?i:"https://"+i;const r=e?.includes("://")&&!/^https?:\/\//i.test(e)?void 0:e;return C(r)+t}function Q(i,e,t){if(document.getElementById(i))return;const n=document.head||document.body,r=document.createElement("script");r.id=i,r.type="text/javascript",r.src=e,r.async=!0,r.crossOrigin="anonymous",r.fetchPriority="high",t?.onLoad&&(r.onload=t.onLoad),t?.onError&&(r.onerror=t.onError),n.appendChild(r)}function P(i){if(!i)return[];try{return JSON.parse(i.replace(/"/g,'"'))}catch{console.error("Settings string contains invalid JSON")}return[]}function X(i){const e=i?P(i):[],t=[],n=[];let r=!1;for(let s=0;s=Te)return;const r=window.__rokt_li_guid__;if(!r||i&&i.includes("://")&&!/^https:\/\//i.test(i))return;const s=window.location.href.split("?")[0].split("#")[0],o="version="+encodeURIComponent(e??"")+"&launcherInstanceGuid="+encodeURIComponent(r)+"&pageUrl="+encodeURIComponent(s),c=i?C(i):"https://apps.rokt.com";F(c+"/v1/wsdk-init/index.html?"+o),F("https://"+be+"/v1/wsdk-init/index.html?"+o+"&isControl=true")}function ze(){return typeof window<"u"&&!!window.location?.search?.toLowerCase().includes("mp_enable_logging=true")}function qe(){return typeof window<"u"?window.location?.href:void 0}function $e(){return typeof window<"u"?window.navigator?.userAgent:void 0}class pe{constructor(){this._logCount={}}incrementAndCheck(e){const n=(this._logCount[e]||0)+1;return this._logCount[e]=n,n>je}}class W{constructor(e,t,n,r,s){this._reporter="mp-wsdk";const o=e.isLoggingEnabled;this._integrationName=t||"",this._launcherInstanceGuid=n,this._accountId=r||null,this._rateLimiter=s||new pe,this._isEnabled=ze()||o}send(e,t,n,r,s,o){if(!(!this._isEnabled||this._rateLimiter.incrementAndCheck(t)))try{const c={additionalInformation:{message:n,version:this._integrationName},severity:t,code:r||x.UNKNOWN_ERROR,url:qe(),deviceInfo:$e(),stackTrace:s,reporter:this._reporter,integration:this._integrationName},u={Accept:"text/plain;charset=UTF-8","Content-Type":"application/json","rokt-launcher-version":this._integrationName,"rokt-wsdk-version":"joint"};this._launcherInstanceGuid&&(u["rokt-launcher-instance-guid"]=this._launcherInstanceGuid),this._accountId&&(u["rokt-account-id"]=this._accountId),fetch(e,{method:"POST",headers:u,body:JSON.stringify(c)}).then(l=>{if(!l.ok){const g=new Error("HTTP "+l.status+" from log endpoint");throw g.statusCode=l.status,g}}).catch(l=>{console.error("ReportingTransport: Failed to send log",l),o&&o(l)})}catch(c){console.error("ReportingTransport: Failed to send log",c),o&&o(c)}}}class ne{constructor(e,t,n,r,s){this._transport=new W(e,t,n,r,s),this._errorUrl=he(e?.errorUrl,e?.integrationDomain,We)}report(e){if(!e)return;const t=e.severity||S.ERROR;this._transport.send(this._errorUrl,t,e.message,e.code,e.stackTrace)}}class re{constructor(e,t,n,r,s,o){this._transport=new W(e,n,r,s,o),this._loggingUrl=he(e?.loggingUrl,e?.integrationDomain,xe),this._errorReportingService=t}log(e){e&&this._transport.send(this._loggingUrl,S.INFO,e.message,e.code,void 0,t=>{if(this._errorReportingService){const n=typeof t.statusCode=="number";this._errorReportingService.report({message:"LoggingService: Failed to send log: "+t.message,code:x.LOG_DELIVERY_FAILURE,severity:n?S.ERROR:S.WARNING})}})}}function Je(i){const e=Y(window.location.href),t=i.EventAttributes?.title||document.title,n=Re(),r=i.ActiveTimeOnSite;return{pageUrl:e,sourceMessageId:i.SourceMessageId,timestamp:i.Timestamp,...t?{pageTitle:t}:{},...n!==void 0?{canonicalUrl:n}:{},...Number.isFinite(r)?{activeTimeOnSite:r}:{}}}const m=class m{constructor(){this.name=d,this.id=L,this.moduleId=L,this.isInitialized=!1,this.launcher=null,this.filters={},this.userAttributes={},this.userIdentifiedInWorkspace=!1,this.testHelpers=null,this.placementEventMappingLookup={},this.placementEventAttributeMappingLookup={},this.integrationName=null,this.errorReportingService=null,this.loggingService=null,this._thankYouElementOnLoadCallback=null,this._isThankYouElementLoaded=!1,this._workspaceSearchInFlightPromise=null}getEventAttributeValue(e,t){const n=e&&e.EventAttributes;return!n||typeof n[t]>"u"?null:n[t]}doesEventAttributeConditionMatch(e,t){if(!e||!E(e.operator))return!1;const n=e.operator.toLowerCase(),r=e.attributeValue;return n==="exists"?t!==null:t==null?!1:n==="equals"?String(t)===String(r):n==="contains"?String(t).indexOf(String(r))!==-1:!1}doesEventMatchRule(e,t){if(!t||!E(t.eventAttributeKey))return!1;const n=t.conditions;if(!Array.isArray(n))return!1;const r=this.getEventAttributeValue(e,t.eventAttributeKey);if(n.length===0)return r!==null;for(let s=0;s{await Ve(n,o),this.initRoktLauncher(o)}).catch(o=>{console.error("Error creating Rokt launcher:",o)})}initRoktLauncher(e){window.Rokt&&(window.Rokt.currentLauncher=e),this.launcher=e;const t=a().Rokt?.filters;t?(this.filters=t,t.filteredUser?this._workspaceSearchInFlightPromise=this.search(t.filteredUser):console.warn("Rokt Kit: No filtered user has been set.")):console.warn("Rokt Kit: No filters have been set."),this.isInitialized=!0,ie(this.domain,this.integrationName),a().Rokt.attachKit(this)}fetchOptimizely(){const e=a()._getActiveForwarders().filter(t=>t.name==="Optimizely");try{if(e.length>0&&window.optimizely){const t=window.optimizely.get("state");return!t||!t.getActiveExperimentIds?{}:t.getActiveExperimentIds().reduce((s,o)=>(s["rokt.custom.optimizely.experiment."+o+".variationId"]=t.getVariationMap()[o].id,s),{})}}catch(t){console.error("Error fetching Optimizely attributes:",t)}return{}}isKitReady(){return!!(this.isInitialized&&this.launcher)}isTargetingDisabled(){return a().Rokt?.launcherOptions?.noTargeting===!0}isPartnerInLocalLauncherTestGroup(){return!!(a().config&&a().config.isLocalLauncherEnabled&&this.isAssignedToSampleGroup())}isAssignedToSampleGroup(){return Math.random()>.5}captureTiming(e){window&&a()&&a().captureTiming&&e&&a().captureTiming(e)}init(e,t,n,r,s){const o=e,c=o.accountId;this.userAttributes=b(s),this._onboardingExpProvider=o.onboardingExpProvider;const u=P(o.placementEventMapping);this.placementEventMappingLookup=Z(u);const l=P(o.placementEventAttributeMapping);this.placementEventAttributeMappingLookup=ee(l),o.hashedEmailUserIdentityType&&(this._mappedEmailSha256Key=o.hashedEmailUserIdentityType.toLowerCase()),this._workspaceIdSyncApiKey=E(o.workspaceIdSyncApiKey)?o.workspaceIdSyncApiKey:void 0;const g=a().Rokt?.domain,{roktExtensionsQueryParams:M,legacyRoktExtensions:R,loadThankYouElement:w}=X(o.roktExtensions),f={...a().Rokt?.launcherOptions||{}};this.integrationName=He(f.integrationName),f.integrationName=this.integrationName,this.domain=g;const A={loggingUrl:o.loggingUrl,errorUrl:o.errorUrl,integrationDomain:g,isLoggingEnabled:a().config?.isLoggingEnabled===!0},I=new ne(A,this.integrationName,window.__rokt_li_guid__,o.accountId),k=new re(A,I,this.integrationName,window.__rokt_li_guid__,o.accountId);if(this.errorReportingService=I,this.loggingService=k,this.isTargetingDisabled())try{q(),$()}catch(h){this.errorReportingService?.report({message:"Rokt Kit: Failed to clear page views when targeting is disabled",code:"PAGE_VIEW_CAPTURE_FAILED",severity:S.INFO,stackTrace:h instanceof Error?h.stack:void 0})}return a()._registerErrorReportingService&&a()._registerErrorReportingService(I),a()._registerLoggingService&&a()._registerLoggingService(k),n?(this.testHelpers={generateLauncherScript:J,generateThankYouElementScript:B,extractRoktExtensionConfig:X,hashEventMessage:te,parseSettingsString:P,generateMappedEventLookup:Z,generateMappedEventAttributeLookup:ee,sendAdBlockMeasurementSignals:ie,createAutoRemovedIframe:F,djb2:ge,setAllowedOriginHashes:h=>{m._allowedOriginHashes=h},ReportingTransport:W,ErrorReportingService:ne,LoggingService:re,RateLimiter:pe,ErrorCodes:x,WSDKErrorSeverity:S},this.attachLauncher(c,f),"Successfully initialized: "+d):(w&&(a().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this),Q(Oe,B(g),{onLoad:()=>{this._isThankYouElementLoaded=!0,this._thankYouElementOnLoadCallback&&this._thankYouElementOnLoadCallback()},onError:h=>{console.error("Error loading Rokt Thank You Element script:",h)}})),this.isLauncherReadyToAttach()?this.attachLauncher(c,f,R):(Q(Pe,J(g,M),{onLoad:()=>{this.isLauncherReadyToAttach()?this.attachLauncher(c,f,R):console.error("Rokt object is not available after script load.")},onError:h=>{console.error("Error loading Rokt launcher script:",h)}}),this.captureTiming(m.PERFORMANCE_MARKS.RoktScriptAppended)),"Successfully initialized: "+d)}process(e){if(this.isTargetingDisabled()||(e.EventDataType===Ue&&(ke(this.loggingService),this.capturePageView(e)),e.EventDataType===Ce&&(de(this.loggingService),q(),$())),!this.isKitReady())return"Kit not ready for forwarder: "+d;if(T(a().Rokt?.setLocalSessionAttribute)&&(K(this.placementEventAttributeMappingLookup)||this.applyPlacementEventAttributeMapping(e),!K(this.placementEventMappingLookup))){const t=te(e.EventDataType,e.EventCategory,e.EventName??"");this.placementEventMappingLookup[String(t)]&&a().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(t)],!0)}return"Successfully sent to forwarder: "+d}setExtensionData(e){if(!this.isKitReady()){console.error("Rokt Kit: Not initialized");return}window.Rokt.setExtensionData(e)}setUserAttribute(e,t){return se(e)||(this.userAttributes[e]=t),"Successfully set user attribute for forwarder: "+d}removeUserAttribute(e){return delete this.userAttributes[e],"Successfully removed user attribute for forwarder: "+d}handleIdentityComplete(e,t){return this.userAttributes=b(e.getAllUserAttributes()),"Successfully called "+t+" for forwarder: "+d}onUserIdentified(e){const t=e;return this.filters.filteredUser=t,this._workspaceSearchInFlightPromise=this.search(t),this.handleIdentityComplete(e,"onUserIdentified")}search(e){const t=this._workspaceIdSyncApiKey;if(!t)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const n=a().Identity?.search;if(typeof n!="function")return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const r=e.getUserIdentities?e.getUserIdentities().userIdentities:null,s={};if(r)for(const u of Object.keys(r)){const l=r[u];E(l)&&l.length>0&&(s[u]=l)}const o=Object.keys(s);if(o.length===0)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const c=o.sort().map(u=>`${u}=${s[u]}`).join("&");return c===this._workspaceLastSearchedIdentitiesKey?this._workspaceSearchInFlightPromise||Promise.resolve():(this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=c,new Promise(u=>{try{n(t,s,l=>{l?.httpCode===200&&(this.userIdentifiedInWorkspace=!0),u()})}catch(l){console.error("Rokt Kit: Workspace IDSync search failed",l),this._workspaceLastSearchedIdentitiesKey=void 0,u()}}))}onLoginComplete(e,t){return this.handleIdentityComplete(e,"onLoginComplete")}onLogoutComplete(e,t){return this.userIdentifiedInWorkspace=!1,this._workspaceSearchInFlightPromise=null,this._workspaceLastSearchedIdentitiesKey=void 0,this.handleIdentityComplete(e,"onLogoutComplete")}onModifyComplete(e,t){return this.handleIdentityComplete(e,"onModifyComplete")}selectPlacements(e){if(this._workspaceSearchInFlightPromise){const t=this._workspaceSearchInFlightPromise;return Promise.race([t,new Promise(n=>setTimeout(n,Ye))]).then(()=>this._dispatchPlacements(e))}return this._dispatchPlacements(e)}_dispatchPlacements(e){const t=e&&e.attributes||{},r={...b(this.userAttributes),...t},s=this.filters||{},o=s.userAttributeFilters||[],c=s.filteredUser||null,u=c?c.getMPID():null;let l;s?s.filterUserAttributes?l=s.filterUserAttributes(r,o):l=r:(console.warn("Rokt Kit: No filters available, using user attributes"),l=r),this.userAttributes=b(l);const g=this._onboardingExpProvider==="Optimizely"?this.fetchOptimizely():{},M=this.returnUserIdentities(c),R=this.returnLocalSessionAttributes(),w=Ae(z(this.loggingService)),f=ve(),A=this.readMpSessionId(),I=this.readMpDeviceId(),k={...M,...l,...g,...R,...w.length?{[Me]:JSON.stringify(w)}:{},...f?{[Ke]:JSON.stringify(f)}:{},...this.userIdentifiedInWorkspace?{[Ne]:!0}:{},...A?{[De]:A}:{},...I?{[Fe]:I}:{},mpid:u},h={...e,attributes:k},j=this.launcher.selectPlacements(h),fe=()=>this.logSelectPlacementsEvent(k);return Promise.resolve(j).then(me=>me?.context?.sessionId?.then(Ee=>this.setRoktSessionId(Ee))).catch(()=>{}).finally(fe),j}hashAttributes(e){return this.isKitReady()?this.launcher.hashAttributes(e):(console.error("Rokt Kit: Not initialized"),null)}use(e){return this.isKitReady()?!e||!E(e)?Promise.reject(new Error("Rokt Kit: Invalid extension name")):this.launcher.use(e):(console.error("Rokt Kit: Not initialized"),Promise.reject(new Error("Rokt Kit: Not initialized")))}onShoppableAdsReady(e){this._isThankYouElementLoaded?e():this._thankYouElementOnLoadCallback=e}};m._allowedOriginHashes=[-553112570,549508659],m.PERFORMANCE_MARKS={RoktScriptAppended:"mp:RoktScriptAppended"},m.EMAIL_SHA256_KEY="emailsha256";let y=m;function Be(){return L}function Qe(i){if(!i){window.console.log("You must pass a config object to register the kit "+d);return}if(!_(i)){window.console.log("'config' must be an object. You passed in a "+typeof i);return}_(i.kits)?i.kits[d]={constructor:y}:(i.kits={},i.kits[d]={constructor:y}),window.console.log("Successfully registered "+d+" to your mParticle configuration")}typeof window<"u"&&window.mParticle&&a().addForwarder&&a().addForwarder({name:d,constructor:y,getId:Be});exports.register=Qe; //# sourceMappingURL=Rokt-Kit.common.js.map diff --git a/kits/rokt/dist/Rokt-Kit.common.js.map b/kits/rokt/dist/Rokt-Kit.common.js.map index 3312d861d..f1063cace 100644 --- a/kits/rokt/dist/Rokt-Kit.common.js.map +++ b/kits/rokt/dist/Rokt-Kit.common.js.map @@ -1 +1 @@ -{"version":3,"file":"Rokt-Kit.common.js","sources":["../src/selectPlacementsAttributePersistence.ts","../src/utils.ts","../src/storage.ts","../src/pageViewStorage.ts","../src/Rokt-Kit.ts"],"sourcesContent":["const SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST = [\n 'active_time_on_site_ms',\n 'billingaddress1',\n 'billingaddress2',\n 'billingcity',\n 'billingstate',\n 'billingzipcode',\n 'cartitems',\n 'ccbin',\n 'confirmationref',\n 'conversiontype',\n 'country',\n 'couponcode',\n 'currency',\n 'language',\n 'paymentserviceprovider',\n 'paymentserviceproviderattribute',\n 'paymenttype',\n 'shippingaddress1',\n 'shippingcity',\n 'shippingcountry',\n 'shippingmethod',\n 'shippingstate',\n 'shippingzipcode',\n 'totalprice',\n];\nconst SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET = new Set(SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST);\n\nexport function isSelectPlacementsAttributePersistenceDenied(key: string): boolean {\n return SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET.has(key.toLowerCase());\n}\n\nexport function removeSelectPlacementsAttributePersistenceDeniedAttributes(\n attributes: Record | null | undefined,\n): Record {\n const filteredAttributes: Record = {};\n const sourceAttributes = attributes || {};\n const attributeKeys = Object.keys(sourceAttributes);\n\n for (let i = 0; i < attributeKeys.length; i++) {\n const key = attributeKeys[i];\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n filteredAttributes[key] = sourceAttributes[key];\n }\n }\n\n return filteredAttributes;\n}\n","export function isObject(value: unknown): value is Record {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nexport function isFunction(value: unknown): value is (...args: Array) => unknown {\n return typeof value === 'function';\n}\n\nexport function isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'object') {\n return Object.keys(value as object).length === 0;\n }\n return false;\n}\n\n// Strips the query string from a URL before it is persisted and sent to Rokt,\n// since query params commonly carry PII (emails, tokens, order refs).\n// Returns the input unchanged if it can't be parsed as a URL.\nexport function sanitizeUrl(href: string): string {\n try {\n const url = new URL(href);\n url.search = '';\n return url.toString();\n } catch {\n return href;\n }\n}\n","import { isObject } from './utils';\n\nconst LS_PROBE_KEY = '__rokt_ls_probe__';\n\nexport function isLocalStorageAvailable(): boolean {\n try {\n window.localStorage.setItem(LS_PROBE_KEY, '1');\n window.localStorage.removeItem(LS_PROBE_KEY);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function readJSON(key: string): unknown {\n try {\n const stored = window.localStorage.getItem(key);\n return stored === null ? null : JSON.parse(stored);\n } catch {\n return null;\n }\n}\n\nexport function writeJSON(key: string, value: unknown): boolean {\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n return true;\n } catch {\n return false;\n }\n}\n\nexport function removeKey(key: string): void {\n try {\n window.localStorage.removeItem(key);\n } catch {\n /* empty */\n }\n}\n\nexport function readNamespacedField(namespaceKey: string, field: string): unknown {\n const blob = readJSON(namespaceKey);\n return isObject(blob) ? blob[field] : undefined;\n}\n\nexport function writeNamespacedField(namespaceKey: string, field: string, value: unknown): boolean {\n const blob = readJSON(namespaceKey);\n const next = isObject(blob) ? { ...blob } : {};\n next[field] = value;\n return writeJSON(namespaceKey, next);\n}\n\nexport function removeNamespacedField(namespaceKey: string, field: string): void {\n const blob = readJSON(namespaceKey);\n if (!isObject(blob) || !(field in blob)) {\n return;\n }\n const next = { ...blob };\n delete next[field];\n if (Object.keys(next).length === 0) {\n removeKey(namespaceKey);\n } else {\n writeJSON(namespaceKey, next);\n }\n}\n","import type { LoggingService } from './Rokt-Kit';\nimport {\n readJSON,\n removeKey,\n readNamespacedField,\n writeNamespacedField,\n removeNamespacedField,\n isLocalStorageAvailable,\n} from './storage';\nimport { sanitizeUrl, isObject } from './utils';\n\nconst LS_NAMESPACE_KEY = 'mp-rokt-kit';\nconst LS_PAGE_VIEWS_FIELD = 'pageViews';\nconst LS_UTM_PARAMS_FIELD = 'utmParams';\nconst LEGACY_PAGE_VIEWS_KEY = 'mpPageViews';\nexport const PAGE_VIEWS_MAX_COUNT = 25;\n\nconst UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'] as const;\ntype UtmKey = (typeof UTM_KEYS)[number];\nexport type UtmParams = Partial>;\n\nexport interface PageEvent {\n pageUrl: string;\n sourceMessageId: string;\n timestamp: number;\n pageTitle?: string;\n canonicalUrl?: string;\n activeTimeOnSite?: number;\n activeTimeOnPage?: number;\n}\n\nfunction capPageViews(views: PageEvent[]): PageEvent[] {\n return views.slice(-PAGE_VIEWS_MAX_COUNT);\n}\n\nexport function migrateLegacyPageViewStorage(loggingService: LoggingService | null): void {\n const legacyViews = readJSON(LEGACY_PAGE_VIEWS_KEY);\n if (legacyViews === null) {\n return;\n }\n\n const alreadyMigrated = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD) !== undefined;\n const needsMigration = !alreadyMigrated && Array.isArray(legacyViews);\n\n if (needsMigration) {\n loggingService?.log({\n message: 'Rokt Kit: Migrating legacy page-view storage',\n code: 'PAGE_VIEW_LEGACY_MIGRATION',\n });\n const migrated = writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, legacyViews);\n if (!migrated) {\n loggingService?.log({\n message: 'Rokt Kit: Failed to migrate legacy page-view storage [reason: migration_retry]',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n removeKey(LEGACY_PAGE_VIEWS_KEY);\n}\n\nexport function loadPageViews(loggingService: LoggingService | null): PageEvent[] {\n migrateLegacyPageViewStorage(loggingService);\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n return Array.isArray(stored) ? (stored as PageEvent[]) : [];\n}\n\nexport function writePageViews(pageViews: PageEvent[]): number {\n const views = capPageViews(pageViews);\n for (let i = 0; i < views.length; i++) {\n const toWrite = views.slice(i);\n if (writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, toWrite)) {\n return toWrite.length;\n }\n }\n return 0;\n}\n\nexport function clearPageViews(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n}\n\nexport function buildPageEvents(pageViews: PageEvent[]): PageEvent[] {\n const views = capPageViews(pageViews);\n return views.map((pageView, index) => {\n const activeTimeOnSite = pageView.activeTimeOnSite;\n const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite);\n\n const next = views[index + 1];\n const nextActiveTimeOnSite = next?.activeTimeOnSite;\n const hasNextActiveTimeOnSite = nextActiveTimeOnSite !== undefined && Number.isFinite(nextActiveTimeOnSite);\n\n const diff = hasActiveTime && hasNextActiveTimeOnSite ? nextActiveTimeOnSite - activeTimeOnSite : undefined;\n\n return {\n pageUrl: pageView.pageUrl,\n sourceMessageId: pageView.sourceMessageId,\n timestamp: pageView.timestamp,\n ...(pageView.pageTitle !== undefined ? { pageTitle: pageView.pageTitle } : {}),\n ...(pageView.canonicalUrl !== undefined ? { canonicalUrl: pageView.canonicalUrl } : {}),\n ...(hasActiveTime ? { activeTimeOnSite } : {}),\n ...(diff !== undefined && diff >= 0 ? { activeTimeOnPage: diff } : {}),\n };\n });\n}\n\nexport function captureUtmParams(loggingService: LoggingService | null): void {\n if (readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD) !== undefined) {\n return;\n }\n const search = new URLSearchParams(window.location.search);\n const params: UtmParams = {};\n for (const key of UTM_KEYS) {\n const value = search.get(key);\n if (value) params[key] = value;\n }\n if (Object.keys(params).length === 0) {\n return;\n }\n const captured = Object.keys(params).join(', ');\n if (!writeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD, params)) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n loggingService?.log({\n message: `Rokt Kit: Failed to persist UTM params [reason: ${reason}]`,\n code: 'UTM_CAPTURE_FAILED',\n });\n return;\n }\n loggingService?.log({\n message: `Rokt Kit: Captured UTM params [${captured}]`,\n code: 'UTM_CAPTURE_SUCCESS',\n });\n}\n\nexport function loadUtmParams(): UtmParams | null {\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n return isObject(stored) ? (stored as UtmParams) : null;\n}\n\nexport function clearUtmParams(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n}\n\nexport function readCanonicalUrl(): string | undefined {\n const link = document.querySelector('link[rel=\"canonical\"]');\n const href = link?.href;\n if (!href) {\n return undefined;\n }\n return sanitizeUrl(href);\n}\n","// Copyright 2025 mParticle, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// ============================================================\n// Types\n// ============================================================\n\nimport { KitInterface, IMParticleUser, SDKEvent } from '@mparticle/web-sdk/internal';\nimport type { IUserIdentities } from '@mparticle/web-sdk';\n\nimport {\n isSelectPlacementsAttributePersistenceDenied,\n removeSelectPlacementsAttributePersistenceDeniedAttributes,\n} from './selectPlacementsAttributePersistence';\n\nimport {\n PageEvent,\n PAGE_VIEWS_MAX_COUNT,\n buildPageEvents,\n migrateLegacyPageViewStorage,\n loadPageViews,\n writePageViews,\n clearPageViews,\n readCanonicalUrl,\n captureUtmParams,\n loadUtmParams,\n clearUtmParams,\n} from './pageViewStorage';\nimport { isLocalStorageAvailable } from './storage';\n\nimport { isObject, isString, isEmpty, isFunction, sanitizeUrl } from './utils';\n\ninterface RoktKitSettings {\n accountId: string;\n roktExtensions?: string;\n placementEventMapping?: string;\n placementEventAttributeMapping?: string;\n hashedEmailUserIdentityType?: string;\n onboardingExpProvider?: string;\n loggingUrl?: string;\n errorUrl?: string;\n workspaceIdSyncApiKey?: string;\n}\n\ninterface EventAttributeCondition {\n operator: string;\n attributeValue: string;\n}\n\ninterface PlacementEventRule {\n eventAttributeKey: string;\n conditions: EventAttributeCondition[];\n}\n\ninterface EventAttributeMapping {\n value: string;\n map: string;\n conditions?: EventAttributeCondition[];\n}\n\ninterface PlacementEventMappingEntry {\n jsmap: string;\n value: string;\n}\n\ninterface RoktExtensionEntry {\n value: string;\n}\n\ninterface RoktSelection {\n context?: {\n sessionId?: Promise;\n };\n then?: (callback: (sel: RoktSelection) => void) => Promise;\n catch?: (callback: () => void) => void;\n}\n\ninterface RoktLauncher {\n selectPlacements(options: Record): RoktSelection | Promise;\n hashAttributes(attributes: Record): Promise>;\n use(extensionName: string): Promise;\n}\n\ninterface RoktGlobal {\n createLauncher(options: Record): Promise;\n createLocalLauncher(options: Record): RoktLauncher;\n currentLauncher?: RoktLauncher;\n setExtensionData(data: Record): void;\n}\n\n// FilteredUser is the IMParticleUser shape we receive after kit filtering.\n// `getMPID` and `getUserIdentities` are inherited from the SDK's `User` base type.\ntype FilteredUser = IMParticleUser;\n\n// TODO: Replace with `IIdentitySearchResult` from `@mparticle/web-sdk` once\n// a version that exports it is published (currently on a feature branch in\n// mParticle/mparticle-web-sdk PR #1255). The shape below is intentionally\n// structurally identical so the swap is a one-line import change.\ninterface WorkspaceIdSyncResult {\n httpCode: number;\n body?: {\n context?: string | null;\n mpid?: string;\n matched_identities?: Record;\n is_ephemeral?: boolean;\n is_logged_in?: boolean;\n };\n}\n\n// TODO: Replace with `IdentitySearchCallback`-compatible reference from\n// `@mparticle/web-sdk` once published (mirrors `SDKIdentityApi.search`).\ntype WorkspaceIdSyncSearcher = (\n apiKey: string,\n knownIdentities: IUserIdentities,\n callback: (result: WorkspaceIdSyncResult) => void,\n) => void;\n\ninterface KitFilters {\n userAttributeFilters?: string[];\n filterUserAttributes?: (attributes: Record, filters?: string[]) => Record;\n filteredUser?: FilteredUser | null;\n}\n\ninterface RoktManager {\n attachKit(kit: RoktKit): void | Promise;\n flushOnShoppableAdsReadyMessageQueue?(kit: RoktKit): void;\n filters?: KitFilters;\n domain?: string;\n launcherOptions?: Record;\n getLocalSessionAttributes?(): Record;\n setLocalSessionAttribute?(key: string, value: unknown): void;\n}\n\ninterface MParticleInstance {\n setIntegrationAttribute(moduleId: number, attrs: Record): void;\n}\n\ninterface OptimizelyState {\n getActiveExperimentIds(): string[];\n getVariationMap(): Record;\n}\n\ninterface OptimizelyGlobal {\n get(key: 'state'): OptimizelyState;\n}\n\n// Our view of the mParticle global with Rokt-specific extensions.\n// We access window.mParticle via an explicit cast (see `mp()` helper below)\n// rather than augmenting Window to avoid conflicts with @mparticle/web-sdk declarations.\ninterface MParticleExtended {\n Rokt: RoktManager;\n addForwarder(config: ForwarderRegistration): void;\n getVersion(): string;\n generateHash(value: string): string | number;\n logEvent(name: string, type: number, attrs?: Record): void;\n EventType: { Other: number };\n getInstance(): MParticleInstance;\n getDeviceId?(): string;\n sessionManager?: { getSession?(): string; getSessionId?(): string };\n _getActiveForwarders(): Array<{ name: string }>;\n config?: { isLocalLauncherEnabled?: boolean; isLoggingEnabled?: boolean };\n captureTiming?(metricName: string): void;\n forwarder?: RoktKit;\n loggedEvents?: Array>;\n _registerErrorReportingService?(service: ErrorReportingService): void;\n _registerLoggingService?(service: LoggingService): void;\n Identity?: { search?: WorkspaceIdSyncSearcher };\n}\n\ninterface TestHelpers {\n generateLauncherScript: (domain: string | undefined, extensions: string[]) => string;\n generateThankYouElementScript: (domain: string | undefined) => string;\n extractRoktExtensionConfig: (settingsString?: string) => RoktExtensionConfig;\n hashEventMessage: (messageType: number, eventType: number, eventName: string) => string | number;\n parseSettingsString: (settingsString?: string) => T[];\n generateMappedEventLookup: (placementEventMapping: PlacementEventMappingEntry[]) => Record;\n generateMappedEventAttributeLookup: (mapping: EventAttributeMapping[]) => Record;\n sendAdBlockMeasurementSignals: (domain: string | undefined, version: string | null) => void;\n createAutoRemovedIframe: (src: string) => void;\n djb2: (str: string) => number;\n setAllowedOriginHashes: (hashes: number[]) => void;\n ReportingTransport: typeof ReportingTransport;\n ErrorReportingService: typeof ErrorReportingService;\n LoggingService: typeof LoggingService;\n RateLimiter: typeof RateLimiter;\n ErrorCodes: typeof ErrorCodes;\n WSDKErrorSeverity: typeof WSDKErrorSeverity;\n}\n\ninterface ForwarderRegistration {\n name: string;\n constructor: new () => RoktKit;\n getId: () => number;\n}\n\ninterface ReportingConfig {\n loggingUrl?: string;\n errorUrl?: string;\n integrationDomain?: string;\n isLoggingEnabled: boolean;\n}\n\ninterface ErrorReport {\n message: string;\n code?: string;\n severity?: string;\n stackTrace?: string;\n}\n\n// A log-delivery failure. statusCode is set when the request reached the server\n// and returned a non-2xx status (server-side); it is absent for network-level\n// failures such as ad-blockers, offline, or CORS rejections (client-side).\ninterface DeliveryError extends Error {\n statusCode?: number;\n}\n\ninterface LogEntry {\n message: string;\n code?: string;\n}\n\ninterface RoktExtensionConfig {\n roktExtensionsQueryParams: string[];\n legacyRoktExtensions: string[];\n loadThankYouElement: boolean;\n}\n\ndeclare global {\n interface Window {\n Rokt?: RoktGlobal;\n __rokt_li_guid__?: string;\n optimizely?: OptimizelyGlobal;\n // mParticle is declared as any to avoid conflicts with @mparticle/web-sdk type declarations.\n // We use the typed mp() accessor for all internal accesses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mParticle: any;\n }\n}\n\n// ============================================================\n// Module-level constants\n// ============================================================\n\nconst name = 'Rokt';\nconst moduleId = 181;\nconst EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements';\nconst ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com';\nconst INIT_LOG_SAMPLING_RATE = 0.1;\nconst ROKT_THANK_YOU_JOURNEY_EXTENSION = 'ThankYouPageJourney';\nconst ROKT_INTEGRATION_SCRIPT_ID = 'rokt-launcher';\nconst ROKT_THANK_YOU_ELEMENT_SCRIPT_ID = 'rokt-thank-you-element';\nconst USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace';\n\nconst MESSAGE_TYPE_PAGE_VIEW = 3; // mParticle MessageType.PageView\nconst MESSAGE_TYPE_SESSION_END = 2; // mParticle MessageType.SessionEnd\nconst PAGE_EVENTS_KEY = 'page_events';\nconst PAGE_VIEW_ATTRIBUTES_KEY = 'page_view_attributes';\nconst MPARTICLE_SESSION_ID_KEY = 'mparticle_session_id';\nconst MPARTICLE_DEVICE_ID_KEY = 'mparticle_device_id';\n\n// Bound on how long selectPlacements will wait for an in-flight Workspace\n// IDSync search before proceeding without the userIdentifiedInWorkspace flag.\n// Long enough to cover the typical /v1/search round-trip (~50ms); short enough that a\n// stalled search never blocks placement rendering on a thank-you page.\nconst WORKSPACE_SEARCH_SELECT_TIMEOUT_MS = 500;\n\n// ============================================================\n// Reporting service constants\n// ============================================================\n\nconst ErrorCodes = {\n UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION',\n IDENTITY_REQUEST: 'IDENTITY_REQUEST',\n LOG_DELIVERY_FAILURE: 'LOG_DELIVERY_FAILURE',\n} as const;\n\nconst WSDKErrorSeverity = {\n ERROR: 'ERROR',\n INFO: 'INFO',\n WARNING: 'WARNING',\n} as const;\n\nconst DEFAULT_ROKT_DOMAIN = 'apps.rokt-api.com';\nconst LOGGING_ENDPOINT = '/v1/log';\nconst ERROR_ENDPOINT = '/v1/errors';\nconst RATE_LIMIT_PER_SEVERITY = 10;\n\n// ============================================================\n// Helper: typed accessor for window.mParticle\n// We use an explicit cast here to avoid conflicts with @mparticle/web-sdk\n// type declarations while still providing full type safety for our usages.\n// ============================================================\n\nfunction mp(): MParticleExtended {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (window as any).mParticle as MParticleExtended;\n}\n\n// ============================================================\n// Module-level utility functions\n// ============================================================\n\nfunction generateLauncherScript(domain: string | undefined, extensions: string[]): string {\n const launcherPath = '/wsdk/integrations/launcher.js';\n const baseUrl = [generateBaseUrl(domain), launcherPath].join('');\n\n if (!extensions || extensions.length === 0) {\n return baseUrl;\n }\n return baseUrl + '?extensions=' + extensions.join(',');\n}\n\nfunction generateThankYouElementScript(domain: string | undefined) {\n const thankYouElementPath = '/rokt-elements/rokt-element-thank-you.js';\n return [generateBaseUrl(domain), thankYouElementPath].join('');\n}\n\nfunction generateBaseUrl(domain: string | undefined) {\n const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN;\n\n if (resolvedDomain.includes('://')) {\n return resolvedDomain.replace(/\\/+$/, '');\n }\n\n const protocol = 'https://';\n\n return [protocol, resolvedDomain].join('');\n}\n\nfunction generateReportingUrl(configuredUrl: string | undefined, domain: string | undefined, endpoint: string): string {\n if (configuredUrl) {\n if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://')) {\n return configuredUrl;\n }\n return 'https://' + configuredUrl;\n }\n\n const hasNonHttpScheme = domain?.includes('://') && !/^https?:\\/\\//i.test(domain);\n const reportingDomain = hasNonHttpScheme ? undefined : domain;\n\n return generateBaseUrl(reportingDomain) + endpoint;\n}\n\nfunction loadRoktScript(\n scriptId: string,\n source: string,\n handlers?: { onLoad?: () => void; onError?: (e: Event | string) => void },\n): void {\n if (document.getElementById(scriptId)) return; // resolves the preexisting script issue\n\n const target = document.head || document.body;\n const script = document.createElement('script');\n script.id = scriptId;\n script.type = 'text/javascript';\n script.src = source;\n script.async = true;\n script.crossOrigin = 'anonymous';\n (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high';\n if (handlers?.onLoad) script.onload = handlers.onLoad;\n if (handlers?.onError) script.onerror = handlers.onError;\n target.appendChild(script);\n}\n\nfunction parseSettingsString(settingsString?: string): T[] {\n if (!settingsString) {\n return [];\n }\n try {\n return JSON.parse(settingsString.replace(/"/g, '\"')) as T[];\n } catch (_error) {\n console.error('Settings string contains invalid JSON');\n }\n return [];\n}\n\nfunction extractRoktExtensionConfig(settingsString?: string): RoktExtensionConfig {\n const settings = settingsString ? parseSettingsString(settingsString) : [];\n const roktExtensionsQueryParams: string[] = [];\n const legacyRoktExtensions: string[] = [];\n let loadThankYouElement = false;\n\n for (let i = 0; i < settings.length; i++) {\n const extensionName = settings[i].value;\n if (extensionName === 'thank-you-journey') {\n loadThankYouElement = true;\n legacyRoktExtensions.push(ROKT_THANK_YOU_JOURNEY_EXTENSION);\n } else {\n roktExtensionsQueryParams.push(extensionName);\n }\n }\n\n return {\n roktExtensionsQueryParams,\n legacyRoktExtensions,\n loadThankYouElement,\n };\n}\n\nasync function registerLegacyExtensions(legacyExtensions: string[], launcher: RoktLauncher | null) {\n const extensions: Promise[] = [];\n if (launcher) {\n for (const extension of legacyExtensions) {\n extensions.push(launcher.use(extension));\n }\n }\n\n return Promise.all(extensions);\n}\n\nfunction generateMappedEventLookup(placementEventMapping: PlacementEventMappingEntry[]): Record {\n if (!placementEventMapping) {\n return {};\n }\n\n const mappedEvents: Record = {};\n for (let i = 0; i < placementEventMapping.length; i++) {\n const mapping = placementEventMapping[i];\n mappedEvents[mapping.jsmap] = mapping.value;\n }\n return mappedEvents;\n}\n\nfunction generateMappedEventAttributeLookup(\n placementEventAttributeMapping: EventAttributeMapping[],\n): Record {\n const mappedAttributeKeys: Record = {};\n if (!Array.isArray(placementEventAttributeMapping)) {\n return mappedAttributeKeys;\n }\n for (let i = 0; i < placementEventAttributeMapping.length; i++) {\n const mapping = placementEventAttributeMapping[i];\n if (!mapping || !isString(mapping.value) || !isString(mapping.map)) {\n continue;\n }\n\n const mappedAttributeKey = mapping.value;\n const eventAttributeKey = mapping.map;\n\n if (!mappedAttributeKeys[mappedAttributeKey]) {\n mappedAttributeKeys[mappedAttributeKey] = [];\n }\n\n mappedAttributeKeys[mappedAttributeKey].push({\n eventAttributeKey: eventAttributeKey,\n conditions: Array.isArray(mapping.conditions) ? mapping.conditions : [],\n });\n }\n return mappedAttributeKeys;\n}\n\nfunction hashEventMessage(messageType: number, eventType: number, eventName: string): string | number {\n return mp().generateHash([messageType, eventType, eventName].join(''));\n}\n\nfunction generateIntegrationName(customIntegrationName?: string): string {\n const coreSdkVersion = mp().getVersion();\n const kitVersion = process.env.PACKAGE_VERSION;\n let integrationName = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion;\n\n if (customIntegrationName) {\n integrationName += '_' + customIntegrationName;\n }\n return integrationName;\n}\n\nfunction djb2(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return hash;\n}\n\nfunction createAutoRemovedIframe(src: string): void {\n const iframe = document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');\n iframe.src = src;\n iframe.onload = function () {\n iframe.onload = null;\n if (iframe.parentNode) {\n iframe.parentNode.removeChild(iframe);\n }\n };\n const target = document.body || document.head;\n if (target) {\n target.appendChild(iframe);\n }\n}\n\nfunction sendAdBlockMeasurementSignals(domain: string | undefined, version: string | null): void {\n const originHash = djb2(window.location.origin);\n const allowedOriginHashes = RoktKit._allowedOriginHashes;\n if (allowedOriginHashes.indexOf(originHash) === -1) {\n return;\n }\n\n if (Math.random() >= INIT_LOG_SAMPLING_RATE) {\n return;\n }\n\n const guid = window.__rokt_li_guid__;\n if (!guid) {\n return;\n }\n\n if (domain && domain.includes('://') && !/^https:\\/\\//i.test(domain)) {\n return;\n }\n\n const pageUrl = window.location.href.split('?')[0].split('#')[0];\n const params =\n 'version=' +\n encodeURIComponent(version ?? '') +\n '&launcherInstanceGuid=' +\n encodeURIComponent(guid) +\n '&pageUrl=' +\n encodeURIComponent(pageUrl);\n\n const existingBaseUrl = domain ? generateBaseUrl(domain) : 'https://apps.rokt.com';\n createAutoRemovedIframe(existingBaseUrl + '/v1/wsdk-init/index.html?' + params);\n\n createAutoRemovedIframe(\n 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true',\n );\n}\n\n// ============================================================\n// Reporting helpers\n// ============================================================\n\nfunction _isDebugModeEnabled(): boolean {\n return typeof window !== 'undefined' && !!window.location?.search?.toLowerCase().includes('mp_enable_logging=true');\n}\n\nfunction _getReportingUrl(): string | undefined {\n return typeof window !== 'undefined' ? window.location?.href : undefined;\n}\n\nfunction _getUserAgent(): string | undefined {\n return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined;\n}\n\nclass RateLimiter {\n private _logCount: Record = {};\n\n incrementAndCheck(severity: string): boolean {\n const count = this._logCount[severity] || 0;\n const newCount = count + 1;\n this._logCount[severity] = newCount;\n return newCount > RATE_LIMIT_PER_SEVERITY;\n }\n}\n\nclass ReportingTransport {\n private _isEnabled: boolean;\n private _integrationName: string;\n private _launcherInstanceGuid: string | undefined;\n private _accountId: string | null;\n private _rateLimiter: RateLimiter;\n private readonly _reporter = 'mp-wsdk';\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid: string | undefined,\n accountId: string | null | undefined,\n rateLimiter?: RateLimiter,\n ) {\n const isLoggingEnabled = config.isLoggingEnabled;\n this._integrationName = integrationName || '';\n this._launcherInstanceGuid = launcherInstanceGuid;\n this._accountId = accountId || null;\n this._rateLimiter = rateLimiter || new RateLimiter();\n this._isEnabled = _isDebugModeEnabled() || isLoggingEnabled;\n }\n\n send(\n url: string,\n severity: string,\n msg: string,\n code?: string,\n stackTrace?: string,\n onError?: (error: DeliveryError) => void,\n ): void {\n if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) {\n return;\n }\n\n try {\n const logRequest = {\n additionalInformation: {\n message: msg,\n version: this._integrationName,\n },\n severity,\n code: code || ErrorCodes.UNKNOWN_ERROR,\n url: _getReportingUrl(),\n deviceInfo: _getUserAgent(),\n stackTrace,\n reporter: this._reporter,\n integration: this._integrationName,\n };\n\n const headers: Record = {\n Accept: 'text/plain;charset=UTF-8',\n 'Content-Type': 'application/json',\n 'rokt-launcher-version': this._integrationName,\n 'rokt-wsdk-version': 'joint',\n };\n\n if (this._launcherInstanceGuid) {\n headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid;\n }\n if (this._accountId) {\n headers['rokt-account-id'] = this._accountId;\n }\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(logRequest),\n })\n .then((response: Response) => {\n // fetch only rejects on network failures; an HTTP 5xx resolves with\n // ok === false. Surface server-side failures so they are not swallowed.\n if (!response.ok) {\n const serverError: DeliveryError = new Error('HTTP ' + response.status + ' from log endpoint');\n serverError.statusCode = response.status;\n throw serverError;\n }\n })\n .catch((error: DeliveryError) => {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error);\n });\n } catch (error) {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error as DeliveryError);\n }\n }\n}\n\nclass ErrorReportingService {\n private _transport: ReportingTransport;\n private _errorUrl: string;\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._errorUrl = generateReportingUrl(config?.errorUrl, config?.integrationDomain, ERROR_ENDPOINT);\n }\n\n report(error: ErrorReport | null | undefined): void {\n if (!error) return;\n const severity = error.severity || WSDKErrorSeverity.ERROR;\n this._transport.send(this._errorUrl, severity, error.message, error.code, error.stackTrace);\n }\n}\n\nclass LoggingService {\n private _transport: ReportingTransport;\n private _loggingUrl: string;\n private _errorReportingService: { report: (e: ErrorReport) => void };\n\n constructor(\n config: ReportingConfig,\n errorReportingService: { report: (e: ErrorReport) => void },\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._loggingUrl = generateReportingUrl(config?.loggingUrl, config?.integrationDomain, LOGGING_ENDPOINT);\n this._errorReportingService = errorReportingService;\n }\n\n log(entry: LogEntry | null | undefined): void {\n if (!entry) return;\n this._transport.send(\n this._loggingUrl,\n WSDKErrorSeverity.INFO,\n entry.message,\n entry.code,\n undefined,\n (error: DeliveryError) => {\n if (this._errorReportingService) {\n // A failed log POST is not itself an SDK error. Network-level failures\n // (ad-blockers, offline, CORS) are client-side noise and reported as a\n // WARNING; only a server-side non-2xx response stays at ERROR severity.\n const isServerSide = typeof error.statusCode === 'number';\n this._errorReportingService.report({\n message: 'LoggingService: Failed to send log: ' + error.message,\n code: ErrorCodes.LOG_DELIVERY_FAILURE,\n severity: isServerSide ? WSDKErrorSeverity.ERROR : WSDKErrorSeverity.WARNING,\n });\n }\n },\n );\n }\n}\n\nfunction buildPageEvent(event: SDKEvent): PageEvent {\n const pageUrl = sanitizeUrl(window.location.href);\n const pageTitle = event.EventAttributes?.title || document.title;\n const canonicalUrl = readCanonicalUrl();\n const activeTimeOnSite = event.ActiveTimeOnSite;\n\n return {\n pageUrl,\n sourceMessageId: event.SourceMessageId,\n timestamp: event.Timestamp,\n ...(pageTitle ? { pageTitle } : {}),\n ...(canonicalUrl !== undefined ? { canonicalUrl } : {}),\n ...(Number.isFinite(activeTimeOnSite) ? { activeTimeOnSite } : {}),\n };\n}\n\n// ============================================================\n// RoktKit class\n// ============================================================\n\nclass RoktKit implements KitInterface {\n // Static field for allowed origin hashes (mutable by testHelpers)\n public static _allowedOriginHashes: number[] = [-553112570, 549508659];\n\n private static readonly PERFORMANCE_MARKS = {\n RoktScriptAppended: 'mp:RoktScriptAppended',\n };\n\n private static readonly EMAIL_SHA256_KEY = 'emailsha256';\n\n // Public fields (accessed by tests and the mParticle framework)\n public name = name;\n public id = moduleId;\n public moduleId = moduleId;\n public isInitialized = false;\n public launcher: RoktLauncher | null = null;\n public filters: KitFilters = {};\n public userAttributes: Record = {};\n // Flag set by the Workspace IDSync flow on a 200 response. Stored on the\n // kit instance and merged into placement attributes inside selectPlacements.\n public userIdentifiedInWorkspace = false;\n public testHelpers: TestHelpers | null = null;\n public placementEventMappingLookup: Record = {};\n public placementEventAttributeMappingLookup: Record = {};\n public integrationName: string | null = null;\n public domain?: string;\n public errorReportingService: ErrorReportingService | null = null;\n public loggingService: LoggingService | null = null;\n\n // Private fields\n private _mappedEmailSha256Key?: string;\n private _onboardingExpProvider?: string;\n private _thankYouElementOnLoadCallback: (() => void) | null = null;\n private _isThankYouElementLoaded = false;\n private _workspaceIdSyncApiKey?: string;\n\n // Held during a search dispatch so the next selectPlacements call;\n // can wait for the HTTP response before reading userIdentifiedInWorkspace;\n // — otherwise the first placement call ships without the flag.\n private _workspaceSearchInFlightPromise: Promise | null = null;\n // Stable serialization of the identifier set sent in the most recent\n // successful search dispatch. If a subsequent identification arrives with\n // an identical set, we skip the network call (the flag is still correct\n // from the prior search). Keyed over the full IUserIdentities map — not\n // just email — so partners passing hashed email through `other`/`other2-10`\n // or any other identifier benefit from the same dedupe. Cleared on logout\n // so a re-login re-evaluates fresh.\n private _workspaceLastSearchedIdentitiesKey?: string;\n\n // ---- Private helpers ----\n\n private getEventAttributeValue(event: SDKEvent, eventAttributeKey: string): unknown {\n const attributes = event && event.EventAttributes;\n if (!attributes) {\n return null;\n }\n\n if (typeof attributes[eventAttributeKey] === 'undefined') {\n return null;\n }\n\n return attributes[eventAttributeKey];\n }\n\n private doesEventAttributeConditionMatch(condition: EventAttributeCondition, actualValue: unknown): boolean {\n if (!condition || !isString(condition.operator)) {\n return false;\n }\n\n const operator = condition.operator.toLowerCase();\n const expectedValue = condition.attributeValue;\n\n if (operator === 'exists') {\n return actualValue !== null;\n }\n\n if (actualValue == null) {\n return false;\n }\n\n if (operator === 'equals') {\n return String(actualValue) === String(expectedValue);\n }\n\n if (operator === 'contains') {\n return String(actualValue).indexOf(String(expectedValue)) !== -1;\n }\n\n return false;\n }\n\n private doesEventMatchRule(event: SDKEvent, rule: PlacementEventRule): boolean {\n if (!rule || !isString(rule.eventAttributeKey)) {\n return false;\n }\n\n const conditions = rule.conditions;\n if (!Array.isArray(conditions)) {\n return false;\n }\n\n const actualValue = this.getEventAttributeValue(event, rule.eventAttributeKey);\n\n if (conditions.length === 0) {\n return actualValue !== null;\n }\n for (let i = 0; i < conditions.length; i++) {\n if (!this.doesEventAttributeConditionMatch(conditions[i], actualValue)) {\n return false;\n }\n }\n\n return true;\n }\n\n private applyPlacementEventAttributeMapping(event: SDKEvent): void {\n const mappedAttributeKeys = Object.keys(this.placementEventAttributeMappingLookup);\n for (let i = 0; i < mappedAttributeKeys.length; i++) {\n const mappedAttributeKey = mappedAttributeKeys[i];\n const rulesForMappedAttributeKey = this.placementEventAttributeMappingLookup[mappedAttributeKey];\n if (isEmpty(rulesForMappedAttributeKey)) {\n continue;\n }\n\n // Require ALL rules for the same key to match (AND).\n let allMatch = true;\n for (let j = 0; j < rulesForMappedAttributeKey.length; j++) {\n if (!this.doesEventMatchRule(event, rulesForMappedAttributeKey[j])) {\n allMatch = false;\n break;\n }\n }\n if (!allMatch) {\n continue;\n }\n\n mp().Rokt.setLocalSessionAttribute?.(mappedAttributeKey, true);\n }\n }\n\n private capturePageView(event: SDKEvent): void {\n let pageUrl: string | undefined;\n\n try {\n pageUrl = sanitizeUrl(window.location.href);\n\n const pageViews = loadPageViews(this.loggingService);\n const pageView = buildPageEvent(event);\n pageViews.push(pageView);\n\n const requested = Math.min(pageViews.length, PAGE_VIEWS_MAX_COUNT);\n const stored = writePageViews(pageViews);\n if (stored === 0) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n this.loggingService?.log({\n message: `Rokt Kit: Failed to persist page view for ${pageUrl} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n } else if (stored < requested) {\n this.loggingService?.log({\n message: `Rokt Kit: Page view storage reduced from ${requested} to ${stored} record(s) under quota pressure [reason: quota_eviction]`,\n code: 'PAGE_VIEW_QUOTA_EVICTION',\n });\n }\n } catch (err) {\n const reason = isLocalStorageAvailable() ? 'exception' : 'ls_unavailable';\n const errMessage = err instanceof Error ? err.message : String(err);\n this.loggingService?.log({\n message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${errMessage} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n private isLauncherReadyToAttach(): boolean {\n return !!window.Rokt && isFunction(window.Rokt.createLauncher);\n }\n\n /**\n * Returns the user identities from the filtered user, if any.\n */\n private returnUserIdentities(filteredUser: FilteredUser | null | undefined): Record {\n if (!filteredUser || !filteredUser.getUserIdentities) {\n return {};\n }\n\n const userIdentities: IUserIdentities = filteredUser.getUserIdentities().userIdentities;\n\n return this.replaceOtherIdentityWithEmailsha256(userIdentities);\n }\n\n private returnLocalSessionAttributes(): Record {\n if (!mp().Rokt || typeof mp().Rokt.getLocalSessionAttributes !== 'function') {\n return {};\n }\n return mp().Rokt.getLocalSessionAttributes!();\n }\n\n private replaceOtherIdentityWithEmailsha256(userIdentities: IUserIdentities): Record {\n const newUserIdentities: Record = { ...(userIdentities || {}) };\n const key = this._mappedEmailSha256Key;\n if (key && userIdentities[key as keyof IUserIdentities]) {\n newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key as keyof IUserIdentities] as string;\n }\n if (key) {\n delete newUserIdentities[key];\n }\n\n return newUserIdentities;\n }\n\n private logSelectPlacementsEvent(attributes: unknown): void {\n if (!window.mParticle || typeof mp().logEvent !== 'function') {\n return;\n }\n\n if (!isObject(attributes)) {\n return;\n }\n\n const EVENT_TYPE_OTHER = mp().EventType.Other;\n\n mp().logEvent(EVENT_NAME_SELECT_PLACEMENTS, EVENT_TYPE_OTHER, attributes as Record);\n }\n\n private setRoktSessionId(sessionId: string): void {\n if (!sessionId || typeof sessionId !== 'string') {\n return;\n }\n try {\n const mpInstance = mp().getInstance();\n if (mpInstance && isFunction(mpInstance.setIntegrationAttribute)) {\n mpInstance.setIntegrationAttribute(moduleId, {\n roktSessionId: sessionId,\n });\n }\n } catch (_e) {\n // Best effort — never let this break the partner page\n }\n }\n\n private readMpSessionId(): string | undefined {\n // The public mParticle.sessionManager facade exposes only getSession(), which already returns\n // the session id. getSessionId() lives on the internal _SessionManager and has never been\n // re-exported, so prefer it if a future core adds it and fall back to getSession() until then.\n const sessionManager = mp()?.sessionManager;\n const readSessionId = sessionManager?.getSessionId ?? sessionManager?.getSession;\n if (!isFunction(readSessionId)) {\n return undefined;\n }\n\n return readSessionId.call(sessionManager) || undefined;\n }\n\n private readMpDeviceId(): string | undefined {\n // The device application stamp (`das`) outlives the session id: core clears the session on\n // timeout, cross-tab rotation and endSession(), but never the device id, which lives in\n // localStorage/cookie for cookieExpiration days (365 by default) and survives login/logout.\n // Read it per call anyway — a partner can reassign it at any time via setDeviceId().\n return mp()?.getDeviceId?.() || undefined;\n }\n\n private attachLauncher(\n accountId: string,\n launcherOptions: Record,\n legacyRoktExtensions: string[] = [],\n ): void {\n const options: Record = {\n accountId,\n ...(launcherOptions || {}),\n };\n\n let launcherPromise: Promise;\n if (this.isPartnerInLocalLauncherTestGroup()) {\n launcherPromise = Promise.resolve(window.Rokt!.createLocalLauncher(options));\n } else {\n launcherPromise = window.Rokt!.createLauncher(options);\n }\n\n launcherPromise\n .then(async (launcher) => {\n await registerLegacyExtensions(legacyRoktExtensions, launcher);\n this.initRoktLauncher(launcher);\n })\n .catch((err: unknown) => {\n console.error('Error creating Rokt launcher:', err);\n });\n }\n\n private initRoktLauncher(launcher: RoktLauncher): void {\n // Assign the launcher to a global variable for later access\n if (window.Rokt) {\n window.Rokt.currentLauncher = launcher;\n }\n // Locally cache the launcher and filters\n this.launcher = launcher;\n\n const roktFilters = mp().Rokt?.filters;\n\n if (!roktFilters) {\n console.warn('Rokt Kit: No filters have been set.');\n } else {\n this.filters = roktFilters;\n if (!roktFilters.filteredUser) {\n console.warn('Rokt Kit: No filtered user has been set.');\n } else {\n this._workspaceSearchInFlightPromise = this.search(roktFilters.filteredUser);\n }\n }\n\n // Kit must be initialized before attaching to the Rokt manager\n this.isInitialized = true;\n\n sendAdBlockMeasurementSignals(this.domain, this.integrationName);\n\n // Attaches the kit to the Rokt manager\n mp().Rokt.attachKit(this);\n }\n\n private fetchOptimizely(): Record {\n const forwarders = mp()\n ._getActiveForwarders()\n .filter((forwarder) => forwarder.name === 'Optimizely');\n\n try {\n if (forwarders.length > 0 && window.optimizely) {\n const optimizelyState = window.optimizely.get('state');\n if (!optimizelyState || !optimizelyState.getActiveExperimentIds) {\n return {};\n }\n const activeExperimentIds = optimizelyState.getActiveExperimentIds();\n const activeExperiments = activeExperimentIds.reduce((acc: Record, expId: string) => {\n acc['rokt.custom.optimizely.experiment.' + expId + '.variationId'] =\n optimizelyState.getVariationMap()[expId].id;\n return acc;\n }, {});\n return activeExperiments;\n }\n } catch (error) {\n console.error('Error fetching Optimizely attributes:', error);\n }\n return {};\n }\n\n private isKitReady(): boolean {\n return !!(this.isInitialized && this.launcher);\n }\n\n // When the partner has opted out of targeting (noTargeting launcher option),\n // the kit must not collect behavioral targeting signals such as page views.\n private isTargetingDisabled(): boolean {\n return (mp().Rokt?.launcherOptions as Record | undefined)?.noTargeting === true;\n }\n\n private isPartnerInLocalLauncherTestGroup(): boolean {\n return !!(mp().config && mp().config!.isLocalLauncherEnabled && this.isAssignedToSampleGroup());\n }\n\n private isAssignedToSampleGroup(): boolean {\n const LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5;\n return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD;\n }\n\n private captureTiming(metricName: string): void {\n if (window && mp() && mp().captureTiming && metricName) {\n mp().captureTiming!(metricName);\n }\n }\n\n // ---- Public methods (mParticle Kit Callbacks) ----\n\n /**\n * Initializes the Rokt forwarder with settings from the mParticle server.\n */\n public init(\n settings: Record,\n _service: unknown,\n testMode: boolean,\n _trackerId: unknown,\n filteredUserAttributes?: Record,\n ): string {\n const kitSettings = settings as unknown as RoktKitSettings;\n const accountId = kitSettings.accountId;\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredUserAttributes);\n this._onboardingExpProvider = kitSettings.onboardingExpProvider;\n\n const placementEventMapping = parseSettingsString(kitSettings.placementEventMapping);\n this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping);\n\n const placementEventAttributeMapping = parseSettingsString(\n kitSettings.placementEventAttributeMapping,\n );\n this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping);\n\n // Set dynamic OTHER_IDENTITY based on server settings\n if (kitSettings.hashedEmailUserIdentityType) {\n this._mappedEmailSha256Key = kitSettings.hashedEmailUserIdentityType.toLowerCase();\n }\n\n this._workspaceIdSyncApiKey = isString(kitSettings.workspaceIdSyncApiKey)\n ? kitSettings.workspaceIdSyncApiKey\n : undefined;\n\n const domain = mp().Rokt?.domain;\n const { roktExtensionsQueryParams, legacyRoktExtensions, loadThankYouElement } = extractRoktExtensionConfig(\n kitSettings.roktExtensions,\n );\n const launcherOptions: Record = {\n ...((mp().Rokt?.launcherOptions as Record) || {}),\n };\n this.integrationName = generateIntegrationName(launcherOptions.integrationName as string | undefined);\n launcherOptions.integrationName = this.integrationName;\n\n this.domain = domain;\n\n const reportingConfig: ReportingConfig = {\n loggingUrl: kitSettings.loggingUrl,\n errorUrl: kitSettings.errorUrl,\n integrationDomain: domain,\n isLoggingEnabled: mp().config?.isLoggingEnabled === true,\n };\n const errorReportingService = new ErrorReportingService(\n reportingConfig,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n const loggingService = new LoggingService(\n reportingConfig,\n errorReportingService,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n\n this.errorReportingService = errorReportingService;\n this.loggingService = loggingService;\n\n if (this.isTargetingDisabled()) {\n try {\n clearPageViews();\n clearUtmParams();\n } catch (err) {\n this.errorReportingService?.report({\n message: 'Rokt Kit: Failed to clear page views when targeting is disabled',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n severity: WSDKErrorSeverity.INFO,\n stackTrace: err instanceof Error ? err.stack : undefined,\n });\n }\n }\n\n if (mp()._registerErrorReportingService) {\n mp()._registerErrorReportingService!(errorReportingService);\n }\n if (mp()._registerLoggingService) {\n mp()._registerLoggingService!(loggingService);\n }\n\n if (testMode) {\n this.testHelpers = {\n generateLauncherScript: generateLauncherScript,\n generateThankYouElementScript: generateThankYouElementScript,\n extractRoktExtensionConfig: extractRoktExtensionConfig,\n hashEventMessage: hashEventMessage,\n parseSettingsString: parseSettingsString,\n generateMappedEventLookup: generateMappedEventLookup,\n generateMappedEventAttributeLookup: generateMappedEventAttributeLookup,\n sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals,\n createAutoRemovedIframe: createAutoRemovedIframe,\n djb2: djb2,\n setAllowedOriginHashes: (hashes: number[]) => {\n RoktKit._allowedOriginHashes = hashes;\n },\n ReportingTransport: ReportingTransport,\n ErrorReportingService: ErrorReportingService,\n LoggingService: LoggingService,\n RateLimiter: RateLimiter,\n ErrorCodes: ErrorCodes,\n WSDKErrorSeverity: WSDKErrorSeverity,\n };\n this.attachLauncher(accountId, launcherOptions);\n return 'Successfully initialized: ' + name;\n }\n\n if (loadThankYouElement) {\n mp().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this);\n loadRoktScript(ROKT_THANK_YOU_ELEMENT_SCRIPT_ID, generateThankYouElementScript(domain), {\n onLoad: () => {\n this._isThankYouElementLoaded = true;\n if (this._thankYouElementOnLoadCallback) {\n this._thankYouElementOnLoadCallback();\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt Thank You Element script:', error);\n },\n });\n }\n\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n loadRoktScript(ROKT_INTEGRATION_SCRIPT_ID, generateLauncherScript(domain, roktExtensionsQueryParams), {\n onLoad: () => {\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n console.error('Rokt object is not available after script load.');\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt launcher script:', error);\n },\n });\n\n this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended);\n }\n\n return 'Successfully initialized: ' + name;\n }\n\n public process(event: SDKEvent): string {\n if (!this.isTargetingDisabled()) {\n if (event.EventDataType === MESSAGE_TYPE_PAGE_VIEW) {\n captureUtmParams(this.loggingService);\n this.capturePageView(event);\n }\n\n if (event.EventDataType === MESSAGE_TYPE_SESSION_END) {\n migrateLegacyPageViewStorage(this.loggingService);\n clearPageViews();\n clearUtmParams();\n }\n }\n\n // The forwarding work below (LSA mapping) depends on the launcher, so guard\n // it here and surface the not-ready signal to the core SDK.\n if (!this.isKitReady()) {\n return 'Kit not ready for forwarder: ' + name;\n }\n\n if (isFunction(mp().Rokt?.setLocalSessionAttribute)) {\n if (!isEmpty(this.placementEventAttributeMappingLookup)) {\n this.applyPlacementEventAttributeMapping(event);\n }\n\n if (!isEmpty(this.placementEventMappingLookup)) {\n const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? '');\n if (this.placementEventMappingLookup[String(hashedEvent)]) {\n mp().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(hashedEvent)], true);\n }\n }\n }\n\n return 'Successfully sent to forwarder: ' + name;\n }\n\n public setExtensionData(partnerExtensionData: Record): void {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return;\n }\n\n window.Rokt!.setExtensionData(partnerExtensionData);\n }\n\n public setUserAttribute(key: string, value: unknown): string {\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n this.userAttributes[key] = value;\n }\n return 'Successfully set user attribute for forwarder: ' + name;\n }\n\n public removeUserAttribute(key: string): string {\n delete this.userAttributes[key];\n return 'Successfully removed user attribute for forwarder: ' + name;\n }\n\n private handleIdentityComplete(user: IMParticleUser, callbackName: string): string {\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(user.getAllUserAttributes());\n return 'Successfully called ' + callbackName + ' for forwarder: ' + name;\n }\n\n public onUserIdentified(user: IMParticleUser): string {\n const filteredUser = user as FilteredUser;\n this.filters.filteredUser = filteredUser;\n this._workspaceSearchInFlightPromise = this.search(filteredUser);\n return this.handleIdentityComplete(user, 'onUserIdentified');\n }\n\n private search(filteredUser: FilteredUser): Promise {\n const apiKey = this._workspaceIdSyncApiKey;\n if (!apiKey) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n const search = mp().Identity?.search;\n if (typeof search !== 'function') {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n const userIdentities: IUserIdentities | null = filteredUser.getUserIdentities\n ? filteredUser.getUserIdentities().userIdentities\n : null;\n\n // Forward every non-empty string identifier the user has — email,\n // customerid, other/other2-10 (commonly used for hashed email),\n // mobile_number, facebook, etc. The host SDK's Identity.search accepts\n // the full IUserIdentities surface and the server validates it.\n const knownIdentities: Record = {};\n if (userIdentities) {\n for (const key of Object.keys(userIdentities) as Array) {\n const value = userIdentities[key];\n if (isString(value) && value.length > 0) {\n knownIdentities[key] = value;\n }\n }\n }\n\n const identityKeys = Object.keys(knownIdentities);\n if (identityKeys.length === 0) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n // Stable cache key: sort keys so insertion-order differences don't\n // cause false misses. The values are partner-supplied strings; no\n // hashing needed — equality on this serialization is sufficient.\n const identitiesKey = identityKeys\n .sort()\n .map((k) => `${k}=${knownIdentities[k]}`)\n .join('&');\n\n // Same identifier set as the last successful dispatch → skip the\n // network call. The current flag value still reflects the correct\n // match status.\n if (identitiesKey === this._workspaceLastSearchedIdentitiesKey) {\n return this._workspaceSearchInFlightPromise || Promise.resolve();\n }\n\n // New / different identifier set → reset and re-search. Cache the key\n // up front so a second concurrent invocation with the same set also\n // dedupes.\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = identitiesKey;\n\n return new Promise((resolve) => {\n try {\n search(apiKey, knownIdentities as IUserIdentities, (result: WorkspaceIdSyncResult) => {\n if (result?.httpCode === 200) {\n this.userIdentifiedInWorkspace = true;\n }\n resolve();\n });\n } catch (err) {\n console.error('Rokt Kit: Workspace IDSync search failed', err);\n // Dispatch failed — clear the cache so the same identifier set\n // can retry on the next identification rather than being stuck\n // behind a poisoned entry that short-circuits future searches.\n this._workspaceLastSearchedIdentitiesKey = undefined;\n resolve();\n }\n });\n }\n\n public onLoginComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onLoginComplete');\n }\n\n public onLogoutComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n // Anonymous sessions must not carry the previous user's match forward.\n // Clear the flag explicitly here. Also clear the identities cache so a\n // re-login (possibly with the same identifiers) dispatches a fresh\n // search rather than reusing a stale answer.\n this.userIdentifiedInWorkspace = false;\n this._workspaceSearchInFlightPromise = null;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return this.handleIdentityComplete(user, 'onLogoutComplete');\n }\n\n public onModifyComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onModifyComplete');\n }\n\n /**\n * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options.\n *\n * If a Workspace IDSync search is in flight from a recent onUserIdentified\n * call, this method waits up to `WORKSPACE_SEARCH_SELECT_TIMEOUT_MS` for it\n * to settle so the first placement call can include the\n * `userIdentifiedInWorkspace` flag without racing the network response.\n * The timeout protects against a stalled or slow search blocking placement\n * rendering — if it fires, selectPlacements proceeds without the flag.\n *\n * Implementation note: this method stays non-async deliberately. First,\n * the public return type is `RoktSelection | Promise |\n * undefined` — a superset of the `RoktSelection | Promise`\n * shape declared for `RoktLauncher.selectPlacements` above (line ~70).\n * Marking this `async` would narrow it to `Promise` and silently change the contract for callers that read\n * the result synchronously. Second, `RoktSelection` has an optional\n * `then?` member, so TS treats it as ambiguously promise-like and\n * rejects it as the awaited return of an async function (TS1058) —\n * working around that would require a cast or wrapping every return in\n * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`;\n * this wrapper just gates it on the in-flight search via `Promise.race`.\n */\n public selectPlacements(options: Record): RoktSelection | Promise | undefined {\n if (this._workspaceSearchInFlightPromise) {\n const inFlight = this._workspaceSearchInFlightPromise;\n return Promise.race([\n inFlight,\n new Promise((resolve) => setTimeout(resolve, WORKSPACE_SEARCH_SELECT_TIMEOUT_MS)),\n ]).then(() => this._dispatchPlacements(options)) as Promise;\n }\n return this._dispatchPlacements(options);\n }\n\n private _dispatchPlacements(options: Record): RoktSelection | Promise | undefined {\n const attributes = ((options && (options.attributes as Record)) || {}) as Record;\n const cachedUserAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(this.userAttributes);\n const placementAttributes: Record = { ...cachedUserAttributes, ...attributes };\n\n const filters = this.filters || {};\n const userAttributeFilters = (filters.userAttributeFilters as string[]) || [];\n const filteredUser = filters.filteredUser || null;\n const mpid = filteredUser ? filteredUser.getMPID() : null;\n\n let filteredAttributes: Record;\n\n if (!filters) {\n console.warn('Rokt Kit: No filters available, using user attributes');\n filteredAttributes = placementAttributes;\n } else if (filters.filterUserAttributes) {\n filteredAttributes = filters.filterUserAttributes(placementAttributes, userAttributeFilters);\n } else {\n filteredAttributes = placementAttributes;\n }\n\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredAttributes);\n\n const optimizelyAttributes = this._onboardingExpProvider === 'Optimizely' ? this.fetchOptimizely() : {};\n\n const filteredUserIdentities = this.returnUserIdentities(filteredUser);\n\n const sessionAttributes = this.returnLocalSessionAttributes();\n const pageEvents = buildPageEvents(loadPageViews(this.loggingService));\n const utmParams = loadUtmParams();\n const mpSessionId = this.readMpSessionId();\n const mpDeviceId = this.readMpDeviceId();\n\n const selectPlacementsAttributes: Record = {\n ...(filteredUserIdentities as Record),\n ...filteredAttributes,\n ...optimizelyAttributes,\n ...sessionAttributes,\n ...(pageEvents.length ? { [PAGE_EVENTS_KEY]: JSON.stringify(pageEvents) } : {}),\n ...(utmParams ? { [PAGE_VIEW_ATTRIBUTES_KEY]: utmParams } : {}),\n ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}),\n ...(mpSessionId ? { [MPARTICLE_SESSION_ID_KEY]: mpSessionId } : {}),\n ...(mpDeviceId ? { [MPARTICLE_DEVICE_ID_KEY]: mpDeviceId } : {}),\n mpid,\n };\n\n const selectPlacementsOptions: Record = { ...options, attributes: selectPlacementsAttributes };\n\n const selection = this.launcher!.selectPlacements(selectPlacementsOptions);\n\n // After selection resolves, sync the Rokt session ID back to mParticle, then log\n const logSelection = () => this.logSelectPlacementsEvent(selectPlacementsAttributes);\n\n void Promise.resolve(selection)\n .then((sel) => sel?.context?.sessionId?.then((sessionId) => this.setRoktSessionId(sessionId)))\n .catch(() => undefined)\n .finally(logSelection);\n\n return selection;\n }\n\n /**\n * Passes attributes to the Rokt Web SDK for client-side hashing.\n */\n public hashAttributes(attributes: Record): Promise> | null {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return null;\n }\n return this.launcher!.hashAttributes(attributes);\n }\n\n /**\n * Enables optional Integration Launcher extensions before selecting placements.\n *\n * @deprecated This functionality has been internalized and will be removed in a future release.\n */\n public use(extensionName: string): Promise {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return Promise.reject(new Error('Rokt Kit: Not initialized'));\n }\n if (!extensionName || !isString(extensionName)) {\n return Promise.reject(new Error('Rokt Kit: Invalid extension name'));\n }\n return this.launcher!.use(extensionName);\n }\n\n /**\n * Registers a callback to be invoked once rokt-thank-you-element.js becomes available.\n */\n public onShoppableAdsReady(callback: () => void) {\n if (this._isThankYouElementLoaded) {\n callback();\n } else {\n this._thankYouElementOnLoadCallback = callback;\n }\n }\n}\n\n// ============================================================\n// Kit registration\n// ============================================================\n\nfunction getId(): number {\n return moduleId;\n}\n\nfunction register(config: { kits?: Record }): void {\n if (!config) {\n window.console.log('You must pass a config object to register the kit ' + name);\n return;\n }\n if (!isObject(config)) {\n window.console.log(\"'config' must be an object. You passed in a \" + typeof config);\n return;\n }\n\n if (isObject(config.kits)) {\n (config.kits as Record)[name] = {\n constructor: RoktKit,\n };\n } else {\n config.kits = {};\n config.kits[name] = {\n constructor: RoktKit,\n };\n }\n window.console.log('Successfully registered ' + name + ' to your mParticle configuration');\n}\n\nif (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) {\n mp().addForwarder({\n name: name,\n constructor: RoktKit,\n getId: getId,\n });\n}\n\nexport { register };\nexport type { LoggingService };\n"],"names":["SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST","SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET","isSelectPlacementsAttributePersistenceDenied","key","removeSelectPlacementsAttributePersistenceDeniedAttributes","attributes","filteredAttributes","sourceAttributes","attributeKeys","i","isObject","value","isString","isFunction","isEmpty","sanitizeUrl","href","url","LS_PROBE_KEY","isLocalStorageAvailable","readJSON","stored","writeJSON","removeKey","readNamespacedField","namespaceKey","field","blob","writeNamespacedField","next","removeNamespacedField","LS_NAMESPACE_KEY","LS_PAGE_VIEWS_FIELD","LS_UTM_PARAMS_FIELD","LEGACY_PAGE_VIEWS_KEY","PAGE_VIEWS_MAX_COUNT","UTM_KEYS","capPageViews","views","migrateLegacyPageViewStorage","loggingService","legacyViews","loadPageViews","writePageViews","pageViews","toWrite","clearPageViews","buildPageEvents","pageView","index","activeTimeOnSite","hasActiveTime","nextActiveTimeOnSite","hasNextActiveTimeOnSite","diff","captureUtmParams","search","params","captured","reason","loadUtmParams","clearUtmParams","readCanonicalUrl","name","moduleId","EVENT_NAME_SELECT_PLACEMENTS","ADBLOCK_CONTROL_DOMAIN","INIT_LOG_SAMPLING_RATE","ROKT_THANK_YOU_JOURNEY_EXTENSION","ROKT_INTEGRATION_SCRIPT_ID","ROKT_THANK_YOU_ELEMENT_SCRIPT_ID","USER_IDENTIFIED_IN_WORKSPACE_KEY","MESSAGE_TYPE_PAGE_VIEW","MESSAGE_TYPE_SESSION_END","PAGE_EVENTS_KEY","PAGE_VIEW_ATTRIBUTES_KEY","MPARTICLE_SESSION_ID_KEY","MPARTICLE_DEVICE_ID_KEY","WORKSPACE_SEARCH_SELECT_TIMEOUT_MS","ErrorCodes","WSDKErrorSeverity","DEFAULT_ROKT_DOMAIN","LOGGING_ENDPOINT","ERROR_ENDPOINT","RATE_LIMIT_PER_SEVERITY","mp","generateLauncherScript","domain","extensions","baseUrl","generateBaseUrl","generateThankYouElementScript","resolvedDomain","generateReportingUrl","configuredUrl","endpoint","reportingDomain","loadRoktScript","scriptId","source","handlers","target","script","parseSettingsString","settingsString","extractRoktExtensionConfig","settings","roktExtensionsQueryParams","legacyRoktExtensions","loadThankYouElement","extensionName","registerLegacyExtensions","legacyExtensions","launcher","extension","generateMappedEventLookup","placementEventMapping","mappedEvents","mapping","generateMappedEventAttributeLookup","placementEventAttributeMapping","mappedAttributeKeys","mappedAttributeKey","eventAttributeKey","hashEventMessage","messageType","eventType","eventName","generateIntegrationName","customIntegrationName","integrationName","djb2","str","hash","createAutoRemovedIframe","src","iframe","sendAdBlockMeasurementSignals","version","originHash","RoktKit","guid","pageUrl","existingBaseUrl","_isDebugModeEnabled","_getReportingUrl","_getUserAgent","RateLimiter","severity","newCount","ReportingTransport","config","launcherInstanceGuid","accountId","rateLimiter","isLoggingEnabled","msg","code","stackTrace","onError","logRequest","headers","response","serverError","error","ErrorReportingService","LoggingService","errorReportingService","entry","isServerSide","buildPageEvent","event","pageTitle","canonicalUrl","_RoktKit","condition","actualValue","operator","expectedValue","rule","conditions","rulesForMappedAttributeKey","allMatch","j","requested","err","errMessage","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","sessionManager","readSessionId","launcherOptions","options","launcherPromise","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","sessionAttributes","pageEvents","utmParams","mpSessionId","mpDeviceId","selectPlacementsAttributes","selectPlacementsOptions","selection","logSelection","sel","callback","getId","register"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"Rokt-Kit.common.js","sources":["../src/selectPlacementsAttributePersistence.ts","../src/utils.ts","../src/storage.ts","../src/pageViewStorage.ts","../src/Rokt-Kit.ts"],"sourcesContent":["const SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST = [\n 'active_time_on_site_ms',\n 'billingaddress1',\n 'billingaddress2',\n 'billingcity',\n 'billingstate',\n 'billingzipcode',\n 'cartitems',\n 'ccbin',\n 'confirmationref',\n 'conversiontype',\n 'country',\n 'couponcode',\n 'currency',\n 'language',\n 'paymentserviceprovider',\n 'paymentserviceproviderattribute',\n 'paymenttype',\n 'shippingaddress1',\n 'shippingcity',\n 'shippingcountry',\n 'shippingmethod',\n 'shippingstate',\n 'shippingzipcode',\n 'totalprice',\n];\nconst SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET = new Set(SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST);\n\nexport function isSelectPlacementsAttributePersistenceDenied(key: string): boolean {\n return SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET.has(key.toLowerCase());\n}\n\nexport function removeSelectPlacementsAttributePersistenceDeniedAttributes(\n attributes: Record | null | undefined,\n): Record {\n const filteredAttributes: Record = {};\n const sourceAttributes = attributes || {};\n const attributeKeys = Object.keys(sourceAttributes);\n\n for (let i = 0; i < attributeKeys.length; i++) {\n const key = attributeKeys[i];\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n filteredAttributes[key] = sourceAttributes[key];\n }\n }\n\n return filteredAttributes;\n}\n","export function isObject(value: unknown): value is Record {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nexport function isFunction(value: unknown): value is (...args: Array) => unknown {\n return typeof value === 'function';\n}\n\nexport function isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'object') {\n return Object.keys(value as object).length === 0;\n }\n return false;\n}\n\n// Strips the query string from a URL before it is persisted and sent to Rokt,\n// since query params commonly carry PII (emails, tokens, order refs).\n// Returns the input unchanged if it can't be parsed as a URL.\nexport function sanitizeUrl(href: string): string {\n try {\n const url = new URL(href);\n url.search = '';\n return url.toString();\n } catch {\n return href;\n }\n}\n","import { isObject } from './utils';\n\nconst LS_PROBE_KEY = '__rokt_ls_probe__';\n\nexport function isLocalStorageAvailable(): boolean {\n try {\n window.localStorage.setItem(LS_PROBE_KEY, '1');\n window.localStorage.removeItem(LS_PROBE_KEY);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function readJSON(key: string): unknown {\n try {\n const stored = window.localStorage.getItem(key);\n return stored === null ? null : JSON.parse(stored);\n } catch {\n return null;\n }\n}\n\nexport function writeJSON(key: string, value: unknown): boolean {\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n return true;\n } catch {\n return false;\n }\n}\n\nexport function removeKey(key: string): void {\n try {\n window.localStorage.removeItem(key);\n } catch {\n /* empty */\n }\n}\n\nexport function readNamespacedField(namespaceKey: string, field: string): unknown {\n const blob = readJSON(namespaceKey);\n return isObject(blob) ? blob[field] : undefined;\n}\n\nexport function writeNamespacedField(namespaceKey: string, field: string, value: unknown): boolean {\n const blob = readJSON(namespaceKey);\n const next = isObject(blob) ? { ...blob } : {};\n next[field] = value;\n return writeJSON(namespaceKey, next);\n}\n\nexport function removeNamespacedField(namespaceKey: string, field: string): void {\n const blob = readJSON(namespaceKey);\n if (!isObject(blob) || !(field in blob)) {\n return;\n }\n const next = { ...blob };\n delete next[field];\n if (Object.keys(next).length === 0) {\n removeKey(namespaceKey);\n } else {\n writeJSON(namespaceKey, next);\n }\n}\n","import type { LoggingService } from './Rokt-Kit';\nimport {\n readJSON,\n removeKey,\n readNamespacedField,\n writeNamespacedField,\n removeNamespacedField,\n isLocalStorageAvailable,\n} from './storage';\nimport { sanitizeUrl, isObject } from './utils';\n\nconst LS_NAMESPACE_KEY = 'mp-rokt-kit';\nconst LS_PAGE_VIEWS_FIELD = 'pageViews';\nconst LS_UTM_PARAMS_FIELD = 'utmParams';\nconst LEGACY_PAGE_VIEWS_KEY = 'mpPageViews';\nexport const PAGE_VIEWS_MAX_COUNT = 25;\n\nconst UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'] as const;\ntype UtmKey = (typeof UTM_KEYS)[number];\nexport type UtmParams = Partial>;\n\nexport interface PageEvent {\n pageUrl: string;\n sourceMessageId: string;\n timestamp: number;\n pageTitle?: string;\n canonicalUrl?: string;\n activeTimeOnSite?: number;\n activeTimeOnPage?: number;\n}\n\nfunction capPageViews(views: PageEvent[]): PageEvent[] {\n return views.slice(-PAGE_VIEWS_MAX_COUNT);\n}\n\nexport function migrateLegacyPageViewStorage(loggingService: LoggingService | null): void {\n const legacyViews = readJSON(LEGACY_PAGE_VIEWS_KEY);\n if (legacyViews === null) {\n return;\n }\n\n const alreadyMigrated = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD) !== undefined;\n const needsMigration = !alreadyMigrated && Array.isArray(legacyViews);\n\n if (needsMigration) {\n loggingService?.log({\n message: 'Rokt Kit: Migrating legacy page-view storage',\n code: 'PAGE_VIEW_LEGACY_MIGRATION',\n });\n const migrated = writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, legacyViews);\n if (!migrated) {\n loggingService?.log({\n message: 'Rokt Kit: Failed to migrate legacy page-view storage [reason: migration_retry]',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n removeKey(LEGACY_PAGE_VIEWS_KEY);\n}\n\nexport function loadPageViews(loggingService: LoggingService | null): PageEvent[] {\n migrateLegacyPageViewStorage(loggingService);\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n return Array.isArray(stored) ? (stored as PageEvent[]) : [];\n}\n\nexport function writePageViews(pageViews: PageEvent[]): number {\n const views = capPageViews(pageViews);\n for (let i = 0; i < views.length; i++) {\n const toWrite = views.slice(i);\n if (writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, toWrite)) {\n return toWrite.length;\n }\n }\n return 0;\n}\n\nexport function clearPageViews(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n}\n\nexport function buildPageEvents(pageViews: PageEvent[]): PageEvent[] {\n const views = capPageViews(pageViews);\n return views.map((pageView, index) => {\n const activeTimeOnSite = pageView.activeTimeOnSite;\n const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite);\n\n const next = views[index + 1];\n const nextActiveTimeOnSite = next?.activeTimeOnSite;\n const hasNextActiveTimeOnSite = nextActiveTimeOnSite !== undefined && Number.isFinite(nextActiveTimeOnSite);\n\n const diff = hasActiveTime && hasNextActiveTimeOnSite ? nextActiveTimeOnSite - activeTimeOnSite : undefined;\n\n return {\n pageUrl: pageView.pageUrl,\n sourceMessageId: pageView.sourceMessageId,\n timestamp: pageView.timestamp,\n ...(pageView.pageTitle !== undefined ? { pageTitle: pageView.pageTitle } : {}),\n ...(pageView.canonicalUrl !== undefined ? { canonicalUrl: pageView.canonicalUrl } : {}),\n ...(hasActiveTime ? { activeTimeOnSite } : {}),\n ...(diff !== undefined && diff >= 0 ? { activeTimeOnPage: diff } : {}),\n };\n });\n}\n\nexport function captureUtmParams(loggingService: LoggingService | null): void {\n if (readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD) !== undefined) {\n return;\n }\n const search = new URLSearchParams(window.location.search);\n const params: UtmParams = {};\n for (const key of UTM_KEYS) {\n const value = search.get(key);\n if (value) params[key] = value;\n }\n if (Object.keys(params).length === 0) {\n return;\n }\n const captured = Object.keys(params).join(', ');\n if (!writeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD, params)) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n loggingService?.log({\n message: `Rokt Kit: Failed to persist UTM params [reason: ${reason}]`,\n code: 'UTM_CAPTURE_FAILED',\n });\n return;\n }\n loggingService?.log({\n message: `Rokt Kit: Captured UTM params [${captured}]`,\n code: 'UTM_CAPTURE_SUCCESS',\n });\n}\n\nexport function loadUtmParams(): UtmParams | null {\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n return isObject(stored) ? (stored as UtmParams) : null;\n}\n\nexport function clearUtmParams(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n}\n\nexport function readCanonicalUrl(): string | undefined {\n const link = document.querySelector('link[rel=\"canonical\"]');\n const href = link?.href;\n if (!href) {\n return undefined;\n }\n return sanitizeUrl(href);\n}\n","// Copyright 2025 mParticle, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// ============================================================\n// Types\n// ============================================================\n\nimport { KitInterface, IMParticleUser, SDKEvent } from '@mparticle/web-sdk/internal';\nimport type { IUserIdentities } from '@mparticle/web-sdk';\n\nimport {\n isSelectPlacementsAttributePersistenceDenied,\n removeSelectPlacementsAttributePersistenceDeniedAttributes,\n} from './selectPlacementsAttributePersistence';\n\nimport {\n PageEvent,\n PAGE_VIEWS_MAX_COUNT,\n buildPageEvents,\n migrateLegacyPageViewStorage,\n loadPageViews,\n writePageViews,\n clearPageViews,\n readCanonicalUrl,\n captureUtmParams,\n loadUtmParams,\n clearUtmParams,\n} from './pageViewStorage';\nimport { isLocalStorageAvailable } from './storage';\n\nimport { isObject, isString, isEmpty, isFunction, sanitizeUrl } from './utils';\n\ninterface RoktKitSettings {\n accountId: string;\n roktExtensions?: string;\n placementEventMapping?: string;\n placementEventAttributeMapping?: string;\n hashedEmailUserIdentityType?: string;\n onboardingExpProvider?: string;\n loggingUrl?: string;\n errorUrl?: string;\n workspaceIdSyncApiKey?: string;\n}\n\ninterface EventAttributeCondition {\n operator: string;\n attributeValue: string;\n}\n\ninterface PlacementEventRule {\n eventAttributeKey: string;\n conditions: EventAttributeCondition[];\n}\n\ninterface EventAttributeMapping {\n value: string;\n map: string;\n conditions?: EventAttributeCondition[];\n}\n\ninterface PlacementEventMappingEntry {\n jsmap: string;\n value: string;\n}\n\ninterface RoktExtensionEntry {\n value: string;\n}\n\ninterface RoktSelection {\n context?: {\n sessionId?: Promise;\n };\n then?: (callback: (sel: RoktSelection) => void) => Promise;\n catch?: (callback: () => void) => void;\n}\n\ninterface RoktLauncher {\n selectPlacements(options: Record): RoktSelection | Promise;\n hashAttributes(attributes: Record): Promise>;\n use(extensionName: string): Promise;\n}\n\ninterface RoktGlobal {\n createLauncher(options: Record): Promise;\n createLocalLauncher(options: Record): RoktLauncher;\n currentLauncher?: RoktLauncher;\n setExtensionData(data: Record): void;\n}\n\n// FilteredUser is the IMParticleUser shape we receive after kit filtering.\n// `getMPID` and `getUserIdentities` are inherited from the SDK's `User` base type.\ntype FilteredUser = IMParticleUser;\n\n// TODO: Replace with `IIdentitySearchResult` from `@mparticle/web-sdk` once\n// a version that exports it is published (currently on a feature branch in\n// mParticle/mparticle-web-sdk PR #1255). The shape below is intentionally\n// structurally identical so the swap is a one-line import change.\ninterface WorkspaceIdSyncResult {\n httpCode: number;\n body?: {\n context?: string | null;\n mpid?: string;\n matched_identities?: Record;\n is_ephemeral?: boolean;\n is_logged_in?: boolean;\n };\n}\n\n// TODO: Replace with `IdentitySearchCallback`-compatible reference from\n// `@mparticle/web-sdk` once published (mirrors `SDKIdentityApi.search`).\ntype WorkspaceIdSyncSearcher = (\n apiKey: string,\n knownIdentities: IUserIdentities,\n callback: (result: WorkspaceIdSyncResult) => void,\n) => void;\n\ninterface KitFilters {\n userAttributeFilters?: string[];\n filterUserAttributes?: (attributes: Record, filters?: string[]) => Record;\n filteredUser?: FilteredUser | null;\n}\n\ninterface RoktManager {\n attachKit(kit: RoktKit): void | Promise;\n flushOnShoppableAdsReadyMessageQueue?(kit: RoktKit): void;\n filters?: KitFilters;\n domain?: string;\n launcherOptions?: Record;\n getLocalSessionAttributes?(): Record;\n setLocalSessionAttribute?(key: string, value: unknown): void;\n}\n\ninterface MParticleInstance {\n setIntegrationAttribute(moduleId: number, attrs: Record): void;\n}\n\ninterface OptimizelyState {\n getActiveExperimentIds(): string[];\n getVariationMap(): Record;\n}\n\ninterface OptimizelyGlobal {\n get(key: 'state'): OptimizelyState;\n}\n\n// Our view of the mParticle global with Rokt-specific extensions.\n// We access window.mParticle via an explicit cast (see `mp()` helper below)\n// rather than augmenting Window to avoid conflicts with @mparticle/web-sdk declarations.\ninterface MParticleExtended {\n Rokt: RoktManager;\n addForwarder(config: ForwarderRegistration): void;\n getVersion(): string;\n generateHash(value: string): string | number;\n logEvent(name: string, type: number, attrs?: Record): void;\n EventType: { Other: number };\n getInstance(): MParticleInstance;\n getDeviceId?(): string;\n sessionManager?: { getSession?(): string; getSessionId?(): string };\n _getActiveForwarders(): Array<{ name: string }>;\n config?: { isLocalLauncherEnabled?: boolean; isLoggingEnabled?: boolean };\n captureTiming?(metricName: string): void;\n forwarder?: RoktKit;\n loggedEvents?: Array>;\n _registerErrorReportingService?(service: ErrorReportingService): void;\n _registerLoggingService?(service: LoggingService): void;\n Identity?: { search?: WorkspaceIdSyncSearcher };\n}\n\ninterface TestHelpers {\n generateLauncherScript: (domain: string | undefined, extensions: string[]) => string;\n generateThankYouElementScript: (domain: string | undefined) => string;\n extractRoktExtensionConfig: (settingsString?: string) => RoktExtensionConfig;\n hashEventMessage: (messageType: number, eventType: number, eventName: string) => string | number;\n parseSettingsString: (settingsString?: string) => T[];\n generateMappedEventLookup: (placementEventMapping: PlacementEventMappingEntry[]) => Record;\n generateMappedEventAttributeLookup: (mapping: EventAttributeMapping[]) => Record;\n sendAdBlockMeasurementSignals: (domain: string | undefined, version: string | null) => void;\n createAutoRemovedIframe: (src: string) => void;\n djb2: (str: string) => number;\n setAllowedOriginHashes: (hashes: number[]) => void;\n ReportingTransport: typeof ReportingTransport;\n ErrorReportingService: typeof ErrorReportingService;\n LoggingService: typeof LoggingService;\n RateLimiter: typeof RateLimiter;\n ErrorCodes: typeof ErrorCodes;\n WSDKErrorSeverity: typeof WSDKErrorSeverity;\n}\n\ninterface ForwarderRegistration {\n name: string;\n constructor: new () => RoktKit;\n getId: () => number;\n}\n\ninterface ReportingConfig {\n loggingUrl?: string;\n errorUrl?: string;\n integrationDomain?: string;\n isLoggingEnabled: boolean;\n}\n\ninterface ErrorReport {\n message: string;\n code?: string;\n severity?: string;\n stackTrace?: string;\n}\n\n// A log-delivery failure. statusCode is set when the request reached the server\n// and returned a non-2xx status (server-side); it is absent for network-level\n// failures such as ad-blockers, offline, or CORS rejections (client-side).\ninterface DeliveryError extends Error {\n statusCode?: number;\n}\n\ninterface LogEntry {\n message: string;\n code?: string;\n}\n\ninterface RoktExtensionConfig {\n roktExtensionsQueryParams: string[];\n legacyRoktExtensions: string[];\n loadThankYouElement: boolean;\n}\n\ndeclare global {\n interface Window {\n Rokt?: RoktGlobal;\n __rokt_li_guid__?: string;\n optimizely?: OptimizelyGlobal;\n // mParticle is declared as any to avoid conflicts with @mparticle/web-sdk type declarations.\n // We use the typed mp() accessor for all internal accesses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mParticle: any;\n }\n}\n\n// ============================================================\n// Module-level constants\n// ============================================================\n\nconst name = 'Rokt';\nconst moduleId = 181;\nconst EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements';\nconst ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com';\nconst INIT_LOG_SAMPLING_RATE = 0.1;\nconst ROKT_THANK_YOU_JOURNEY_EXTENSION = 'ThankYouPageJourney';\nconst ROKT_INTEGRATION_SCRIPT_ID = 'rokt-launcher';\nconst ROKT_THANK_YOU_ELEMENT_SCRIPT_ID = 'rokt-thank-you-element';\nconst USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace';\n\nconst MESSAGE_TYPE_PAGE_VIEW = 3; // mParticle MessageType.PageView\nconst MESSAGE_TYPE_SESSION_END = 2; // mParticle MessageType.SessionEnd\nconst PAGE_EVENTS_KEY = 'page_events';\nconst PAGE_VIEW_ATTRIBUTES_KEY = 'page_view_attributes';\nconst MPARTICLE_SESSION_ID_KEY = 'mparticle_session_id';\nconst MPARTICLE_DEVICE_ID_KEY = 'mparticle_device_id';\n\n// Bound on how long selectPlacements will wait for an in-flight Workspace\n// IDSync search before proceeding without the userIdentifiedInWorkspace flag.\n// Long enough to cover the typical /v1/search round-trip (~50ms); short enough that a\n// stalled search never blocks placement rendering on a thank-you page.\nconst WORKSPACE_SEARCH_SELECT_TIMEOUT_MS = 500;\n\n// ============================================================\n// Reporting service constants\n// ============================================================\n\nconst ErrorCodes = {\n UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION',\n IDENTITY_REQUEST: 'IDENTITY_REQUEST',\n LOG_DELIVERY_FAILURE: 'LOG_DELIVERY_FAILURE',\n} as const;\n\nconst WSDKErrorSeverity = {\n ERROR: 'ERROR',\n INFO: 'INFO',\n WARNING: 'WARNING',\n} as const;\n\nconst DEFAULT_ROKT_DOMAIN = 'apps.rokt-api.com';\nconst LOGGING_ENDPOINT = '/v1/log';\nconst ERROR_ENDPOINT = '/v1/errors';\nconst RATE_LIMIT_PER_SEVERITY = 10;\n\n// ============================================================\n// Helper: typed accessor for window.mParticle\n// We use an explicit cast here to avoid conflicts with @mparticle/web-sdk\n// type declarations while still providing full type safety for our usages.\n// ============================================================\n\nfunction mp(): MParticleExtended {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (window as any).mParticle as MParticleExtended;\n}\n\n// ============================================================\n// Module-level utility functions\n// ============================================================\n\nfunction generateLauncherScript(domain: string | undefined, extensions: string[]): string {\n const launcherPath = '/wsdk/integrations/launcher.js';\n const baseUrl = [generateBaseUrl(domain), launcherPath].join('');\n\n if (!extensions || extensions.length === 0) {\n return baseUrl;\n }\n return baseUrl + '?extensions=' + extensions.join(',');\n}\n\nfunction generateThankYouElementScript(domain: string | undefined) {\n const thankYouElementPath = '/rokt-elements/rokt-element-thank-you.js';\n return [generateBaseUrl(domain), thankYouElementPath].join('');\n}\n\nfunction generateBaseUrl(domain: string | undefined) {\n const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN;\n\n if (resolvedDomain.includes('://')) {\n return resolvedDomain.replace(/\\/+$/, '');\n }\n\n const protocol = 'https://';\n\n return [protocol, resolvedDomain].join('');\n}\n\nfunction generateReportingUrl(configuredUrl: string | undefined, domain: string | undefined, endpoint: string): string {\n if (configuredUrl) {\n if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://')) {\n return configuredUrl;\n }\n return 'https://' + configuredUrl;\n }\n\n const hasNonHttpScheme = domain?.includes('://') && !/^https?:\\/\\//i.test(domain);\n const reportingDomain = hasNonHttpScheme ? undefined : domain;\n\n return generateBaseUrl(reportingDomain) + endpoint;\n}\n\nfunction loadRoktScript(\n scriptId: string,\n source: string,\n handlers?: { onLoad?: () => void; onError?: (e: Event | string) => void },\n): void {\n if (document.getElementById(scriptId)) return; // resolves the preexisting script issue\n\n const target = document.head || document.body;\n const script = document.createElement('script');\n script.id = scriptId;\n script.type = 'text/javascript';\n script.src = source;\n script.async = true;\n script.crossOrigin = 'anonymous';\n (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high';\n if (handlers?.onLoad) script.onload = handlers.onLoad;\n if (handlers?.onError) script.onerror = handlers.onError;\n target.appendChild(script);\n}\n\nfunction parseSettingsString(settingsString?: string): T[] {\n if (!settingsString) {\n return [];\n }\n try {\n return JSON.parse(settingsString.replace(/"/g, '\"')) as T[];\n } catch (_error) {\n console.error('Settings string contains invalid JSON');\n }\n return [];\n}\n\nfunction extractRoktExtensionConfig(settingsString?: string): RoktExtensionConfig {\n const settings = settingsString ? parseSettingsString(settingsString) : [];\n const roktExtensionsQueryParams: string[] = [];\n const legacyRoktExtensions: string[] = [];\n let loadThankYouElement = false;\n\n for (let i = 0; i < settings.length; i++) {\n const extensionName = settings[i].value;\n if (extensionName === 'thank-you-journey') {\n loadThankYouElement = true;\n legacyRoktExtensions.push(ROKT_THANK_YOU_JOURNEY_EXTENSION);\n } else {\n roktExtensionsQueryParams.push(extensionName);\n }\n }\n\n return {\n roktExtensionsQueryParams,\n legacyRoktExtensions,\n loadThankYouElement,\n };\n}\n\nasync function registerLegacyExtensions(legacyExtensions: string[], launcher: RoktLauncher | null) {\n const extensions: Promise[] = [];\n if (launcher) {\n for (const extension of legacyExtensions) {\n extensions.push(launcher.use(extension));\n }\n }\n\n return Promise.all(extensions);\n}\n\nfunction generateMappedEventLookup(placementEventMapping: PlacementEventMappingEntry[]): Record {\n if (!placementEventMapping) {\n return {};\n }\n\n const mappedEvents: Record = {};\n for (let i = 0; i < placementEventMapping.length; i++) {\n const mapping = placementEventMapping[i];\n mappedEvents[mapping.jsmap] = mapping.value;\n }\n return mappedEvents;\n}\n\nfunction generateMappedEventAttributeLookup(\n placementEventAttributeMapping: EventAttributeMapping[],\n): Record {\n const mappedAttributeKeys: Record = {};\n if (!Array.isArray(placementEventAttributeMapping)) {\n return mappedAttributeKeys;\n }\n for (let i = 0; i < placementEventAttributeMapping.length; i++) {\n const mapping = placementEventAttributeMapping[i];\n if (!mapping || !isString(mapping.value) || !isString(mapping.map)) {\n continue;\n }\n\n const mappedAttributeKey = mapping.value;\n const eventAttributeKey = mapping.map;\n\n if (!mappedAttributeKeys[mappedAttributeKey]) {\n mappedAttributeKeys[mappedAttributeKey] = [];\n }\n\n mappedAttributeKeys[mappedAttributeKey].push({\n eventAttributeKey: eventAttributeKey,\n conditions: Array.isArray(mapping.conditions) ? mapping.conditions : [],\n });\n }\n return mappedAttributeKeys;\n}\n\nfunction hashEventMessage(messageType: number, eventType: number, eventName: string): string | number {\n return mp().generateHash([messageType, eventType, eventName].join(''));\n}\n\nfunction generateIntegrationName(customIntegrationName?: string): string {\n const coreSdkVersion = mp().getVersion();\n const kitVersion = process.env.PACKAGE_VERSION;\n let integrationName = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion;\n\n if (customIntegrationName) {\n integrationName += '_' + customIntegrationName;\n }\n return integrationName;\n}\n\nfunction djb2(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return hash;\n}\n\nfunction createAutoRemovedIframe(src: string): void {\n const iframe = document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');\n iframe.src = src;\n iframe.onload = function () {\n iframe.onload = null;\n if (iframe.parentNode) {\n iframe.parentNode.removeChild(iframe);\n }\n };\n const target = document.body || document.head;\n if (target) {\n target.appendChild(iframe);\n }\n}\n\nfunction sendAdBlockMeasurementSignals(domain: string | undefined, version: string | null): void {\n const originHash = djb2(window.location.origin);\n const allowedOriginHashes = RoktKit._allowedOriginHashes;\n if (allowedOriginHashes.indexOf(originHash) === -1) {\n return;\n }\n\n if (Math.random() >= INIT_LOG_SAMPLING_RATE) {\n return;\n }\n\n const guid = window.__rokt_li_guid__;\n if (!guid) {\n return;\n }\n\n if (domain && domain.includes('://') && !/^https:\\/\\//i.test(domain)) {\n return;\n }\n\n const pageUrl = window.location.href.split('?')[0].split('#')[0];\n const params =\n 'version=' +\n encodeURIComponent(version ?? '') +\n '&launcherInstanceGuid=' +\n encodeURIComponent(guid) +\n '&pageUrl=' +\n encodeURIComponent(pageUrl);\n\n const existingBaseUrl = domain ? generateBaseUrl(domain) : 'https://apps.rokt.com';\n createAutoRemovedIframe(existingBaseUrl + '/v1/wsdk-init/index.html?' + params);\n\n createAutoRemovedIframe(\n 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true',\n );\n}\n\n// ============================================================\n// Reporting helpers\n// ============================================================\n\nfunction _isDebugModeEnabled(): boolean {\n return typeof window !== 'undefined' && !!window.location?.search?.toLowerCase().includes('mp_enable_logging=true');\n}\n\nfunction _getReportingUrl(): string | undefined {\n return typeof window !== 'undefined' ? window.location?.href : undefined;\n}\n\nfunction _getUserAgent(): string | undefined {\n return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined;\n}\n\nclass RateLimiter {\n private _logCount: Record = {};\n\n incrementAndCheck(severity: string): boolean {\n const count = this._logCount[severity] || 0;\n const newCount = count + 1;\n this._logCount[severity] = newCount;\n return newCount > RATE_LIMIT_PER_SEVERITY;\n }\n}\n\nclass ReportingTransport {\n private _isEnabled: boolean;\n private _integrationName: string;\n private _launcherInstanceGuid: string | undefined;\n private _accountId: string | null;\n private _rateLimiter: RateLimiter;\n private readonly _reporter = 'mp-wsdk';\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid: string | undefined,\n accountId: string | null | undefined,\n rateLimiter?: RateLimiter,\n ) {\n const isLoggingEnabled = config.isLoggingEnabled;\n this._integrationName = integrationName || '';\n this._launcherInstanceGuid = launcherInstanceGuid;\n this._accountId = accountId || null;\n this._rateLimiter = rateLimiter || new RateLimiter();\n this._isEnabled = _isDebugModeEnabled() || isLoggingEnabled;\n }\n\n send(\n url: string,\n severity: string,\n msg: string,\n code?: string,\n stackTrace?: string,\n onError?: (error: DeliveryError) => void,\n ): void {\n if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) {\n return;\n }\n\n try {\n const logRequest = {\n additionalInformation: {\n message: msg,\n version: this._integrationName,\n },\n severity,\n code: code || ErrorCodes.UNKNOWN_ERROR,\n url: _getReportingUrl(),\n deviceInfo: _getUserAgent(),\n stackTrace,\n reporter: this._reporter,\n integration: this._integrationName,\n };\n\n const headers: Record = {\n Accept: 'text/plain;charset=UTF-8',\n 'Content-Type': 'application/json',\n 'rokt-launcher-version': this._integrationName,\n 'rokt-wsdk-version': 'joint',\n };\n\n if (this._launcherInstanceGuid) {\n headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid;\n }\n if (this._accountId) {\n headers['rokt-account-id'] = this._accountId;\n }\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(logRequest),\n })\n .then((response: Response) => {\n // fetch only rejects on network failures; an HTTP 5xx resolves with\n // ok === false. Surface server-side failures so they are not swallowed.\n if (!response.ok) {\n const serverError: DeliveryError = new Error('HTTP ' + response.status + ' from log endpoint');\n serverError.statusCode = response.status;\n throw serverError;\n }\n })\n .catch((error: DeliveryError) => {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error);\n });\n } catch (error) {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error as DeliveryError);\n }\n }\n}\n\nclass ErrorReportingService {\n private _transport: ReportingTransport;\n private _errorUrl: string;\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._errorUrl = generateReportingUrl(config?.errorUrl, config?.integrationDomain, ERROR_ENDPOINT);\n }\n\n report(error: ErrorReport | null | undefined): void {\n if (!error) return;\n const severity = error.severity || WSDKErrorSeverity.ERROR;\n this._transport.send(this._errorUrl, severity, error.message, error.code, error.stackTrace);\n }\n}\n\nclass LoggingService {\n private _transport: ReportingTransport;\n private _loggingUrl: string;\n private _errorReportingService: { report: (e: ErrorReport) => void };\n\n constructor(\n config: ReportingConfig,\n errorReportingService: { report: (e: ErrorReport) => void },\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._loggingUrl = generateReportingUrl(config?.loggingUrl, config?.integrationDomain, LOGGING_ENDPOINT);\n this._errorReportingService = errorReportingService;\n }\n\n log(entry: LogEntry | null | undefined): void {\n if (!entry) return;\n this._transport.send(\n this._loggingUrl,\n WSDKErrorSeverity.INFO,\n entry.message,\n entry.code,\n undefined,\n (error: DeliveryError) => {\n if (this._errorReportingService) {\n // A failed log POST is not itself an SDK error. Network-level failures\n // (ad-blockers, offline, CORS) are client-side noise and reported as a\n // WARNING; only a server-side non-2xx response stays at ERROR severity.\n const isServerSide = typeof error.statusCode === 'number';\n this._errorReportingService.report({\n message: 'LoggingService: Failed to send log: ' + error.message,\n code: ErrorCodes.LOG_DELIVERY_FAILURE,\n severity: isServerSide ? WSDKErrorSeverity.ERROR : WSDKErrorSeverity.WARNING,\n });\n }\n },\n );\n }\n}\n\nfunction buildPageEvent(event: SDKEvent): PageEvent {\n const pageUrl = sanitizeUrl(window.location.href);\n const pageTitle = event.EventAttributes?.title || document.title;\n const canonicalUrl = readCanonicalUrl();\n const activeTimeOnSite = event.ActiveTimeOnSite;\n\n return {\n pageUrl,\n sourceMessageId: event.SourceMessageId,\n timestamp: event.Timestamp,\n ...(pageTitle ? { pageTitle } : {}),\n ...(canonicalUrl !== undefined ? { canonicalUrl } : {}),\n ...(Number.isFinite(activeTimeOnSite) ? { activeTimeOnSite } : {}),\n };\n}\n\n// ============================================================\n// RoktKit class\n// ============================================================\n\nclass RoktKit implements KitInterface {\n // Static field for allowed origin hashes (mutable by testHelpers)\n public static _allowedOriginHashes: number[] = [-553112570, 549508659];\n\n private static readonly PERFORMANCE_MARKS = {\n RoktScriptAppended: 'mp:RoktScriptAppended',\n };\n\n private static readonly EMAIL_SHA256_KEY = 'emailsha256';\n\n // Public fields (accessed by tests and the mParticle framework)\n public name = name;\n public id = moduleId;\n public moduleId = moduleId;\n public isInitialized = false;\n public launcher: RoktLauncher | null = null;\n public filters: KitFilters = {};\n public userAttributes: Record = {};\n // Flag set by the Workspace IDSync flow on a 200 response. Stored on the\n // kit instance and merged into placement attributes inside selectPlacements.\n public userIdentifiedInWorkspace = false;\n public testHelpers: TestHelpers | null = null;\n public placementEventMappingLookup: Record = {};\n public placementEventAttributeMappingLookup: Record = {};\n public integrationName: string | null = null;\n public domain?: string;\n public errorReportingService: ErrorReportingService | null = null;\n public loggingService: LoggingService | null = null;\n\n // Private fields\n private _mappedEmailSha256Key?: string;\n private _onboardingExpProvider?: string;\n private _thankYouElementOnLoadCallback: (() => void) | null = null;\n private _isThankYouElementLoaded = false;\n private _workspaceIdSyncApiKey?: string;\n\n // Held during a search dispatch so the next selectPlacements call;\n // can wait for the HTTP response before reading userIdentifiedInWorkspace;\n // — otherwise the first placement call ships without the flag.\n private _workspaceSearchInFlightPromise: Promise | null = null;\n // Stable serialization of the identifier set sent in the most recent\n // successful search dispatch. If a subsequent identification arrives with\n // an identical set, we skip the network call (the flag is still correct\n // from the prior search). Keyed over the full IUserIdentities map — not\n // just email — so partners passing hashed email through `other`/`other2-10`\n // or any other identifier benefit from the same dedupe. Cleared on logout\n // so a re-login re-evaluates fresh.\n private _workspaceLastSearchedIdentitiesKey?: string;\n\n // ---- Private helpers ----\n\n private getEventAttributeValue(event: SDKEvent, eventAttributeKey: string): unknown {\n const attributes = event && event.EventAttributes;\n if (!attributes) {\n return null;\n }\n\n if (typeof attributes[eventAttributeKey] === 'undefined') {\n return null;\n }\n\n return attributes[eventAttributeKey];\n }\n\n private doesEventAttributeConditionMatch(condition: EventAttributeCondition, actualValue: unknown): boolean {\n if (!condition || !isString(condition.operator)) {\n return false;\n }\n\n const operator = condition.operator.toLowerCase();\n const expectedValue = condition.attributeValue;\n\n if (operator === 'exists') {\n return actualValue !== null;\n }\n\n if (actualValue == null) {\n return false;\n }\n\n if (operator === 'equals') {\n return String(actualValue) === String(expectedValue);\n }\n\n if (operator === 'contains') {\n return String(actualValue).indexOf(String(expectedValue)) !== -1;\n }\n\n return false;\n }\n\n private doesEventMatchRule(event: SDKEvent, rule: PlacementEventRule): boolean {\n if (!rule || !isString(rule.eventAttributeKey)) {\n return false;\n }\n\n const conditions = rule.conditions;\n if (!Array.isArray(conditions)) {\n return false;\n }\n\n const actualValue = this.getEventAttributeValue(event, rule.eventAttributeKey);\n\n if (conditions.length === 0) {\n return actualValue !== null;\n }\n for (let i = 0; i < conditions.length; i++) {\n if (!this.doesEventAttributeConditionMatch(conditions[i], actualValue)) {\n return false;\n }\n }\n\n return true;\n }\n\n private applyPlacementEventAttributeMapping(event: SDKEvent): void {\n const mappedAttributeKeys = Object.keys(this.placementEventAttributeMappingLookup);\n for (let i = 0; i < mappedAttributeKeys.length; i++) {\n const mappedAttributeKey = mappedAttributeKeys[i];\n const rulesForMappedAttributeKey = this.placementEventAttributeMappingLookup[mappedAttributeKey];\n if (isEmpty(rulesForMappedAttributeKey)) {\n continue;\n }\n\n // Require ALL rules for the same key to match (AND).\n let allMatch = true;\n for (let j = 0; j < rulesForMappedAttributeKey.length; j++) {\n if (!this.doesEventMatchRule(event, rulesForMappedAttributeKey[j])) {\n allMatch = false;\n break;\n }\n }\n if (!allMatch) {\n continue;\n }\n\n mp().Rokt.setLocalSessionAttribute?.(mappedAttributeKey, true);\n }\n }\n\n private capturePageView(event: SDKEvent): void {\n let pageUrl: string | undefined;\n\n try {\n pageUrl = sanitizeUrl(window.location.href);\n\n const pageViews = loadPageViews(this.loggingService);\n const pageView = buildPageEvent(event);\n pageViews.push(pageView);\n\n const requested = Math.min(pageViews.length, PAGE_VIEWS_MAX_COUNT);\n const stored = writePageViews(pageViews);\n if (stored === 0) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n this.loggingService?.log({\n message: `Rokt Kit: Failed to persist page view for ${pageUrl} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n } else if (stored < requested) {\n this.loggingService?.log({\n message: `Rokt Kit: Page view storage reduced from ${requested} to ${stored} record(s) under quota pressure [reason: quota_eviction]`,\n code: 'PAGE_VIEW_QUOTA_EVICTION',\n });\n }\n } catch (err) {\n const reason = isLocalStorageAvailable() ? 'exception' : 'ls_unavailable';\n const errMessage = err instanceof Error ? err.message : String(err);\n this.loggingService?.log({\n message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${errMessage} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n private isLauncherReadyToAttach(): boolean {\n return !!window.Rokt && isFunction(window.Rokt.createLauncher);\n }\n\n /**\n * Returns the user identities from the filtered user, if any.\n */\n private returnUserIdentities(filteredUser: FilteredUser | null | undefined): Record {\n if (!filteredUser || !filteredUser.getUserIdentities) {\n return {};\n }\n\n const userIdentities: IUserIdentities = filteredUser.getUserIdentities().userIdentities;\n\n return this.replaceOtherIdentityWithEmailsha256(userIdentities);\n }\n\n private returnLocalSessionAttributes(): Record {\n if (!mp().Rokt || typeof mp().Rokt.getLocalSessionAttributes !== 'function') {\n return {};\n }\n return mp().Rokt.getLocalSessionAttributes!();\n }\n\n private replaceOtherIdentityWithEmailsha256(userIdentities: IUserIdentities): Record {\n const newUserIdentities: Record = { ...(userIdentities || {}) };\n const key = this._mappedEmailSha256Key;\n if (key && userIdentities[key as keyof IUserIdentities]) {\n newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key as keyof IUserIdentities] as string;\n }\n if (key) {\n delete newUserIdentities[key];\n }\n\n return newUserIdentities;\n }\n\n private logSelectPlacementsEvent(attributes: unknown): void {\n if (!window.mParticle || typeof mp().logEvent !== 'function') {\n return;\n }\n\n if (!isObject(attributes)) {\n return;\n }\n\n const EVENT_TYPE_OTHER = mp().EventType.Other;\n\n mp().logEvent(EVENT_NAME_SELECT_PLACEMENTS, EVENT_TYPE_OTHER, attributes as Record);\n }\n\n private setRoktSessionId(sessionId: string): void {\n if (!sessionId || typeof sessionId !== 'string') {\n return;\n }\n try {\n const mpInstance = mp().getInstance();\n if (mpInstance && isFunction(mpInstance.setIntegrationAttribute)) {\n mpInstance.setIntegrationAttribute(moduleId, {\n roktSessionId: sessionId,\n });\n }\n } catch (_e) {\n // Best effort — never let this break the partner page\n }\n }\n\n private readMpSessionId(): string | undefined {\n // The public mParticle.sessionManager facade exposes only getSession(), which already returns\n // the session id. getSessionId() lives on the internal _SessionManager and has never been\n // re-exported, so prefer it if a future core adds it and fall back to getSession() until then.\n const sessionManager = mp()?.sessionManager;\n const readSessionId = sessionManager?.getSessionId ?? sessionManager?.getSession;\n if (!isFunction(readSessionId)) {\n return undefined;\n }\n\n return readSessionId.call(sessionManager) || undefined;\n }\n\n private readMpDeviceId(): string | undefined {\n // The device application stamp (`das`) outlives the session id: core clears the session on\n // timeout, cross-tab rotation and endSession(), but never the device id, which lives in\n // localStorage/cookie for cookieExpiration days (365 by default) and survives login/logout.\n // Read it per call anyway — a partner can reassign it at any time via setDeviceId().\n return mp()?.getDeviceId?.() || undefined;\n }\n\n private attachLauncher(\n accountId: string,\n launcherOptions: Record,\n legacyRoktExtensions: string[] = [],\n ): void {\n const options: Record = {\n accountId,\n ...(launcherOptions || {}),\n };\n\n let launcherPromise: Promise;\n if (this.isPartnerInLocalLauncherTestGroup()) {\n launcherPromise = Promise.resolve(window.Rokt!.createLocalLauncher(options));\n } else {\n launcherPromise = window.Rokt!.createLauncher(options);\n }\n\n launcherPromise\n .then(async (launcher) => {\n await registerLegacyExtensions(legacyRoktExtensions, launcher);\n this.initRoktLauncher(launcher);\n })\n .catch((err: unknown) => {\n console.error('Error creating Rokt launcher:', err);\n });\n }\n\n private initRoktLauncher(launcher: RoktLauncher): void {\n // Assign the launcher to a global variable for later access\n if (window.Rokt) {\n window.Rokt.currentLauncher = launcher;\n }\n // Locally cache the launcher and filters\n this.launcher = launcher;\n\n const roktFilters = mp().Rokt?.filters;\n\n if (!roktFilters) {\n console.warn('Rokt Kit: No filters have been set.');\n } else {\n this.filters = roktFilters;\n if (!roktFilters.filteredUser) {\n console.warn('Rokt Kit: No filtered user has been set.');\n } else {\n this._workspaceSearchInFlightPromise = this.search(roktFilters.filteredUser);\n }\n }\n\n // Kit must be initialized before attaching to the Rokt manager\n this.isInitialized = true;\n\n sendAdBlockMeasurementSignals(this.domain, this.integrationName);\n\n // Attaches the kit to the Rokt manager\n mp().Rokt.attachKit(this);\n }\n\n private fetchOptimizely(): Record {\n const forwarders = mp()\n ._getActiveForwarders()\n .filter((forwarder) => forwarder.name === 'Optimizely');\n\n try {\n if (forwarders.length > 0 && window.optimizely) {\n const optimizelyState = window.optimizely.get('state');\n if (!optimizelyState || !optimizelyState.getActiveExperimentIds) {\n return {};\n }\n const activeExperimentIds = optimizelyState.getActiveExperimentIds();\n const activeExperiments = activeExperimentIds.reduce((acc: Record, expId: string) => {\n acc['rokt.custom.optimizely.experiment.' + expId + '.variationId'] =\n optimizelyState.getVariationMap()[expId].id;\n return acc;\n }, {});\n return activeExperiments;\n }\n } catch (error) {\n console.error('Error fetching Optimizely attributes:', error);\n }\n return {};\n }\n\n private isKitReady(): boolean {\n return !!(this.isInitialized && this.launcher);\n }\n\n // When the partner has opted out of targeting (noTargeting launcher option),\n // the kit must not collect behavioral targeting signals such as page views.\n private isTargetingDisabled(): boolean {\n return (mp().Rokt?.launcherOptions as Record | undefined)?.noTargeting === true;\n }\n\n private isPartnerInLocalLauncherTestGroup(): boolean {\n return !!(mp().config && mp().config!.isLocalLauncherEnabled && this.isAssignedToSampleGroup());\n }\n\n private isAssignedToSampleGroup(): boolean {\n const LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5;\n return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD;\n }\n\n private captureTiming(metricName: string): void {\n if (window && mp() && mp().captureTiming && metricName) {\n mp().captureTiming!(metricName);\n }\n }\n\n // ---- Public methods (mParticle Kit Callbacks) ----\n\n /**\n * Initializes the Rokt forwarder with settings from the mParticle server.\n */\n public init(\n settings: Record,\n _service: unknown,\n testMode: boolean,\n _trackerId: unknown,\n filteredUserAttributes?: Record,\n ): string {\n const kitSettings = settings as unknown as RoktKitSettings;\n const accountId = kitSettings.accountId;\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredUserAttributes);\n this._onboardingExpProvider = kitSettings.onboardingExpProvider;\n\n const placementEventMapping = parseSettingsString(kitSettings.placementEventMapping);\n this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping);\n\n const placementEventAttributeMapping = parseSettingsString(\n kitSettings.placementEventAttributeMapping,\n );\n this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping);\n\n // Set dynamic OTHER_IDENTITY based on server settings\n if (kitSettings.hashedEmailUserIdentityType) {\n this._mappedEmailSha256Key = kitSettings.hashedEmailUserIdentityType.toLowerCase();\n }\n\n this._workspaceIdSyncApiKey = isString(kitSettings.workspaceIdSyncApiKey)\n ? kitSettings.workspaceIdSyncApiKey\n : undefined;\n\n const domain = mp().Rokt?.domain;\n const { roktExtensionsQueryParams, legacyRoktExtensions, loadThankYouElement } = extractRoktExtensionConfig(\n kitSettings.roktExtensions,\n );\n const launcherOptions: Record = {\n ...((mp().Rokt?.launcherOptions as Record) || {}),\n };\n this.integrationName = generateIntegrationName(launcherOptions.integrationName as string | undefined);\n launcherOptions.integrationName = this.integrationName;\n\n this.domain = domain;\n\n const reportingConfig: ReportingConfig = {\n loggingUrl: kitSettings.loggingUrl,\n errorUrl: kitSettings.errorUrl,\n integrationDomain: domain,\n isLoggingEnabled: mp().config?.isLoggingEnabled === true,\n };\n const errorReportingService = new ErrorReportingService(\n reportingConfig,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n const loggingService = new LoggingService(\n reportingConfig,\n errorReportingService,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n\n this.errorReportingService = errorReportingService;\n this.loggingService = loggingService;\n\n if (this.isTargetingDisabled()) {\n try {\n clearPageViews();\n clearUtmParams();\n } catch (err) {\n this.errorReportingService?.report({\n message: 'Rokt Kit: Failed to clear page views when targeting is disabled',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n severity: WSDKErrorSeverity.INFO,\n stackTrace: err instanceof Error ? err.stack : undefined,\n });\n }\n }\n\n if (mp()._registerErrorReportingService) {\n mp()._registerErrorReportingService!(errorReportingService);\n }\n if (mp()._registerLoggingService) {\n mp()._registerLoggingService!(loggingService);\n }\n\n if (testMode) {\n this.testHelpers = {\n generateLauncherScript: generateLauncherScript,\n generateThankYouElementScript: generateThankYouElementScript,\n extractRoktExtensionConfig: extractRoktExtensionConfig,\n hashEventMessage: hashEventMessage,\n parseSettingsString: parseSettingsString,\n generateMappedEventLookup: generateMappedEventLookup,\n generateMappedEventAttributeLookup: generateMappedEventAttributeLookup,\n sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals,\n createAutoRemovedIframe: createAutoRemovedIframe,\n djb2: djb2,\n setAllowedOriginHashes: (hashes: number[]) => {\n RoktKit._allowedOriginHashes = hashes;\n },\n ReportingTransport: ReportingTransport,\n ErrorReportingService: ErrorReportingService,\n LoggingService: LoggingService,\n RateLimiter: RateLimiter,\n ErrorCodes: ErrorCodes,\n WSDKErrorSeverity: WSDKErrorSeverity,\n };\n this.attachLauncher(accountId, launcherOptions);\n return 'Successfully initialized: ' + name;\n }\n\n if (loadThankYouElement) {\n mp().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this);\n loadRoktScript(ROKT_THANK_YOU_ELEMENT_SCRIPT_ID, generateThankYouElementScript(domain), {\n onLoad: () => {\n this._isThankYouElementLoaded = true;\n if (this._thankYouElementOnLoadCallback) {\n this._thankYouElementOnLoadCallback();\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt Thank You Element script:', error);\n },\n });\n }\n\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n loadRoktScript(ROKT_INTEGRATION_SCRIPT_ID, generateLauncherScript(domain, roktExtensionsQueryParams), {\n onLoad: () => {\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n console.error('Rokt object is not available after script load.');\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt launcher script:', error);\n },\n });\n\n this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended);\n }\n\n return 'Successfully initialized: ' + name;\n }\n\n public process(event: SDKEvent): string {\n if (!this.isTargetingDisabled()) {\n if (event.EventDataType === MESSAGE_TYPE_PAGE_VIEW) {\n captureUtmParams(this.loggingService);\n this.capturePageView(event);\n }\n\n if (event.EventDataType === MESSAGE_TYPE_SESSION_END) {\n migrateLegacyPageViewStorage(this.loggingService);\n clearPageViews();\n clearUtmParams();\n }\n }\n\n // The forwarding work below (LSA mapping) depends on the launcher, so guard\n // it here and surface the not-ready signal to the core SDK.\n if (!this.isKitReady()) {\n return 'Kit not ready for forwarder: ' + name;\n }\n\n if (isFunction(mp().Rokt?.setLocalSessionAttribute)) {\n if (!isEmpty(this.placementEventAttributeMappingLookup)) {\n this.applyPlacementEventAttributeMapping(event);\n }\n\n if (!isEmpty(this.placementEventMappingLookup)) {\n const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? '');\n if (this.placementEventMappingLookup[String(hashedEvent)]) {\n mp().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(hashedEvent)], true);\n }\n }\n }\n\n return 'Successfully sent to forwarder: ' + name;\n }\n\n public setExtensionData(partnerExtensionData: Record): void {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return;\n }\n\n window.Rokt!.setExtensionData(partnerExtensionData);\n }\n\n public setUserAttribute(key: string, value: unknown): string {\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n this.userAttributes[key] = value;\n }\n return 'Successfully set user attribute for forwarder: ' + name;\n }\n\n public removeUserAttribute(key: string): string {\n delete this.userAttributes[key];\n return 'Successfully removed user attribute for forwarder: ' + name;\n }\n\n private handleIdentityComplete(user: IMParticleUser, callbackName: string): string {\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(user.getAllUserAttributes());\n return 'Successfully called ' + callbackName + ' for forwarder: ' + name;\n }\n\n public onUserIdentified(user: IMParticleUser): string {\n const filteredUser = user as FilteredUser;\n this.filters.filteredUser = filteredUser;\n this._workspaceSearchInFlightPromise = this.search(filteredUser);\n return this.handleIdentityComplete(user, 'onUserIdentified');\n }\n\n private search(filteredUser: FilteredUser): Promise {\n const apiKey = this._workspaceIdSyncApiKey;\n if (!apiKey) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n const search = mp().Identity?.search;\n if (typeof search !== 'function') {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n const userIdentities: IUserIdentities | null = filteredUser.getUserIdentities\n ? filteredUser.getUserIdentities().userIdentities\n : null;\n\n // Forward every non-empty string identifier the user has — email,\n // customerid, other/other2-10 (commonly used for hashed email),\n // mobile_number, facebook, etc. The host SDK's Identity.search accepts\n // the full IUserIdentities surface and the server validates it.\n const knownIdentities: Record = {};\n if (userIdentities) {\n for (const key of Object.keys(userIdentities) as Array) {\n const value = userIdentities[key];\n if (isString(value) && value.length > 0) {\n knownIdentities[key] = value;\n }\n }\n }\n\n const identityKeys = Object.keys(knownIdentities);\n if (identityKeys.length === 0) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n // Stable cache key: sort keys so insertion-order differences don't\n // cause false misses. The values are partner-supplied strings; no\n // hashing needed — equality on this serialization is sufficient.\n const identitiesKey = identityKeys\n .sort()\n .map((k) => `${k}=${knownIdentities[k]}`)\n .join('&');\n\n // Same identifier set as the last successful dispatch → skip the\n // network call. The current flag value still reflects the correct\n // match status.\n if (identitiesKey === this._workspaceLastSearchedIdentitiesKey) {\n return this._workspaceSearchInFlightPromise || Promise.resolve();\n }\n\n // New / different identifier set → reset and re-search. Cache the key\n // up front so a second concurrent invocation with the same set also\n // dedupes.\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = identitiesKey;\n\n return new Promise((resolve) => {\n try {\n search(apiKey, knownIdentities as IUserIdentities, (result: WorkspaceIdSyncResult) => {\n if (result?.httpCode === 200) {\n this.userIdentifiedInWorkspace = true;\n }\n resolve();\n });\n } catch (err) {\n console.error('Rokt Kit: Workspace IDSync search failed', err);\n // Dispatch failed — clear the cache so the same identifier set\n // can retry on the next identification rather than being stuck\n // behind a poisoned entry that short-circuits future searches.\n this._workspaceLastSearchedIdentitiesKey = undefined;\n resolve();\n }\n });\n }\n\n public onLoginComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onLoginComplete');\n }\n\n public onLogoutComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n // Anonymous sessions must not carry the previous user's match forward.\n // Clear the flag explicitly here. Also clear the identities cache so a\n // re-login (possibly with the same identifiers) dispatches a fresh\n // search rather than reusing a stale answer.\n this.userIdentifiedInWorkspace = false;\n this._workspaceSearchInFlightPromise = null;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return this.handleIdentityComplete(user, 'onLogoutComplete');\n }\n\n public onModifyComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onModifyComplete');\n }\n\n /**\n * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options.\n *\n * If a Workspace IDSync search is in flight from a recent onUserIdentified\n * call, this method waits up to `WORKSPACE_SEARCH_SELECT_TIMEOUT_MS` for it\n * to settle so the first placement call can include the\n * `userIdentifiedInWorkspace` flag without racing the network response.\n * The timeout protects against a stalled or slow search blocking placement\n * rendering — if it fires, selectPlacements proceeds without the flag.\n *\n * Implementation note: this method stays non-async deliberately. First,\n * the public return type is `RoktSelection | Promise |\n * undefined` — a superset of the `RoktSelection | Promise`\n * shape declared for `RoktLauncher.selectPlacements` above (line ~70).\n * Marking this `async` would narrow it to `Promise` and silently change the contract for callers that read\n * the result synchronously. Second, `RoktSelection` has an optional\n * `then?` member, so TS treats it as ambiguously promise-like and\n * rejects it as the awaited return of an async function (TS1058) —\n * working around that would require a cast or wrapping every return in\n * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`;\n * this wrapper just gates it on the in-flight search via `Promise.race`.\n */\n public selectPlacements(options: Record): RoktSelection | Promise | undefined {\n if (this._workspaceSearchInFlightPromise) {\n const inFlight = this._workspaceSearchInFlightPromise;\n return Promise.race([\n inFlight,\n new Promise((resolve) => setTimeout(resolve, WORKSPACE_SEARCH_SELECT_TIMEOUT_MS)),\n ]).then(() => this._dispatchPlacements(options)) as Promise;\n }\n return this._dispatchPlacements(options);\n }\n\n private _dispatchPlacements(options: Record): RoktSelection | Promise | undefined {\n const attributes = ((options && (options.attributes as Record)) || {}) as Record;\n const cachedUserAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(this.userAttributes);\n const placementAttributes: Record = { ...cachedUserAttributes, ...attributes };\n\n const filters = this.filters || {};\n const userAttributeFilters = (filters.userAttributeFilters as string[]) || [];\n const filteredUser = filters.filteredUser || null;\n const mpid = filteredUser ? filteredUser.getMPID() : null;\n\n let filteredAttributes: Record;\n\n if (!filters) {\n console.warn('Rokt Kit: No filters available, using user attributes');\n filteredAttributes = placementAttributes;\n } else if (filters.filterUserAttributes) {\n filteredAttributes = filters.filterUserAttributes(placementAttributes, userAttributeFilters);\n } else {\n filteredAttributes = placementAttributes;\n }\n\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredAttributes);\n\n const optimizelyAttributes = this._onboardingExpProvider === 'Optimizely' ? this.fetchOptimizely() : {};\n\n const filteredUserIdentities = this.returnUserIdentities(filteredUser);\n\n const sessionAttributes = this.returnLocalSessionAttributes();\n const pageEvents = buildPageEvents(loadPageViews(this.loggingService));\n const utmParams = loadUtmParams();\n const mpSessionId = this.readMpSessionId();\n const mpDeviceId = this.readMpDeviceId();\n\n const selectPlacementsAttributes: Record = {\n ...(filteredUserIdentities as Record),\n ...filteredAttributes,\n ...optimizelyAttributes,\n ...sessionAttributes,\n ...(pageEvents.length ? { [PAGE_EVENTS_KEY]: JSON.stringify(pageEvents) } : {}),\n ...(utmParams ? { [PAGE_VIEW_ATTRIBUTES_KEY]: JSON.stringify(utmParams) } : {}),\n ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}),\n ...(mpSessionId ? { [MPARTICLE_SESSION_ID_KEY]: mpSessionId } : {}),\n ...(mpDeviceId ? { [MPARTICLE_DEVICE_ID_KEY]: mpDeviceId } : {}),\n mpid,\n };\n\n const selectPlacementsOptions: Record = { ...options, attributes: selectPlacementsAttributes };\n\n const selection = this.launcher!.selectPlacements(selectPlacementsOptions);\n\n // After selection resolves, sync the Rokt session ID back to mParticle, then log\n const logSelection = () => this.logSelectPlacementsEvent(selectPlacementsAttributes);\n\n void Promise.resolve(selection)\n .then((sel) => sel?.context?.sessionId?.then((sessionId) => this.setRoktSessionId(sessionId)))\n .catch(() => undefined)\n .finally(logSelection);\n\n return selection;\n }\n\n /**\n * Passes attributes to the Rokt Web SDK for client-side hashing.\n */\n public hashAttributes(attributes: Record): Promise> | null {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return null;\n }\n return this.launcher!.hashAttributes(attributes);\n }\n\n /**\n * Enables optional Integration Launcher extensions before selecting placements.\n *\n * @deprecated This functionality has been internalized and will be removed in a future release.\n */\n public use(extensionName: string): Promise {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return Promise.reject(new Error('Rokt Kit: Not initialized'));\n }\n if (!extensionName || !isString(extensionName)) {\n return Promise.reject(new Error('Rokt Kit: Invalid extension name'));\n }\n return this.launcher!.use(extensionName);\n }\n\n /**\n * Registers a callback to be invoked once rokt-thank-you-element.js becomes available.\n */\n public onShoppableAdsReady(callback: () => void) {\n if (this._isThankYouElementLoaded) {\n callback();\n } else {\n this._thankYouElementOnLoadCallback = callback;\n }\n }\n}\n\n// ============================================================\n// Kit registration\n// ============================================================\n\nfunction getId(): number {\n return moduleId;\n}\n\nfunction register(config: { kits?: Record }): void {\n if (!config) {\n window.console.log('You must pass a config object to register the kit ' + name);\n return;\n }\n if (!isObject(config)) {\n window.console.log(\"'config' must be an object. You passed in a \" + typeof config);\n return;\n }\n\n if (isObject(config.kits)) {\n (config.kits as Record)[name] = {\n constructor: RoktKit,\n };\n } else {\n config.kits = {};\n config.kits[name] = {\n constructor: RoktKit,\n };\n }\n window.console.log('Successfully registered ' + name + ' to your mParticle configuration');\n}\n\nif (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) {\n mp().addForwarder({\n name: name,\n constructor: RoktKit,\n getId: getId,\n });\n}\n\nexport { register };\nexport type { LoggingService };\n"],"names":["SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST","SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET","isSelectPlacementsAttributePersistenceDenied","key","removeSelectPlacementsAttributePersistenceDeniedAttributes","attributes","filteredAttributes","sourceAttributes","attributeKeys","i","isObject","value","isString","isFunction","isEmpty","sanitizeUrl","href","url","LS_PROBE_KEY","isLocalStorageAvailable","readJSON","stored","writeJSON","removeKey","readNamespacedField","namespaceKey","field","blob","writeNamespacedField","next","removeNamespacedField","LS_NAMESPACE_KEY","LS_PAGE_VIEWS_FIELD","LS_UTM_PARAMS_FIELD","LEGACY_PAGE_VIEWS_KEY","PAGE_VIEWS_MAX_COUNT","UTM_KEYS","capPageViews","views","migrateLegacyPageViewStorage","loggingService","legacyViews","loadPageViews","writePageViews","pageViews","toWrite","clearPageViews","buildPageEvents","pageView","index","activeTimeOnSite","hasActiveTime","nextActiveTimeOnSite","hasNextActiveTimeOnSite","diff","captureUtmParams","search","params","captured","reason","loadUtmParams","clearUtmParams","readCanonicalUrl","name","moduleId","EVENT_NAME_SELECT_PLACEMENTS","ADBLOCK_CONTROL_DOMAIN","INIT_LOG_SAMPLING_RATE","ROKT_THANK_YOU_JOURNEY_EXTENSION","ROKT_INTEGRATION_SCRIPT_ID","ROKT_THANK_YOU_ELEMENT_SCRIPT_ID","USER_IDENTIFIED_IN_WORKSPACE_KEY","MESSAGE_TYPE_PAGE_VIEW","MESSAGE_TYPE_SESSION_END","PAGE_EVENTS_KEY","PAGE_VIEW_ATTRIBUTES_KEY","MPARTICLE_SESSION_ID_KEY","MPARTICLE_DEVICE_ID_KEY","WORKSPACE_SEARCH_SELECT_TIMEOUT_MS","ErrorCodes","WSDKErrorSeverity","DEFAULT_ROKT_DOMAIN","LOGGING_ENDPOINT","ERROR_ENDPOINT","RATE_LIMIT_PER_SEVERITY","mp","generateLauncherScript","domain","extensions","baseUrl","generateBaseUrl","generateThankYouElementScript","resolvedDomain","generateReportingUrl","configuredUrl","endpoint","reportingDomain","loadRoktScript","scriptId","source","handlers","target","script","parseSettingsString","settingsString","extractRoktExtensionConfig","settings","roktExtensionsQueryParams","legacyRoktExtensions","loadThankYouElement","extensionName","registerLegacyExtensions","legacyExtensions","launcher","extension","generateMappedEventLookup","placementEventMapping","mappedEvents","mapping","generateMappedEventAttributeLookup","placementEventAttributeMapping","mappedAttributeKeys","mappedAttributeKey","eventAttributeKey","hashEventMessage","messageType","eventType","eventName","generateIntegrationName","customIntegrationName","integrationName","djb2","str","hash","createAutoRemovedIframe","src","iframe","sendAdBlockMeasurementSignals","version","originHash","RoktKit","guid","pageUrl","existingBaseUrl","_isDebugModeEnabled","_getReportingUrl","_getUserAgent","RateLimiter","severity","newCount","ReportingTransport","config","launcherInstanceGuid","accountId","rateLimiter","isLoggingEnabled","msg","code","stackTrace","onError","logRequest","headers","response","serverError","error","ErrorReportingService","LoggingService","errorReportingService","entry","isServerSide","buildPageEvent","event","pageTitle","canonicalUrl","_RoktKit","condition","actualValue","operator","expectedValue","rule","conditions","rulesForMappedAttributeKey","allMatch","j","requested","err","errMessage","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","sessionManager","readSessionId","launcherOptions","options","launcherPromise","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","sessionAttributes","pageEvents","utmParams","mpSessionId","mpDeviceId","selectPlacementsAttributes","selectPlacementsOptions","selection","logSelection","sel","callback","getId","register"],"mappings":"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"} \ No newline at end of file diff --git a/kits/rokt/dist/Rokt-Kit.esm.js b/kits/rokt/dist/Rokt-Kit.esm.js index 128fd8ce7..d351185ec 100644 --- a/kits/rokt/dist/Rokt-Kit.esm.js +++ b/kits/rokt/dist/Rokt-Kit.esm.js @@ -763,7 +763,7 @@ const m = class m { ...g, ...v, ...w.length ? { [Me]: JSON.stringify(w) } : {}, - ...f ? { [Ke]: f } : {}, + ...f ? { [Ke]: JSON.stringify(f) } : {}, ...this.userIdentifiedInWorkspace ? { [Ne]: !0 } : {}, ...A ? { [De]: A } : {}, ...I ? { [Fe]: I } : {}, diff --git a/kits/rokt/dist/Rokt-Kit.esm.js.map b/kits/rokt/dist/Rokt-Kit.esm.js.map index 524e8047a..50feb4c44 100644 --- a/kits/rokt/dist/Rokt-Kit.esm.js.map +++ b/kits/rokt/dist/Rokt-Kit.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"Rokt-Kit.esm.js","sources":["../src/selectPlacementsAttributePersistence.ts","../src/utils.ts","../src/storage.ts","../src/pageViewStorage.ts","../src/Rokt-Kit.ts"],"sourcesContent":["const SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST = [\n 'active_time_on_site_ms',\n 'billingaddress1',\n 'billingaddress2',\n 'billingcity',\n 'billingstate',\n 'billingzipcode',\n 'cartitems',\n 'ccbin',\n 'confirmationref',\n 'conversiontype',\n 'country',\n 'couponcode',\n 'currency',\n 'language',\n 'paymentserviceprovider',\n 'paymentserviceproviderattribute',\n 'paymenttype',\n 'shippingaddress1',\n 'shippingcity',\n 'shippingcountry',\n 'shippingmethod',\n 'shippingstate',\n 'shippingzipcode',\n 'totalprice',\n];\nconst SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET = new Set(SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST);\n\nexport function isSelectPlacementsAttributePersistenceDenied(key: string): boolean {\n return SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET.has(key.toLowerCase());\n}\n\nexport function removeSelectPlacementsAttributePersistenceDeniedAttributes(\n attributes: Record | null | undefined,\n): Record {\n const filteredAttributes: Record = {};\n const sourceAttributes = attributes || {};\n const attributeKeys = Object.keys(sourceAttributes);\n\n for (let i = 0; i < attributeKeys.length; i++) {\n const key = attributeKeys[i];\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n filteredAttributes[key] = sourceAttributes[key];\n }\n }\n\n return filteredAttributes;\n}\n","export function isObject(value: unknown): value is Record {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nexport function isFunction(value: unknown): value is (...args: Array) => unknown {\n return typeof value === 'function';\n}\n\nexport function isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'object') {\n return Object.keys(value as object).length === 0;\n }\n return false;\n}\n\n// Strips the query string from a URL before it is persisted and sent to Rokt,\n// since query params commonly carry PII (emails, tokens, order refs).\n// Returns the input unchanged if it can't be parsed as a URL.\nexport function sanitizeUrl(href: string): string {\n try {\n const url = new URL(href);\n url.search = '';\n return url.toString();\n } catch {\n return href;\n }\n}\n","import { isObject } from './utils';\n\nconst LS_PROBE_KEY = '__rokt_ls_probe__';\n\nexport function isLocalStorageAvailable(): boolean {\n try {\n window.localStorage.setItem(LS_PROBE_KEY, '1');\n window.localStorage.removeItem(LS_PROBE_KEY);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function readJSON(key: string): unknown {\n try {\n const stored = window.localStorage.getItem(key);\n return stored === null ? null : JSON.parse(stored);\n } catch {\n return null;\n }\n}\n\nexport function writeJSON(key: string, value: unknown): boolean {\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n return true;\n } catch {\n return false;\n }\n}\n\nexport function removeKey(key: string): void {\n try {\n window.localStorage.removeItem(key);\n } catch {\n /* empty */\n }\n}\n\nexport function readNamespacedField(namespaceKey: string, field: string): unknown {\n const blob = readJSON(namespaceKey);\n return isObject(blob) ? blob[field] : undefined;\n}\n\nexport function writeNamespacedField(namespaceKey: string, field: string, value: unknown): boolean {\n const blob = readJSON(namespaceKey);\n const next = isObject(blob) ? { ...blob } : {};\n next[field] = value;\n return writeJSON(namespaceKey, next);\n}\n\nexport function removeNamespacedField(namespaceKey: string, field: string): void {\n const blob = readJSON(namespaceKey);\n if (!isObject(blob) || !(field in blob)) {\n return;\n }\n const next = { ...blob };\n delete next[field];\n if (Object.keys(next).length === 0) {\n removeKey(namespaceKey);\n } else {\n writeJSON(namespaceKey, next);\n }\n}\n","import type { LoggingService } from './Rokt-Kit';\nimport {\n readJSON,\n removeKey,\n readNamespacedField,\n writeNamespacedField,\n removeNamespacedField,\n isLocalStorageAvailable,\n} from './storage';\nimport { sanitizeUrl, isObject } from './utils';\n\nconst LS_NAMESPACE_KEY = 'mp-rokt-kit';\nconst LS_PAGE_VIEWS_FIELD = 'pageViews';\nconst LS_UTM_PARAMS_FIELD = 'utmParams';\nconst LEGACY_PAGE_VIEWS_KEY = 'mpPageViews';\nexport const PAGE_VIEWS_MAX_COUNT = 25;\n\nconst UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'] as const;\ntype UtmKey = (typeof UTM_KEYS)[number];\nexport type UtmParams = Partial>;\n\nexport interface PageEvent {\n pageUrl: string;\n sourceMessageId: string;\n timestamp: number;\n pageTitle?: string;\n canonicalUrl?: string;\n activeTimeOnSite?: number;\n activeTimeOnPage?: number;\n}\n\nfunction capPageViews(views: PageEvent[]): PageEvent[] {\n return views.slice(-PAGE_VIEWS_MAX_COUNT);\n}\n\nexport function migrateLegacyPageViewStorage(loggingService: LoggingService | null): void {\n const legacyViews = readJSON(LEGACY_PAGE_VIEWS_KEY);\n if (legacyViews === null) {\n return;\n }\n\n const alreadyMigrated = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD) !== undefined;\n const needsMigration = !alreadyMigrated && Array.isArray(legacyViews);\n\n if (needsMigration) {\n loggingService?.log({\n message: 'Rokt Kit: Migrating legacy page-view storage',\n code: 'PAGE_VIEW_LEGACY_MIGRATION',\n });\n const migrated = writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, legacyViews);\n if (!migrated) {\n loggingService?.log({\n message: 'Rokt Kit: Failed to migrate legacy page-view storage [reason: migration_retry]',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n removeKey(LEGACY_PAGE_VIEWS_KEY);\n}\n\nexport function loadPageViews(loggingService: LoggingService | null): PageEvent[] {\n migrateLegacyPageViewStorage(loggingService);\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n return Array.isArray(stored) ? (stored as PageEvent[]) : [];\n}\n\nexport function writePageViews(pageViews: PageEvent[]): number {\n const views = capPageViews(pageViews);\n for (let i = 0; i < views.length; i++) {\n const toWrite = views.slice(i);\n if (writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, toWrite)) {\n return toWrite.length;\n }\n }\n return 0;\n}\n\nexport function clearPageViews(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n}\n\nexport function buildPageEvents(pageViews: PageEvent[]): PageEvent[] {\n const views = capPageViews(pageViews);\n return views.map((pageView, index) => {\n const activeTimeOnSite = pageView.activeTimeOnSite;\n const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite);\n\n const next = views[index + 1];\n const nextActiveTimeOnSite = next?.activeTimeOnSite;\n const hasNextActiveTimeOnSite = nextActiveTimeOnSite !== undefined && Number.isFinite(nextActiveTimeOnSite);\n\n const diff = hasActiveTime && hasNextActiveTimeOnSite ? nextActiveTimeOnSite - activeTimeOnSite : undefined;\n\n return {\n pageUrl: pageView.pageUrl,\n sourceMessageId: pageView.sourceMessageId,\n timestamp: pageView.timestamp,\n ...(pageView.pageTitle !== undefined ? { pageTitle: pageView.pageTitle } : {}),\n ...(pageView.canonicalUrl !== undefined ? { canonicalUrl: pageView.canonicalUrl } : {}),\n ...(hasActiveTime ? { activeTimeOnSite } : {}),\n ...(diff !== undefined && diff >= 0 ? { activeTimeOnPage: diff } : {}),\n };\n });\n}\n\nexport function captureUtmParams(loggingService: LoggingService | null): void {\n if (readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD) !== undefined) {\n return;\n }\n const search = new URLSearchParams(window.location.search);\n const params: UtmParams = {};\n for (const key of UTM_KEYS) {\n const value = search.get(key);\n if (value) params[key] = value;\n }\n if (Object.keys(params).length === 0) {\n return;\n }\n const captured = Object.keys(params).join(', ');\n if (!writeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD, params)) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n loggingService?.log({\n message: `Rokt Kit: Failed to persist UTM params [reason: ${reason}]`,\n code: 'UTM_CAPTURE_FAILED',\n });\n return;\n }\n loggingService?.log({\n message: `Rokt Kit: Captured UTM params [${captured}]`,\n code: 'UTM_CAPTURE_SUCCESS',\n });\n}\n\nexport function loadUtmParams(): UtmParams | null {\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n return isObject(stored) ? (stored as UtmParams) : null;\n}\n\nexport function clearUtmParams(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n}\n\nexport function readCanonicalUrl(): string | undefined {\n const link = document.querySelector('link[rel=\"canonical\"]');\n const href = link?.href;\n if (!href) {\n return undefined;\n }\n return sanitizeUrl(href);\n}\n","// Copyright 2025 mParticle, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// ============================================================\n// Types\n// ============================================================\n\nimport { KitInterface, IMParticleUser, SDKEvent } from '@mparticle/web-sdk/internal';\nimport type { IUserIdentities } from '@mparticle/web-sdk';\n\nimport {\n isSelectPlacementsAttributePersistenceDenied,\n removeSelectPlacementsAttributePersistenceDeniedAttributes,\n} from './selectPlacementsAttributePersistence';\n\nimport {\n PageEvent,\n PAGE_VIEWS_MAX_COUNT,\n buildPageEvents,\n migrateLegacyPageViewStorage,\n loadPageViews,\n writePageViews,\n clearPageViews,\n readCanonicalUrl,\n captureUtmParams,\n loadUtmParams,\n clearUtmParams,\n} from './pageViewStorage';\nimport { isLocalStorageAvailable } from './storage';\n\nimport { isObject, isString, isEmpty, isFunction, sanitizeUrl } from './utils';\n\ninterface RoktKitSettings {\n accountId: string;\n roktExtensions?: string;\n placementEventMapping?: string;\n placementEventAttributeMapping?: string;\n hashedEmailUserIdentityType?: string;\n onboardingExpProvider?: string;\n loggingUrl?: string;\n errorUrl?: string;\n workspaceIdSyncApiKey?: string;\n}\n\ninterface EventAttributeCondition {\n operator: string;\n attributeValue: string;\n}\n\ninterface PlacementEventRule {\n eventAttributeKey: string;\n conditions: EventAttributeCondition[];\n}\n\ninterface EventAttributeMapping {\n value: string;\n map: string;\n conditions?: EventAttributeCondition[];\n}\n\ninterface PlacementEventMappingEntry {\n jsmap: string;\n value: string;\n}\n\ninterface RoktExtensionEntry {\n value: string;\n}\n\ninterface RoktSelection {\n context?: {\n sessionId?: Promise;\n };\n then?: (callback: (sel: RoktSelection) => void) => Promise;\n catch?: (callback: () => void) => void;\n}\n\ninterface RoktLauncher {\n selectPlacements(options: Record): RoktSelection | Promise;\n hashAttributes(attributes: Record): Promise>;\n use(extensionName: string): Promise;\n}\n\ninterface RoktGlobal {\n createLauncher(options: Record): Promise;\n createLocalLauncher(options: Record): RoktLauncher;\n currentLauncher?: RoktLauncher;\n setExtensionData(data: Record): void;\n}\n\n// FilteredUser is the IMParticleUser shape we receive after kit filtering.\n// `getMPID` and `getUserIdentities` are inherited from the SDK's `User` base type.\ntype FilteredUser = IMParticleUser;\n\n// TODO: Replace with `IIdentitySearchResult` from `@mparticle/web-sdk` once\n// a version that exports it is published (currently on a feature branch in\n// mParticle/mparticle-web-sdk PR #1255). The shape below is intentionally\n// structurally identical so the swap is a one-line import change.\ninterface WorkspaceIdSyncResult {\n httpCode: number;\n body?: {\n context?: string | null;\n mpid?: string;\n matched_identities?: Record;\n is_ephemeral?: boolean;\n is_logged_in?: boolean;\n };\n}\n\n// TODO: Replace with `IdentitySearchCallback`-compatible reference from\n// `@mparticle/web-sdk` once published (mirrors `SDKIdentityApi.search`).\ntype WorkspaceIdSyncSearcher = (\n apiKey: string,\n knownIdentities: IUserIdentities,\n callback: (result: WorkspaceIdSyncResult) => void,\n) => void;\n\ninterface KitFilters {\n userAttributeFilters?: string[];\n filterUserAttributes?: (attributes: Record, filters?: string[]) => Record;\n filteredUser?: FilteredUser | null;\n}\n\ninterface RoktManager {\n attachKit(kit: RoktKit): void | Promise;\n flushOnShoppableAdsReadyMessageQueue?(kit: RoktKit): void;\n filters?: KitFilters;\n domain?: string;\n launcherOptions?: Record;\n getLocalSessionAttributes?(): Record;\n setLocalSessionAttribute?(key: string, value: unknown): void;\n}\n\ninterface MParticleInstance {\n setIntegrationAttribute(moduleId: number, attrs: Record): void;\n}\n\ninterface OptimizelyState {\n getActiveExperimentIds(): string[];\n getVariationMap(): Record;\n}\n\ninterface OptimizelyGlobal {\n get(key: 'state'): OptimizelyState;\n}\n\n// Our view of the mParticle global with Rokt-specific extensions.\n// We access window.mParticle via an explicit cast (see `mp()` helper below)\n// rather than augmenting Window to avoid conflicts with @mparticle/web-sdk declarations.\ninterface MParticleExtended {\n Rokt: RoktManager;\n addForwarder(config: ForwarderRegistration): void;\n getVersion(): string;\n generateHash(value: string): string | number;\n logEvent(name: string, type: number, attrs?: Record): void;\n EventType: { Other: number };\n getInstance(): MParticleInstance;\n getDeviceId?(): string;\n sessionManager?: { getSession?(): string; getSessionId?(): string };\n _getActiveForwarders(): Array<{ name: string }>;\n config?: { isLocalLauncherEnabled?: boolean; isLoggingEnabled?: boolean };\n captureTiming?(metricName: string): void;\n forwarder?: RoktKit;\n loggedEvents?: Array>;\n _registerErrorReportingService?(service: ErrorReportingService): void;\n _registerLoggingService?(service: LoggingService): void;\n Identity?: { search?: WorkspaceIdSyncSearcher };\n}\n\ninterface TestHelpers {\n generateLauncherScript: (domain: string | undefined, extensions: string[]) => string;\n generateThankYouElementScript: (domain: string | undefined) => string;\n extractRoktExtensionConfig: (settingsString?: string) => RoktExtensionConfig;\n hashEventMessage: (messageType: number, eventType: number, eventName: string) => string | number;\n parseSettingsString: (settingsString?: string) => T[];\n generateMappedEventLookup: (placementEventMapping: PlacementEventMappingEntry[]) => Record;\n generateMappedEventAttributeLookup: (mapping: EventAttributeMapping[]) => Record;\n sendAdBlockMeasurementSignals: (domain: string | undefined, version: string | null) => void;\n createAutoRemovedIframe: (src: string) => void;\n djb2: (str: string) => number;\n setAllowedOriginHashes: (hashes: number[]) => void;\n ReportingTransport: typeof ReportingTransport;\n ErrorReportingService: typeof ErrorReportingService;\n LoggingService: typeof LoggingService;\n RateLimiter: typeof RateLimiter;\n ErrorCodes: typeof ErrorCodes;\n WSDKErrorSeverity: typeof WSDKErrorSeverity;\n}\n\ninterface ForwarderRegistration {\n name: string;\n constructor: new () => RoktKit;\n getId: () => number;\n}\n\ninterface ReportingConfig {\n loggingUrl?: string;\n errorUrl?: string;\n integrationDomain?: string;\n isLoggingEnabled: boolean;\n}\n\ninterface ErrorReport {\n message: string;\n code?: string;\n severity?: string;\n stackTrace?: string;\n}\n\n// A log-delivery failure. statusCode is set when the request reached the server\n// and returned a non-2xx status (server-side); it is absent for network-level\n// failures such as ad-blockers, offline, or CORS rejections (client-side).\ninterface DeliveryError extends Error {\n statusCode?: number;\n}\n\ninterface LogEntry {\n message: string;\n code?: string;\n}\n\ninterface RoktExtensionConfig {\n roktExtensionsQueryParams: string[];\n legacyRoktExtensions: string[];\n loadThankYouElement: boolean;\n}\n\ndeclare global {\n interface Window {\n Rokt?: RoktGlobal;\n __rokt_li_guid__?: string;\n optimizely?: OptimizelyGlobal;\n // mParticle is declared as any to avoid conflicts with @mparticle/web-sdk type declarations.\n // We use the typed mp() accessor for all internal accesses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mParticle: any;\n }\n}\n\n// ============================================================\n// Module-level constants\n// ============================================================\n\nconst name = 'Rokt';\nconst moduleId = 181;\nconst EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements';\nconst ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com';\nconst INIT_LOG_SAMPLING_RATE = 0.1;\nconst ROKT_THANK_YOU_JOURNEY_EXTENSION = 'ThankYouPageJourney';\nconst ROKT_INTEGRATION_SCRIPT_ID = 'rokt-launcher';\nconst ROKT_THANK_YOU_ELEMENT_SCRIPT_ID = 'rokt-thank-you-element';\nconst USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace';\n\nconst MESSAGE_TYPE_PAGE_VIEW = 3; // mParticle MessageType.PageView\nconst MESSAGE_TYPE_SESSION_END = 2; // mParticle MessageType.SessionEnd\nconst PAGE_EVENTS_KEY = 'page_events';\nconst PAGE_VIEW_ATTRIBUTES_KEY = 'page_view_attributes';\nconst MPARTICLE_SESSION_ID_KEY = 'mparticle_session_id';\nconst MPARTICLE_DEVICE_ID_KEY = 'mparticle_device_id';\n\n// Bound on how long selectPlacements will wait for an in-flight Workspace\n// IDSync search before proceeding without the userIdentifiedInWorkspace flag.\n// Long enough to cover the typical /v1/search round-trip (~50ms); short enough that a\n// stalled search never blocks placement rendering on a thank-you page.\nconst WORKSPACE_SEARCH_SELECT_TIMEOUT_MS = 500;\n\n// ============================================================\n// Reporting service constants\n// ============================================================\n\nconst ErrorCodes = {\n UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION',\n IDENTITY_REQUEST: 'IDENTITY_REQUEST',\n LOG_DELIVERY_FAILURE: 'LOG_DELIVERY_FAILURE',\n} as const;\n\nconst WSDKErrorSeverity = {\n ERROR: 'ERROR',\n INFO: 'INFO',\n WARNING: 'WARNING',\n} as const;\n\nconst DEFAULT_ROKT_DOMAIN = 'apps.rokt-api.com';\nconst LOGGING_ENDPOINT = '/v1/log';\nconst ERROR_ENDPOINT = '/v1/errors';\nconst RATE_LIMIT_PER_SEVERITY = 10;\n\n// ============================================================\n// Helper: typed accessor for window.mParticle\n// We use an explicit cast here to avoid conflicts with @mparticle/web-sdk\n// type declarations while still providing full type safety for our usages.\n// ============================================================\n\nfunction mp(): MParticleExtended {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (window as any).mParticle as MParticleExtended;\n}\n\n// ============================================================\n// Module-level utility functions\n// ============================================================\n\nfunction generateLauncherScript(domain: string | undefined, extensions: string[]): string {\n const launcherPath = '/wsdk/integrations/launcher.js';\n const baseUrl = [generateBaseUrl(domain), launcherPath].join('');\n\n if (!extensions || extensions.length === 0) {\n return baseUrl;\n }\n return baseUrl + '?extensions=' + extensions.join(',');\n}\n\nfunction generateThankYouElementScript(domain: string | undefined) {\n const thankYouElementPath = '/rokt-elements/rokt-element-thank-you.js';\n return [generateBaseUrl(domain), thankYouElementPath].join('');\n}\n\nfunction generateBaseUrl(domain: string | undefined) {\n const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN;\n\n if (resolvedDomain.includes('://')) {\n return resolvedDomain.replace(/\\/+$/, '');\n }\n\n const protocol = 'https://';\n\n return [protocol, resolvedDomain].join('');\n}\n\nfunction generateReportingUrl(configuredUrl: string | undefined, domain: string | undefined, endpoint: string): string {\n if (configuredUrl) {\n if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://')) {\n return configuredUrl;\n }\n return 'https://' + configuredUrl;\n }\n\n const hasNonHttpScheme = domain?.includes('://') && !/^https?:\\/\\//i.test(domain);\n const reportingDomain = hasNonHttpScheme ? undefined : domain;\n\n return generateBaseUrl(reportingDomain) + endpoint;\n}\n\nfunction loadRoktScript(\n scriptId: string,\n source: string,\n handlers?: { onLoad?: () => void; onError?: (e: Event | string) => void },\n): void {\n if (document.getElementById(scriptId)) return; // resolves the preexisting script issue\n\n const target = document.head || document.body;\n const script = document.createElement('script');\n script.id = scriptId;\n script.type = 'text/javascript';\n script.src = source;\n script.async = true;\n script.crossOrigin = 'anonymous';\n (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high';\n if (handlers?.onLoad) script.onload = handlers.onLoad;\n if (handlers?.onError) script.onerror = handlers.onError;\n target.appendChild(script);\n}\n\nfunction parseSettingsString(settingsString?: string): T[] {\n if (!settingsString) {\n return [];\n }\n try {\n return JSON.parse(settingsString.replace(/"/g, '\"')) as T[];\n } catch (_error) {\n console.error('Settings string contains invalid JSON');\n }\n return [];\n}\n\nfunction extractRoktExtensionConfig(settingsString?: string): RoktExtensionConfig {\n const settings = settingsString ? parseSettingsString(settingsString) : [];\n const roktExtensionsQueryParams: string[] = [];\n const legacyRoktExtensions: string[] = [];\n let loadThankYouElement = false;\n\n for (let i = 0; i < settings.length; i++) {\n const extensionName = settings[i].value;\n if (extensionName === 'thank-you-journey') {\n loadThankYouElement = true;\n legacyRoktExtensions.push(ROKT_THANK_YOU_JOURNEY_EXTENSION);\n } else {\n roktExtensionsQueryParams.push(extensionName);\n }\n }\n\n return {\n roktExtensionsQueryParams,\n legacyRoktExtensions,\n loadThankYouElement,\n };\n}\n\nasync function registerLegacyExtensions(legacyExtensions: string[], launcher: RoktLauncher | null) {\n const extensions: Promise[] = [];\n if (launcher) {\n for (const extension of legacyExtensions) {\n extensions.push(launcher.use(extension));\n }\n }\n\n return Promise.all(extensions);\n}\n\nfunction generateMappedEventLookup(placementEventMapping: PlacementEventMappingEntry[]): Record {\n if (!placementEventMapping) {\n return {};\n }\n\n const mappedEvents: Record = {};\n for (let i = 0; i < placementEventMapping.length; i++) {\n const mapping = placementEventMapping[i];\n mappedEvents[mapping.jsmap] = mapping.value;\n }\n return mappedEvents;\n}\n\nfunction generateMappedEventAttributeLookup(\n placementEventAttributeMapping: EventAttributeMapping[],\n): Record {\n const mappedAttributeKeys: Record = {};\n if (!Array.isArray(placementEventAttributeMapping)) {\n return mappedAttributeKeys;\n }\n for (let i = 0; i < placementEventAttributeMapping.length; i++) {\n const mapping = placementEventAttributeMapping[i];\n if (!mapping || !isString(mapping.value) || !isString(mapping.map)) {\n continue;\n }\n\n const mappedAttributeKey = mapping.value;\n const eventAttributeKey = mapping.map;\n\n if (!mappedAttributeKeys[mappedAttributeKey]) {\n mappedAttributeKeys[mappedAttributeKey] = [];\n }\n\n mappedAttributeKeys[mappedAttributeKey].push({\n eventAttributeKey: eventAttributeKey,\n conditions: Array.isArray(mapping.conditions) ? mapping.conditions : [],\n });\n }\n return mappedAttributeKeys;\n}\n\nfunction hashEventMessage(messageType: number, eventType: number, eventName: string): string | number {\n return mp().generateHash([messageType, eventType, eventName].join(''));\n}\n\nfunction generateIntegrationName(customIntegrationName?: string): string {\n const coreSdkVersion = mp().getVersion();\n const kitVersion = process.env.PACKAGE_VERSION;\n let integrationName = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion;\n\n if (customIntegrationName) {\n integrationName += '_' + customIntegrationName;\n }\n return integrationName;\n}\n\nfunction djb2(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return hash;\n}\n\nfunction createAutoRemovedIframe(src: string): void {\n const iframe = document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');\n iframe.src = src;\n iframe.onload = function () {\n iframe.onload = null;\n if (iframe.parentNode) {\n iframe.parentNode.removeChild(iframe);\n }\n };\n const target = document.body || document.head;\n if (target) {\n target.appendChild(iframe);\n }\n}\n\nfunction sendAdBlockMeasurementSignals(domain: string | undefined, version: string | null): void {\n const originHash = djb2(window.location.origin);\n const allowedOriginHashes = RoktKit._allowedOriginHashes;\n if (allowedOriginHashes.indexOf(originHash) === -1) {\n return;\n }\n\n if (Math.random() >= INIT_LOG_SAMPLING_RATE) {\n return;\n }\n\n const guid = window.__rokt_li_guid__;\n if (!guid) {\n return;\n }\n\n if (domain && domain.includes('://') && !/^https:\\/\\//i.test(domain)) {\n return;\n }\n\n const pageUrl = window.location.href.split('?')[0].split('#')[0];\n const params =\n 'version=' +\n encodeURIComponent(version ?? '') +\n '&launcherInstanceGuid=' +\n encodeURIComponent(guid) +\n '&pageUrl=' +\n encodeURIComponent(pageUrl);\n\n const existingBaseUrl = domain ? generateBaseUrl(domain) : 'https://apps.rokt.com';\n createAutoRemovedIframe(existingBaseUrl + '/v1/wsdk-init/index.html?' + params);\n\n createAutoRemovedIframe(\n 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true',\n );\n}\n\n// ============================================================\n// Reporting helpers\n// ============================================================\n\nfunction _isDebugModeEnabled(): boolean {\n return typeof window !== 'undefined' && !!window.location?.search?.toLowerCase().includes('mp_enable_logging=true');\n}\n\nfunction _getReportingUrl(): string | undefined {\n return typeof window !== 'undefined' ? window.location?.href : undefined;\n}\n\nfunction _getUserAgent(): string | undefined {\n return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined;\n}\n\nclass RateLimiter {\n private _logCount: Record = {};\n\n incrementAndCheck(severity: string): boolean {\n const count = this._logCount[severity] || 0;\n const newCount = count + 1;\n this._logCount[severity] = newCount;\n return newCount > RATE_LIMIT_PER_SEVERITY;\n }\n}\n\nclass ReportingTransport {\n private _isEnabled: boolean;\n private _integrationName: string;\n private _launcherInstanceGuid: string | undefined;\n private _accountId: string | null;\n private _rateLimiter: RateLimiter;\n private readonly _reporter = 'mp-wsdk';\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid: string | undefined,\n accountId: string | null | undefined,\n rateLimiter?: RateLimiter,\n ) {\n const isLoggingEnabled = config.isLoggingEnabled;\n this._integrationName = integrationName || '';\n this._launcherInstanceGuid = launcherInstanceGuid;\n this._accountId = accountId || null;\n this._rateLimiter = rateLimiter || new RateLimiter();\n this._isEnabled = _isDebugModeEnabled() || isLoggingEnabled;\n }\n\n send(\n url: string,\n severity: string,\n msg: string,\n code?: string,\n stackTrace?: string,\n onError?: (error: DeliveryError) => void,\n ): void {\n if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) {\n return;\n }\n\n try {\n const logRequest = {\n additionalInformation: {\n message: msg,\n version: this._integrationName,\n },\n severity,\n code: code || ErrorCodes.UNKNOWN_ERROR,\n url: _getReportingUrl(),\n deviceInfo: _getUserAgent(),\n stackTrace,\n reporter: this._reporter,\n integration: this._integrationName,\n };\n\n const headers: Record = {\n Accept: 'text/plain;charset=UTF-8',\n 'Content-Type': 'application/json',\n 'rokt-launcher-version': this._integrationName,\n 'rokt-wsdk-version': 'joint',\n };\n\n if (this._launcherInstanceGuid) {\n headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid;\n }\n if (this._accountId) {\n headers['rokt-account-id'] = this._accountId;\n }\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(logRequest),\n })\n .then((response: Response) => {\n // fetch only rejects on network failures; an HTTP 5xx resolves with\n // ok === false. Surface server-side failures so they are not swallowed.\n if (!response.ok) {\n const serverError: DeliveryError = new Error('HTTP ' + response.status + ' from log endpoint');\n serverError.statusCode = response.status;\n throw serverError;\n }\n })\n .catch((error: DeliveryError) => {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error);\n });\n } catch (error) {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error as DeliveryError);\n }\n }\n}\n\nclass ErrorReportingService {\n private _transport: ReportingTransport;\n private _errorUrl: string;\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._errorUrl = generateReportingUrl(config?.errorUrl, config?.integrationDomain, ERROR_ENDPOINT);\n }\n\n report(error: ErrorReport | null | undefined): void {\n if (!error) return;\n const severity = error.severity || WSDKErrorSeverity.ERROR;\n this._transport.send(this._errorUrl, severity, error.message, error.code, error.stackTrace);\n }\n}\n\nclass LoggingService {\n private _transport: ReportingTransport;\n private _loggingUrl: string;\n private _errorReportingService: { report: (e: ErrorReport) => void };\n\n constructor(\n config: ReportingConfig,\n errorReportingService: { report: (e: ErrorReport) => void },\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._loggingUrl = generateReportingUrl(config?.loggingUrl, config?.integrationDomain, LOGGING_ENDPOINT);\n this._errorReportingService = errorReportingService;\n }\n\n log(entry: LogEntry | null | undefined): void {\n if (!entry) return;\n this._transport.send(\n this._loggingUrl,\n WSDKErrorSeverity.INFO,\n entry.message,\n entry.code,\n undefined,\n (error: DeliveryError) => {\n if (this._errorReportingService) {\n // A failed log POST is not itself an SDK error. Network-level failures\n // (ad-blockers, offline, CORS) are client-side noise and reported as a\n // WARNING; only a server-side non-2xx response stays at ERROR severity.\n const isServerSide = typeof error.statusCode === 'number';\n this._errorReportingService.report({\n message: 'LoggingService: Failed to send log: ' + error.message,\n code: ErrorCodes.LOG_DELIVERY_FAILURE,\n severity: isServerSide ? WSDKErrorSeverity.ERROR : WSDKErrorSeverity.WARNING,\n });\n }\n },\n );\n }\n}\n\nfunction buildPageEvent(event: SDKEvent): PageEvent {\n const pageUrl = sanitizeUrl(window.location.href);\n const pageTitle = event.EventAttributes?.title || document.title;\n const canonicalUrl = readCanonicalUrl();\n const activeTimeOnSite = event.ActiveTimeOnSite;\n\n return {\n pageUrl,\n sourceMessageId: event.SourceMessageId,\n timestamp: event.Timestamp,\n ...(pageTitle ? { pageTitle } : {}),\n ...(canonicalUrl !== undefined ? { canonicalUrl } : {}),\n ...(Number.isFinite(activeTimeOnSite) ? { activeTimeOnSite } : {}),\n };\n}\n\n// ============================================================\n// RoktKit class\n// ============================================================\n\nclass RoktKit implements KitInterface {\n // Static field for allowed origin hashes (mutable by testHelpers)\n public static _allowedOriginHashes: number[] = [-553112570, 549508659];\n\n private static readonly PERFORMANCE_MARKS = {\n RoktScriptAppended: 'mp:RoktScriptAppended',\n };\n\n private static readonly EMAIL_SHA256_KEY = 'emailsha256';\n\n // Public fields (accessed by tests and the mParticle framework)\n public name = name;\n public id = moduleId;\n public moduleId = moduleId;\n public isInitialized = false;\n public launcher: RoktLauncher | null = null;\n public filters: KitFilters = {};\n public userAttributes: Record = {};\n // Flag set by the Workspace IDSync flow on a 200 response. Stored on the\n // kit instance and merged into placement attributes inside selectPlacements.\n public userIdentifiedInWorkspace = false;\n public testHelpers: TestHelpers | null = null;\n public placementEventMappingLookup: Record = {};\n public placementEventAttributeMappingLookup: Record = {};\n public integrationName: string | null = null;\n public domain?: string;\n public errorReportingService: ErrorReportingService | null = null;\n public loggingService: LoggingService | null = null;\n\n // Private fields\n private _mappedEmailSha256Key?: string;\n private _onboardingExpProvider?: string;\n private _thankYouElementOnLoadCallback: (() => void) | null = null;\n private _isThankYouElementLoaded = false;\n private _workspaceIdSyncApiKey?: string;\n\n // Held during a search dispatch so the next selectPlacements call;\n // can wait for the HTTP response before reading userIdentifiedInWorkspace;\n // — otherwise the first placement call ships without the flag.\n private _workspaceSearchInFlightPromise: Promise | null = null;\n // Stable serialization of the identifier set sent in the most recent\n // successful search dispatch. If a subsequent identification arrives with\n // an identical set, we skip the network call (the flag is still correct\n // from the prior search). Keyed over the full IUserIdentities map — not\n // just email — so partners passing hashed email through `other`/`other2-10`\n // or any other identifier benefit from the same dedupe. Cleared on logout\n // so a re-login re-evaluates fresh.\n private _workspaceLastSearchedIdentitiesKey?: string;\n\n // ---- Private helpers ----\n\n private getEventAttributeValue(event: SDKEvent, eventAttributeKey: string): unknown {\n const attributes = event && event.EventAttributes;\n if (!attributes) {\n return null;\n }\n\n if (typeof attributes[eventAttributeKey] === 'undefined') {\n return null;\n }\n\n return attributes[eventAttributeKey];\n }\n\n private doesEventAttributeConditionMatch(condition: EventAttributeCondition, actualValue: unknown): boolean {\n if (!condition || !isString(condition.operator)) {\n return false;\n }\n\n const operator = condition.operator.toLowerCase();\n const expectedValue = condition.attributeValue;\n\n if (operator === 'exists') {\n return actualValue !== null;\n }\n\n if (actualValue == null) {\n return false;\n }\n\n if (operator === 'equals') {\n return String(actualValue) === String(expectedValue);\n }\n\n if (operator === 'contains') {\n return String(actualValue).indexOf(String(expectedValue)) !== -1;\n }\n\n return false;\n }\n\n private doesEventMatchRule(event: SDKEvent, rule: PlacementEventRule): boolean {\n if (!rule || !isString(rule.eventAttributeKey)) {\n return false;\n }\n\n const conditions = rule.conditions;\n if (!Array.isArray(conditions)) {\n return false;\n }\n\n const actualValue = this.getEventAttributeValue(event, rule.eventAttributeKey);\n\n if (conditions.length === 0) {\n return actualValue !== null;\n }\n for (let i = 0; i < conditions.length; i++) {\n if (!this.doesEventAttributeConditionMatch(conditions[i], actualValue)) {\n return false;\n }\n }\n\n return true;\n }\n\n private applyPlacementEventAttributeMapping(event: SDKEvent): void {\n const mappedAttributeKeys = Object.keys(this.placementEventAttributeMappingLookup);\n for (let i = 0; i < mappedAttributeKeys.length; i++) {\n const mappedAttributeKey = mappedAttributeKeys[i];\n const rulesForMappedAttributeKey = this.placementEventAttributeMappingLookup[mappedAttributeKey];\n if (isEmpty(rulesForMappedAttributeKey)) {\n continue;\n }\n\n // Require ALL rules for the same key to match (AND).\n let allMatch = true;\n for (let j = 0; j < rulesForMappedAttributeKey.length; j++) {\n if (!this.doesEventMatchRule(event, rulesForMappedAttributeKey[j])) {\n allMatch = false;\n break;\n }\n }\n if (!allMatch) {\n continue;\n }\n\n mp().Rokt.setLocalSessionAttribute?.(mappedAttributeKey, true);\n }\n }\n\n private capturePageView(event: SDKEvent): void {\n let pageUrl: string | undefined;\n\n try {\n pageUrl = sanitizeUrl(window.location.href);\n\n const pageViews = loadPageViews(this.loggingService);\n const pageView = buildPageEvent(event);\n pageViews.push(pageView);\n\n const requested = Math.min(pageViews.length, PAGE_VIEWS_MAX_COUNT);\n const stored = writePageViews(pageViews);\n if (stored === 0) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n this.loggingService?.log({\n message: `Rokt Kit: Failed to persist page view for ${pageUrl} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n } else if (stored < requested) {\n this.loggingService?.log({\n message: `Rokt Kit: Page view storage reduced from ${requested} to ${stored} record(s) under quota pressure [reason: quota_eviction]`,\n code: 'PAGE_VIEW_QUOTA_EVICTION',\n });\n }\n } catch (err) {\n const reason = isLocalStorageAvailable() ? 'exception' : 'ls_unavailable';\n const errMessage = err instanceof Error ? err.message : String(err);\n this.loggingService?.log({\n message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${errMessage} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n private isLauncherReadyToAttach(): boolean {\n return !!window.Rokt && isFunction(window.Rokt.createLauncher);\n }\n\n /**\n * Returns the user identities from the filtered user, if any.\n */\n private returnUserIdentities(filteredUser: FilteredUser | null | undefined): Record {\n if (!filteredUser || !filteredUser.getUserIdentities) {\n return {};\n }\n\n const userIdentities: IUserIdentities = filteredUser.getUserIdentities().userIdentities;\n\n return this.replaceOtherIdentityWithEmailsha256(userIdentities);\n }\n\n private returnLocalSessionAttributes(): Record {\n if (!mp().Rokt || typeof mp().Rokt.getLocalSessionAttributes !== 'function') {\n return {};\n }\n return mp().Rokt.getLocalSessionAttributes!();\n }\n\n private replaceOtherIdentityWithEmailsha256(userIdentities: IUserIdentities): Record {\n const newUserIdentities: Record = { ...(userIdentities || {}) };\n const key = this._mappedEmailSha256Key;\n if (key && userIdentities[key as keyof IUserIdentities]) {\n newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key as keyof IUserIdentities] as string;\n }\n if (key) {\n delete newUserIdentities[key];\n }\n\n return newUserIdentities;\n }\n\n private logSelectPlacementsEvent(attributes: unknown): void {\n if (!window.mParticle || typeof mp().logEvent !== 'function') {\n return;\n }\n\n if (!isObject(attributes)) {\n return;\n }\n\n const EVENT_TYPE_OTHER = mp().EventType.Other;\n\n mp().logEvent(EVENT_NAME_SELECT_PLACEMENTS, EVENT_TYPE_OTHER, attributes as Record);\n }\n\n private setRoktSessionId(sessionId: string): void {\n if (!sessionId || typeof sessionId !== 'string') {\n return;\n }\n try {\n const mpInstance = mp().getInstance();\n if (mpInstance && isFunction(mpInstance.setIntegrationAttribute)) {\n mpInstance.setIntegrationAttribute(moduleId, {\n roktSessionId: sessionId,\n });\n }\n } catch (_e) {\n // Best effort — never let this break the partner page\n }\n }\n\n private readMpSessionId(): string | undefined {\n // The public mParticle.sessionManager facade exposes only getSession(), which already returns\n // the session id. getSessionId() lives on the internal _SessionManager and has never been\n // re-exported, so prefer it if a future core adds it and fall back to getSession() until then.\n const sessionManager = mp()?.sessionManager;\n const readSessionId = sessionManager?.getSessionId ?? sessionManager?.getSession;\n if (!isFunction(readSessionId)) {\n return undefined;\n }\n\n return readSessionId.call(sessionManager) || undefined;\n }\n\n private readMpDeviceId(): string | undefined {\n // The device application stamp (`das`) outlives the session id: core clears the session on\n // timeout, cross-tab rotation and endSession(), but never the device id, which lives in\n // localStorage/cookie for cookieExpiration days (365 by default) and survives login/logout.\n // Read it per call anyway — a partner can reassign it at any time via setDeviceId().\n return mp()?.getDeviceId?.() || undefined;\n }\n\n private attachLauncher(\n accountId: string,\n launcherOptions: Record,\n legacyRoktExtensions: string[] = [],\n ): void {\n const options: Record = {\n accountId,\n ...(launcherOptions || {}),\n };\n\n let launcherPromise: Promise;\n if (this.isPartnerInLocalLauncherTestGroup()) {\n launcherPromise = Promise.resolve(window.Rokt!.createLocalLauncher(options));\n } else {\n launcherPromise = window.Rokt!.createLauncher(options);\n }\n\n launcherPromise\n .then(async (launcher) => {\n await registerLegacyExtensions(legacyRoktExtensions, launcher);\n this.initRoktLauncher(launcher);\n })\n .catch((err: unknown) => {\n console.error('Error creating Rokt launcher:', err);\n });\n }\n\n private initRoktLauncher(launcher: RoktLauncher): void {\n // Assign the launcher to a global variable for later access\n if (window.Rokt) {\n window.Rokt.currentLauncher = launcher;\n }\n // Locally cache the launcher and filters\n this.launcher = launcher;\n\n const roktFilters = mp().Rokt?.filters;\n\n if (!roktFilters) {\n console.warn('Rokt Kit: No filters have been set.');\n } else {\n this.filters = roktFilters;\n if (!roktFilters.filteredUser) {\n console.warn('Rokt Kit: No filtered user has been set.');\n } else {\n this._workspaceSearchInFlightPromise = this.search(roktFilters.filteredUser);\n }\n }\n\n // Kit must be initialized before attaching to the Rokt manager\n this.isInitialized = true;\n\n sendAdBlockMeasurementSignals(this.domain, this.integrationName);\n\n // Attaches the kit to the Rokt manager\n mp().Rokt.attachKit(this);\n }\n\n private fetchOptimizely(): Record {\n const forwarders = mp()\n ._getActiveForwarders()\n .filter((forwarder) => forwarder.name === 'Optimizely');\n\n try {\n if (forwarders.length > 0 && window.optimizely) {\n const optimizelyState = window.optimizely.get('state');\n if (!optimizelyState || !optimizelyState.getActiveExperimentIds) {\n return {};\n }\n const activeExperimentIds = optimizelyState.getActiveExperimentIds();\n const activeExperiments = activeExperimentIds.reduce((acc: Record, expId: string) => {\n acc['rokt.custom.optimizely.experiment.' + expId + '.variationId'] =\n optimizelyState.getVariationMap()[expId].id;\n return acc;\n }, {});\n return activeExperiments;\n }\n } catch (error) {\n console.error('Error fetching Optimizely attributes:', error);\n }\n return {};\n }\n\n private isKitReady(): boolean {\n return !!(this.isInitialized && this.launcher);\n }\n\n // When the partner has opted out of targeting (noTargeting launcher option),\n // the kit must not collect behavioral targeting signals such as page views.\n private isTargetingDisabled(): boolean {\n return (mp().Rokt?.launcherOptions as Record | undefined)?.noTargeting === true;\n }\n\n private isPartnerInLocalLauncherTestGroup(): boolean {\n return !!(mp().config && mp().config!.isLocalLauncherEnabled && this.isAssignedToSampleGroup());\n }\n\n private isAssignedToSampleGroup(): boolean {\n const LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5;\n return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD;\n }\n\n private captureTiming(metricName: string): void {\n if (window && mp() && mp().captureTiming && metricName) {\n mp().captureTiming!(metricName);\n }\n }\n\n // ---- Public methods (mParticle Kit Callbacks) ----\n\n /**\n * Initializes the Rokt forwarder with settings from the mParticle server.\n */\n public init(\n settings: Record,\n _service: unknown,\n testMode: boolean,\n _trackerId: unknown,\n filteredUserAttributes?: Record,\n ): string {\n const kitSettings = settings as unknown as RoktKitSettings;\n const accountId = kitSettings.accountId;\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredUserAttributes);\n this._onboardingExpProvider = kitSettings.onboardingExpProvider;\n\n const placementEventMapping = parseSettingsString(kitSettings.placementEventMapping);\n this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping);\n\n const placementEventAttributeMapping = parseSettingsString(\n kitSettings.placementEventAttributeMapping,\n );\n this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping);\n\n // Set dynamic OTHER_IDENTITY based on server settings\n if (kitSettings.hashedEmailUserIdentityType) {\n this._mappedEmailSha256Key = kitSettings.hashedEmailUserIdentityType.toLowerCase();\n }\n\n this._workspaceIdSyncApiKey = isString(kitSettings.workspaceIdSyncApiKey)\n ? kitSettings.workspaceIdSyncApiKey\n : undefined;\n\n const domain = mp().Rokt?.domain;\n const { roktExtensionsQueryParams, legacyRoktExtensions, loadThankYouElement } = extractRoktExtensionConfig(\n kitSettings.roktExtensions,\n );\n const launcherOptions: Record = {\n ...((mp().Rokt?.launcherOptions as Record) || {}),\n };\n this.integrationName = generateIntegrationName(launcherOptions.integrationName as string | undefined);\n launcherOptions.integrationName = this.integrationName;\n\n this.domain = domain;\n\n const reportingConfig: ReportingConfig = {\n loggingUrl: kitSettings.loggingUrl,\n errorUrl: kitSettings.errorUrl,\n integrationDomain: domain,\n isLoggingEnabled: mp().config?.isLoggingEnabled === true,\n };\n const errorReportingService = new ErrorReportingService(\n reportingConfig,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n const loggingService = new LoggingService(\n reportingConfig,\n errorReportingService,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n\n this.errorReportingService = errorReportingService;\n this.loggingService = loggingService;\n\n if (this.isTargetingDisabled()) {\n try {\n clearPageViews();\n clearUtmParams();\n } catch (err) {\n this.errorReportingService?.report({\n message: 'Rokt Kit: Failed to clear page views when targeting is disabled',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n severity: WSDKErrorSeverity.INFO,\n stackTrace: err instanceof Error ? err.stack : undefined,\n });\n }\n }\n\n if (mp()._registerErrorReportingService) {\n mp()._registerErrorReportingService!(errorReportingService);\n }\n if (mp()._registerLoggingService) {\n mp()._registerLoggingService!(loggingService);\n }\n\n if (testMode) {\n this.testHelpers = {\n generateLauncherScript: generateLauncherScript,\n generateThankYouElementScript: generateThankYouElementScript,\n extractRoktExtensionConfig: extractRoktExtensionConfig,\n hashEventMessage: hashEventMessage,\n parseSettingsString: parseSettingsString,\n generateMappedEventLookup: generateMappedEventLookup,\n generateMappedEventAttributeLookup: generateMappedEventAttributeLookup,\n sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals,\n createAutoRemovedIframe: createAutoRemovedIframe,\n djb2: djb2,\n setAllowedOriginHashes: (hashes: number[]) => {\n RoktKit._allowedOriginHashes = hashes;\n },\n ReportingTransport: ReportingTransport,\n ErrorReportingService: ErrorReportingService,\n LoggingService: LoggingService,\n RateLimiter: RateLimiter,\n ErrorCodes: ErrorCodes,\n WSDKErrorSeverity: WSDKErrorSeverity,\n };\n this.attachLauncher(accountId, launcherOptions);\n return 'Successfully initialized: ' + name;\n }\n\n if (loadThankYouElement) {\n mp().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this);\n loadRoktScript(ROKT_THANK_YOU_ELEMENT_SCRIPT_ID, generateThankYouElementScript(domain), {\n onLoad: () => {\n this._isThankYouElementLoaded = true;\n if (this._thankYouElementOnLoadCallback) {\n this._thankYouElementOnLoadCallback();\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt Thank You Element script:', error);\n },\n });\n }\n\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n loadRoktScript(ROKT_INTEGRATION_SCRIPT_ID, generateLauncherScript(domain, roktExtensionsQueryParams), {\n onLoad: () => {\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n console.error('Rokt object is not available after script load.');\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt launcher script:', error);\n },\n });\n\n this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended);\n }\n\n return 'Successfully initialized: ' + name;\n }\n\n public process(event: SDKEvent): string {\n if (!this.isTargetingDisabled()) {\n if (event.EventDataType === MESSAGE_TYPE_PAGE_VIEW) {\n captureUtmParams(this.loggingService);\n this.capturePageView(event);\n }\n\n if (event.EventDataType === MESSAGE_TYPE_SESSION_END) {\n migrateLegacyPageViewStorage(this.loggingService);\n clearPageViews();\n clearUtmParams();\n }\n }\n\n // The forwarding work below (LSA mapping) depends on the launcher, so guard\n // it here and surface the not-ready signal to the core SDK.\n if (!this.isKitReady()) {\n return 'Kit not ready for forwarder: ' + name;\n }\n\n if (isFunction(mp().Rokt?.setLocalSessionAttribute)) {\n if (!isEmpty(this.placementEventAttributeMappingLookup)) {\n this.applyPlacementEventAttributeMapping(event);\n }\n\n if (!isEmpty(this.placementEventMappingLookup)) {\n const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? '');\n if (this.placementEventMappingLookup[String(hashedEvent)]) {\n mp().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(hashedEvent)], true);\n }\n }\n }\n\n return 'Successfully sent to forwarder: ' + name;\n }\n\n public setExtensionData(partnerExtensionData: Record): void {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return;\n }\n\n window.Rokt!.setExtensionData(partnerExtensionData);\n }\n\n public setUserAttribute(key: string, value: unknown): string {\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n this.userAttributes[key] = value;\n }\n return 'Successfully set user attribute for forwarder: ' + name;\n }\n\n public removeUserAttribute(key: string): string {\n delete this.userAttributes[key];\n return 'Successfully removed user attribute for forwarder: ' + name;\n }\n\n private handleIdentityComplete(user: IMParticleUser, callbackName: string): string {\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(user.getAllUserAttributes());\n return 'Successfully called ' + callbackName + ' for forwarder: ' + name;\n }\n\n public onUserIdentified(user: IMParticleUser): string {\n const filteredUser = user as FilteredUser;\n this.filters.filteredUser = filteredUser;\n this._workspaceSearchInFlightPromise = this.search(filteredUser);\n return this.handleIdentityComplete(user, 'onUserIdentified');\n }\n\n private search(filteredUser: FilteredUser): Promise {\n const apiKey = this._workspaceIdSyncApiKey;\n if (!apiKey) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n const search = mp().Identity?.search;\n if (typeof search !== 'function') {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n const userIdentities: IUserIdentities | null = filteredUser.getUserIdentities\n ? filteredUser.getUserIdentities().userIdentities\n : null;\n\n // Forward every non-empty string identifier the user has — email,\n // customerid, other/other2-10 (commonly used for hashed email),\n // mobile_number, facebook, etc. The host SDK's Identity.search accepts\n // the full IUserIdentities surface and the server validates it.\n const knownIdentities: Record = {};\n if (userIdentities) {\n for (const key of Object.keys(userIdentities) as Array) {\n const value = userIdentities[key];\n if (isString(value) && value.length > 0) {\n knownIdentities[key] = value;\n }\n }\n }\n\n const identityKeys = Object.keys(knownIdentities);\n if (identityKeys.length === 0) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n // Stable cache key: sort keys so insertion-order differences don't\n // cause false misses. The values are partner-supplied strings; no\n // hashing needed — equality on this serialization is sufficient.\n const identitiesKey = identityKeys\n .sort()\n .map((k) => `${k}=${knownIdentities[k]}`)\n .join('&');\n\n // Same identifier set as the last successful dispatch → skip the\n // network call. The current flag value still reflects the correct\n // match status.\n if (identitiesKey === this._workspaceLastSearchedIdentitiesKey) {\n return this._workspaceSearchInFlightPromise || Promise.resolve();\n }\n\n // New / different identifier set → reset and re-search. Cache the key\n // up front so a second concurrent invocation with the same set also\n // dedupes.\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = identitiesKey;\n\n return new Promise((resolve) => {\n try {\n search(apiKey, knownIdentities as IUserIdentities, (result: WorkspaceIdSyncResult) => {\n if (result?.httpCode === 200) {\n this.userIdentifiedInWorkspace = true;\n }\n resolve();\n });\n } catch (err) {\n console.error('Rokt Kit: Workspace IDSync search failed', err);\n // Dispatch failed — clear the cache so the same identifier set\n // can retry on the next identification rather than being stuck\n // behind a poisoned entry that short-circuits future searches.\n this._workspaceLastSearchedIdentitiesKey = undefined;\n resolve();\n }\n });\n }\n\n public onLoginComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onLoginComplete');\n }\n\n public onLogoutComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n // Anonymous sessions must not carry the previous user's match forward.\n // Clear the flag explicitly here. Also clear the identities cache so a\n // re-login (possibly with the same identifiers) dispatches a fresh\n // search rather than reusing a stale answer.\n this.userIdentifiedInWorkspace = false;\n this._workspaceSearchInFlightPromise = null;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return this.handleIdentityComplete(user, 'onLogoutComplete');\n }\n\n public onModifyComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onModifyComplete');\n }\n\n /**\n * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options.\n *\n * If a Workspace IDSync search is in flight from a recent onUserIdentified\n * call, this method waits up to `WORKSPACE_SEARCH_SELECT_TIMEOUT_MS` for it\n * to settle so the first placement call can include the\n * `userIdentifiedInWorkspace` flag without racing the network response.\n * The timeout protects against a stalled or slow search blocking placement\n * rendering — if it fires, selectPlacements proceeds without the flag.\n *\n * Implementation note: this method stays non-async deliberately. First,\n * the public return type is `RoktSelection | Promise |\n * undefined` — a superset of the `RoktSelection | Promise`\n * shape declared for `RoktLauncher.selectPlacements` above (line ~70).\n * Marking this `async` would narrow it to `Promise` and silently change the contract for callers that read\n * the result synchronously. Second, `RoktSelection` has an optional\n * `then?` member, so TS treats it as ambiguously promise-like and\n * rejects it as the awaited return of an async function (TS1058) —\n * working around that would require a cast or wrapping every return in\n * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`;\n * this wrapper just gates it on the in-flight search via `Promise.race`.\n */\n public selectPlacements(options: Record): RoktSelection | Promise | undefined {\n if (this._workspaceSearchInFlightPromise) {\n const inFlight = this._workspaceSearchInFlightPromise;\n return Promise.race([\n inFlight,\n new Promise((resolve) => setTimeout(resolve, WORKSPACE_SEARCH_SELECT_TIMEOUT_MS)),\n ]).then(() => this._dispatchPlacements(options)) as Promise;\n }\n return this._dispatchPlacements(options);\n }\n\n private _dispatchPlacements(options: Record): RoktSelection | Promise | undefined {\n const attributes = ((options && (options.attributes as Record)) || {}) as Record;\n const cachedUserAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(this.userAttributes);\n const placementAttributes: Record = { ...cachedUserAttributes, ...attributes };\n\n const filters = this.filters || {};\n const userAttributeFilters = (filters.userAttributeFilters as string[]) || [];\n const filteredUser = filters.filteredUser || null;\n const mpid = filteredUser ? filteredUser.getMPID() : null;\n\n let filteredAttributes: Record;\n\n if (!filters) {\n console.warn('Rokt Kit: No filters available, using user attributes');\n filteredAttributes = placementAttributes;\n } else if (filters.filterUserAttributes) {\n filteredAttributes = filters.filterUserAttributes(placementAttributes, userAttributeFilters);\n } else {\n filteredAttributes = placementAttributes;\n }\n\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredAttributes);\n\n const optimizelyAttributes = this._onboardingExpProvider === 'Optimizely' ? this.fetchOptimizely() : {};\n\n const filteredUserIdentities = this.returnUserIdentities(filteredUser);\n\n const sessionAttributes = this.returnLocalSessionAttributes();\n const pageEvents = buildPageEvents(loadPageViews(this.loggingService));\n const utmParams = loadUtmParams();\n const mpSessionId = this.readMpSessionId();\n const mpDeviceId = this.readMpDeviceId();\n\n const selectPlacementsAttributes: Record = {\n ...(filteredUserIdentities as Record),\n ...filteredAttributes,\n ...optimizelyAttributes,\n ...sessionAttributes,\n ...(pageEvents.length ? { [PAGE_EVENTS_KEY]: JSON.stringify(pageEvents) } : {}),\n ...(utmParams ? { [PAGE_VIEW_ATTRIBUTES_KEY]: utmParams } : {}),\n ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}),\n ...(mpSessionId ? { [MPARTICLE_SESSION_ID_KEY]: mpSessionId } : {}),\n ...(mpDeviceId ? { [MPARTICLE_DEVICE_ID_KEY]: mpDeviceId } : {}),\n mpid,\n };\n\n const selectPlacementsOptions: Record = { ...options, attributes: selectPlacementsAttributes };\n\n const selection = this.launcher!.selectPlacements(selectPlacementsOptions);\n\n // After selection resolves, sync the Rokt session ID back to mParticle, then log\n const logSelection = () => this.logSelectPlacementsEvent(selectPlacementsAttributes);\n\n void Promise.resolve(selection)\n .then((sel) => sel?.context?.sessionId?.then((sessionId) => this.setRoktSessionId(sessionId)))\n .catch(() => undefined)\n .finally(logSelection);\n\n return selection;\n }\n\n /**\n * Passes attributes to the Rokt Web SDK for client-side hashing.\n */\n public hashAttributes(attributes: Record): Promise> | null {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return null;\n }\n return this.launcher!.hashAttributes(attributes);\n }\n\n /**\n * Enables optional Integration Launcher extensions before selecting placements.\n *\n * @deprecated This functionality has been internalized and will be removed in a future release.\n */\n public use(extensionName: string): Promise {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return Promise.reject(new Error('Rokt Kit: Not initialized'));\n }\n if (!extensionName || !isString(extensionName)) {\n return Promise.reject(new Error('Rokt Kit: Invalid extension name'));\n }\n return this.launcher!.use(extensionName);\n }\n\n /**\n * Registers a callback to be invoked once rokt-thank-you-element.js becomes available.\n */\n public onShoppableAdsReady(callback: () => void) {\n if (this._isThankYouElementLoaded) {\n callback();\n } else {\n this._thankYouElementOnLoadCallback = callback;\n }\n }\n}\n\n// ============================================================\n// Kit registration\n// ============================================================\n\nfunction getId(): number {\n return moduleId;\n}\n\nfunction register(config: { kits?: Record }): void {\n if (!config) {\n window.console.log('You must pass a config object to register the kit ' + name);\n return;\n }\n if (!isObject(config)) {\n window.console.log(\"'config' must be an object. You passed in a \" + typeof config);\n return;\n }\n\n if (isObject(config.kits)) {\n (config.kits as Record)[name] = {\n constructor: RoktKit,\n };\n } else {\n config.kits = {};\n config.kits[name] = {\n constructor: RoktKit,\n };\n }\n window.console.log('Successfully registered ' + name + ' to your mParticle configuration');\n}\n\nif (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) {\n mp().addForwarder({\n name: name,\n constructor: RoktKit,\n getId: getId,\n });\n}\n\nexport { register };\nexport type { LoggingService };\n"],"names":["SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST","SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET","isSelectPlacementsAttributePersistenceDenied","key","removeSelectPlacementsAttributePersistenceDeniedAttributes","attributes","filteredAttributes","sourceAttributes","attributeKeys","i","isObject","value","isString","isFunction","isEmpty","sanitizeUrl","href","url","LS_PROBE_KEY","isLocalStorageAvailable","readJSON","stored","writeJSON","removeKey","readNamespacedField","namespaceKey","field","blob","writeNamespacedField","next","removeNamespacedField","LS_NAMESPACE_KEY","LS_PAGE_VIEWS_FIELD","LS_UTM_PARAMS_FIELD","LEGACY_PAGE_VIEWS_KEY","PAGE_VIEWS_MAX_COUNT","UTM_KEYS","capPageViews","views","migrateLegacyPageViewStorage","loggingService","legacyViews","loadPageViews","writePageViews","pageViews","toWrite","clearPageViews","buildPageEvents","pageView","index","activeTimeOnSite","hasActiveTime","nextActiveTimeOnSite","hasNextActiveTimeOnSite","diff","captureUtmParams","search","params","captured","reason","loadUtmParams","clearUtmParams","readCanonicalUrl","name","moduleId","EVENT_NAME_SELECT_PLACEMENTS","ADBLOCK_CONTROL_DOMAIN","INIT_LOG_SAMPLING_RATE","ROKT_THANK_YOU_JOURNEY_EXTENSION","ROKT_INTEGRATION_SCRIPT_ID","ROKT_THANK_YOU_ELEMENT_SCRIPT_ID","USER_IDENTIFIED_IN_WORKSPACE_KEY","MESSAGE_TYPE_PAGE_VIEW","MESSAGE_TYPE_SESSION_END","PAGE_EVENTS_KEY","PAGE_VIEW_ATTRIBUTES_KEY","MPARTICLE_SESSION_ID_KEY","MPARTICLE_DEVICE_ID_KEY","WORKSPACE_SEARCH_SELECT_TIMEOUT_MS","ErrorCodes","WSDKErrorSeverity","DEFAULT_ROKT_DOMAIN","LOGGING_ENDPOINT","ERROR_ENDPOINT","RATE_LIMIT_PER_SEVERITY","mp","generateLauncherScript","domain","extensions","baseUrl","generateBaseUrl","generateThankYouElementScript","resolvedDomain","generateReportingUrl","configuredUrl","endpoint","reportingDomain","loadRoktScript","scriptId","source","handlers","target","script","parseSettingsString","settingsString","extractRoktExtensionConfig","settings","roktExtensionsQueryParams","legacyRoktExtensions","loadThankYouElement","extensionName","registerLegacyExtensions","legacyExtensions","launcher","extension","generateMappedEventLookup","placementEventMapping","mappedEvents","mapping","generateMappedEventAttributeLookup","placementEventAttributeMapping","mappedAttributeKeys","mappedAttributeKey","eventAttributeKey","hashEventMessage","messageType","eventType","eventName","generateIntegrationName","customIntegrationName","integrationName","djb2","str","hash","createAutoRemovedIframe","src","iframe","sendAdBlockMeasurementSignals","version","originHash","RoktKit","guid","pageUrl","existingBaseUrl","_isDebugModeEnabled","_getReportingUrl","_getUserAgent","RateLimiter","severity","newCount","ReportingTransport","config","launcherInstanceGuid","accountId","rateLimiter","isLoggingEnabled","msg","code","stackTrace","onError","logRequest","headers","response","serverError","error","ErrorReportingService","LoggingService","errorReportingService","entry","isServerSide","buildPageEvent","event","pageTitle","canonicalUrl","_RoktKit","condition","actualValue","operator","expectedValue","rule","conditions","rulesForMappedAttributeKey","allMatch","j","requested","err","errMessage","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","sessionManager","readSessionId","launcherOptions","options","launcherPromise","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","sessionAttributes","pageEvents","utmParams","mpSessionId","mpDeviceId","selectPlacementsAttributes","selectPlacementsOptions","selection","logSelection","sel","callback","getId","register"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"Rokt-Kit.esm.js","sources":["../src/selectPlacementsAttributePersistence.ts","../src/utils.ts","../src/storage.ts","../src/pageViewStorage.ts","../src/Rokt-Kit.ts"],"sourcesContent":["const SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST = [\n 'active_time_on_site_ms',\n 'billingaddress1',\n 'billingaddress2',\n 'billingcity',\n 'billingstate',\n 'billingzipcode',\n 'cartitems',\n 'ccbin',\n 'confirmationref',\n 'conversiontype',\n 'country',\n 'couponcode',\n 'currency',\n 'language',\n 'paymentserviceprovider',\n 'paymentserviceproviderattribute',\n 'paymenttype',\n 'shippingaddress1',\n 'shippingcity',\n 'shippingcountry',\n 'shippingmethod',\n 'shippingstate',\n 'shippingzipcode',\n 'totalprice',\n];\nconst SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET = new Set(SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST);\n\nexport function isSelectPlacementsAttributePersistenceDenied(key: string): boolean {\n return SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET.has(key.toLowerCase());\n}\n\nexport function removeSelectPlacementsAttributePersistenceDeniedAttributes(\n attributes: Record | null | undefined,\n): Record {\n const filteredAttributes: Record = {};\n const sourceAttributes = attributes || {};\n const attributeKeys = Object.keys(sourceAttributes);\n\n for (let i = 0; i < attributeKeys.length; i++) {\n const key = attributeKeys[i];\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n filteredAttributes[key] = sourceAttributes[key];\n }\n }\n\n return filteredAttributes;\n}\n","export function isObject(value: unknown): value is Record {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nexport function isFunction(value: unknown): value is (...args: Array) => unknown {\n return typeof value === 'function';\n}\n\nexport function isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'object') {\n return Object.keys(value as object).length === 0;\n }\n return false;\n}\n\n// Strips the query string from a URL before it is persisted and sent to Rokt,\n// since query params commonly carry PII (emails, tokens, order refs).\n// Returns the input unchanged if it can't be parsed as a URL.\nexport function sanitizeUrl(href: string): string {\n try {\n const url = new URL(href);\n url.search = '';\n return url.toString();\n } catch {\n return href;\n }\n}\n","import { isObject } from './utils';\n\nconst LS_PROBE_KEY = '__rokt_ls_probe__';\n\nexport function isLocalStorageAvailable(): boolean {\n try {\n window.localStorage.setItem(LS_PROBE_KEY, '1');\n window.localStorage.removeItem(LS_PROBE_KEY);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function readJSON(key: string): unknown {\n try {\n const stored = window.localStorage.getItem(key);\n return stored === null ? null : JSON.parse(stored);\n } catch {\n return null;\n }\n}\n\nexport function writeJSON(key: string, value: unknown): boolean {\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n return true;\n } catch {\n return false;\n }\n}\n\nexport function removeKey(key: string): void {\n try {\n window.localStorage.removeItem(key);\n } catch {\n /* empty */\n }\n}\n\nexport function readNamespacedField(namespaceKey: string, field: string): unknown {\n const blob = readJSON(namespaceKey);\n return isObject(blob) ? blob[field] : undefined;\n}\n\nexport function writeNamespacedField(namespaceKey: string, field: string, value: unknown): boolean {\n const blob = readJSON(namespaceKey);\n const next = isObject(blob) ? { ...blob } : {};\n next[field] = value;\n return writeJSON(namespaceKey, next);\n}\n\nexport function removeNamespacedField(namespaceKey: string, field: string): void {\n const blob = readJSON(namespaceKey);\n if (!isObject(blob) || !(field in blob)) {\n return;\n }\n const next = { ...blob };\n delete next[field];\n if (Object.keys(next).length === 0) {\n removeKey(namespaceKey);\n } else {\n writeJSON(namespaceKey, next);\n }\n}\n","import type { LoggingService } from './Rokt-Kit';\nimport {\n readJSON,\n removeKey,\n readNamespacedField,\n writeNamespacedField,\n removeNamespacedField,\n isLocalStorageAvailable,\n} from './storage';\nimport { sanitizeUrl, isObject } from './utils';\n\nconst LS_NAMESPACE_KEY = 'mp-rokt-kit';\nconst LS_PAGE_VIEWS_FIELD = 'pageViews';\nconst LS_UTM_PARAMS_FIELD = 'utmParams';\nconst LEGACY_PAGE_VIEWS_KEY = 'mpPageViews';\nexport const PAGE_VIEWS_MAX_COUNT = 25;\n\nconst UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'] as const;\ntype UtmKey = (typeof UTM_KEYS)[number];\nexport type UtmParams = Partial>;\n\nexport interface PageEvent {\n pageUrl: string;\n sourceMessageId: string;\n timestamp: number;\n pageTitle?: string;\n canonicalUrl?: string;\n activeTimeOnSite?: number;\n activeTimeOnPage?: number;\n}\n\nfunction capPageViews(views: PageEvent[]): PageEvent[] {\n return views.slice(-PAGE_VIEWS_MAX_COUNT);\n}\n\nexport function migrateLegacyPageViewStorage(loggingService: LoggingService | null): void {\n const legacyViews = readJSON(LEGACY_PAGE_VIEWS_KEY);\n if (legacyViews === null) {\n return;\n }\n\n const alreadyMigrated = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD) !== undefined;\n const needsMigration = !alreadyMigrated && Array.isArray(legacyViews);\n\n if (needsMigration) {\n loggingService?.log({\n message: 'Rokt Kit: Migrating legacy page-view storage',\n code: 'PAGE_VIEW_LEGACY_MIGRATION',\n });\n const migrated = writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, legacyViews);\n if (!migrated) {\n loggingService?.log({\n message: 'Rokt Kit: Failed to migrate legacy page-view storage [reason: migration_retry]',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n removeKey(LEGACY_PAGE_VIEWS_KEY);\n}\n\nexport function loadPageViews(loggingService: LoggingService | null): PageEvent[] {\n migrateLegacyPageViewStorage(loggingService);\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n return Array.isArray(stored) ? (stored as PageEvent[]) : [];\n}\n\nexport function writePageViews(pageViews: PageEvent[]): number {\n const views = capPageViews(pageViews);\n for (let i = 0; i < views.length; i++) {\n const toWrite = views.slice(i);\n if (writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, toWrite)) {\n return toWrite.length;\n }\n }\n return 0;\n}\n\nexport function clearPageViews(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n}\n\nexport function buildPageEvents(pageViews: PageEvent[]): PageEvent[] {\n const views = capPageViews(pageViews);\n return views.map((pageView, index) => {\n const activeTimeOnSite = pageView.activeTimeOnSite;\n const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite);\n\n const next = views[index + 1];\n const nextActiveTimeOnSite = next?.activeTimeOnSite;\n const hasNextActiveTimeOnSite = nextActiveTimeOnSite !== undefined && Number.isFinite(nextActiveTimeOnSite);\n\n const diff = hasActiveTime && hasNextActiveTimeOnSite ? nextActiveTimeOnSite - activeTimeOnSite : undefined;\n\n return {\n pageUrl: pageView.pageUrl,\n sourceMessageId: pageView.sourceMessageId,\n timestamp: pageView.timestamp,\n ...(pageView.pageTitle !== undefined ? { pageTitle: pageView.pageTitle } : {}),\n ...(pageView.canonicalUrl !== undefined ? { canonicalUrl: pageView.canonicalUrl } : {}),\n ...(hasActiveTime ? { activeTimeOnSite } : {}),\n ...(diff !== undefined && diff >= 0 ? { activeTimeOnPage: diff } : {}),\n };\n });\n}\n\nexport function captureUtmParams(loggingService: LoggingService | null): void {\n if (readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD) !== undefined) {\n return;\n }\n const search = new URLSearchParams(window.location.search);\n const params: UtmParams = {};\n for (const key of UTM_KEYS) {\n const value = search.get(key);\n if (value) params[key] = value;\n }\n if (Object.keys(params).length === 0) {\n return;\n }\n const captured = Object.keys(params).join(', ');\n if (!writeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD, params)) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n loggingService?.log({\n message: `Rokt Kit: Failed to persist UTM params [reason: ${reason}]`,\n code: 'UTM_CAPTURE_FAILED',\n });\n return;\n }\n loggingService?.log({\n message: `Rokt Kit: Captured UTM params [${captured}]`,\n code: 'UTM_CAPTURE_SUCCESS',\n });\n}\n\nexport function loadUtmParams(): UtmParams | null {\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n return isObject(stored) ? (stored as UtmParams) : null;\n}\n\nexport function clearUtmParams(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n}\n\nexport function readCanonicalUrl(): string | undefined {\n const link = document.querySelector('link[rel=\"canonical\"]');\n const href = link?.href;\n if (!href) {\n return undefined;\n }\n return sanitizeUrl(href);\n}\n","// Copyright 2025 mParticle, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// ============================================================\n// Types\n// ============================================================\n\nimport { KitInterface, IMParticleUser, SDKEvent } from '@mparticle/web-sdk/internal';\nimport type { IUserIdentities } from '@mparticle/web-sdk';\n\nimport {\n isSelectPlacementsAttributePersistenceDenied,\n removeSelectPlacementsAttributePersistenceDeniedAttributes,\n} from './selectPlacementsAttributePersistence';\n\nimport {\n PageEvent,\n PAGE_VIEWS_MAX_COUNT,\n buildPageEvents,\n migrateLegacyPageViewStorage,\n loadPageViews,\n writePageViews,\n clearPageViews,\n readCanonicalUrl,\n captureUtmParams,\n loadUtmParams,\n clearUtmParams,\n} from './pageViewStorage';\nimport { isLocalStorageAvailable } from './storage';\n\nimport { isObject, isString, isEmpty, isFunction, sanitizeUrl } from './utils';\n\ninterface RoktKitSettings {\n accountId: string;\n roktExtensions?: string;\n placementEventMapping?: string;\n placementEventAttributeMapping?: string;\n hashedEmailUserIdentityType?: string;\n onboardingExpProvider?: string;\n loggingUrl?: string;\n errorUrl?: string;\n workspaceIdSyncApiKey?: string;\n}\n\ninterface EventAttributeCondition {\n operator: string;\n attributeValue: string;\n}\n\ninterface PlacementEventRule {\n eventAttributeKey: string;\n conditions: EventAttributeCondition[];\n}\n\ninterface EventAttributeMapping {\n value: string;\n map: string;\n conditions?: EventAttributeCondition[];\n}\n\ninterface PlacementEventMappingEntry {\n jsmap: string;\n value: string;\n}\n\ninterface RoktExtensionEntry {\n value: string;\n}\n\ninterface RoktSelection {\n context?: {\n sessionId?: Promise;\n };\n then?: (callback: (sel: RoktSelection) => void) => Promise;\n catch?: (callback: () => void) => void;\n}\n\ninterface RoktLauncher {\n selectPlacements(options: Record): RoktSelection | Promise;\n hashAttributes(attributes: Record): Promise>;\n use(extensionName: string): Promise;\n}\n\ninterface RoktGlobal {\n createLauncher(options: Record): Promise;\n createLocalLauncher(options: Record): RoktLauncher;\n currentLauncher?: RoktLauncher;\n setExtensionData(data: Record): void;\n}\n\n// FilteredUser is the IMParticleUser shape we receive after kit filtering.\n// `getMPID` and `getUserIdentities` are inherited from the SDK's `User` base type.\ntype FilteredUser = IMParticleUser;\n\n// TODO: Replace with `IIdentitySearchResult` from `@mparticle/web-sdk` once\n// a version that exports it is published (currently on a feature branch in\n// mParticle/mparticle-web-sdk PR #1255). The shape below is intentionally\n// structurally identical so the swap is a one-line import change.\ninterface WorkspaceIdSyncResult {\n httpCode: number;\n body?: {\n context?: string | null;\n mpid?: string;\n matched_identities?: Record;\n is_ephemeral?: boolean;\n is_logged_in?: boolean;\n };\n}\n\n// TODO: Replace with `IdentitySearchCallback`-compatible reference from\n// `@mparticle/web-sdk` once published (mirrors `SDKIdentityApi.search`).\ntype WorkspaceIdSyncSearcher = (\n apiKey: string,\n knownIdentities: IUserIdentities,\n callback: (result: WorkspaceIdSyncResult) => void,\n) => void;\n\ninterface KitFilters {\n userAttributeFilters?: string[];\n filterUserAttributes?: (attributes: Record, filters?: string[]) => Record;\n filteredUser?: FilteredUser | null;\n}\n\ninterface RoktManager {\n attachKit(kit: RoktKit): void | Promise;\n flushOnShoppableAdsReadyMessageQueue?(kit: RoktKit): void;\n filters?: KitFilters;\n domain?: string;\n launcherOptions?: Record;\n getLocalSessionAttributes?(): Record;\n setLocalSessionAttribute?(key: string, value: unknown): void;\n}\n\ninterface MParticleInstance {\n setIntegrationAttribute(moduleId: number, attrs: Record): void;\n}\n\ninterface OptimizelyState {\n getActiveExperimentIds(): string[];\n getVariationMap(): Record;\n}\n\ninterface OptimizelyGlobal {\n get(key: 'state'): OptimizelyState;\n}\n\n// Our view of the mParticle global with Rokt-specific extensions.\n// We access window.mParticle via an explicit cast (see `mp()` helper below)\n// rather than augmenting Window to avoid conflicts with @mparticle/web-sdk declarations.\ninterface MParticleExtended {\n Rokt: RoktManager;\n addForwarder(config: ForwarderRegistration): void;\n getVersion(): string;\n generateHash(value: string): string | number;\n logEvent(name: string, type: number, attrs?: Record): void;\n EventType: { Other: number };\n getInstance(): MParticleInstance;\n getDeviceId?(): string;\n sessionManager?: { getSession?(): string; getSessionId?(): string };\n _getActiveForwarders(): Array<{ name: string }>;\n config?: { isLocalLauncherEnabled?: boolean; isLoggingEnabled?: boolean };\n captureTiming?(metricName: string): void;\n forwarder?: RoktKit;\n loggedEvents?: Array>;\n _registerErrorReportingService?(service: ErrorReportingService): void;\n _registerLoggingService?(service: LoggingService): void;\n Identity?: { search?: WorkspaceIdSyncSearcher };\n}\n\ninterface TestHelpers {\n generateLauncherScript: (domain: string | undefined, extensions: string[]) => string;\n generateThankYouElementScript: (domain: string | undefined) => string;\n extractRoktExtensionConfig: (settingsString?: string) => RoktExtensionConfig;\n hashEventMessage: (messageType: number, eventType: number, eventName: string) => string | number;\n parseSettingsString: (settingsString?: string) => T[];\n generateMappedEventLookup: (placementEventMapping: PlacementEventMappingEntry[]) => Record;\n generateMappedEventAttributeLookup: (mapping: EventAttributeMapping[]) => Record;\n sendAdBlockMeasurementSignals: (domain: string | undefined, version: string | null) => void;\n createAutoRemovedIframe: (src: string) => void;\n djb2: (str: string) => number;\n setAllowedOriginHashes: (hashes: number[]) => void;\n ReportingTransport: typeof ReportingTransport;\n ErrorReportingService: typeof ErrorReportingService;\n LoggingService: typeof LoggingService;\n RateLimiter: typeof RateLimiter;\n ErrorCodes: typeof ErrorCodes;\n WSDKErrorSeverity: typeof WSDKErrorSeverity;\n}\n\ninterface ForwarderRegistration {\n name: string;\n constructor: new () => RoktKit;\n getId: () => number;\n}\n\ninterface ReportingConfig {\n loggingUrl?: string;\n errorUrl?: string;\n integrationDomain?: string;\n isLoggingEnabled: boolean;\n}\n\ninterface ErrorReport {\n message: string;\n code?: string;\n severity?: string;\n stackTrace?: string;\n}\n\n// A log-delivery failure. statusCode is set when the request reached the server\n// and returned a non-2xx status (server-side); it is absent for network-level\n// failures such as ad-blockers, offline, or CORS rejections (client-side).\ninterface DeliveryError extends Error {\n statusCode?: number;\n}\n\ninterface LogEntry {\n message: string;\n code?: string;\n}\n\ninterface RoktExtensionConfig {\n roktExtensionsQueryParams: string[];\n legacyRoktExtensions: string[];\n loadThankYouElement: boolean;\n}\n\ndeclare global {\n interface Window {\n Rokt?: RoktGlobal;\n __rokt_li_guid__?: string;\n optimizely?: OptimizelyGlobal;\n // mParticle is declared as any to avoid conflicts with @mparticle/web-sdk type declarations.\n // We use the typed mp() accessor for all internal accesses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mParticle: any;\n }\n}\n\n// ============================================================\n// Module-level constants\n// ============================================================\n\nconst name = 'Rokt';\nconst moduleId = 181;\nconst EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements';\nconst ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com';\nconst INIT_LOG_SAMPLING_RATE = 0.1;\nconst ROKT_THANK_YOU_JOURNEY_EXTENSION = 'ThankYouPageJourney';\nconst ROKT_INTEGRATION_SCRIPT_ID = 'rokt-launcher';\nconst ROKT_THANK_YOU_ELEMENT_SCRIPT_ID = 'rokt-thank-you-element';\nconst USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace';\n\nconst MESSAGE_TYPE_PAGE_VIEW = 3; // mParticle MessageType.PageView\nconst MESSAGE_TYPE_SESSION_END = 2; // mParticle MessageType.SessionEnd\nconst PAGE_EVENTS_KEY = 'page_events';\nconst PAGE_VIEW_ATTRIBUTES_KEY = 'page_view_attributes';\nconst MPARTICLE_SESSION_ID_KEY = 'mparticle_session_id';\nconst MPARTICLE_DEVICE_ID_KEY = 'mparticle_device_id';\n\n// Bound on how long selectPlacements will wait for an in-flight Workspace\n// IDSync search before proceeding without the userIdentifiedInWorkspace flag.\n// Long enough to cover the typical /v1/search round-trip (~50ms); short enough that a\n// stalled search never blocks placement rendering on a thank-you page.\nconst WORKSPACE_SEARCH_SELECT_TIMEOUT_MS = 500;\n\n// ============================================================\n// Reporting service constants\n// ============================================================\n\nconst ErrorCodes = {\n UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION',\n IDENTITY_REQUEST: 'IDENTITY_REQUEST',\n LOG_DELIVERY_FAILURE: 'LOG_DELIVERY_FAILURE',\n} as const;\n\nconst WSDKErrorSeverity = {\n ERROR: 'ERROR',\n INFO: 'INFO',\n WARNING: 'WARNING',\n} as const;\n\nconst DEFAULT_ROKT_DOMAIN = 'apps.rokt-api.com';\nconst LOGGING_ENDPOINT = '/v1/log';\nconst ERROR_ENDPOINT = '/v1/errors';\nconst RATE_LIMIT_PER_SEVERITY = 10;\n\n// ============================================================\n// Helper: typed accessor for window.mParticle\n// We use an explicit cast here to avoid conflicts with @mparticle/web-sdk\n// type declarations while still providing full type safety for our usages.\n// ============================================================\n\nfunction mp(): MParticleExtended {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (window as any).mParticle as MParticleExtended;\n}\n\n// ============================================================\n// Module-level utility functions\n// ============================================================\n\nfunction generateLauncherScript(domain: string | undefined, extensions: string[]): string {\n const launcherPath = '/wsdk/integrations/launcher.js';\n const baseUrl = [generateBaseUrl(domain), launcherPath].join('');\n\n if (!extensions || extensions.length === 0) {\n return baseUrl;\n }\n return baseUrl + '?extensions=' + extensions.join(',');\n}\n\nfunction generateThankYouElementScript(domain: string | undefined) {\n const thankYouElementPath = '/rokt-elements/rokt-element-thank-you.js';\n return [generateBaseUrl(domain), thankYouElementPath].join('');\n}\n\nfunction generateBaseUrl(domain: string | undefined) {\n const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN;\n\n if (resolvedDomain.includes('://')) {\n return resolvedDomain.replace(/\\/+$/, '');\n }\n\n const protocol = 'https://';\n\n return [protocol, resolvedDomain].join('');\n}\n\nfunction generateReportingUrl(configuredUrl: string | undefined, domain: string | undefined, endpoint: string): string {\n if (configuredUrl) {\n if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://')) {\n return configuredUrl;\n }\n return 'https://' + configuredUrl;\n }\n\n const hasNonHttpScheme = domain?.includes('://') && !/^https?:\\/\\//i.test(domain);\n const reportingDomain = hasNonHttpScheme ? undefined : domain;\n\n return generateBaseUrl(reportingDomain) + endpoint;\n}\n\nfunction loadRoktScript(\n scriptId: string,\n source: string,\n handlers?: { onLoad?: () => void; onError?: (e: Event | string) => void },\n): void {\n if (document.getElementById(scriptId)) return; // resolves the preexisting script issue\n\n const target = document.head || document.body;\n const script = document.createElement('script');\n script.id = scriptId;\n script.type = 'text/javascript';\n script.src = source;\n script.async = true;\n script.crossOrigin = 'anonymous';\n (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high';\n if (handlers?.onLoad) script.onload = handlers.onLoad;\n if (handlers?.onError) script.onerror = handlers.onError;\n target.appendChild(script);\n}\n\nfunction parseSettingsString(settingsString?: string): T[] {\n if (!settingsString) {\n return [];\n }\n try {\n return JSON.parse(settingsString.replace(/"/g, '\"')) as T[];\n } catch (_error) {\n console.error('Settings string contains invalid JSON');\n }\n return [];\n}\n\nfunction extractRoktExtensionConfig(settingsString?: string): RoktExtensionConfig {\n const settings = settingsString ? parseSettingsString(settingsString) : [];\n const roktExtensionsQueryParams: string[] = [];\n const legacyRoktExtensions: string[] = [];\n let loadThankYouElement = false;\n\n for (let i = 0; i < settings.length; i++) {\n const extensionName = settings[i].value;\n if (extensionName === 'thank-you-journey') {\n loadThankYouElement = true;\n legacyRoktExtensions.push(ROKT_THANK_YOU_JOURNEY_EXTENSION);\n } else {\n roktExtensionsQueryParams.push(extensionName);\n }\n }\n\n return {\n roktExtensionsQueryParams,\n legacyRoktExtensions,\n loadThankYouElement,\n };\n}\n\nasync function registerLegacyExtensions(legacyExtensions: string[], launcher: RoktLauncher | null) {\n const extensions: Promise[] = [];\n if (launcher) {\n for (const extension of legacyExtensions) {\n extensions.push(launcher.use(extension));\n }\n }\n\n return Promise.all(extensions);\n}\n\nfunction generateMappedEventLookup(placementEventMapping: PlacementEventMappingEntry[]): Record {\n if (!placementEventMapping) {\n return {};\n }\n\n const mappedEvents: Record = {};\n for (let i = 0; i < placementEventMapping.length; i++) {\n const mapping = placementEventMapping[i];\n mappedEvents[mapping.jsmap] = mapping.value;\n }\n return mappedEvents;\n}\n\nfunction generateMappedEventAttributeLookup(\n placementEventAttributeMapping: EventAttributeMapping[],\n): Record {\n const mappedAttributeKeys: Record = {};\n if (!Array.isArray(placementEventAttributeMapping)) {\n return mappedAttributeKeys;\n }\n for (let i = 0; i < placementEventAttributeMapping.length; i++) {\n const mapping = placementEventAttributeMapping[i];\n if (!mapping || !isString(mapping.value) || !isString(mapping.map)) {\n continue;\n }\n\n const mappedAttributeKey = mapping.value;\n const eventAttributeKey = mapping.map;\n\n if (!mappedAttributeKeys[mappedAttributeKey]) {\n mappedAttributeKeys[mappedAttributeKey] = [];\n }\n\n mappedAttributeKeys[mappedAttributeKey].push({\n eventAttributeKey: eventAttributeKey,\n conditions: Array.isArray(mapping.conditions) ? mapping.conditions : [],\n });\n }\n return mappedAttributeKeys;\n}\n\nfunction hashEventMessage(messageType: number, eventType: number, eventName: string): string | number {\n return mp().generateHash([messageType, eventType, eventName].join(''));\n}\n\nfunction generateIntegrationName(customIntegrationName?: string): string {\n const coreSdkVersion = mp().getVersion();\n const kitVersion = process.env.PACKAGE_VERSION;\n let integrationName = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion;\n\n if (customIntegrationName) {\n integrationName += '_' + customIntegrationName;\n }\n return integrationName;\n}\n\nfunction djb2(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return hash;\n}\n\nfunction createAutoRemovedIframe(src: string): void {\n const iframe = document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');\n iframe.src = src;\n iframe.onload = function () {\n iframe.onload = null;\n if (iframe.parentNode) {\n iframe.parentNode.removeChild(iframe);\n }\n };\n const target = document.body || document.head;\n if (target) {\n target.appendChild(iframe);\n }\n}\n\nfunction sendAdBlockMeasurementSignals(domain: string | undefined, version: string | null): void {\n const originHash = djb2(window.location.origin);\n const allowedOriginHashes = RoktKit._allowedOriginHashes;\n if (allowedOriginHashes.indexOf(originHash) === -1) {\n return;\n }\n\n if (Math.random() >= INIT_LOG_SAMPLING_RATE) {\n return;\n }\n\n const guid = window.__rokt_li_guid__;\n if (!guid) {\n return;\n }\n\n if (domain && domain.includes('://') && !/^https:\\/\\//i.test(domain)) {\n return;\n }\n\n const pageUrl = window.location.href.split('?')[0].split('#')[0];\n const params =\n 'version=' +\n encodeURIComponent(version ?? '') +\n '&launcherInstanceGuid=' +\n encodeURIComponent(guid) +\n '&pageUrl=' +\n encodeURIComponent(pageUrl);\n\n const existingBaseUrl = domain ? generateBaseUrl(domain) : 'https://apps.rokt.com';\n createAutoRemovedIframe(existingBaseUrl + '/v1/wsdk-init/index.html?' + params);\n\n createAutoRemovedIframe(\n 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true',\n );\n}\n\n// ============================================================\n// Reporting helpers\n// ============================================================\n\nfunction _isDebugModeEnabled(): boolean {\n return typeof window !== 'undefined' && !!window.location?.search?.toLowerCase().includes('mp_enable_logging=true');\n}\n\nfunction _getReportingUrl(): string | undefined {\n return typeof window !== 'undefined' ? window.location?.href : undefined;\n}\n\nfunction _getUserAgent(): string | undefined {\n return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined;\n}\n\nclass RateLimiter {\n private _logCount: Record = {};\n\n incrementAndCheck(severity: string): boolean {\n const count = this._logCount[severity] || 0;\n const newCount = count + 1;\n this._logCount[severity] = newCount;\n return newCount > RATE_LIMIT_PER_SEVERITY;\n }\n}\n\nclass ReportingTransport {\n private _isEnabled: boolean;\n private _integrationName: string;\n private _launcherInstanceGuid: string | undefined;\n private _accountId: string | null;\n private _rateLimiter: RateLimiter;\n private readonly _reporter = 'mp-wsdk';\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid: string | undefined,\n accountId: string | null | undefined,\n rateLimiter?: RateLimiter,\n ) {\n const isLoggingEnabled = config.isLoggingEnabled;\n this._integrationName = integrationName || '';\n this._launcherInstanceGuid = launcherInstanceGuid;\n this._accountId = accountId || null;\n this._rateLimiter = rateLimiter || new RateLimiter();\n this._isEnabled = _isDebugModeEnabled() || isLoggingEnabled;\n }\n\n send(\n url: string,\n severity: string,\n msg: string,\n code?: string,\n stackTrace?: string,\n onError?: (error: DeliveryError) => void,\n ): void {\n if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) {\n return;\n }\n\n try {\n const logRequest = {\n additionalInformation: {\n message: msg,\n version: this._integrationName,\n },\n severity,\n code: code || ErrorCodes.UNKNOWN_ERROR,\n url: _getReportingUrl(),\n deviceInfo: _getUserAgent(),\n stackTrace,\n reporter: this._reporter,\n integration: this._integrationName,\n };\n\n const headers: Record = {\n Accept: 'text/plain;charset=UTF-8',\n 'Content-Type': 'application/json',\n 'rokt-launcher-version': this._integrationName,\n 'rokt-wsdk-version': 'joint',\n };\n\n if (this._launcherInstanceGuid) {\n headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid;\n }\n if (this._accountId) {\n headers['rokt-account-id'] = this._accountId;\n }\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(logRequest),\n })\n .then((response: Response) => {\n // fetch only rejects on network failures; an HTTP 5xx resolves with\n // ok === false. Surface server-side failures so they are not swallowed.\n if (!response.ok) {\n const serverError: DeliveryError = new Error('HTTP ' + response.status + ' from log endpoint');\n serverError.statusCode = response.status;\n throw serverError;\n }\n })\n .catch((error: DeliveryError) => {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error);\n });\n } catch (error) {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error as DeliveryError);\n }\n }\n}\n\nclass ErrorReportingService {\n private _transport: ReportingTransport;\n private _errorUrl: string;\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._errorUrl = generateReportingUrl(config?.errorUrl, config?.integrationDomain, ERROR_ENDPOINT);\n }\n\n report(error: ErrorReport | null | undefined): void {\n if (!error) return;\n const severity = error.severity || WSDKErrorSeverity.ERROR;\n this._transport.send(this._errorUrl, severity, error.message, error.code, error.stackTrace);\n }\n}\n\nclass LoggingService {\n private _transport: ReportingTransport;\n private _loggingUrl: string;\n private _errorReportingService: { report: (e: ErrorReport) => void };\n\n constructor(\n config: ReportingConfig,\n errorReportingService: { report: (e: ErrorReport) => void },\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._loggingUrl = generateReportingUrl(config?.loggingUrl, config?.integrationDomain, LOGGING_ENDPOINT);\n this._errorReportingService = errorReportingService;\n }\n\n log(entry: LogEntry | null | undefined): void {\n if (!entry) return;\n this._transport.send(\n this._loggingUrl,\n WSDKErrorSeverity.INFO,\n entry.message,\n entry.code,\n undefined,\n (error: DeliveryError) => {\n if (this._errorReportingService) {\n // A failed log POST is not itself an SDK error. Network-level failures\n // (ad-blockers, offline, CORS) are client-side noise and reported as a\n // WARNING; only a server-side non-2xx response stays at ERROR severity.\n const isServerSide = typeof error.statusCode === 'number';\n this._errorReportingService.report({\n message: 'LoggingService: Failed to send log: ' + error.message,\n code: ErrorCodes.LOG_DELIVERY_FAILURE,\n severity: isServerSide ? WSDKErrorSeverity.ERROR : WSDKErrorSeverity.WARNING,\n });\n }\n },\n );\n }\n}\n\nfunction buildPageEvent(event: SDKEvent): PageEvent {\n const pageUrl = sanitizeUrl(window.location.href);\n const pageTitle = event.EventAttributes?.title || document.title;\n const canonicalUrl = readCanonicalUrl();\n const activeTimeOnSite = event.ActiveTimeOnSite;\n\n return {\n pageUrl,\n sourceMessageId: event.SourceMessageId,\n timestamp: event.Timestamp,\n ...(pageTitle ? { pageTitle } : {}),\n ...(canonicalUrl !== undefined ? { canonicalUrl } : {}),\n ...(Number.isFinite(activeTimeOnSite) ? { activeTimeOnSite } : {}),\n };\n}\n\n// ============================================================\n// RoktKit class\n// ============================================================\n\nclass RoktKit implements KitInterface {\n // Static field for allowed origin hashes (mutable by testHelpers)\n public static _allowedOriginHashes: number[] = [-553112570, 549508659];\n\n private static readonly PERFORMANCE_MARKS = {\n RoktScriptAppended: 'mp:RoktScriptAppended',\n };\n\n private static readonly EMAIL_SHA256_KEY = 'emailsha256';\n\n // Public fields (accessed by tests and the mParticle framework)\n public name = name;\n public id = moduleId;\n public moduleId = moduleId;\n public isInitialized = false;\n public launcher: RoktLauncher | null = null;\n public filters: KitFilters = {};\n public userAttributes: Record = {};\n // Flag set by the Workspace IDSync flow on a 200 response. Stored on the\n // kit instance and merged into placement attributes inside selectPlacements.\n public userIdentifiedInWorkspace = false;\n public testHelpers: TestHelpers | null = null;\n public placementEventMappingLookup: Record = {};\n public placementEventAttributeMappingLookup: Record = {};\n public integrationName: string | null = null;\n public domain?: string;\n public errorReportingService: ErrorReportingService | null = null;\n public loggingService: LoggingService | null = null;\n\n // Private fields\n private _mappedEmailSha256Key?: string;\n private _onboardingExpProvider?: string;\n private _thankYouElementOnLoadCallback: (() => void) | null = null;\n private _isThankYouElementLoaded = false;\n private _workspaceIdSyncApiKey?: string;\n\n // Held during a search dispatch so the next selectPlacements call;\n // can wait for the HTTP response before reading userIdentifiedInWorkspace;\n // — otherwise the first placement call ships without the flag.\n private _workspaceSearchInFlightPromise: Promise | null = null;\n // Stable serialization of the identifier set sent in the most recent\n // successful search dispatch. If a subsequent identification arrives with\n // an identical set, we skip the network call (the flag is still correct\n // from the prior search). Keyed over the full IUserIdentities map — not\n // just email — so partners passing hashed email through `other`/`other2-10`\n // or any other identifier benefit from the same dedupe. Cleared on logout\n // so a re-login re-evaluates fresh.\n private _workspaceLastSearchedIdentitiesKey?: string;\n\n // ---- Private helpers ----\n\n private getEventAttributeValue(event: SDKEvent, eventAttributeKey: string): unknown {\n const attributes = event && event.EventAttributes;\n if (!attributes) {\n return null;\n }\n\n if (typeof attributes[eventAttributeKey] === 'undefined') {\n return null;\n }\n\n return attributes[eventAttributeKey];\n }\n\n private doesEventAttributeConditionMatch(condition: EventAttributeCondition, actualValue: unknown): boolean {\n if (!condition || !isString(condition.operator)) {\n return false;\n }\n\n const operator = condition.operator.toLowerCase();\n const expectedValue = condition.attributeValue;\n\n if (operator === 'exists') {\n return actualValue !== null;\n }\n\n if (actualValue == null) {\n return false;\n }\n\n if (operator === 'equals') {\n return String(actualValue) === String(expectedValue);\n }\n\n if (operator === 'contains') {\n return String(actualValue).indexOf(String(expectedValue)) !== -1;\n }\n\n return false;\n }\n\n private doesEventMatchRule(event: SDKEvent, rule: PlacementEventRule): boolean {\n if (!rule || !isString(rule.eventAttributeKey)) {\n return false;\n }\n\n const conditions = rule.conditions;\n if (!Array.isArray(conditions)) {\n return false;\n }\n\n const actualValue = this.getEventAttributeValue(event, rule.eventAttributeKey);\n\n if (conditions.length === 0) {\n return actualValue !== null;\n }\n for (let i = 0; i < conditions.length; i++) {\n if (!this.doesEventAttributeConditionMatch(conditions[i], actualValue)) {\n return false;\n }\n }\n\n return true;\n }\n\n private applyPlacementEventAttributeMapping(event: SDKEvent): void {\n const mappedAttributeKeys = Object.keys(this.placementEventAttributeMappingLookup);\n for (let i = 0; i < mappedAttributeKeys.length; i++) {\n const mappedAttributeKey = mappedAttributeKeys[i];\n const rulesForMappedAttributeKey = this.placementEventAttributeMappingLookup[mappedAttributeKey];\n if (isEmpty(rulesForMappedAttributeKey)) {\n continue;\n }\n\n // Require ALL rules for the same key to match (AND).\n let allMatch = true;\n for (let j = 0; j < rulesForMappedAttributeKey.length; j++) {\n if (!this.doesEventMatchRule(event, rulesForMappedAttributeKey[j])) {\n allMatch = false;\n break;\n }\n }\n if (!allMatch) {\n continue;\n }\n\n mp().Rokt.setLocalSessionAttribute?.(mappedAttributeKey, true);\n }\n }\n\n private capturePageView(event: SDKEvent): void {\n let pageUrl: string | undefined;\n\n try {\n pageUrl = sanitizeUrl(window.location.href);\n\n const pageViews = loadPageViews(this.loggingService);\n const pageView = buildPageEvent(event);\n pageViews.push(pageView);\n\n const requested = Math.min(pageViews.length, PAGE_VIEWS_MAX_COUNT);\n const stored = writePageViews(pageViews);\n if (stored === 0) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n this.loggingService?.log({\n message: `Rokt Kit: Failed to persist page view for ${pageUrl} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n } else if (stored < requested) {\n this.loggingService?.log({\n message: `Rokt Kit: Page view storage reduced from ${requested} to ${stored} record(s) under quota pressure [reason: quota_eviction]`,\n code: 'PAGE_VIEW_QUOTA_EVICTION',\n });\n }\n } catch (err) {\n const reason = isLocalStorageAvailable() ? 'exception' : 'ls_unavailable';\n const errMessage = err instanceof Error ? err.message : String(err);\n this.loggingService?.log({\n message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${errMessage} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n private isLauncherReadyToAttach(): boolean {\n return !!window.Rokt && isFunction(window.Rokt.createLauncher);\n }\n\n /**\n * Returns the user identities from the filtered user, if any.\n */\n private returnUserIdentities(filteredUser: FilteredUser | null | undefined): Record {\n if (!filteredUser || !filteredUser.getUserIdentities) {\n return {};\n }\n\n const userIdentities: IUserIdentities = filteredUser.getUserIdentities().userIdentities;\n\n return this.replaceOtherIdentityWithEmailsha256(userIdentities);\n }\n\n private returnLocalSessionAttributes(): Record {\n if (!mp().Rokt || typeof mp().Rokt.getLocalSessionAttributes !== 'function') {\n return {};\n }\n return mp().Rokt.getLocalSessionAttributes!();\n }\n\n private replaceOtherIdentityWithEmailsha256(userIdentities: IUserIdentities): Record {\n const newUserIdentities: Record = { ...(userIdentities || {}) };\n const key = this._mappedEmailSha256Key;\n if (key && userIdentities[key as keyof IUserIdentities]) {\n newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key as keyof IUserIdentities] as string;\n }\n if (key) {\n delete newUserIdentities[key];\n }\n\n return newUserIdentities;\n }\n\n private logSelectPlacementsEvent(attributes: unknown): void {\n if (!window.mParticle || typeof mp().logEvent !== 'function') {\n return;\n }\n\n if (!isObject(attributes)) {\n return;\n }\n\n const EVENT_TYPE_OTHER = mp().EventType.Other;\n\n mp().logEvent(EVENT_NAME_SELECT_PLACEMENTS, EVENT_TYPE_OTHER, attributes as Record);\n }\n\n private setRoktSessionId(sessionId: string): void {\n if (!sessionId || typeof sessionId !== 'string') {\n return;\n }\n try {\n const mpInstance = mp().getInstance();\n if (mpInstance && isFunction(mpInstance.setIntegrationAttribute)) {\n mpInstance.setIntegrationAttribute(moduleId, {\n roktSessionId: sessionId,\n });\n }\n } catch (_e) {\n // Best effort — never let this break the partner page\n }\n }\n\n private readMpSessionId(): string | undefined {\n // The public mParticle.sessionManager facade exposes only getSession(), which already returns\n // the session id. getSessionId() lives on the internal _SessionManager and has never been\n // re-exported, so prefer it if a future core adds it and fall back to getSession() until then.\n const sessionManager = mp()?.sessionManager;\n const readSessionId = sessionManager?.getSessionId ?? sessionManager?.getSession;\n if (!isFunction(readSessionId)) {\n return undefined;\n }\n\n return readSessionId.call(sessionManager) || undefined;\n }\n\n private readMpDeviceId(): string | undefined {\n // The device application stamp (`das`) outlives the session id: core clears the session on\n // timeout, cross-tab rotation and endSession(), but never the device id, which lives in\n // localStorage/cookie for cookieExpiration days (365 by default) and survives login/logout.\n // Read it per call anyway — a partner can reassign it at any time via setDeviceId().\n return mp()?.getDeviceId?.() || undefined;\n }\n\n private attachLauncher(\n accountId: string,\n launcherOptions: Record,\n legacyRoktExtensions: string[] = [],\n ): void {\n const options: Record = {\n accountId,\n ...(launcherOptions || {}),\n };\n\n let launcherPromise: Promise;\n if (this.isPartnerInLocalLauncherTestGroup()) {\n launcherPromise = Promise.resolve(window.Rokt!.createLocalLauncher(options));\n } else {\n launcherPromise = window.Rokt!.createLauncher(options);\n }\n\n launcherPromise\n .then(async (launcher) => {\n await registerLegacyExtensions(legacyRoktExtensions, launcher);\n this.initRoktLauncher(launcher);\n })\n .catch((err: unknown) => {\n console.error('Error creating Rokt launcher:', err);\n });\n }\n\n private initRoktLauncher(launcher: RoktLauncher): void {\n // Assign the launcher to a global variable for later access\n if (window.Rokt) {\n window.Rokt.currentLauncher = launcher;\n }\n // Locally cache the launcher and filters\n this.launcher = launcher;\n\n const roktFilters = mp().Rokt?.filters;\n\n if (!roktFilters) {\n console.warn('Rokt Kit: No filters have been set.');\n } else {\n this.filters = roktFilters;\n if (!roktFilters.filteredUser) {\n console.warn('Rokt Kit: No filtered user has been set.');\n } else {\n this._workspaceSearchInFlightPromise = this.search(roktFilters.filteredUser);\n }\n }\n\n // Kit must be initialized before attaching to the Rokt manager\n this.isInitialized = true;\n\n sendAdBlockMeasurementSignals(this.domain, this.integrationName);\n\n // Attaches the kit to the Rokt manager\n mp().Rokt.attachKit(this);\n }\n\n private fetchOptimizely(): Record {\n const forwarders = mp()\n ._getActiveForwarders()\n .filter((forwarder) => forwarder.name === 'Optimizely');\n\n try {\n if (forwarders.length > 0 && window.optimizely) {\n const optimizelyState = window.optimizely.get('state');\n if (!optimizelyState || !optimizelyState.getActiveExperimentIds) {\n return {};\n }\n const activeExperimentIds = optimizelyState.getActiveExperimentIds();\n const activeExperiments = activeExperimentIds.reduce((acc: Record, expId: string) => {\n acc['rokt.custom.optimizely.experiment.' + expId + '.variationId'] =\n optimizelyState.getVariationMap()[expId].id;\n return acc;\n }, {});\n return activeExperiments;\n }\n } catch (error) {\n console.error('Error fetching Optimizely attributes:', error);\n }\n return {};\n }\n\n private isKitReady(): boolean {\n return !!(this.isInitialized && this.launcher);\n }\n\n // When the partner has opted out of targeting (noTargeting launcher option),\n // the kit must not collect behavioral targeting signals such as page views.\n private isTargetingDisabled(): boolean {\n return (mp().Rokt?.launcherOptions as Record | undefined)?.noTargeting === true;\n }\n\n private isPartnerInLocalLauncherTestGroup(): boolean {\n return !!(mp().config && mp().config!.isLocalLauncherEnabled && this.isAssignedToSampleGroup());\n }\n\n private isAssignedToSampleGroup(): boolean {\n const LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5;\n return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD;\n }\n\n private captureTiming(metricName: string): void {\n if (window && mp() && mp().captureTiming && metricName) {\n mp().captureTiming!(metricName);\n }\n }\n\n // ---- Public methods (mParticle Kit Callbacks) ----\n\n /**\n * Initializes the Rokt forwarder with settings from the mParticle server.\n */\n public init(\n settings: Record,\n _service: unknown,\n testMode: boolean,\n _trackerId: unknown,\n filteredUserAttributes?: Record,\n ): string {\n const kitSettings = settings as unknown as RoktKitSettings;\n const accountId = kitSettings.accountId;\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredUserAttributes);\n this._onboardingExpProvider = kitSettings.onboardingExpProvider;\n\n const placementEventMapping = parseSettingsString(kitSettings.placementEventMapping);\n this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping);\n\n const placementEventAttributeMapping = parseSettingsString(\n kitSettings.placementEventAttributeMapping,\n );\n this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping);\n\n // Set dynamic OTHER_IDENTITY based on server settings\n if (kitSettings.hashedEmailUserIdentityType) {\n this._mappedEmailSha256Key = kitSettings.hashedEmailUserIdentityType.toLowerCase();\n }\n\n this._workspaceIdSyncApiKey = isString(kitSettings.workspaceIdSyncApiKey)\n ? kitSettings.workspaceIdSyncApiKey\n : undefined;\n\n const domain = mp().Rokt?.domain;\n const { roktExtensionsQueryParams, legacyRoktExtensions, loadThankYouElement } = extractRoktExtensionConfig(\n kitSettings.roktExtensions,\n );\n const launcherOptions: Record = {\n ...((mp().Rokt?.launcherOptions as Record) || {}),\n };\n this.integrationName = generateIntegrationName(launcherOptions.integrationName as string | undefined);\n launcherOptions.integrationName = this.integrationName;\n\n this.domain = domain;\n\n const reportingConfig: ReportingConfig = {\n loggingUrl: kitSettings.loggingUrl,\n errorUrl: kitSettings.errorUrl,\n integrationDomain: domain,\n isLoggingEnabled: mp().config?.isLoggingEnabled === true,\n };\n const errorReportingService = new ErrorReportingService(\n reportingConfig,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n const loggingService = new LoggingService(\n reportingConfig,\n errorReportingService,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n\n this.errorReportingService = errorReportingService;\n this.loggingService = loggingService;\n\n if (this.isTargetingDisabled()) {\n try {\n clearPageViews();\n clearUtmParams();\n } catch (err) {\n this.errorReportingService?.report({\n message: 'Rokt Kit: Failed to clear page views when targeting is disabled',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n severity: WSDKErrorSeverity.INFO,\n stackTrace: err instanceof Error ? err.stack : undefined,\n });\n }\n }\n\n if (mp()._registerErrorReportingService) {\n mp()._registerErrorReportingService!(errorReportingService);\n }\n if (mp()._registerLoggingService) {\n mp()._registerLoggingService!(loggingService);\n }\n\n if (testMode) {\n this.testHelpers = {\n generateLauncherScript: generateLauncherScript,\n generateThankYouElementScript: generateThankYouElementScript,\n extractRoktExtensionConfig: extractRoktExtensionConfig,\n hashEventMessage: hashEventMessage,\n parseSettingsString: parseSettingsString,\n generateMappedEventLookup: generateMappedEventLookup,\n generateMappedEventAttributeLookup: generateMappedEventAttributeLookup,\n sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals,\n createAutoRemovedIframe: createAutoRemovedIframe,\n djb2: djb2,\n setAllowedOriginHashes: (hashes: number[]) => {\n RoktKit._allowedOriginHashes = hashes;\n },\n ReportingTransport: ReportingTransport,\n ErrorReportingService: ErrorReportingService,\n LoggingService: LoggingService,\n RateLimiter: RateLimiter,\n ErrorCodes: ErrorCodes,\n WSDKErrorSeverity: WSDKErrorSeverity,\n };\n this.attachLauncher(accountId, launcherOptions);\n return 'Successfully initialized: ' + name;\n }\n\n if (loadThankYouElement) {\n mp().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this);\n loadRoktScript(ROKT_THANK_YOU_ELEMENT_SCRIPT_ID, generateThankYouElementScript(domain), {\n onLoad: () => {\n this._isThankYouElementLoaded = true;\n if (this._thankYouElementOnLoadCallback) {\n this._thankYouElementOnLoadCallback();\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt Thank You Element script:', error);\n },\n });\n }\n\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n loadRoktScript(ROKT_INTEGRATION_SCRIPT_ID, generateLauncherScript(domain, roktExtensionsQueryParams), {\n onLoad: () => {\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n console.error('Rokt object is not available after script load.');\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt launcher script:', error);\n },\n });\n\n this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended);\n }\n\n return 'Successfully initialized: ' + name;\n }\n\n public process(event: SDKEvent): string {\n if (!this.isTargetingDisabled()) {\n if (event.EventDataType === MESSAGE_TYPE_PAGE_VIEW) {\n captureUtmParams(this.loggingService);\n this.capturePageView(event);\n }\n\n if (event.EventDataType === MESSAGE_TYPE_SESSION_END) {\n migrateLegacyPageViewStorage(this.loggingService);\n clearPageViews();\n clearUtmParams();\n }\n }\n\n // The forwarding work below (LSA mapping) depends on the launcher, so guard\n // it here and surface the not-ready signal to the core SDK.\n if (!this.isKitReady()) {\n return 'Kit not ready for forwarder: ' + name;\n }\n\n if (isFunction(mp().Rokt?.setLocalSessionAttribute)) {\n if (!isEmpty(this.placementEventAttributeMappingLookup)) {\n this.applyPlacementEventAttributeMapping(event);\n }\n\n if (!isEmpty(this.placementEventMappingLookup)) {\n const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? '');\n if (this.placementEventMappingLookup[String(hashedEvent)]) {\n mp().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(hashedEvent)], true);\n }\n }\n }\n\n return 'Successfully sent to forwarder: ' + name;\n }\n\n public setExtensionData(partnerExtensionData: Record): void {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return;\n }\n\n window.Rokt!.setExtensionData(partnerExtensionData);\n }\n\n public setUserAttribute(key: string, value: unknown): string {\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n this.userAttributes[key] = value;\n }\n return 'Successfully set user attribute for forwarder: ' + name;\n }\n\n public removeUserAttribute(key: string): string {\n delete this.userAttributes[key];\n return 'Successfully removed user attribute for forwarder: ' + name;\n }\n\n private handleIdentityComplete(user: IMParticleUser, callbackName: string): string {\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(user.getAllUserAttributes());\n return 'Successfully called ' + callbackName + ' for forwarder: ' + name;\n }\n\n public onUserIdentified(user: IMParticleUser): string {\n const filteredUser = user as FilteredUser;\n this.filters.filteredUser = filteredUser;\n this._workspaceSearchInFlightPromise = this.search(filteredUser);\n return this.handleIdentityComplete(user, 'onUserIdentified');\n }\n\n private search(filteredUser: FilteredUser): Promise {\n const apiKey = this._workspaceIdSyncApiKey;\n if (!apiKey) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n const search = mp().Identity?.search;\n if (typeof search !== 'function') {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n const userIdentities: IUserIdentities | null = filteredUser.getUserIdentities\n ? filteredUser.getUserIdentities().userIdentities\n : null;\n\n // Forward every non-empty string identifier the user has — email,\n // customerid, other/other2-10 (commonly used for hashed email),\n // mobile_number, facebook, etc. The host SDK's Identity.search accepts\n // the full IUserIdentities surface and the server validates it.\n const knownIdentities: Record = {};\n if (userIdentities) {\n for (const key of Object.keys(userIdentities) as Array) {\n const value = userIdentities[key];\n if (isString(value) && value.length > 0) {\n knownIdentities[key] = value;\n }\n }\n }\n\n const identityKeys = Object.keys(knownIdentities);\n if (identityKeys.length === 0) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n // Stable cache key: sort keys so insertion-order differences don't\n // cause false misses. The values are partner-supplied strings; no\n // hashing needed — equality on this serialization is sufficient.\n const identitiesKey = identityKeys\n .sort()\n .map((k) => `${k}=${knownIdentities[k]}`)\n .join('&');\n\n // Same identifier set as the last successful dispatch → skip the\n // network call. The current flag value still reflects the correct\n // match status.\n if (identitiesKey === this._workspaceLastSearchedIdentitiesKey) {\n return this._workspaceSearchInFlightPromise || Promise.resolve();\n }\n\n // New / different identifier set → reset and re-search. Cache the key\n // up front so a second concurrent invocation with the same set also\n // dedupes.\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = identitiesKey;\n\n return new Promise((resolve) => {\n try {\n search(apiKey, knownIdentities as IUserIdentities, (result: WorkspaceIdSyncResult) => {\n if (result?.httpCode === 200) {\n this.userIdentifiedInWorkspace = true;\n }\n resolve();\n });\n } catch (err) {\n console.error('Rokt Kit: Workspace IDSync search failed', err);\n // Dispatch failed — clear the cache so the same identifier set\n // can retry on the next identification rather than being stuck\n // behind a poisoned entry that short-circuits future searches.\n this._workspaceLastSearchedIdentitiesKey = undefined;\n resolve();\n }\n });\n }\n\n public onLoginComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onLoginComplete');\n }\n\n public onLogoutComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n // Anonymous sessions must not carry the previous user's match forward.\n // Clear the flag explicitly here. Also clear the identities cache so a\n // re-login (possibly with the same identifiers) dispatches a fresh\n // search rather than reusing a stale answer.\n this.userIdentifiedInWorkspace = false;\n this._workspaceSearchInFlightPromise = null;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return this.handleIdentityComplete(user, 'onLogoutComplete');\n }\n\n public onModifyComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onModifyComplete');\n }\n\n /**\n * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options.\n *\n * If a Workspace IDSync search is in flight from a recent onUserIdentified\n * call, this method waits up to `WORKSPACE_SEARCH_SELECT_TIMEOUT_MS` for it\n * to settle so the first placement call can include the\n * `userIdentifiedInWorkspace` flag without racing the network response.\n * The timeout protects against a stalled or slow search blocking placement\n * rendering — if it fires, selectPlacements proceeds without the flag.\n *\n * Implementation note: this method stays non-async deliberately. First,\n * the public return type is `RoktSelection | Promise |\n * undefined` — a superset of the `RoktSelection | Promise`\n * shape declared for `RoktLauncher.selectPlacements` above (line ~70).\n * Marking this `async` would narrow it to `Promise` and silently change the contract for callers that read\n * the result synchronously. Second, `RoktSelection` has an optional\n * `then?` member, so TS treats it as ambiguously promise-like and\n * rejects it as the awaited return of an async function (TS1058) —\n * working around that would require a cast or wrapping every return in\n * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`;\n * this wrapper just gates it on the in-flight search via `Promise.race`.\n */\n public selectPlacements(options: Record): RoktSelection | Promise | undefined {\n if (this._workspaceSearchInFlightPromise) {\n const inFlight = this._workspaceSearchInFlightPromise;\n return Promise.race([\n inFlight,\n new Promise((resolve) => setTimeout(resolve, WORKSPACE_SEARCH_SELECT_TIMEOUT_MS)),\n ]).then(() => this._dispatchPlacements(options)) as Promise;\n }\n return this._dispatchPlacements(options);\n }\n\n private _dispatchPlacements(options: Record): RoktSelection | Promise | undefined {\n const attributes = ((options && (options.attributes as Record)) || {}) as Record;\n const cachedUserAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(this.userAttributes);\n const placementAttributes: Record = { ...cachedUserAttributes, ...attributes };\n\n const filters = this.filters || {};\n const userAttributeFilters = (filters.userAttributeFilters as string[]) || [];\n const filteredUser = filters.filteredUser || null;\n const mpid = filteredUser ? filteredUser.getMPID() : null;\n\n let filteredAttributes: Record;\n\n if (!filters) {\n console.warn('Rokt Kit: No filters available, using user attributes');\n filteredAttributes = placementAttributes;\n } else if (filters.filterUserAttributes) {\n filteredAttributes = filters.filterUserAttributes(placementAttributes, userAttributeFilters);\n } else {\n filteredAttributes = placementAttributes;\n }\n\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredAttributes);\n\n const optimizelyAttributes = this._onboardingExpProvider === 'Optimizely' ? this.fetchOptimizely() : {};\n\n const filteredUserIdentities = this.returnUserIdentities(filteredUser);\n\n const sessionAttributes = this.returnLocalSessionAttributes();\n const pageEvents = buildPageEvents(loadPageViews(this.loggingService));\n const utmParams = loadUtmParams();\n const mpSessionId = this.readMpSessionId();\n const mpDeviceId = this.readMpDeviceId();\n\n const selectPlacementsAttributes: Record = {\n ...(filteredUserIdentities as Record),\n ...filteredAttributes,\n ...optimizelyAttributes,\n ...sessionAttributes,\n ...(pageEvents.length ? { [PAGE_EVENTS_KEY]: JSON.stringify(pageEvents) } : {}),\n ...(utmParams ? { [PAGE_VIEW_ATTRIBUTES_KEY]: JSON.stringify(utmParams) } : {}),\n ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}),\n ...(mpSessionId ? { [MPARTICLE_SESSION_ID_KEY]: mpSessionId } : {}),\n ...(mpDeviceId ? { [MPARTICLE_DEVICE_ID_KEY]: mpDeviceId } : {}),\n mpid,\n };\n\n const selectPlacementsOptions: Record = { ...options, attributes: selectPlacementsAttributes };\n\n const selection = this.launcher!.selectPlacements(selectPlacementsOptions);\n\n // After selection resolves, sync the Rokt session ID back to mParticle, then log\n const logSelection = () => this.logSelectPlacementsEvent(selectPlacementsAttributes);\n\n void Promise.resolve(selection)\n .then((sel) => sel?.context?.sessionId?.then((sessionId) => this.setRoktSessionId(sessionId)))\n .catch(() => undefined)\n .finally(logSelection);\n\n return selection;\n }\n\n /**\n * Passes attributes to the Rokt Web SDK for client-side hashing.\n */\n public hashAttributes(attributes: Record): Promise> | null {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return null;\n }\n return this.launcher!.hashAttributes(attributes);\n }\n\n /**\n * Enables optional Integration Launcher extensions before selecting placements.\n *\n * @deprecated This functionality has been internalized and will be removed in a future release.\n */\n public use(extensionName: string): Promise {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return Promise.reject(new Error('Rokt Kit: Not initialized'));\n }\n if (!extensionName || !isString(extensionName)) {\n return Promise.reject(new Error('Rokt Kit: Invalid extension name'));\n }\n return this.launcher!.use(extensionName);\n }\n\n /**\n * Registers a callback to be invoked once rokt-thank-you-element.js becomes available.\n */\n public onShoppableAdsReady(callback: () => void) {\n if (this._isThankYouElementLoaded) {\n callback();\n } else {\n this._thankYouElementOnLoadCallback = callback;\n }\n }\n}\n\n// ============================================================\n// Kit registration\n// ============================================================\n\nfunction getId(): number {\n return moduleId;\n}\n\nfunction register(config: { kits?: Record }): void {\n if (!config) {\n window.console.log('You must pass a config object to register the kit ' + name);\n return;\n }\n if (!isObject(config)) {\n window.console.log(\"'config' must be an object. You passed in a \" + typeof config);\n return;\n }\n\n if (isObject(config.kits)) {\n (config.kits as Record)[name] = {\n constructor: RoktKit,\n };\n } else {\n config.kits = {};\n config.kits[name] = {\n constructor: RoktKit,\n };\n }\n window.console.log('Successfully registered ' + name + ' to your mParticle configuration');\n}\n\nif (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) {\n mp().addForwarder({\n name: name,\n constructor: RoktKit,\n getId: getId,\n });\n}\n\nexport { register };\nexport type { LoggingService };\n"],"names":["SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST","SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET","isSelectPlacementsAttributePersistenceDenied","key","removeSelectPlacementsAttributePersistenceDeniedAttributes","attributes","filteredAttributes","sourceAttributes","attributeKeys","i","isObject","value","isString","isFunction","isEmpty","sanitizeUrl","href","url","LS_PROBE_KEY","isLocalStorageAvailable","readJSON","stored","writeJSON","removeKey","readNamespacedField","namespaceKey","field","blob","writeNamespacedField","next","removeNamespacedField","LS_NAMESPACE_KEY","LS_PAGE_VIEWS_FIELD","LS_UTM_PARAMS_FIELD","LEGACY_PAGE_VIEWS_KEY","PAGE_VIEWS_MAX_COUNT","UTM_KEYS","capPageViews","views","migrateLegacyPageViewStorage","loggingService","legacyViews","loadPageViews","writePageViews","pageViews","toWrite","clearPageViews","buildPageEvents","pageView","index","activeTimeOnSite","hasActiveTime","nextActiveTimeOnSite","hasNextActiveTimeOnSite","diff","captureUtmParams","search","params","captured","reason","loadUtmParams","clearUtmParams","readCanonicalUrl","name","moduleId","EVENT_NAME_SELECT_PLACEMENTS","ADBLOCK_CONTROL_DOMAIN","INIT_LOG_SAMPLING_RATE","ROKT_THANK_YOU_JOURNEY_EXTENSION","ROKT_INTEGRATION_SCRIPT_ID","ROKT_THANK_YOU_ELEMENT_SCRIPT_ID","USER_IDENTIFIED_IN_WORKSPACE_KEY","MESSAGE_TYPE_PAGE_VIEW","MESSAGE_TYPE_SESSION_END","PAGE_EVENTS_KEY","PAGE_VIEW_ATTRIBUTES_KEY","MPARTICLE_SESSION_ID_KEY","MPARTICLE_DEVICE_ID_KEY","WORKSPACE_SEARCH_SELECT_TIMEOUT_MS","ErrorCodes","WSDKErrorSeverity","DEFAULT_ROKT_DOMAIN","LOGGING_ENDPOINT","ERROR_ENDPOINT","RATE_LIMIT_PER_SEVERITY","mp","generateLauncherScript","domain","extensions","baseUrl","generateBaseUrl","generateThankYouElementScript","resolvedDomain","generateReportingUrl","configuredUrl","endpoint","reportingDomain","loadRoktScript","scriptId","source","handlers","target","script","parseSettingsString","settingsString","extractRoktExtensionConfig","settings","roktExtensionsQueryParams","legacyRoktExtensions","loadThankYouElement","extensionName","registerLegacyExtensions","legacyExtensions","launcher","extension","generateMappedEventLookup","placementEventMapping","mappedEvents","mapping","generateMappedEventAttributeLookup","placementEventAttributeMapping","mappedAttributeKeys","mappedAttributeKey","eventAttributeKey","hashEventMessage","messageType","eventType","eventName","generateIntegrationName","customIntegrationName","integrationName","djb2","str","hash","createAutoRemovedIframe","src","iframe","sendAdBlockMeasurementSignals","version","originHash","RoktKit","guid","pageUrl","existingBaseUrl","_isDebugModeEnabled","_getReportingUrl","_getUserAgent","RateLimiter","severity","newCount","ReportingTransport","config","launcherInstanceGuid","accountId","rateLimiter","isLoggingEnabled","msg","code","stackTrace","onError","logRequest","headers","response","serverError","error","ErrorReportingService","LoggingService","errorReportingService","entry","isServerSide","buildPageEvent","event","pageTitle","canonicalUrl","_RoktKit","condition","actualValue","operator","expectedValue","rule","conditions","rulesForMappedAttributeKey","allMatch","j","requested","err","errMessage","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","sessionManager","readSessionId","launcherOptions","options","launcherPromise","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","sessionAttributes","pageEvents","utmParams","mpSessionId","mpDeviceId","selectPlacementsAttributes","selectPlacementsOptions","selection","logSelection","sel","callback","getId","register"],"mappings":"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"} \ No newline at end of file diff --git a/kits/rokt/dist/Rokt-Kit.iife.js b/kits/rokt/dist/Rokt-Kit.iife.js index 374d5a999..ff9f50bc5 100644 --- a/kits/rokt/dist/Rokt-Kit.iife.js +++ b/kits/rokt/dist/Rokt-Kit.iife.js @@ -1,2 +1,2 @@ -var RoktKit=(function(M){"use strict";const me=["active_time_on_site_ms","billingaddress1","billingaddress2","billingcity","billingstate","billingzipcode","cartitems","ccbin","confirmationref","conversiontype","country","couponcode","currency","language","paymentserviceprovider","paymentserviceproviderattribute","paymenttype","shippingaddress1","shippingcity","shippingcountry","shippingmethod","shippingstate","shippingzipcode","totalprice"],Ee=new Set(me);function V(i){return Ee.has(i.toLowerCase())}function R(i){const e={},t=i||{},n=Object.keys(t);for(let r=0;r{const r=t.activeTimeOnSite,s=r!==void 0&&Number.isFinite(r),c=e[n+1]?.activeTimeOnSite,u=c!==void 0&&Number.isFinite(c),l=s&&u?c-r:void 0;return{pageUrl:t.pageUrl,sourceMessageId:t.sourceMessageId,timestamp:t.timestamp,...t.pageTitle!==void 0?{pageTitle:t.pageTitle}:{},...t.canonicalUrl!==void 0?{canonicalUrl:t.canonicalUrl}:{},...s?{activeTimeOnSite:r}:{},...l!==void 0&&l>=0?{activeTimeOnPage:l}:{}}})}function ye(i){if(T(g,L)!==void 0)return;const e=new URLSearchParams(window.location.search),t={};for(const r of _e){const s=e.get(r);s&&(t[r]=s)}if(Object.keys(t).length===0)return;const n=Object.keys(t).join(", ");if(!Y(g,L,t)){const r=F()?"quota":"ls_unavailable";i?.log({message:`Rokt Kit: Failed to persist UTM params [reason: ${r}]`,code:"UTM_CAPTURE_FAILED"});return}i?.log({message:`Rokt Kit: Captured UTM params [${n}]`,code:"UTM_CAPTURE_SUCCESS"})}function Ae(){const i=T(g,L);return E(i)?i:null}function te(){$(g,L)}function ke(){const e=document.querySelector('link[rel="canonical"]')?.href;if(e)return D(e)}const d="Rokt",P=181,ve="selectPlacements",Re="apps.roktecommerce.com",we=.1,be="ThankYouPageJourney",Te="rokt-launcher",Le="rokt-thank-you-element",Pe="userIdentifiedInWorkspace",Oe=3,Ne=2,Ue="page_events",Ce="page_view_attributes",Me="mparticle_session_id",Ke="mparticle_device_id",De=500,G={UNKNOWN_ERROR:"UNKNOWN_ERROR",UNHANDLED_EXCEPTION:"UNHANDLED_EXCEPTION",IDENTITY_REQUEST:"IDENTITY_REQUEST",LOG_DELIVERY_FAILURE:"LOG_DELIVERY_FAILURE"},I={ERROR:"ERROR",INFO:"INFO",WARNING:"WARNING"},Fe="apps.rokt-api.com",Ye="/v1/log",Ge="/v1/errors",xe=10;function a(){return window.mParticle}function ie(i,e){const n=[O(i),"/wsdk/integrations/launcher.js"].join("");return!e||e.length===0?n:n+"?extensions="+e.join(",")}function ne(i){return[O(i),"/rokt-elements/rokt-element-thank-you.js"].join("")}function O(i){const e=typeof i<"u"?i:Fe;return e.includes("://")?e.replace(/\/+$/,""):["https://",e].join("")}function re(i,e,t){if(i)return i.startsWith("http://")||i.startsWith("https://")?i:"https://"+i;const r=e?.includes("://")&&!/^https?:\/\//i.test(e)?void 0:e;return O(r)+t}function se(i,e,t){if(document.getElementById(i))return;const n=document.head||document.body,r=document.createElement("script");r.id=i,r.type="text/javascript",r.src=e,r.async=!0,r.crossOrigin="anonymous",r.fetchPriority="high",t?.onLoad&&(r.onload=t.onLoad),t?.onError&&(r.onerror=t.onError),n.appendChild(r)}function N(i){if(!i)return[];try{return JSON.parse(i.replace(/"/g,'"'))}catch{console.error("Settings string contains invalid JSON")}return[]}function oe(i){const e=i?N(i):[],t=[],n=[];let r=!1;for(let s=0;s=we)return;const r=window.__rokt_li_guid__;if(!r||i&&i.includes("://")&&!/^https:\/\//i.test(i))return;const s=window.location.href.split("?")[0].split("#")[0],o="version="+encodeURIComponent(e??"")+"&launcherInstanceGuid="+encodeURIComponent(r)+"&pageUrl="+encodeURIComponent(s),c=i?O(i):"https://apps.rokt.com";x(c+"/v1/wsdk-init/index.html?"+o),x("https://"+Re+"/v1/wsdk-init/index.html?"+o+"&isControl=true")}function Ve(){return typeof window<"u"&&!!window.location?.search?.toLowerCase().includes("mp_enable_logging=true")}function He(){return typeof window<"u"?window.location?.href:void 0}function ze(){return typeof window<"u"?window.navigator?.userAgent:void 0}class he{constructor(){this._logCount={}}incrementAndCheck(e){const n=(this._logCount[e]||0)+1;return this._logCount[e]=n,n>xe}}class W{constructor(e,t,n,r,s){this._reporter="mp-wsdk";const o=e.isLoggingEnabled;this._integrationName=t||"",this._launcherInstanceGuid=n,this._accountId=r||null,this._rateLimiter=s||new he,this._isEnabled=Ve()||o}send(e,t,n,r,s,o){if(!(!this._isEnabled||this._rateLimiter.incrementAndCheck(t)))try{const c={additionalInformation:{message:n,version:this._integrationName},severity:t,code:r||G.UNKNOWN_ERROR,url:He(),deviceInfo:ze(),stackTrace:s,reporter:this._reporter,integration:this._integrationName},u={Accept:"text/plain;charset=UTF-8","Content-Type":"application/json","rokt-launcher-version":this._integrationName,"rokt-wsdk-version":"joint"};this._launcherInstanceGuid&&(u["rokt-launcher-instance-guid"]=this._launcherInstanceGuid),this._accountId&&(u["rokt-account-id"]=this._accountId),fetch(e,{method:"POST",headers:u,body:JSON.stringify(c)}).then(l=>{if(!l.ok){const p=new Error("HTTP "+l.status+" from log endpoint");throw p.statusCode=l.status,p}}).catch(l=>{console.error("ReportingTransport: Failed to send log",l),o&&o(l)})}catch(c){console.error("ReportingTransport: Failed to send log",c),o&&o(c)}}}class ge{constructor(e,t,n,r,s){this._transport=new W(e,t,n,r,s),this._errorUrl=re(e?.errorUrl,e?.integrationDomain,Ge)}report(e){if(!e)return;const t=e.severity||I.ERROR;this._transport.send(this._errorUrl,t,e.message,e.code,e.stackTrace)}}class pe{constructor(e,t,n,r,s,o){this._transport=new W(e,n,r,s,o),this._loggingUrl=re(e?.loggingUrl,e?.integrationDomain,Ye),this._errorReportingService=t}log(e){e&&this._transport.send(this._loggingUrl,I.INFO,e.message,e.code,void 0,t=>{if(this._errorReportingService){const n=typeof t.statusCode=="number";this._errorReportingService.report({message:"LoggingService: Failed to send log: "+t.message,code:G.LOG_DELIVERY_FAILURE,severity:n?I.ERROR:I.WARNING})}})}}function qe(i){const e=D(window.location.href),t=i.EventAttributes?.title||document.title,n=ke(),r=i.ActiveTimeOnSite;return{pageUrl:e,sourceMessageId:i.SourceMessageId,timestamp:i.Timestamp,...t?{pageTitle:t}:{},...n!==void 0?{canonicalUrl:n}:{},...Number.isFinite(r)?{activeTimeOnSite:r}:{}}}const f=class f{constructor(){this.name=d,this.id=P,this.moduleId=P,this.isInitialized=!1,this.launcher=null,this.filters={},this.userAttributes={},this.userIdentifiedInWorkspace=!1,this.testHelpers=null,this.placementEventMappingLookup={},this.placementEventAttributeMappingLookup={},this.integrationName=null,this.errorReportingService=null,this.loggingService=null,this._thankYouElementOnLoadCallback=null,this._isThankYouElementLoaded=!1,this._workspaceSearchInFlightPromise=null}getEventAttributeValue(e,t){const n=e&&e.EventAttributes;return!n||typeof n[t]>"u"?null:n[t]}doesEventAttributeConditionMatch(e,t){if(!e||!_(e.operator))return!1;const n=e.operator.toLowerCase(),r=e.attributeValue;return n==="exists"?t!==null:t==null?!1:n==="equals"?String(t)===String(r):n==="contains"?String(t).indexOf(String(r))!==-1:!1}doesEventMatchRule(e,t){if(!t||!_(t.eventAttributeKey))return!1;const n=t.conditions;if(!Array.isArray(n))return!1;const r=this.getEventAttributeValue(e,t.eventAttributeKey);if(n.length===0)return r!==null;for(let s=0;s{await We(n,o),this.initRoktLauncher(o)}).catch(o=>{console.error("Error creating Rokt launcher:",o)})}initRoktLauncher(e){window.Rokt&&(window.Rokt.currentLauncher=e),this.launcher=e;const t=a().Rokt?.filters;t?(this.filters=t,t.filteredUser?this._workspaceSearchInFlightPromise=this.search(t.filteredUser):console.warn("Rokt Kit: No filtered user has been set.")):console.warn("Rokt Kit: No filters have been set."),this.isInitialized=!0,de(this.domain,this.integrationName),a().Rokt.attachKit(this)}fetchOptimizely(){const e=a()._getActiveForwarders().filter(t=>t.name==="Optimizely");try{if(e.length>0&&window.optimizely){const t=window.optimizely.get("state");return!t||!t.getActiveExperimentIds?{}:t.getActiveExperimentIds().reduce((s,o)=>(s["rokt.custom.optimizely.experiment."+o+".variationId"]=t.getVariationMap()[o].id,s),{})}}catch(t){console.error("Error fetching Optimizely attributes:",t)}return{}}isKitReady(){return!!(this.isInitialized&&this.launcher)}isTargetingDisabled(){return a().Rokt?.launcherOptions?.noTargeting===!0}isPartnerInLocalLauncherTestGroup(){return!!(a().config&&a().config.isLocalLauncherEnabled&&this.isAssignedToSampleGroup())}isAssignedToSampleGroup(){return Math.random()>.5}captureTiming(e){window&&a()&&a().captureTiming&&e&&a().captureTiming(e)}init(e,t,n,r,s){const o=e,c=o.accountId;this.userAttributes=R(s),this._onboardingExpProvider=o.onboardingExpProvider;const u=N(o.placementEventMapping);this.placementEventMappingLookup=ae(u);const l=N(o.placementEventAttributeMapping);this.placementEventAttributeMappingLookup=ce(l),o.hashedEmailUserIdentityType&&(this._mappedEmailSha256Key=o.hashedEmailUserIdentityType.toLowerCase()),this._workspaceIdSyncApiKey=_(o.workspaceIdSyncApiKey)?o.workspaceIdSyncApiKey:void 0;const p=a().Rokt?.domain,{roktExtensionsQueryParams:j,legacyRoktExtensions:U,loadThankYouElement:C}=oe(o.roktExtensions),m={...a().Rokt?.launcherOptions||{}};this.integrationName=je(m.integrationName),m.integrationName=this.integrationName,this.domain=p;const k={loggingUrl:o.loggingUrl,errorUrl:o.errorUrl,integrationDomain:p,isLoggingEnabled:a().config?.isLoggingEnabled===!0},y=new ge(k,this.integrationName,window.__rokt_li_guid__,o.accountId),v=new pe(k,y,this.integrationName,window.__rokt_li_guid__,o.accountId);if(this.errorReportingService=y,this.loggingService=v,this.isTargetingDisabled())try{ee(),te()}catch(h){this.errorReportingService?.report({message:"Rokt Kit: Failed to clear page views when targeting is disabled",code:"PAGE_VIEW_CAPTURE_FAILED",severity:I.INFO,stackTrace:h instanceof Error?h.stack:void 0})}return a()._registerErrorReportingService&&a()._registerErrorReportingService(y),a()._registerLoggingService&&a()._registerLoggingService(v),n?(this.testHelpers={generateLauncherScript:ie,generateThankYouElementScript:ne,extractRoktExtensionConfig:oe,hashEventMessage:le,parseSettingsString:N,generateMappedEventLookup:ae,generateMappedEventAttributeLookup:ce,sendAdBlockMeasurementSignals:de,createAutoRemovedIframe:x,djb2:ue,setAllowedOriginHashes:h=>{f._allowedOriginHashes=h},ReportingTransport:W,ErrorReportingService:ge,LoggingService:pe,RateLimiter:he,ErrorCodes:G,WSDKErrorSeverity:I},this.attachLauncher(c,m),"Successfully initialized: "+d):(C&&(a().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this),se(Le,ne(p),{onLoad:()=>{this._isThankYouElementLoaded=!0,this._thankYouElementOnLoadCallback&&this._thankYouElementOnLoadCallback()},onError:h=>{console.error("Error loading Rokt Thank You Element script:",h)}})),this.isLauncherReadyToAttach()?this.attachLauncher(c,m,U):(se(Te,ie(p,j),{onLoad:()=>{this.isLauncherReadyToAttach()?this.attachLauncher(c,m,U):console.error("Rokt object is not available after script load.")},onError:h=>{console.error("Error loading Rokt launcher script:",h)}}),this.captureTiming(f.PERFORMANCE_MARKS.RoktScriptAppended)),"Successfully initialized: "+d)}process(e){if(this.isTargetingDisabled()||(e.EventDataType===Oe&&(ye(this.loggingService),this.capturePageView(e)),e.EventDataType===Ne&&(X(this.loggingService),ee(),te())),!this.isKitReady())return"Kit not ready for forwarder: "+d;if(w(a().Rokt?.setLocalSessionAttribute)&&(K(this.placementEventAttributeMappingLookup)||this.applyPlacementEventAttributeMapping(e),!K(this.placementEventMappingLookup))){const t=le(e.EventDataType,e.EventCategory,e.EventName??"");this.placementEventMappingLookup[String(t)]&&a().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(t)],!0)}return"Successfully sent to forwarder: "+d}setExtensionData(e){if(!this.isKitReady()){console.error("Rokt Kit: Not initialized");return}window.Rokt.setExtensionData(e)}setUserAttribute(e,t){return V(e)||(this.userAttributes[e]=t),"Successfully set user attribute for forwarder: "+d}removeUserAttribute(e){return delete this.userAttributes[e],"Successfully removed user attribute for forwarder: "+d}handleIdentityComplete(e,t){return this.userAttributes=R(e.getAllUserAttributes()),"Successfully called "+t+" for forwarder: "+d}onUserIdentified(e){const t=e;return this.filters.filteredUser=t,this._workspaceSearchInFlightPromise=this.search(t),this.handleIdentityComplete(e,"onUserIdentified")}search(e){const t=this._workspaceIdSyncApiKey;if(!t)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const n=a().Identity?.search;if(typeof n!="function")return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const r=e.getUserIdentities?e.getUserIdentities().userIdentities:null,s={};if(r)for(const u of Object.keys(r)){const l=r[u];_(l)&&l.length>0&&(s[u]=l)}const o=Object.keys(s);if(o.length===0)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const c=o.sort().map(u=>`${u}=${s[u]}`).join("&");return c===this._workspaceLastSearchedIdentitiesKey?this._workspaceSearchInFlightPromise||Promise.resolve():(this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=c,new Promise(u=>{try{n(t,s,l=>{l?.httpCode===200&&(this.userIdentifiedInWorkspace=!0),u()})}catch(l){console.error("Rokt Kit: Workspace IDSync search failed",l),this._workspaceLastSearchedIdentitiesKey=void 0,u()}}))}onLoginComplete(e,t){return this.handleIdentityComplete(e,"onLoginComplete")}onLogoutComplete(e,t){return this.userIdentifiedInWorkspace=!1,this._workspaceSearchInFlightPromise=null,this._workspaceLastSearchedIdentitiesKey=void 0,this.handleIdentityComplete(e,"onLogoutComplete")}onModifyComplete(e,t){return this.handleIdentityComplete(e,"onModifyComplete")}selectPlacements(e){if(this._workspaceSearchInFlightPromise){const t=this._workspaceSearchInFlightPromise;return Promise.race([t,new Promise(n=>setTimeout(n,De))]).then(()=>this._dispatchPlacements(e))}return this._dispatchPlacements(e)}_dispatchPlacements(e){const t=e&&e.attributes||{},r={...R(this.userAttributes),...t},s=this.filters||{},o=s.userAttributeFilters||[],c=s.filteredUser||null,u=c?c.getMPID():null;let l;s?s.filterUserAttributes?l=s.filterUserAttributes(r,o):l=r:(console.warn("Rokt Kit: No filters available, using user attributes"),l=r),this.userAttributes=R(l);const p=this._onboardingExpProvider==="Optimizely"?this.fetchOptimizely():{},j=this.returnUserIdentities(c),U=this.returnLocalSessionAttributes(),C=Se(Z(this.loggingService)),m=Ae(),k=this.readMpSessionId(),y=this.readMpDeviceId(),v={...j,...l,...p,...U,...C.length?{[Ue]:JSON.stringify(C)}:{},...m?{[Ce]:m}:{},...this.userIdentifiedInWorkspace?{[Pe]:!0}:{},...k?{[Me]:k}:{},...y?{[Ke]:y}:{},mpid:u},h={...e,attributes:v},fe=this.launcher.selectPlacements(h),Be=()=>this.logSelectPlacementsEvent(v);return Promise.resolve(fe).then(Qe=>Qe?.context?.sessionId?.then(Xe=>this.setRoktSessionId(Xe))).catch(()=>{}).finally(Be),fe}hashAttributes(e){return this.isKitReady()?this.launcher.hashAttributes(e):(console.error("Rokt Kit: Not initialized"),null)}use(e){return this.isKitReady()?!e||!_(e)?Promise.reject(new Error("Rokt Kit: Invalid extension name")):this.launcher.use(e):(console.error("Rokt Kit: Not initialized"),Promise.reject(new Error("Rokt Kit: Not initialized")))}onShoppableAdsReady(e){this._isThankYouElementLoaded?e():this._thankYouElementOnLoadCallback=e}};f._allowedOriginHashes=[-553112570,549508659],f.PERFORMANCE_MARKS={RoktScriptAppended:"mp:RoktScriptAppended"},f.EMAIL_SHA256_KEY="emailsha256";let S=f;function $e(){return P}function Je(i){if(!i){window.console.log("You must pass a config object to register the kit "+d);return}if(!E(i)){window.console.log("'config' must be an object. You passed in a "+typeof i);return}E(i.kits)?i.kits[d]={constructor:S}:(i.kits={},i.kits[d]={constructor:S}),window.console.log("Successfully registered "+d+" to your mParticle configuration")}return typeof window<"u"&&window.mParticle&&a().addForwarder&&a().addForwarder({name:d,constructor:S,getId:$e}),M.register=Je,Object.defineProperty(M,Symbol.toStringTag,{value:"Module"}),M})({}); +var RoktKit=(function(M){"use strict";const me=["active_time_on_site_ms","billingaddress1","billingaddress2","billingcity","billingstate","billingzipcode","cartitems","ccbin","confirmationref","conversiontype","country","couponcode","currency","language","paymentserviceprovider","paymentserviceproviderattribute","paymenttype","shippingaddress1","shippingcity","shippingcountry","shippingmethod","shippingstate","shippingzipcode","totalprice"],Ee=new Set(me);function V(i){return Ee.has(i.toLowerCase())}function R(i){const e={},t=i||{},n=Object.keys(t);for(let r=0;r{const r=t.activeTimeOnSite,s=r!==void 0&&Number.isFinite(r),c=e[n+1]?.activeTimeOnSite,u=c!==void 0&&Number.isFinite(c),l=s&&u?c-r:void 0;return{pageUrl:t.pageUrl,sourceMessageId:t.sourceMessageId,timestamp:t.timestamp,...t.pageTitle!==void 0?{pageTitle:t.pageTitle}:{},...t.canonicalUrl!==void 0?{canonicalUrl:t.canonicalUrl}:{},...s?{activeTimeOnSite:r}:{},...l!==void 0&&l>=0?{activeTimeOnPage:l}:{}}})}function ye(i){if(T(g,L)!==void 0)return;const e=new URLSearchParams(window.location.search),t={};for(const r of _e){const s=e.get(r);s&&(t[r]=s)}if(Object.keys(t).length===0)return;const n=Object.keys(t).join(", ");if(!Y(g,L,t)){const r=F()?"quota":"ls_unavailable";i?.log({message:`Rokt Kit: Failed to persist UTM params [reason: ${r}]`,code:"UTM_CAPTURE_FAILED"});return}i?.log({message:`Rokt Kit: Captured UTM params [${n}]`,code:"UTM_CAPTURE_SUCCESS"})}function Ae(){const i=T(g,L);return E(i)?i:null}function te(){$(g,L)}function ke(){const e=document.querySelector('link[rel="canonical"]')?.href;if(e)return D(e)}const d="Rokt",P=181,ve="selectPlacements",Re="apps.roktecommerce.com",we=.1,be="ThankYouPageJourney",Te="rokt-launcher",Le="rokt-thank-you-element",Pe="userIdentifiedInWorkspace",Oe=3,Ne=2,Ue="page_events",Ce="page_view_attributes",Me="mparticle_session_id",Ke="mparticle_device_id",De=500,G={UNKNOWN_ERROR:"UNKNOWN_ERROR",UNHANDLED_EXCEPTION:"UNHANDLED_EXCEPTION",IDENTITY_REQUEST:"IDENTITY_REQUEST",LOG_DELIVERY_FAILURE:"LOG_DELIVERY_FAILURE"},I={ERROR:"ERROR",INFO:"INFO",WARNING:"WARNING"},Fe="apps.rokt-api.com",Ye="/v1/log",Ge="/v1/errors",xe=10;function a(){return window.mParticle}function ie(i,e){const n=[O(i),"/wsdk/integrations/launcher.js"].join("");return!e||e.length===0?n:n+"?extensions="+e.join(",")}function ne(i){return[O(i),"/rokt-elements/rokt-element-thank-you.js"].join("")}function O(i){const e=typeof i<"u"?i:Fe;return e.includes("://")?e.replace(/\/+$/,""):["https://",e].join("")}function re(i,e,t){if(i)return i.startsWith("http://")||i.startsWith("https://")?i:"https://"+i;const r=e?.includes("://")&&!/^https?:\/\//i.test(e)?void 0:e;return O(r)+t}function se(i,e,t){if(document.getElementById(i))return;const n=document.head||document.body,r=document.createElement("script");r.id=i,r.type="text/javascript",r.src=e,r.async=!0,r.crossOrigin="anonymous",r.fetchPriority="high",t?.onLoad&&(r.onload=t.onLoad),t?.onError&&(r.onerror=t.onError),n.appendChild(r)}function N(i){if(!i)return[];try{return JSON.parse(i.replace(/"/g,'"'))}catch{console.error("Settings string contains invalid JSON")}return[]}function oe(i){const e=i?N(i):[],t=[],n=[];let r=!1;for(let s=0;s=we)return;const r=window.__rokt_li_guid__;if(!r||i&&i.includes("://")&&!/^https:\/\//i.test(i))return;const s=window.location.href.split("?")[0].split("#")[0],o="version="+encodeURIComponent(e??"")+"&launcherInstanceGuid="+encodeURIComponent(r)+"&pageUrl="+encodeURIComponent(s),c=i?O(i):"https://apps.rokt.com";x(c+"/v1/wsdk-init/index.html?"+o),x("https://"+Re+"/v1/wsdk-init/index.html?"+o+"&isControl=true")}function Ve(){return typeof window<"u"&&!!window.location?.search?.toLowerCase().includes("mp_enable_logging=true")}function He(){return typeof window<"u"?window.location?.href:void 0}function ze(){return typeof window<"u"?window.navigator?.userAgent:void 0}class he{constructor(){this._logCount={}}incrementAndCheck(e){const n=(this._logCount[e]||0)+1;return this._logCount[e]=n,n>xe}}class W{constructor(e,t,n,r,s){this._reporter="mp-wsdk";const o=e.isLoggingEnabled;this._integrationName=t||"",this._launcherInstanceGuid=n,this._accountId=r||null,this._rateLimiter=s||new he,this._isEnabled=Ve()||o}send(e,t,n,r,s,o){if(!(!this._isEnabled||this._rateLimiter.incrementAndCheck(t)))try{const c={additionalInformation:{message:n,version:this._integrationName},severity:t,code:r||G.UNKNOWN_ERROR,url:He(),deviceInfo:ze(),stackTrace:s,reporter:this._reporter,integration:this._integrationName},u={Accept:"text/plain;charset=UTF-8","Content-Type":"application/json","rokt-launcher-version":this._integrationName,"rokt-wsdk-version":"joint"};this._launcherInstanceGuid&&(u["rokt-launcher-instance-guid"]=this._launcherInstanceGuid),this._accountId&&(u["rokt-account-id"]=this._accountId),fetch(e,{method:"POST",headers:u,body:JSON.stringify(c)}).then(l=>{if(!l.ok){const p=new Error("HTTP "+l.status+" from log endpoint");throw p.statusCode=l.status,p}}).catch(l=>{console.error("ReportingTransport: Failed to send log",l),o&&o(l)})}catch(c){console.error("ReportingTransport: Failed to send log",c),o&&o(c)}}}class ge{constructor(e,t,n,r,s){this._transport=new W(e,t,n,r,s),this._errorUrl=re(e?.errorUrl,e?.integrationDomain,Ge)}report(e){if(!e)return;const t=e.severity||I.ERROR;this._transport.send(this._errorUrl,t,e.message,e.code,e.stackTrace)}}class pe{constructor(e,t,n,r,s,o){this._transport=new W(e,n,r,s,o),this._loggingUrl=re(e?.loggingUrl,e?.integrationDomain,Ye),this._errorReportingService=t}log(e){e&&this._transport.send(this._loggingUrl,I.INFO,e.message,e.code,void 0,t=>{if(this._errorReportingService){const n=typeof t.statusCode=="number";this._errorReportingService.report({message:"LoggingService: Failed to send log: "+t.message,code:G.LOG_DELIVERY_FAILURE,severity:n?I.ERROR:I.WARNING})}})}}function qe(i){const e=D(window.location.href),t=i.EventAttributes?.title||document.title,n=ke(),r=i.ActiveTimeOnSite;return{pageUrl:e,sourceMessageId:i.SourceMessageId,timestamp:i.Timestamp,...t?{pageTitle:t}:{},...n!==void 0?{canonicalUrl:n}:{},...Number.isFinite(r)?{activeTimeOnSite:r}:{}}}const f=class f{constructor(){this.name=d,this.id=P,this.moduleId=P,this.isInitialized=!1,this.launcher=null,this.filters={},this.userAttributes={},this.userIdentifiedInWorkspace=!1,this.testHelpers=null,this.placementEventMappingLookup={},this.placementEventAttributeMappingLookup={},this.integrationName=null,this.errorReportingService=null,this.loggingService=null,this._thankYouElementOnLoadCallback=null,this._isThankYouElementLoaded=!1,this._workspaceSearchInFlightPromise=null}getEventAttributeValue(e,t){const n=e&&e.EventAttributes;return!n||typeof n[t]>"u"?null:n[t]}doesEventAttributeConditionMatch(e,t){if(!e||!_(e.operator))return!1;const n=e.operator.toLowerCase(),r=e.attributeValue;return n==="exists"?t!==null:t==null?!1:n==="equals"?String(t)===String(r):n==="contains"?String(t).indexOf(String(r))!==-1:!1}doesEventMatchRule(e,t){if(!t||!_(t.eventAttributeKey))return!1;const n=t.conditions;if(!Array.isArray(n))return!1;const r=this.getEventAttributeValue(e,t.eventAttributeKey);if(n.length===0)return r!==null;for(let s=0;s{await We(n,o),this.initRoktLauncher(o)}).catch(o=>{console.error("Error creating Rokt launcher:",o)})}initRoktLauncher(e){window.Rokt&&(window.Rokt.currentLauncher=e),this.launcher=e;const t=a().Rokt?.filters;t?(this.filters=t,t.filteredUser?this._workspaceSearchInFlightPromise=this.search(t.filteredUser):console.warn("Rokt Kit: No filtered user has been set.")):console.warn("Rokt Kit: No filters have been set."),this.isInitialized=!0,de(this.domain,this.integrationName),a().Rokt.attachKit(this)}fetchOptimizely(){const e=a()._getActiveForwarders().filter(t=>t.name==="Optimizely");try{if(e.length>0&&window.optimizely){const t=window.optimizely.get("state");return!t||!t.getActiveExperimentIds?{}:t.getActiveExperimentIds().reduce((s,o)=>(s["rokt.custom.optimizely.experiment."+o+".variationId"]=t.getVariationMap()[o].id,s),{})}}catch(t){console.error("Error fetching Optimizely attributes:",t)}return{}}isKitReady(){return!!(this.isInitialized&&this.launcher)}isTargetingDisabled(){return a().Rokt?.launcherOptions?.noTargeting===!0}isPartnerInLocalLauncherTestGroup(){return!!(a().config&&a().config.isLocalLauncherEnabled&&this.isAssignedToSampleGroup())}isAssignedToSampleGroup(){return Math.random()>.5}captureTiming(e){window&&a()&&a().captureTiming&&e&&a().captureTiming(e)}init(e,t,n,r,s){const o=e,c=o.accountId;this.userAttributes=R(s),this._onboardingExpProvider=o.onboardingExpProvider;const u=N(o.placementEventMapping);this.placementEventMappingLookup=ae(u);const l=N(o.placementEventAttributeMapping);this.placementEventAttributeMappingLookup=ce(l),o.hashedEmailUserIdentityType&&(this._mappedEmailSha256Key=o.hashedEmailUserIdentityType.toLowerCase()),this._workspaceIdSyncApiKey=_(o.workspaceIdSyncApiKey)?o.workspaceIdSyncApiKey:void 0;const p=a().Rokt?.domain,{roktExtensionsQueryParams:j,legacyRoktExtensions:U,loadThankYouElement:C}=oe(o.roktExtensions),m={...a().Rokt?.launcherOptions||{}};this.integrationName=je(m.integrationName),m.integrationName=this.integrationName,this.domain=p;const k={loggingUrl:o.loggingUrl,errorUrl:o.errorUrl,integrationDomain:p,isLoggingEnabled:a().config?.isLoggingEnabled===!0},y=new ge(k,this.integrationName,window.__rokt_li_guid__,o.accountId),v=new pe(k,y,this.integrationName,window.__rokt_li_guid__,o.accountId);if(this.errorReportingService=y,this.loggingService=v,this.isTargetingDisabled())try{ee(),te()}catch(h){this.errorReportingService?.report({message:"Rokt Kit: Failed to clear page views when targeting is disabled",code:"PAGE_VIEW_CAPTURE_FAILED",severity:I.INFO,stackTrace:h instanceof Error?h.stack:void 0})}return a()._registerErrorReportingService&&a()._registerErrorReportingService(y),a()._registerLoggingService&&a()._registerLoggingService(v),n?(this.testHelpers={generateLauncherScript:ie,generateThankYouElementScript:ne,extractRoktExtensionConfig:oe,hashEventMessage:le,parseSettingsString:N,generateMappedEventLookup:ae,generateMappedEventAttributeLookup:ce,sendAdBlockMeasurementSignals:de,createAutoRemovedIframe:x,djb2:ue,setAllowedOriginHashes:h=>{f._allowedOriginHashes=h},ReportingTransport:W,ErrorReportingService:ge,LoggingService:pe,RateLimiter:he,ErrorCodes:G,WSDKErrorSeverity:I},this.attachLauncher(c,m),"Successfully initialized: "+d):(C&&(a().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this),se(Le,ne(p),{onLoad:()=>{this._isThankYouElementLoaded=!0,this._thankYouElementOnLoadCallback&&this._thankYouElementOnLoadCallback()},onError:h=>{console.error("Error loading Rokt Thank You Element script:",h)}})),this.isLauncherReadyToAttach()?this.attachLauncher(c,m,U):(se(Te,ie(p,j),{onLoad:()=>{this.isLauncherReadyToAttach()?this.attachLauncher(c,m,U):console.error("Rokt object is not available after script load.")},onError:h=>{console.error("Error loading Rokt launcher script:",h)}}),this.captureTiming(f.PERFORMANCE_MARKS.RoktScriptAppended)),"Successfully initialized: "+d)}process(e){if(this.isTargetingDisabled()||(e.EventDataType===Oe&&(ye(this.loggingService),this.capturePageView(e)),e.EventDataType===Ne&&(X(this.loggingService),ee(),te())),!this.isKitReady())return"Kit not ready for forwarder: "+d;if(w(a().Rokt?.setLocalSessionAttribute)&&(K(this.placementEventAttributeMappingLookup)||this.applyPlacementEventAttributeMapping(e),!K(this.placementEventMappingLookup))){const t=le(e.EventDataType,e.EventCategory,e.EventName??"");this.placementEventMappingLookup[String(t)]&&a().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(t)],!0)}return"Successfully sent to forwarder: "+d}setExtensionData(e){if(!this.isKitReady()){console.error("Rokt Kit: Not initialized");return}window.Rokt.setExtensionData(e)}setUserAttribute(e,t){return V(e)||(this.userAttributes[e]=t),"Successfully set user attribute for forwarder: "+d}removeUserAttribute(e){return delete this.userAttributes[e],"Successfully removed user attribute for forwarder: "+d}handleIdentityComplete(e,t){return this.userAttributes=R(e.getAllUserAttributes()),"Successfully called "+t+" for forwarder: "+d}onUserIdentified(e){const t=e;return this.filters.filteredUser=t,this._workspaceSearchInFlightPromise=this.search(t),this.handleIdentityComplete(e,"onUserIdentified")}search(e){const t=this._workspaceIdSyncApiKey;if(!t)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const n=a().Identity?.search;if(typeof n!="function")return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const r=e.getUserIdentities?e.getUserIdentities().userIdentities:null,s={};if(r)for(const u of Object.keys(r)){const l=r[u];_(l)&&l.length>0&&(s[u]=l)}const o=Object.keys(s);if(o.length===0)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const c=o.sort().map(u=>`${u}=${s[u]}`).join("&");return c===this._workspaceLastSearchedIdentitiesKey?this._workspaceSearchInFlightPromise||Promise.resolve():(this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=c,new Promise(u=>{try{n(t,s,l=>{l?.httpCode===200&&(this.userIdentifiedInWorkspace=!0),u()})}catch(l){console.error("Rokt Kit: Workspace IDSync search failed",l),this._workspaceLastSearchedIdentitiesKey=void 0,u()}}))}onLoginComplete(e,t){return this.handleIdentityComplete(e,"onLoginComplete")}onLogoutComplete(e,t){return this.userIdentifiedInWorkspace=!1,this._workspaceSearchInFlightPromise=null,this._workspaceLastSearchedIdentitiesKey=void 0,this.handleIdentityComplete(e,"onLogoutComplete")}onModifyComplete(e,t){return this.handleIdentityComplete(e,"onModifyComplete")}selectPlacements(e){if(this._workspaceSearchInFlightPromise){const t=this._workspaceSearchInFlightPromise;return Promise.race([t,new Promise(n=>setTimeout(n,De))]).then(()=>this._dispatchPlacements(e))}return this._dispatchPlacements(e)}_dispatchPlacements(e){const t=e&&e.attributes||{},r={...R(this.userAttributes),...t},s=this.filters||{},o=s.userAttributeFilters||[],c=s.filteredUser||null,u=c?c.getMPID():null;let l;s?s.filterUserAttributes?l=s.filterUserAttributes(r,o):l=r:(console.warn("Rokt Kit: No filters available, using user attributes"),l=r),this.userAttributes=R(l);const p=this._onboardingExpProvider==="Optimizely"?this.fetchOptimizely():{},j=this.returnUserIdentities(c),U=this.returnLocalSessionAttributes(),C=Se(Z(this.loggingService)),m=Ae(),k=this.readMpSessionId(),y=this.readMpDeviceId(),v={...j,...l,...p,...U,...C.length?{[Ue]:JSON.stringify(C)}:{},...m?{[Ce]:JSON.stringify(m)}:{},...this.userIdentifiedInWorkspace?{[Pe]:!0}:{},...k?{[Me]:k}:{},...y?{[Ke]:y}:{},mpid:u},h={...e,attributes:v},fe=this.launcher.selectPlacements(h),Be=()=>this.logSelectPlacementsEvent(v);return Promise.resolve(fe).then(Qe=>Qe?.context?.sessionId?.then(Xe=>this.setRoktSessionId(Xe))).catch(()=>{}).finally(Be),fe}hashAttributes(e){return this.isKitReady()?this.launcher.hashAttributes(e):(console.error("Rokt Kit: Not initialized"),null)}use(e){return this.isKitReady()?!e||!_(e)?Promise.reject(new Error("Rokt Kit: Invalid extension name")):this.launcher.use(e):(console.error("Rokt Kit: Not initialized"),Promise.reject(new Error("Rokt Kit: Not initialized")))}onShoppableAdsReady(e){this._isThankYouElementLoaded?e():this._thankYouElementOnLoadCallback=e}};f._allowedOriginHashes=[-553112570,549508659],f.PERFORMANCE_MARKS={RoktScriptAppended:"mp:RoktScriptAppended"},f.EMAIL_SHA256_KEY="emailsha256";let S=f;function $e(){return P}function Je(i){if(!i){window.console.log("You must pass a config object to register the kit "+d);return}if(!E(i)){window.console.log("'config' must be an object. You passed in a "+typeof i);return}E(i.kits)?i.kits[d]={constructor:S}:(i.kits={},i.kits[d]={constructor:S}),window.console.log("Successfully registered "+d+" to your mParticle configuration")}return typeof window<"u"&&window.mParticle&&a().addForwarder&&a().addForwarder({name:d,constructor:S,getId:$e}),M.register=Je,Object.defineProperty(M,Symbol.toStringTag,{value:"Module"}),M})({}); //# sourceMappingURL=Rokt-Kit.iife.js.map diff --git a/kits/rokt/dist/Rokt-Kit.iife.js.map b/kits/rokt/dist/Rokt-Kit.iife.js.map index 6e82cf887..bd3153081 100644 --- a/kits/rokt/dist/Rokt-Kit.iife.js.map +++ b/kits/rokt/dist/Rokt-Kit.iife.js.map @@ -1 +1 @@ -{"version":3,"file":"Rokt-Kit.iife.js","sources":["../src/selectPlacementsAttributePersistence.ts","../src/utils.ts","../src/storage.ts","../src/pageViewStorage.ts","../src/Rokt-Kit.ts"],"sourcesContent":["const SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST = [\n 'active_time_on_site_ms',\n 'billingaddress1',\n 'billingaddress2',\n 'billingcity',\n 'billingstate',\n 'billingzipcode',\n 'cartitems',\n 'ccbin',\n 'confirmationref',\n 'conversiontype',\n 'country',\n 'couponcode',\n 'currency',\n 'language',\n 'paymentserviceprovider',\n 'paymentserviceproviderattribute',\n 'paymenttype',\n 'shippingaddress1',\n 'shippingcity',\n 'shippingcountry',\n 'shippingmethod',\n 'shippingstate',\n 'shippingzipcode',\n 'totalprice',\n];\nconst SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET = new Set(SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST);\n\nexport function isSelectPlacementsAttributePersistenceDenied(key: string): boolean {\n return SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET.has(key.toLowerCase());\n}\n\nexport function removeSelectPlacementsAttributePersistenceDeniedAttributes(\n attributes: Record | null | undefined,\n): Record {\n const filteredAttributes: Record = {};\n const sourceAttributes = attributes || {};\n const attributeKeys = Object.keys(sourceAttributes);\n\n for (let i = 0; i < attributeKeys.length; i++) {\n const key = attributeKeys[i];\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n filteredAttributes[key] = sourceAttributes[key];\n }\n }\n\n return filteredAttributes;\n}\n","export function isObject(value: unknown): value is Record {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nexport function isFunction(value: unknown): value is (...args: Array) => unknown {\n return typeof value === 'function';\n}\n\nexport function isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'object') {\n return Object.keys(value as object).length === 0;\n }\n return false;\n}\n\n// Strips the query string from a URL before it is persisted and sent to Rokt,\n// since query params commonly carry PII (emails, tokens, order refs).\n// Returns the input unchanged if it can't be parsed as a URL.\nexport function sanitizeUrl(href: string): string {\n try {\n const url = new URL(href);\n url.search = '';\n return url.toString();\n } catch {\n return href;\n }\n}\n","import { isObject } from './utils';\n\nconst LS_PROBE_KEY = '__rokt_ls_probe__';\n\nexport function isLocalStorageAvailable(): boolean {\n try {\n window.localStorage.setItem(LS_PROBE_KEY, '1');\n window.localStorage.removeItem(LS_PROBE_KEY);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function readJSON(key: string): unknown {\n try {\n const stored = window.localStorage.getItem(key);\n return stored === null ? null : JSON.parse(stored);\n } catch {\n return null;\n }\n}\n\nexport function writeJSON(key: string, value: unknown): boolean {\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n return true;\n } catch {\n return false;\n }\n}\n\nexport function removeKey(key: string): void {\n try {\n window.localStorage.removeItem(key);\n } catch {\n /* empty */\n }\n}\n\nexport function readNamespacedField(namespaceKey: string, field: string): unknown {\n const blob = readJSON(namespaceKey);\n return isObject(blob) ? blob[field] : undefined;\n}\n\nexport function writeNamespacedField(namespaceKey: string, field: string, value: unknown): boolean {\n const blob = readJSON(namespaceKey);\n const next = isObject(blob) ? { ...blob } : {};\n next[field] = value;\n return writeJSON(namespaceKey, next);\n}\n\nexport function removeNamespacedField(namespaceKey: string, field: string): void {\n const blob = readJSON(namespaceKey);\n if (!isObject(blob) || !(field in blob)) {\n return;\n }\n const next = { ...blob };\n delete next[field];\n if (Object.keys(next).length === 0) {\n removeKey(namespaceKey);\n } else {\n writeJSON(namespaceKey, next);\n }\n}\n","import type { LoggingService } from './Rokt-Kit';\nimport {\n readJSON,\n removeKey,\n readNamespacedField,\n writeNamespacedField,\n removeNamespacedField,\n isLocalStorageAvailable,\n} from './storage';\nimport { sanitizeUrl, isObject } from './utils';\n\nconst LS_NAMESPACE_KEY = 'mp-rokt-kit';\nconst LS_PAGE_VIEWS_FIELD = 'pageViews';\nconst LS_UTM_PARAMS_FIELD = 'utmParams';\nconst LEGACY_PAGE_VIEWS_KEY = 'mpPageViews';\nexport const PAGE_VIEWS_MAX_COUNT = 25;\n\nconst UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'] as const;\ntype UtmKey = (typeof UTM_KEYS)[number];\nexport type UtmParams = Partial>;\n\nexport interface PageEvent {\n pageUrl: string;\n sourceMessageId: string;\n timestamp: number;\n pageTitle?: string;\n canonicalUrl?: string;\n activeTimeOnSite?: number;\n activeTimeOnPage?: number;\n}\n\nfunction capPageViews(views: PageEvent[]): PageEvent[] {\n return views.slice(-PAGE_VIEWS_MAX_COUNT);\n}\n\nexport function migrateLegacyPageViewStorage(loggingService: LoggingService | null): void {\n const legacyViews = readJSON(LEGACY_PAGE_VIEWS_KEY);\n if (legacyViews === null) {\n return;\n }\n\n const alreadyMigrated = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD) !== undefined;\n const needsMigration = !alreadyMigrated && Array.isArray(legacyViews);\n\n if (needsMigration) {\n loggingService?.log({\n message: 'Rokt Kit: Migrating legacy page-view storage',\n code: 'PAGE_VIEW_LEGACY_MIGRATION',\n });\n const migrated = writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, legacyViews);\n if (!migrated) {\n loggingService?.log({\n message: 'Rokt Kit: Failed to migrate legacy page-view storage [reason: migration_retry]',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n removeKey(LEGACY_PAGE_VIEWS_KEY);\n}\n\nexport function loadPageViews(loggingService: LoggingService | null): PageEvent[] {\n migrateLegacyPageViewStorage(loggingService);\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n return Array.isArray(stored) ? (stored as PageEvent[]) : [];\n}\n\nexport function writePageViews(pageViews: PageEvent[]): number {\n const views = capPageViews(pageViews);\n for (let i = 0; i < views.length; i++) {\n const toWrite = views.slice(i);\n if (writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, toWrite)) {\n return toWrite.length;\n }\n }\n return 0;\n}\n\nexport function clearPageViews(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n}\n\nexport function buildPageEvents(pageViews: PageEvent[]): PageEvent[] {\n const views = capPageViews(pageViews);\n return views.map((pageView, index) => {\n const activeTimeOnSite = pageView.activeTimeOnSite;\n const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite);\n\n const next = views[index + 1];\n const nextActiveTimeOnSite = next?.activeTimeOnSite;\n const hasNextActiveTimeOnSite = nextActiveTimeOnSite !== undefined && Number.isFinite(nextActiveTimeOnSite);\n\n const diff = hasActiveTime && hasNextActiveTimeOnSite ? nextActiveTimeOnSite - activeTimeOnSite : undefined;\n\n return {\n pageUrl: pageView.pageUrl,\n sourceMessageId: pageView.sourceMessageId,\n timestamp: pageView.timestamp,\n ...(pageView.pageTitle !== undefined ? { pageTitle: pageView.pageTitle } : {}),\n ...(pageView.canonicalUrl !== undefined ? { canonicalUrl: pageView.canonicalUrl } : {}),\n ...(hasActiveTime ? { activeTimeOnSite } : {}),\n ...(diff !== undefined && diff >= 0 ? { activeTimeOnPage: diff } : {}),\n };\n });\n}\n\nexport function captureUtmParams(loggingService: LoggingService | null): void {\n if (readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD) !== undefined) {\n return;\n }\n const search = new URLSearchParams(window.location.search);\n const params: UtmParams = {};\n for (const key of UTM_KEYS) {\n const value = search.get(key);\n if (value) params[key] = value;\n }\n if (Object.keys(params).length === 0) {\n return;\n }\n const captured = Object.keys(params).join(', ');\n if (!writeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD, params)) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n loggingService?.log({\n message: `Rokt Kit: Failed to persist UTM params [reason: ${reason}]`,\n code: 'UTM_CAPTURE_FAILED',\n });\n return;\n }\n loggingService?.log({\n message: `Rokt Kit: Captured UTM params [${captured}]`,\n code: 'UTM_CAPTURE_SUCCESS',\n });\n}\n\nexport function loadUtmParams(): UtmParams | null {\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n return isObject(stored) ? (stored as UtmParams) : null;\n}\n\nexport function clearUtmParams(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n}\n\nexport function readCanonicalUrl(): string | undefined {\n const link = document.querySelector('link[rel=\"canonical\"]');\n const href = link?.href;\n if (!href) {\n return undefined;\n }\n return sanitizeUrl(href);\n}\n","// Copyright 2025 mParticle, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// ============================================================\n// Types\n// ============================================================\n\nimport { KitInterface, IMParticleUser, SDKEvent } from '@mparticle/web-sdk/internal';\nimport type { IUserIdentities } from '@mparticle/web-sdk';\n\nimport {\n isSelectPlacementsAttributePersistenceDenied,\n removeSelectPlacementsAttributePersistenceDeniedAttributes,\n} from './selectPlacementsAttributePersistence';\n\nimport {\n PageEvent,\n PAGE_VIEWS_MAX_COUNT,\n buildPageEvents,\n migrateLegacyPageViewStorage,\n loadPageViews,\n writePageViews,\n clearPageViews,\n readCanonicalUrl,\n captureUtmParams,\n loadUtmParams,\n clearUtmParams,\n} from './pageViewStorage';\nimport { isLocalStorageAvailable } from './storage';\n\nimport { isObject, isString, isEmpty, isFunction, sanitizeUrl } from './utils';\n\ninterface RoktKitSettings {\n accountId: string;\n roktExtensions?: string;\n placementEventMapping?: string;\n placementEventAttributeMapping?: string;\n hashedEmailUserIdentityType?: string;\n onboardingExpProvider?: string;\n loggingUrl?: string;\n errorUrl?: string;\n workspaceIdSyncApiKey?: string;\n}\n\ninterface EventAttributeCondition {\n operator: string;\n attributeValue: string;\n}\n\ninterface PlacementEventRule {\n eventAttributeKey: string;\n conditions: EventAttributeCondition[];\n}\n\ninterface EventAttributeMapping {\n value: string;\n map: string;\n conditions?: EventAttributeCondition[];\n}\n\ninterface PlacementEventMappingEntry {\n jsmap: string;\n value: string;\n}\n\ninterface RoktExtensionEntry {\n value: string;\n}\n\ninterface RoktSelection {\n context?: {\n sessionId?: Promise;\n };\n then?: (callback: (sel: RoktSelection) => void) => Promise;\n catch?: (callback: () => void) => void;\n}\n\ninterface RoktLauncher {\n selectPlacements(options: Record): RoktSelection | Promise;\n hashAttributes(attributes: Record): Promise>;\n use(extensionName: string): Promise;\n}\n\ninterface RoktGlobal {\n createLauncher(options: Record): Promise;\n createLocalLauncher(options: Record): RoktLauncher;\n currentLauncher?: RoktLauncher;\n setExtensionData(data: Record): void;\n}\n\n// FilteredUser is the IMParticleUser shape we receive after kit filtering.\n// `getMPID` and `getUserIdentities` are inherited from the SDK's `User` base type.\ntype FilteredUser = IMParticleUser;\n\n// TODO: Replace with `IIdentitySearchResult` from `@mparticle/web-sdk` once\n// a version that exports it is published (currently on a feature branch in\n// mParticle/mparticle-web-sdk PR #1255). The shape below is intentionally\n// structurally identical so the swap is a one-line import change.\ninterface WorkspaceIdSyncResult {\n httpCode: number;\n body?: {\n context?: string | null;\n mpid?: string;\n matched_identities?: Record;\n is_ephemeral?: boolean;\n is_logged_in?: boolean;\n };\n}\n\n// TODO: Replace with `IdentitySearchCallback`-compatible reference from\n// `@mparticle/web-sdk` once published (mirrors `SDKIdentityApi.search`).\ntype WorkspaceIdSyncSearcher = (\n apiKey: string,\n knownIdentities: IUserIdentities,\n callback: (result: WorkspaceIdSyncResult) => void,\n) => void;\n\ninterface KitFilters {\n userAttributeFilters?: string[];\n filterUserAttributes?: (attributes: Record, filters?: string[]) => Record;\n filteredUser?: FilteredUser | null;\n}\n\ninterface RoktManager {\n attachKit(kit: RoktKit): void | Promise;\n flushOnShoppableAdsReadyMessageQueue?(kit: RoktKit): void;\n filters?: KitFilters;\n domain?: string;\n launcherOptions?: Record;\n getLocalSessionAttributes?(): Record;\n setLocalSessionAttribute?(key: string, value: unknown): void;\n}\n\ninterface MParticleInstance {\n setIntegrationAttribute(moduleId: number, attrs: Record): void;\n}\n\ninterface OptimizelyState {\n getActiveExperimentIds(): string[];\n getVariationMap(): Record;\n}\n\ninterface OptimizelyGlobal {\n get(key: 'state'): OptimizelyState;\n}\n\n// Our view of the mParticle global with Rokt-specific extensions.\n// We access window.mParticle via an explicit cast (see `mp()` helper below)\n// rather than augmenting Window to avoid conflicts with @mparticle/web-sdk declarations.\ninterface MParticleExtended {\n Rokt: RoktManager;\n addForwarder(config: ForwarderRegistration): void;\n getVersion(): string;\n generateHash(value: string): string | number;\n logEvent(name: string, type: number, attrs?: Record): void;\n EventType: { Other: number };\n getInstance(): MParticleInstance;\n getDeviceId?(): string;\n sessionManager?: { getSession?(): string; getSessionId?(): string };\n _getActiveForwarders(): Array<{ name: string }>;\n config?: { isLocalLauncherEnabled?: boolean; isLoggingEnabled?: boolean };\n captureTiming?(metricName: string): void;\n forwarder?: RoktKit;\n loggedEvents?: Array>;\n _registerErrorReportingService?(service: ErrorReportingService): void;\n _registerLoggingService?(service: LoggingService): void;\n Identity?: { search?: WorkspaceIdSyncSearcher };\n}\n\ninterface TestHelpers {\n generateLauncherScript: (domain: string | undefined, extensions: string[]) => string;\n generateThankYouElementScript: (domain: string | undefined) => string;\n extractRoktExtensionConfig: (settingsString?: string) => RoktExtensionConfig;\n hashEventMessage: (messageType: number, eventType: number, eventName: string) => string | number;\n parseSettingsString: (settingsString?: string) => T[];\n generateMappedEventLookup: (placementEventMapping: PlacementEventMappingEntry[]) => Record;\n generateMappedEventAttributeLookup: (mapping: EventAttributeMapping[]) => Record;\n sendAdBlockMeasurementSignals: (domain: string | undefined, version: string | null) => void;\n createAutoRemovedIframe: (src: string) => void;\n djb2: (str: string) => number;\n setAllowedOriginHashes: (hashes: number[]) => void;\n ReportingTransport: typeof ReportingTransport;\n ErrorReportingService: typeof ErrorReportingService;\n LoggingService: typeof LoggingService;\n RateLimiter: typeof RateLimiter;\n ErrorCodes: typeof ErrorCodes;\n WSDKErrorSeverity: typeof WSDKErrorSeverity;\n}\n\ninterface ForwarderRegistration {\n name: string;\n constructor: new () => RoktKit;\n getId: () => number;\n}\n\ninterface ReportingConfig {\n loggingUrl?: string;\n errorUrl?: string;\n integrationDomain?: string;\n isLoggingEnabled: boolean;\n}\n\ninterface ErrorReport {\n message: string;\n code?: string;\n severity?: string;\n stackTrace?: string;\n}\n\n// A log-delivery failure. statusCode is set when the request reached the server\n// and returned a non-2xx status (server-side); it is absent for network-level\n// failures such as ad-blockers, offline, or CORS rejections (client-side).\ninterface DeliveryError extends Error {\n statusCode?: number;\n}\n\ninterface LogEntry {\n message: string;\n code?: string;\n}\n\ninterface RoktExtensionConfig {\n roktExtensionsQueryParams: string[];\n legacyRoktExtensions: string[];\n loadThankYouElement: boolean;\n}\n\ndeclare global {\n interface Window {\n Rokt?: RoktGlobal;\n __rokt_li_guid__?: string;\n optimizely?: OptimizelyGlobal;\n // mParticle is declared as any to avoid conflicts with @mparticle/web-sdk type declarations.\n // We use the typed mp() accessor for all internal accesses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mParticle: any;\n }\n}\n\n// ============================================================\n// Module-level constants\n// ============================================================\n\nconst name = 'Rokt';\nconst moduleId = 181;\nconst EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements';\nconst ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com';\nconst INIT_LOG_SAMPLING_RATE = 0.1;\nconst ROKT_THANK_YOU_JOURNEY_EXTENSION = 'ThankYouPageJourney';\nconst ROKT_INTEGRATION_SCRIPT_ID = 'rokt-launcher';\nconst ROKT_THANK_YOU_ELEMENT_SCRIPT_ID = 'rokt-thank-you-element';\nconst USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace';\n\nconst MESSAGE_TYPE_PAGE_VIEW = 3; // mParticle MessageType.PageView\nconst MESSAGE_TYPE_SESSION_END = 2; // mParticle MessageType.SessionEnd\nconst PAGE_EVENTS_KEY = 'page_events';\nconst PAGE_VIEW_ATTRIBUTES_KEY = 'page_view_attributes';\nconst MPARTICLE_SESSION_ID_KEY = 'mparticle_session_id';\nconst MPARTICLE_DEVICE_ID_KEY = 'mparticle_device_id';\n\n// Bound on how long selectPlacements will wait for an in-flight Workspace\n// IDSync search before proceeding without the userIdentifiedInWorkspace flag.\n// Long enough to cover the typical /v1/search round-trip (~50ms); short enough that a\n// stalled search never blocks placement rendering on a thank-you page.\nconst WORKSPACE_SEARCH_SELECT_TIMEOUT_MS = 500;\n\n// ============================================================\n// Reporting service constants\n// ============================================================\n\nconst ErrorCodes = {\n UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION',\n IDENTITY_REQUEST: 'IDENTITY_REQUEST',\n LOG_DELIVERY_FAILURE: 'LOG_DELIVERY_FAILURE',\n} as const;\n\nconst WSDKErrorSeverity = {\n ERROR: 'ERROR',\n INFO: 'INFO',\n WARNING: 'WARNING',\n} as const;\n\nconst DEFAULT_ROKT_DOMAIN = 'apps.rokt-api.com';\nconst LOGGING_ENDPOINT = '/v1/log';\nconst ERROR_ENDPOINT = '/v1/errors';\nconst RATE_LIMIT_PER_SEVERITY = 10;\n\n// ============================================================\n// Helper: typed accessor for window.mParticle\n// We use an explicit cast here to avoid conflicts with @mparticle/web-sdk\n// type declarations while still providing full type safety for our usages.\n// ============================================================\n\nfunction mp(): MParticleExtended {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (window as any).mParticle as MParticleExtended;\n}\n\n// ============================================================\n// Module-level utility functions\n// ============================================================\n\nfunction generateLauncherScript(domain: string | undefined, extensions: string[]): string {\n const launcherPath = '/wsdk/integrations/launcher.js';\n const baseUrl = [generateBaseUrl(domain), launcherPath].join('');\n\n if (!extensions || extensions.length === 0) {\n return baseUrl;\n }\n return baseUrl + '?extensions=' + extensions.join(',');\n}\n\nfunction generateThankYouElementScript(domain: string | undefined) {\n const thankYouElementPath = '/rokt-elements/rokt-element-thank-you.js';\n return [generateBaseUrl(domain), thankYouElementPath].join('');\n}\n\nfunction generateBaseUrl(domain: string | undefined) {\n const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN;\n\n if (resolvedDomain.includes('://')) {\n return resolvedDomain.replace(/\\/+$/, '');\n }\n\n const protocol = 'https://';\n\n return [protocol, resolvedDomain].join('');\n}\n\nfunction generateReportingUrl(configuredUrl: string | undefined, domain: string | undefined, endpoint: string): string {\n if (configuredUrl) {\n if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://')) {\n return configuredUrl;\n }\n return 'https://' + configuredUrl;\n }\n\n const hasNonHttpScheme = domain?.includes('://') && !/^https?:\\/\\//i.test(domain);\n const reportingDomain = hasNonHttpScheme ? undefined : domain;\n\n return generateBaseUrl(reportingDomain) + endpoint;\n}\n\nfunction loadRoktScript(\n scriptId: string,\n source: string,\n handlers?: { onLoad?: () => void; onError?: (e: Event | string) => void },\n): void {\n if (document.getElementById(scriptId)) return; // resolves the preexisting script issue\n\n const target = document.head || document.body;\n const script = document.createElement('script');\n script.id = scriptId;\n script.type = 'text/javascript';\n script.src = source;\n script.async = true;\n script.crossOrigin = 'anonymous';\n (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high';\n if (handlers?.onLoad) script.onload = handlers.onLoad;\n if (handlers?.onError) script.onerror = handlers.onError;\n target.appendChild(script);\n}\n\nfunction parseSettingsString(settingsString?: string): T[] {\n if (!settingsString) {\n return [];\n }\n try {\n return JSON.parse(settingsString.replace(/"/g, '\"')) as T[];\n } catch (_error) {\n console.error('Settings string contains invalid JSON');\n }\n return [];\n}\n\nfunction extractRoktExtensionConfig(settingsString?: string): RoktExtensionConfig {\n const settings = settingsString ? parseSettingsString(settingsString) : [];\n const roktExtensionsQueryParams: string[] = [];\n const legacyRoktExtensions: string[] = [];\n let loadThankYouElement = false;\n\n for (let i = 0; i < settings.length; i++) {\n const extensionName = settings[i].value;\n if (extensionName === 'thank-you-journey') {\n loadThankYouElement = true;\n legacyRoktExtensions.push(ROKT_THANK_YOU_JOURNEY_EXTENSION);\n } else {\n roktExtensionsQueryParams.push(extensionName);\n }\n }\n\n return {\n roktExtensionsQueryParams,\n legacyRoktExtensions,\n loadThankYouElement,\n };\n}\n\nasync function registerLegacyExtensions(legacyExtensions: string[], launcher: RoktLauncher | null) {\n const extensions: Promise[] = [];\n if (launcher) {\n for (const extension of legacyExtensions) {\n extensions.push(launcher.use(extension));\n }\n }\n\n return Promise.all(extensions);\n}\n\nfunction generateMappedEventLookup(placementEventMapping: PlacementEventMappingEntry[]): Record {\n if (!placementEventMapping) {\n return {};\n }\n\n const mappedEvents: Record = {};\n for (let i = 0; i < placementEventMapping.length; i++) {\n const mapping = placementEventMapping[i];\n mappedEvents[mapping.jsmap] = mapping.value;\n }\n return mappedEvents;\n}\n\nfunction generateMappedEventAttributeLookup(\n placementEventAttributeMapping: EventAttributeMapping[],\n): Record {\n const mappedAttributeKeys: Record = {};\n if (!Array.isArray(placementEventAttributeMapping)) {\n return mappedAttributeKeys;\n }\n for (let i = 0; i < placementEventAttributeMapping.length; i++) {\n const mapping = placementEventAttributeMapping[i];\n if (!mapping || !isString(mapping.value) || !isString(mapping.map)) {\n continue;\n }\n\n const mappedAttributeKey = mapping.value;\n const eventAttributeKey = mapping.map;\n\n if (!mappedAttributeKeys[mappedAttributeKey]) {\n mappedAttributeKeys[mappedAttributeKey] = [];\n }\n\n mappedAttributeKeys[mappedAttributeKey].push({\n eventAttributeKey: eventAttributeKey,\n conditions: Array.isArray(mapping.conditions) ? mapping.conditions : [],\n });\n }\n return mappedAttributeKeys;\n}\n\nfunction hashEventMessage(messageType: number, eventType: number, eventName: string): string | number {\n return mp().generateHash([messageType, eventType, eventName].join(''));\n}\n\nfunction generateIntegrationName(customIntegrationName?: string): string {\n const coreSdkVersion = mp().getVersion();\n const kitVersion = process.env.PACKAGE_VERSION;\n let integrationName = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion;\n\n if (customIntegrationName) {\n integrationName += '_' + customIntegrationName;\n }\n return integrationName;\n}\n\nfunction djb2(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return hash;\n}\n\nfunction createAutoRemovedIframe(src: string): void {\n const iframe = document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');\n iframe.src = src;\n iframe.onload = function () {\n iframe.onload = null;\n if (iframe.parentNode) {\n iframe.parentNode.removeChild(iframe);\n }\n };\n const target = document.body || document.head;\n if (target) {\n target.appendChild(iframe);\n }\n}\n\nfunction sendAdBlockMeasurementSignals(domain: string | undefined, version: string | null): void {\n const originHash = djb2(window.location.origin);\n const allowedOriginHashes = RoktKit._allowedOriginHashes;\n if (allowedOriginHashes.indexOf(originHash) === -1) {\n return;\n }\n\n if (Math.random() >= INIT_LOG_SAMPLING_RATE) {\n return;\n }\n\n const guid = window.__rokt_li_guid__;\n if (!guid) {\n return;\n }\n\n if (domain && domain.includes('://') && !/^https:\\/\\//i.test(domain)) {\n return;\n }\n\n const pageUrl = window.location.href.split('?')[0].split('#')[0];\n const params =\n 'version=' +\n encodeURIComponent(version ?? '') +\n '&launcherInstanceGuid=' +\n encodeURIComponent(guid) +\n '&pageUrl=' +\n encodeURIComponent(pageUrl);\n\n const existingBaseUrl = domain ? generateBaseUrl(domain) : 'https://apps.rokt.com';\n createAutoRemovedIframe(existingBaseUrl + '/v1/wsdk-init/index.html?' + params);\n\n createAutoRemovedIframe(\n 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true',\n );\n}\n\n// ============================================================\n// Reporting helpers\n// ============================================================\n\nfunction _isDebugModeEnabled(): boolean {\n return typeof window !== 'undefined' && !!window.location?.search?.toLowerCase().includes('mp_enable_logging=true');\n}\n\nfunction _getReportingUrl(): string | undefined {\n return typeof window !== 'undefined' ? window.location?.href : undefined;\n}\n\nfunction _getUserAgent(): string | undefined {\n return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined;\n}\n\nclass RateLimiter {\n private _logCount: Record = {};\n\n incrementAndCheck(severity: string): boolean {\n const count = this._logCount[severity] || 0;\n const newCount = count + 1;\n this._logCount[severity] = newCount;\n return newCount > RATE_LIMIT_PER_SEVERITY;\n }\n}\n\nclass ReportingTransport {\n private _isEnabled: boolean;\n private _integrationName: string;\n private _launcherInstanceGuid: string | undefined;\n private _accountId: string | null;\n private _rateLimiter: RateLimiter;\n private readonly _reporter = 'mp-wsdk';\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid: string | undefined,\n accountId: string | null | undefined,\n rateLimiter?: RateLimiter,\n ) {\n const isLoggingEnabled = config.isLoggingEnabled;\n this._integrationName = integrationName || '';\n this._launcherInstanceGuid = launcherInstanceGuid;\n this._accountId = accountId || null;\n this._rateLimiter = rateLimiter || new RateLimiter();\n this._isEnabled = _isDebugModeEnabled() || isLoggingEnabled;\n }\n\n send(\n url: string,\n severity: string,\n msg: string,\n code?: string,\n stackTrace?: string,\n onError?: (error: DeliveryError) => void,\n ): void {\n if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) {\n return;\n }\n\n try {\n const logRequest = {\n additionalInformation: {\n message: msg,\n version: this._integrationName,\n },\n severity,\n code: code || ErrorCodes.UNKNOWN_ERROR,\n url: _getReportingUrl(),\n deviceInfo: _getUserAgent(),\n stackTrace,\n reporter: this._reporter,\n integration: this._integrationName,\n };\n\n const headers: Record = {\n Accept: 'text/plain;charset=UTF-8',\n 'Content-Type': 'application/json',\n 'rokt-launcher-version': this._integrationName,\n 'rokt-wsdk-version': 'joint',\n };\n\n if (this._launcherInstanceGuid) {\n headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid;\n }\n if (this._accountId) {\n headers['rokt-account-id'] = this._accountId;\n }\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(logRequest),\n })\n .then((response: Response) => {\n // fetch only rejects on network failures; an HTTP 5xx resolves with\n // ok === false. Surface server-side failures so they are not swallowed.\n if (!response.ok) {\n const serverError: DeliveryError = new Error('HTTP ' + response.status + ' from log endpoint');\n serverError.statusCode = response.status;\n throw serverError;\n }\n })\n .catch((error: DeliveryError) => {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error);\n });\n } catch (error) {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error as DeliveryError);\n }\n }\n}\n\nclass ErrorReportingService {\n private _transport: ReportingTransport;\n private _errorUrl: string;\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._errorUrl = generateReportingUrl(config?.errorUrl, config?.integrationDomain, ERROR_ENDPOINT);\n }\n\n report(error: ErrorReport | null | undefined): void {\n if (!error) return;\n const severity = error.severity || WSDKErrorSeverity.ERROR;\n this._transport.send(this._errorUrl, severity, error.message, error.code, error.stackTrace);\n }\n}\n\nclass LoggingService {\n private _transport: ReportingTransport;\n private _loggingUrl: string;\n private _errorReportingService: { report: (e: ErrorReport) => void };\n\n constructor(\n config: ReportingConfig,\n errorReportingService: { report: (e: ErrorReport) => void },\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._loggingUrl = generateReportingUrl(config?.loggingUrl, config?.integrationDomain, LOGGING_ENDPOINT);\n this._errorReportingService = errorReportingService;\n }\n\n log(entry: LogEntry | null | undefined): void {\n if (!entry) return;\n this._transport.send(\n this._loggingUrl,\n WSDKErrorSeverity.INFO,\n entry.message,\n entry.code,\n undefined,\n (error: DeliveryError) => {\n if (this._errorReportingService) {\n // A failed log POST is not itself an SDK error. Network-level failures\n // (ad-blockers, offline, CORS) are client-side noise and reported as a\n // WARNING; only a server-side non-2xx response stays at ERROR severity.\n const isServerSide = typeof error.statusCode === 'number';\n this._errorReportingService.report({\n message: 'LoggingService: Failed to send log: ' + error.message,\n code: ErrorCodes.LOG_DELIVERY_FAILURE,\n severity: isServerSide ? WSDKErrorSeverity.ERROR : WSDKErrorSeverity.WARNING,\n });\n }\n },\n );\n }\n}\n\nfunction buildPageEvent(event: SDKEvent): PageEvent {\n const pageUrl = sanitizeUrl(window.location.href);\n const pageTitle = event.EventAttributes?.title || document.title;\n const canonicalUrl = readCanonicalUrl();\n const activeTimeOnSite = event.ActiveTimeOnSite;\n\n return {\n pageUrl,\n sourceMessageId: event.SourceMessageId,\n timestamp: event.Timestamp,\n ...(pageTitle ? { pageTitle } : {}),\n ...(canonicalUrl !== undefined ? { canonicalUrl } : {}),\n ...(Number.isFinite(activeTimeOnSite) ? { activeTimeOnSite } : {}),\n };\n}\n\n// ============================================================\n// RoktKit class\n// ============================================================\n\nclass RoktKit implements KitInterface {\n // Static field for allowed origin hashes (mutable by testHelpers)\n public static _allowedOriginHashes: number[] = [-553112570, 549508659];\n\n private static readonly PERFORMANCE_MARKS = {\n RoktScriptAppended: 'mp:RoktScriptAppended',\n };\n\n private static readonly EMAIL_SHA256_KEY = 'emailsha256';\n\n // Public fields (accessed by tests and the mParticle framework)\n public name = name;\n public id = moduleId;\n public moduleId = moduleId;\n public isInitialized = false;\n public launcher: RoktLauncher | null = null;\n public filters: KitFilters = {};\n public userAttributes: Record = {};\n // Flag set by the Workspace IDSync flow on a 200 response. Stored on the\n // kit instance and merged into placement attributes inside selectPlacements.\n public userIdentifiedInWorkspace = false;\n public testHelpers: TestHelpers | null = null;\n public placementEventMappingLookup: Record = {};\n public placementEventAttributeMappingLookup: Record = {};\n public integrationName: string | null = null;\n public domain?: string;\n public errorReportingService: ErrorReportingService | null = null;\n public loggingService: LoggingService | null = null;\n\n // Private fields\n private _mappedEmailSha256Key?: string;\n private _onboardingExpProvider?: string;\n private _thankYouElementOnLoadCallback: (() => void) | null = null;\n private _isThankYouElementLoaded = false;\n private _workspaceIdSyncApiKey?: string;\n\n // Held during a search dispatch so the next selectPlacements call;\n // can wait for the HTTP response before reading userIdentifiedInWorkspace;\n // — otherwise the first placement call ships without the flag.\n private _workspaceSearchInFlightPromise: Promise | null = null;\n // Stable serialization of the identifier set sent in the most recent\n // successful search dispatch. If a subsequent identification arrives with\n // an identical set, we skip the network call (the flag is still correct\n // from the prior search). Keyed over the full IUserIdentities map — not\n // just email — so partners passing hashed email through `other`/`other2-10`\n // or any other identifier benefit from the same dedupe. Cleared on logout\n // so a re-login re-evaluates fresh.\n private _workspaceLastSearchedIdentitiesKey?: string;\n\n // ---- Private helpers ----\n\n private getEventAttributeValue(event: SDKEvent, eventAttributeKey: string): unknown {\n const attributes = event && event.EventAttributes;\n if (!attributes) {\n return null;\n }\n\n if (typeof attributes[eventAttributeKey] === 'undefined') {\n return null;\n }\n\n return attributes[eventAttributeKey];\n }\n\n private doesEventAttributeConditionMatch(condition: EventAttributeCondition, actualValue: unknown): boolean {\n if (!condition || !isString(condition.operator)) {\n return false;\n }\n\n const operator = condition.operator.toLowerCase();\n const expectedValue = condition.attributeValue;\n\n if (operator === 'exists') {\n return actualValue !== null;\n }\n\n if (actualValue == null) {\n return false;\n }\n\n if (operator === 'equals') {\n return String(actualValue) === String(expectedValue);\n }\n\n if (operator === 'contains') {\n return String(actualValue).indexOf(String(expectedValue)) !== -1;\n }\n\n return false;\n }\n\n private doesEventMatchRule(event: SDKEvent, rule: PlacementEventRule): boolean {\n if (!rule || !isString(rule.eventAttributeKey)) {\n return false;\n }\n\n const conditions = rule.conditions;\n if (!Array.isArray(conditions)) {\n return false;\n }\n\n const actualValue = this.getEventAttributeValue(event, rule.eventAttributeKey);\n\n if (conditions.length === 0) {\n return actualValue !== null;\n }\n for (let i = 0; i < conditions.length; i++) {\n if (!this.doesEventAttributeConditionMatch(conditions[i], actualValue)) {\n return false;\n }\n }\n\n return true;\n }\n\n private applyPlacementEventAttributeMapping(event: SDKEvent): void {\n const mappedAttributeKeys = Object.keys(this.placementEventAttributeMappingLookup);\n for (let i = 0; i < mappedAttributeKeys.length; i++) {\n const mappedAttributeKey = mappedAttributeKeys[i];\n const rulesForMappedAttributeKey = this.placementEventAttributeMappingLookup[mappedAttributeKey];\n if (isEmpty(rulesForMappedAttributeKey)) {\n continue;\n }\n\n // Require ALL rules for the same key to match (AND).\n let allMatch = true;\n for (let j = 0; j < rulesForMappedAttributeKey.length; j++) {\n if (!this.doesEventMatchRule(event, rulesForMappedAttributeKey[j])) {\n allMatch = false;\n break;\n }\n }\n if (!allMatch) {\n continue;\n }\n\n mp().Rokt.setLocalSessionAttribute?.(mappedAttributeKey, true);\n }\n }\n\n private capturePageView(event: SDKEvent): void {\n let pageUrl: string | undefined;\n\n try {\n pageUrl = sanitizeUrl(window.location.href);\n\n const pageViews = loadPageViews(this.loggingService);\n const pageView = buildPageEvent(event);\n pageViews.push(pageView);\n\n const requested = Math.min(pageViews.length, PAGE_VIEWS_MAX_COUNT);\n const stored = writePageViews(pageViews);\n if (stored === 0) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n this.loggingService?.log({\n message: `Rokt Kit: Failed to persist page view for ${pageUrl} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n } else if (stored < requested) {\n this.loggingService?.log({\n message: `Rokt Kit: Page view storage reduced from ${requested} to ${stored} record(s) under quota pressure [reason: quota_eviction]`,\n code: 'PAGE_VIEW_QUOTA_EVICTION',\n });\n }\n } catch (err) {\n const reason = isLocalStorageAvailable() ? 'exception' : 'ls_unavailable';\n const errMessage = err instanceof Error ? err.message : String(err);\n this.loggingService?.log({\n message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${errMessage} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n private isLauncherReadyToAttach(): boolean {\n return !!window.Rokt && isFunction(window.Rokt.createLauncher);\n }\n\n /**\n * Returns the user identities from the filtered user, if any.\n */\n private returnUserIdentities(filteredUser: FilteredUser | null | undefined): Record {\n if (!filteredUser || !filteredUser.getUserIdentities) {\n return {};\n }\n\n const userIdentities: IUserIdentities = filteredUser.getUserIdentities().userIdentities;\n\n return this.replaceOtherIdentityWithEmailsha256(userIdentities);\n }\n\n private returnLocalSessionAttributes(): Record {\n if (!mp().Rokt || typeof mp().Rokt.getLocalSessionAttributes !== 'function') {\n return {};\n }\n return mp().Rokt.getLocalSessionAttributes!();\n }\n\n private replaceOtherIdentityWithEmailsha256(userIdentities: IUserIdentities): Record {\n const newUserIdentities: Record = { ...(userIdentities || {}) };\n const key = this._mappedEmailSha256Key;\n if (key && userIdentities[key as keyof IUserIdentities]) {\n newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key as keyof IUserIdentities] as string;\n }\n if (key) {\n delete newUserIdentities[key];\n }\n\n return newUserIdentities;\n }\n\n private logSelectPlacementsEvent(attributes: unknown): void {\n if (!window.mParticle || typeof mp().logEvent !== 'function') {\n return;\n }\n\n if (!isObject(attributes)) {\n return;\n }\n\n const EVENT_TYPE_OTHER = mp().EventType.Other;\n\n mp().logEvent(EVENT_NAME_SELECT_PLACEMENTS, EVENT_TYPE_OTHER, attributes as Record);\n }\n\n private setRoktSessionId(sessionId: string): void {\n if (!sessionId || typeof sessionId !== 'string') {\n return;\n }\n try {\n const mpInstance = mp().getInstance();\n if (mpInstance && isFunction(mpInstance.setIntegrationAttribute)) {\n mpInstance.setIntegrationAttribute(moduleId, {\n roktSessionId: sessionId,\n });\n }\n } catch (_e) {\n // Best effort — never let this break the partner page\n }\n }\n\n private readMpSessionId(): string | undefined {\n // The public mParticle.sessionManager facade exposes only getSession(), which already returns\n // the session id. getSessionId() lives on the internal _SessionManager and has never been\n // re-exported, so prefer it if a future core adds it and fall back to getSession() until then.\n const sessionManager = mp()?.sessionManager;\n const readSessionId = sessionManager?.getSessionId ?? sessionManager?.getSession;\n if (!isFunction(readSessionId)) {\n return undefined;\n }\n\n return readSessionId.call(sessionManager) || undefined;\n }\n\n private readMpDeviceId(): string | undefined {\n // The device application stamp (`das`) outlives the session id: core clears the session on\n // timeout, cross-tab rotation and endSession(), but never the device id, which lives in\n // localStorage/cookie for cookieExpiration days (365 by default) and survives login/logout.\n // Read it per call anyway — a partner can reassign it at any time via setDeviceId().\n return mp()?.getDeviceId?.() || undefined;\n }\n\n private attachLauncher(\n accountId: string,\n launcherOptions: Record,\n legacyRoktExtensions: string[] = [],\n ): void {\n const options: Record = {\n accountId,\n ...(launcherOptions || {}),\n };\n\n let launcherPromise: Promise;\n if (this.isPartnerInLocalLauncherTestGroup()) {\n launcherPromise = Promise.resolve(window.Rokt!.createLocalLauncher(options));\n } else {\n launcherPromise = window.Rokt!.createLauncher(options);\n }\n\n launcherPromise\n .then(async (launcher) => {\n await registerLegacyExtensions(legacyRoktExtensions, launcher);\n this.initRoktLauncher(launcher);\n })\n .catch((err: unknown) => {\n console.error('Error creating Rokt launcher:', err);\n });\n }\n\n private initRoktLauncher(launcher: RoktLauncher): void {\n // Assign the launcher to a global variable for later access\n if (window.Rokt) {\n window.Rokt.currentLauncher = launcher;\n }\n // Locally cache the launcher and filters\n this.launcher = launcher;\n\n const roktFilters = mp().Rokt?.filters;\n\n if (!roktFilters) {\n console.warn('Rokt Kit: No filters have been set.');\n } else {\n this.filters = roktFilters;\n if (!roktFilters.filteredUser) {\n console.warn('Rokt Kit: No filtered user has been set.');\n } else {\n this._workspaceSearchInFlightPromise = this.search(roktFilters.filteredUser);\n }\n }\n\n // Kit must be initialized before attaching to the Rokt manager\n this.isInitialized = true;\n\n sendAdBlockMeasurementSignals(this.domain, this.integrationName);\n\n // Attaches the kit to the Rokt manager\n mp().Rokt.attachKit(this);\n }\n\n private fetchOptimizely(): Record {\n const forwarders = mp()\n ._getActiveForwarders()\n .filter((forwarder) => forwarder.name === 'Optimizely');\n\n try {\n if (forwarders.length > 0 && window.optimizely) {\n const optimizelyState = window.optimizely.get('state');\n if (!optimizelyState || !optimizelyState.getActiveExperimentIds) {\n return {};\n }\n const activeExperimentIds = optimizelyState.getActiveExperimentIds();\n const activeExperiments = activeExperimentIds.reduce((acc: Record, expId: string) => {\n acc['rokt.custom.optimizely.experiment.' + expId + '.variationId'] =\n optimizelyState.getVariationMap()[expId].id;\n return acc;\n }, {});\n return activeExperiments;\n }\n } catch (error) {\n console.error('Error fetching Optimizely attributes:', error);\n }\n return {};\n }\n\n private isKitReady(): boolean {\n return !!(this.isInitialized && this.launcher);\n }\n\n // When the partner has opted out of targeting (noTargeting launcher option),\n // the kit must not collect behavioral targeting signals such as page views.\n private isTargetingDisabled(): boolean {\n return (mp().Rokt?.launcherOptions as Record | undefined)?.noTargeting === true;\n }\n\n private isPartnerInLocalLauncherTestGroup(): boolean {\n return !!(mp().config && mp().config!.isLocalLauncherEnabled && this.isAssignedToSampleGroup());\n }\n\n private isAssignedToSampleGroup(): boolean {\n const LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5;\n return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD;\n }\n\n private captureTiming(metricName: string): void {\n if (window && mp() && mp().captureTiming && metricName) {\n mp().captureTiming!(metricName);\n }\n }\n\n // ---- Public methods (mParticle Kit Callbacks) ----\n\n /**\n * Initializes the Rokt forwarder with settings from the mParticle server.\n */\n public init(\n settings: Record,\n _service: unknown,\n testMode: boolean,\n _trackerId: unknown,\n filteredUserAttributes?: Record,\n ): string {\n const kitSettings = settings as unknown as RoktKitSettings;\n const accountId = kitSettings.accountId;\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredUserAttributes);\n this._onboardingExpProvider = kitSettings.onboardingExpProvider;\n\n const placementEventMapping = parseSettingsString(kitSettings.placementEventMapping);\n this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping);\n\n const placementEventAttributeMapping = parseSettingsString(\n kitSettings.placementEventAttributeMapping,\n );\n this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping);\n\n // Set dynamic OTHER_IDENTITY based on server settings\n if (kitSettings.hashedEmailUserIdentityType) {\n this._mappedEmailSha256Key = kitSettings.hashedEmailUserIdentityType.toLowerCase();\n }\n\n this._workspaceIdSyncApiKey = isString(kitSettings.workspaceIdSyncApiKey)\n ? kitSettings.workspaceIdSyncApiKey\n : undefined;\n\n const domain = mp().Rokt?.domain;\n const { roktExtensionsQueryParams, legacyRoktExtensions, loadThankYouElement } = extractRoktExtensionConfig(\n kitSettings.roktExtensions,\n );\n const launcherOptions: Record = {\n ...((mp().Rokt?.launcherOptions as Record) || {}),\n };\n this.integrationName = generateIntegrationName(launcherOptions.integrationName as string | undefined);\n launcherOptions.integrationName = this.integrationName;\n\n this.domain = domain;\n\n const reportingConfig: ReportingConfig = {\n loggingUrl: kitSettings.loggingUrl,\n errorUrl: kitSettings.errorUrl,\n integrationDomain: domain,\n isLoggingEnabled: mp().config?.isLoggingEnabled === true,\n };\n const errorReportingService = new ErrorReportingService(\n reportingConfig,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n const loggingService = new LoggingService(\n reportingConfig,\n errorReportingService,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n\n this.errorReportingService = errorReportingService;\n this.loggingService = loggingService;\n\n if (this.isTargetingDisabled()) {\n try {\n clearPageViews();\n clearUtmParams();\n } catch (err) {\n this.errorReportingService?.report({\n message: 'Rokt Kit: Failed to clear page views when targeting is disabled',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n severity: WSDKErrorSeverity.INFO,\n stackTrace: err instanceof Error ? err.stack : undefined,\n });\n }\n }\n\n if (mp()._registerErrorReportingService) {\n mp()._registerErrorReportingService!(errorReportingService);\n }\n if (mp()._registerLoggingService) {\n mp()._registerLoggingService!(loggingService);\n }\n\n if (testMode) {\n this.testHelpers = {\n generateLauncherScript: generateLauncherScript,\n generateThankYouElementScript: generateThankYouElementScript,\n extractRoktExtensionConfig: extractRoktExtensionConfig,\n hashEventMessage: hashEventMessage,\n parseSettingsString: parseSettingsString,\n generateMappedEventLookup: generateMappedEventLookup,\n generateMappedEventAttributeLookup: generateMappedEventAttributeLookup,\n sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals,\n createAutoRemovedIframe: createAutoRemovedIframe,\n djb2: djb2,\n setAllowedOriginHashes: (hashes: number[]) => {\n RoktKit._allowedOriginHashes = hashes;\n },\n ReportingTransport: ReportingTransport,\n ErrorReportingService: ErrorReportingService,\n LoggingService: LoggingService,\n RateLimiter: RateLimiter,\n ErrorCodes: ErrorCodes,\n WSDKErrorSeverity: WSDKErrorSeverity,\n };\n this.attachLauncher(accountId, launcherOptions);\n return 'Successfully initialized: ' + name;\n }\n\n if (loadThankYouElement) {\n mp().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this);\n loadRoktScript(ROKT_THANK_YOU_ELEMENT_SCRIPT_ID, generateThankYouElementScript(domain), {\n onLoad: () => {\n this._isThankYouElementLoaded = true;\n if (this._thankYouElementOnLoadCallback) {\n this._thankYouElementOnLoadCallback();\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt Thank You Element script:', error);\n },\n });\n }\n\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n loadRoktScript(ROKT_INTEGRATION_SCRIPT_ID, generateLauncherScript(domain, roktExtensionsQueryParams), {\n onLoad: () => {\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n console.error('Rokt object is not available after script load.');\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt launcher script:', error);\n },\n });\n\n this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended);\n }\n\n return 'Successfully initialized: ' + name;\n }\n\n public process(event: SDKEvent): string {\n if (!this.isTargetingDisabled()) {\n if (event.EventDataType === MESSAGE_TYPE_PAGE_VIEW) {\n captureUtmParams(this.loggingService);\n this.capturePageView(event);\n }\n\n if (event.EventDataType === MESSAGE_TYPE_SESSION_END) {\n migrateLegacyPageViewStorage(this.loggingService);\n clearPageViews();\n clearUtmParams();\n }\n }\n\n // The forwarding work below (LSA mapping) depends on the launcher, so guard\n // it here and surface the not-ready signal to the core SDK.\n if (!this.isKitReady()) {\n return 'Kit not ready for forwarder: ' + name;\n }\n\n if (isFunction(mp().Rokt?.setLocalSessionAttribute)) {\n if (!isEmpty(this.placementEventAttributeMappingLookup)) {\n this.applyPlacementEventAttributeMapping(event);\n }\n\n if (!isEmpty(this.placementEventMappingLookup)) {\n const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? '');\n if (this.placementEventMappingLookup[String(hashedEvent)]) {\n mp().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(hashedEvent)], true);\n }\n }\n }\n\n return 'Successfully sent to forwarder: ' + name;\n }\n\n public setExtensionData(partnerExtensionData: Record): void {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return;\n }\n\n window.Rokt!.setExtensionData(partnerExtensionData);\n }\n\n public setUserAttribute(key: string, value: unknown): string {\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n this.userAttributes[key] = value;\n }\n return 'Successfully set user attribute for forwarder: ' + name;\n }\n\n public removeUserAttribute(key: string): string {\n delete this.userAttributes[key];\n return 'Successfully removed user attribute for forwarder: ' + name;\n }\n\n private handleIdentityComplete(user: IMParticleUser, callbackName: string): string {\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(user.getAllUserAttributes());\n return 'Successfully called ' + callbackName + ' for forwarder: ' + name;\n }\n\n public onUserIdentified(user: IMParticleUser): string {\n const filteredUser = user as FilteredUser;\n this.filters.filteredUser = filteredUser;\n this._workspaceSearchInFlightPromise = this.search(filteredUser);\n return this.handleIdentityComplete(user, 'onUserIdentified');\n }\n\n private search(filteredUser: FilteredUser): Promise {\n const apiKey = this._workspaceIdSyncApiKey;\n if (!apiKey) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n const search = mp().Identity?.search;\n if (typeof search !== 'function') {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n const userIdentities: IUserIdentities | null = filteredUser.getUserIdentities\n ? filteredUser.getUserIdentities().userIdentities\n : null;\n\n // Forward every non-empty string identifier the user has — email,\n // customerid, other/other2-10 (commonly used for hashed email),\n // mobile_number, facebook, etc. The host SDK's Identity.search accepts\n // the full IUserIdentities surface and the server validates it.\n const knownIdentities: Record = {};\n if (userIdentities) {\n for (const key of Object.keys(userIdentities) as Array) {\n const value = userIdentities[key];\n if (isString(value) && value.length > 0) {\n knownIdentities[key] = value;\n }\n }\n }\n\n const identityKeys = Object.keys(knownIdentities);\n if (identityKeys.length === 0) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n // Stable cache key: sort keys so insertion-order differences don't\n // cause false misses. The values are partner-supplied strings; no\n // hashing needed — equality on this serialization is sufficient.\n const identitiesKey = identityKeys\n .sort()\n .map((k) => `${k}=${knownIdentities[k]}`)\n .join('&');\n\n // Same identifier set as the last successful dispatch → skip the\n // network call. The current flag value still reflects the correct\n // match status.\n if (identitiesKey === this._workspaceLastSearchedIdentitiesKey) {\n return this._workspaceSearchInFlightPromise || Promise.resolve();\n }\n\n // New / different identifier set → reset and re-search. Cache the key\n // up front so a second concurrent invocation with the same set also\n // dedupes.\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = identitiesKey;\n\n return new Promise((resolve) => {\n try {\n search(apiKey, knownIdentities as IUserIdentities, (result: WorkspaceIdSyncResult) => {\n if (result?.httpCode === 200) {\n this.userIdentifiedInWorkspace = true;\n }\n resolve();\n });\n } catch (err) {\n console.error('Rokt Kit: Workspace IDSync search failed', err);\n // Dispatch failed — clear the cache so the same identifier set\n // can retry on the next identification rather than being stuck\n // behind a poisoned entry that short-circuits future searches.\n this._workspaceLastSearchedIdentitiesKey = undefined;\n resolve();\n }\n });\n }\n\n public onLoginComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onLoginComplete');\n }\n\n public onLogoutComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n // Anonymous sessions must not carry the previous user's match forward.\n // Clear the flag explicitly here. Also clear the identities cache so a\n // re-login (possibly with the same identifiers) dispatches a fresh\n // search rather than reusing a stale answer.\n this.userIdentifiedInWorkspace = false;\n this._workspaceSearchInFlightPromise = null;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return this.handleIdentityComplete(user, 'onLogoutComplete');\n }\n\n public onModifyComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onModifyComplete');\n }\n\n /**\n * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options.\n *\n * If a Workspace IDSync search is in flight from a recent onUserIdentified\n * call, this method waits up to `WORKSPACE_SEARCH_SELECT_TIMEOUT_MS` for it\n * to settle so the first placement call can include the\n * `userIdentifiedInWorkspace` flag without racing the network response.\n * The timeout protects against a stalled or slow search blocking placement\n * rendering — if it fires, selectPlacements proceeds without the flag.\n *\n * Implementation note: this method stays non-async deliberately. First,\n * the public return type is `RoktSelection | Promise |\n * undefined` — a superset of the `RoktSelection | Promise`\n * shape declared for `RoktLauncher.selectPlacements` above (line ~70).\n * Marking this `async` would narrow it to `Promise` and silently change the contract for callers that read\n * the result synchronously. Second, `RoktSelection` has an optional\n * `then?` member, so TS treats it as ambiguously promise-like and\n * rejects it as the awaited return of an async function (TS1058) —\n * working around that would require a cast or wrapping every return in\n * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`;\n * this wrapper just gates it on the in-flight search via `Promise.race`.\n */\n public selectPlacements(options: Record): RoktSelection | Promise | undefined {\n if (this._workspaceSearchInFlightPromise) {\n const inFlight = this._workspaceSearchInFlightPromise;\n return Promise.race([\n inFlight,\n new Promise((resolve) => setTimeout(resolve, WORKSPACE_SEARCH_SELECT_TIMEOUT_MS)),\n ]).then(() => this._dispatchPlacements(options)) as Promise;\n }\n return this._dispatchPlacements(options);\n }\n\n private _dispatchPlacements(options: Record): RoktSelection | Promise | undefined {\n const attributes = ((options && (options.attributes as Record)) || {}) as Record;\n const cachedUserAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(this.userAttributes);\n const placementAttributes: Record = { ...cachedUserAttributes, ...attributes };\n\n const filters = this.filters || {};\n const userAttributeFilters = (filters.userAttributeFilters as string[]) || [];\n const filteredUser = filters.filteredUser || null;\n const mpid = filteredUser ? filteredUser.getMPID() : null;\n\n let filteredAttributes: Record;\n\n if (!filters) {\n console.warn('Rokt Kit: No filters available, using user attributes');\n filteredAttributes = placementAttributes;\n } else if (filters.filterUserAttributes) {\n filteredAttributes = filters.filterUserAttributes(placementAttributes, userAttributeFilters);\n } else {\n filteredAttributes = placementAttributes;\n }\n\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredAttributes);\n\n const optimizelyAttributes = this._onboardingExpProvider === 'Optimizely' ? this.fetchOptimizely() : {};\n\n const filteredUserIdentities = this.returnUserIdentities(filteredUser);\n\n const sessionAttributes = this.returnLocalSessionAttributes();\n const pageEvents = buildPageEvents(loadPageViews(this.loggingService));\n const utmParams = loadUtmParams();\n const mpSessionId = this.readMpSessionId();\n const mpDeviceId = this.readMpDeviceId();\n\n const selectPlacementsAttributes: Record = {\n ...(filteredUserIdentities as Record),\n ...filteredAttributes,\n ...optimizelyAttributes,\n ...sessionAttributes,\n ...(pageEvents.length ? { [PAGE_EVENTS_KEY]: JSON.stringify(pageEvents) } : {}),\n ...(utmParams ? { [PAGE_VIEW_ATTRIBUTES_KEY]: utmParams } : {}),\n ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}),\n ...(mpSessionId ? { [MPARTICLE_SESSION_ID_KEY]: mpSessionId } : {}),\n ...(mpDeviceId ? { [MPARTICLE_DEVICE_ID_KEY]: mpDeviceId } : {}),\n mpid,\n };\n\n const selectPlacementsOptions: Record = { ...options, attributes: selectPlacementsAttributes };\n\n const selection = this.launcher!.selectPlacements(selectPlacementsOptions);\n\n // After selection resolves, sync the Rokt session ID back to mParticle, then log\n const logSelection = () => this.logSelectPlacementsEvent(selectPlacementsAttributes);\n\n void Promise.resolve(selection)\n .then((sel) => sel?.context?.sessionId?.then((sessionId) => this.setRoktSessionId(sessionId)))\n .catch(() => undefined)\n .finally(logSelection);\n\n return selection;\n }\n\n /**\n * Passes attributes to the Rokt Web SDK for client-side hashing.\n */\n public hashAttributes(attributes: Record): Promise> | null {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return null;\n }\n return this.launcher!.hashAttributes(attributes);\n }\n\n /**\n * Enables optional Integration Launcher extensions before selecting placements.\n *\n * @deprecated This functionality has been internalized and will be removed in a future release.\n */\n public use(extensionName: string): Promise {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return Promise.reject(new Error('Rokt Kit: Not initialized'));\n }\n if (!extensionName || !isString(extensionName)) {\n return Promise.reject(new Error('Rokt Kit: Invalid extension name'));\n }\n return this.launcher!.use(extensionName);\n }\n\n /**\n * Registers a callback to be invoked once rokt-thank-you-element.js becomes available.\n */\n public onShoppableAdsReady(callback: () => void) {\n if (this._isThankYouElementLoaded) {\n callback();\n } else {\n this._thankYouElementOnLoadCallback = callback;\n }\n }\n}\n\n// ============================================================\n// Kit registration\n// ============================================================\n\nfunction getId(): number {\n return moduleId;\n}\n\nfunction register(config: { kits?: Record }): void {\n if (!config) {\n window.console.log('You must pass a config object to register the kit ' + name);\n return;\n }\n if (!isObject(config)) {\n window.console.log(\"'config' must be an object. You passed in a \" + typeof config);\n return;\n }\n\n if (isObject(config.kits)) {\n (config.kits as Record)[name] = {\n constructor: RoktKit,\n };\n } else {\n config.kits = {};\n config.kits[name] = {\n constructor: RoktKit,\n };\n }\n window.console.log('Successfully registered ' + name + ' to your mParticle configuration');\n}\n\nif (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) {\n mp().addForwarder({\n name: name,\n constructor: RoktKit,\n getId: getId,\n });\n}\n\nexport { register };\nexport type { LoggingService };\n"],"names":["SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST","SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET","isSelectPlacementsAttributePersistenceDenied","key","removeSelectPlacementsAttributePersistenceDeniedAttributes","attributes","filteredAttributes","sourceAttributes","attributeKeys","i","isObject","value","isString","isFunction","isEmpty","sanitizeUrl","href","url","LS_PROBE_KEY","isLocalStorageAvailable","readJSON","stored","writeJSON","removeKey","readNamespacedField","namespaceKey","field","blob","writeNamespacedField","next","removeNamespacedField","LS_NAMESPACE_KEY","LS_PAGE_VIEWS_FIELD","LS_UTM_PARAMS_FIELD","LEGACY_PAGE_VIEWS_KEY","PAGE_VIEWS_MAX_COUNT","UTM_KEYS","capPageViews","views","migrateLegacyPageViewStorage","loggingService","legacyViews","loadPageViews","writePageViews","pageViews","toWrite","clearPageViews","buildPageEvents","pageView","index","activeTimeOnSite","hasActiveTime","nextActiveTimeOnSite","hasNextActiveTimeOnSite","diff","captureUtmParams","search","params","captured","reason","loadUtmParams","clearUtmParams","readCanonicalUrl","name","moduleId","EVENT_NAME_SELECT_PLACEMENTS","ADBLOCK_CONTROL_DOMAIN","INIT_LOG_SAMPLING_RATE","ROKT_THANK_YOU_JOURNEY_EXTENSION","ROKT_INTEGRATION_SCRIPT_ID","ROKT_THANK_YOU_ELEMENT_SCRIPT_ID","USER_IDENTIFIED_IN_WORKSPACE_KEY","MESSAGE_TYPE_PAGE_VIEW","MESSAGE_TYPE_SESSION_END","PAGE_EVENTS_KEY","PAGE_VIEW_ATTRIBUTES_KEY","MPARTICLE_SESSION_ID_KEY","MPARTICLE_DEVICE_ID_KEY","WORKSPACE_SEARCH_SELECT_TIMEOUT_MS","ErrorCodes","WSDKErrorSeverity","DEFAULT_ROKT_DOMAIN","LOGGING_ENDPOINT","ERROR_ENDPOINT","RATE_LIMIT_PER_SEVERITY","mp","generateLauncherScript","domain","extensions","baseUrl","generateBaseUrl","generateThankYouElementScript","resolvedDomain","generateReportingUrl","configuredUrl","endpoint","reportingDomain","loadRoktScript","scriptId","source","handlers","target","script","parseSettingsString","settingsString","extractRoktExtensionConfig","settings","roktExtensionsQueryParams","legacyRoktExtensions","loadThankYouElement","extensionName","registerLegacyExtensions","legacyExtensions","launcher","extension","generateMappedEventLookup","placementEventMapping","mappedEvents","mapping","generateMappedEventAttributeLookup","placementEventAttributeMapping","mappedAttributeKeys","mappedAttributeKey","eventAttributeKey","hashEventMessage","messageType","eventType","eventName","generateIntegrationName","customIntegrationName","integrationName","djb2","str","hash","createAutoRemovedIframe","src","iframe","sendAdBlockMeasurementSignals","version","originHash","RoktKit","guid","pageUrl","existingBaseUrl","_isDebugModeEnabled","_getReportingUrl","_getUserAgent","RateLimiter","severity","newCount","ReportingTransport","config","launcherInstanceGuid","accountId","rateLimiter","isLoggingEnabled","msg","code","stackTrace","onError","logRequest","headers","response","serverError","error","ErrorReportingService","LoggingService","errorReportingService","entry","isServerSide","buildPageEvent","event","pageTitle","canonicalUrl","_RoktKit","condition","actualValue","operator","expectedValue","rule","conditions","rulesForMappedAttributeKey","allMatch","j","requested","err","errMessage","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","sessionManager","readSessionId","launcherOptions","options","launcherPromise","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","sessionAttributes","pageEvents","utmParams","mpSessionId","mpDeviceId","selectPlacementsAttributes","selectPlacementsOptions","selection","logSelection","sel","callback","getId","register"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"Rokt-Kit.iife.js","sources":["../src/selectPlacementsAttributePersistence.ts","../src/utils.ts","../src/storage.ts","../src/pageViewStorage.ts","../src/Rokt-Kit.ts"],"sourcesContent":["const SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST = [\n 'active_time_on_site_ms',\n 'billingaddress1',\n 'billingaddress2',\n 'billingcity',\n 'billingstate',\n 'billingzipcode',\n 'cartitems',\n 'ccbin',\n 'confirmationref',\n 'conversiontype',\n 'country',\n 'couponcode',\n 'currency',\n 'language',\n 'paymentserviceprovider',\n 'paymentserviceproviderattribute',\n 'paymenttype',\n 'shippingaddress1',\n 'shippingcity',\n 'shippingcountry',\n 'shippingmethod',\n 'shippingstate',\n 'shippingzipcode',\n 'totalprice',\n];\nconst SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET = new Set(SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST);\n\nexport function isSelectPlacementsAttributePersistenceDenied(key: string): boolean {\n return SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET.has(key.toLowerCase());\n}\n\nexport function removeSelectPlacementsAttributePersistenceDeniedAttributes(\n attributes: Record | null | undefined,\n): Record {\n const filteredAttributes: Record = {};\n const sourceAttributes = attributes || {};\n const attributeKeys = Object.keys(sourceAttributes);\n\n for (let i = 0; i < attributeKeys.length; i++) {\n const key = attributeKeys[i];\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n filteredAttributes[key] = sourceAttributes[key];\n }\n }\n\n return filteredAttributes;\n}\n","export function isObject(value: unknown): value is Record {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\nexport function isFunction(value: unknown): value is (...args: Array) => unknown {\n return typeof value === 'function';\n}\n\nexport function isEmpty(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'object') {\n return Object.keys(value as object).length === 0;\n }\n return false;\n}\n\n// Strips the query string from a URL before it is persisted and sent to Rokt,\n// since query params commonly carry PII (emails, tokens, order refs).\n// Returns the input unchanged if it can't be parsed as a URL.\nexport function sanitizeUrl(href: string): string {\n try {\n const url = new URL(href);\n url.search = '';\n return url.toString();\n } catch {\n return href;\n }\n}\n","import { isObject } from './utils';\n\nconst LS_PROBE_KEY = '__rokt_ls_probe__';\n\nexport function isLocalStorageAvailable(): boolean {\n try {\n window.localStorage.setItem(LS_PROBE_KEY, '1');\n window.localStorage.removeItem(LS_PROBE_KEY);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function readJSON(key: string): unknown {\n try {\n const stored = window.localStorage.getItem(key);\n return stored === null ? null : JSON.parse(stored);\n } catch {\n return null;\n }\n}\n\nexport function writeJSON(key: string, value: unknown): boolean {\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n return true;\n } catch {\n return false;\n }\n}\n\nexport function removeKey(key: string): void {\n try {\n window.localStorage.removeItem(key);\n } catch {\n /* empty */\n }\n}\n\nexport function readNamespacedField(namespaceKey: string, field: string): unknown {\n const blob = readJSON(namespaceKey);\n return isObject(blob) ? blob[field] : undefined;\n}\n\nexport function writeNamespacedField(namespaceKey: string, field: string, value: unknown): boolean {\n const blob = readJSON(namespaceKey);\n const next = isObject(blob) ? { ...blob } : {};\n next[field] = value;\n return writeJSON(namespaceKey, next);\n}\n\nexport function removeNamespacedField(namespaceKey: string, field: string): void {\n const blob = readJSON(namespaceKey);\n if (!isObject(blob) || !(field in blob)) {\n return;\n }\n const next = { ...blob };\n delete next[field];\n if (Object.keys(next).length === 0) {\n removeKey(namespaceKey);\n } else {\n writeJSON(namespaceKey, next);\n }\n}\n","import type { LoggingService } from './Rokt-Kit';\nimport {\n readJSON,\n removeKey,\n readNamespacedField,\n writeNamespacedField,\n removeNamespacedField,\n isLocalStorageAvailable,\n} from './storage';\nimport { sanitizeUrl, isObject } from './utils';\n\nconst LS_NAMESPACE_KEY = 'mp-rokt-kit';\nconst LS_PAGE_VIEWS_FIELD = 'pageViews';\nconst LS_UTM_PARAMS_FIELD = 'utmParams';\nconst LEGACY_PAGE_VIEWS_KEY = 'mpPageViews';\nexport const PAGE_VIEWS_MAX_COUNT = 25;\n\nconst UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'] as const;\ntype UtmKey = (typeof UTM_KEYS)[number];\nexport type UtmParams = Partial>;\n\nexport interface PageEvent {\n pageUrl: string;\n sourceMessageId: string;\n timestamp: number;\n pageTitle?: string;\n canonicalUrl?: string;\n activeTimeOnSite?: number;\n activeTimeOnPage?: number;\n}\n\nfunction capPageViews(views: PageEvent[]): PageEvent[] {\n return views.slice(-PAGE_VIEWS_MAX_COUNT);\n}\n\nexport function migrateLegacyPageViewStorage(loggingService: LoggingService | null): void {\n const legacyViews = readJSON(LEGACY_PAGE_VIEWS_KEY);\n if (legacyViews === null) {\n return;\n }\n\n const alreadyMigrated = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD) !== undefined;\n const needsMigration = !alreadyMigrated && Array.isArray(legacyViews);\n\n if (needsMigration) {\n loggingService?.log({\n message: 'Rokt Kit: Migrating legacy page-view storage',\n code: 'PAGE_VIEW_LEGACY_MIGRATION',\n });\n const migrated = writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, legacyViews);\n if (!migrated) {\n loggingService?.log({\n message: 'Rokt Kit: Failed to migrate legacy page-view storage [reason: migration_retry]',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n removeKey(LEGACY_PAGE_VIEWS_KEY);\n}\n\nexport function loadPageViews(loggingService: LoggingService | null): PageEvent[] {\n migrateLegacyPageViewStorage(loggingService);\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n return Array.isArray(stored) ? (stored as PageEvent[]) : [];\n}\n\nexport function writePageViews(pageViews: PageEvent[]): number {\n const views = capPageViews(pageViews);\n for (let i = 0; i < views.length; i++) {\n const toWrite = views.slice(i);\n if (writeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, toWrite)) {\n return toWrite.length;\n }\n }\n return 0;\n}\n\nexport function clearPageViews(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n}\n\nexport function buildPageEvents(pageViews: PageEvent[]): PageEvent[] {\n const views = capPageViews(pageViews);\n return views.map((pageView, index) => {\n const activeTimeOnSite = pageView.activeTimeOnSite;\n const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite);\n\n const next = views[index + 1];\n const nextActiveTimeOnSite = next?.activeTimeOnSite;\n const hasNextActiveTimeOnSite = nextActiveTimeOnSite !== undefined && Number.isFinite(nextActiveTimeOnSite);\n\n const diff = hasActiveTime && hasNextActiveTimeOnSite ? nextActiveTimeOnSite - activeTimeOnSite : undefined;\n\n return {\n pageUrl: pageView.pageUrl,\n sourceMessageId: pageView.sourceMessageId,\n timestamp: pageView.timestamp,\n ...(pageView.pageTitle !== undefined ? { pageTitle: pageView.pageTitle } : {}),\n ...(pageView.canonicalUrl !== undefined ? { canonicalUrl: pageView.canonicalUrl } : {}),\n ...(hasActiveTime ? { activeTimeOnSite } : {}),\n ...(diff !== undefined && diff >= 0 ? { activeTimeOnPage: diff } : {}),\n };\n });\n}\n\nexport function captureUtmParams(loggingService: LoggingService | null): void {\n if (readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD) !== undefined) {\n return;\n }\n const search = new URLSearchParams(window.location.search);\n const params: UtmParams = {};\n for (const key of UTM_KEYS) {\n const value = search.get(key);\n if (value) params[key] = value;\n }\n if (Object.keys(params).length === 0) {\n return;\n }\n const captured = Object.keys(params).join(', ');\n if (!writeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD, params)) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n loggingService?.log({\n message: `Rokt Kit: Failed to persist UTM params [reason: ${reason}]`,\n code: 'UTM_CAPTURE_FAILED',\n });\n return;\n }\n loggingService?.log({\n message: `Rokt Kit: Captured UTM params [${captured}]`,\n code: 'UTM_CAPTURE_SUCCESS',\n });\n}\n\nexport function loadUtmParams(): UtmParams | null {\n const stored = readNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n return isObject(stored) ? (stored as UtmParams) : null;\n}\n\nexport function clearUtmParams(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_UTM_PARAMS_FIELD);\n}\n\nexport function readCanonicalUrl(): string | undefined {\n const link = document.querySelector('link[rel=\"canonical\"]');\n const href = link?.href;\n if (!href) {\n return undefined;\n }\n return sanitizeUrl(href);\n}\n","// Copyright 2025 mParticle, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// ============================================================\n// Types\n// ============================================================\n\nimport { KitInterface, IMParticleUser, SDKEvent } from '@mparticle/web-sdk/internal';\nimport type { IUserIdentities } from '@mparticle/web-sdk';\n\nimport {\n isSelectPlacementsAttributePersistenceDenied,\n removeSelectPlacementsAttributePersistenceDeniedAttributes,\n} from './selectPlacementsAttributePersistence';\n\nimport {\n PageEvent,\n PAGE_VIEWS_MAX_COUNT,\n buildPageEvents,\n migrateLegacyPageViewStorage,\n loadPageViews,\n writePageViews,\n clearPageViews,\n readCanonicalUrl,\n captureUtmParams,\n loadUtmParams,\n clearUtmParams,\n} from './pageViewStorage';\nimport { isLocalStorageAvailable } from './storage';\n\nimport { isObject, isString, isEmpty, isFunction, sanitizeUrl } from './utils';\n\ninterface RoktKitSettings {\n accountId: string;\n roktExtensions?: string;\n placementEventMapping?: string;\n placementEventAttributeMapping?: string;\n hashedEmailUserIdentityType?: string;\n onboardingExpProvider?: string;\n loggingUrl?: string;\n errorUrl?: string;\n workspaceIdSyncApiKey?: string;\n}\n\ninterface EventAttributeCondition {\n operator: string;\n attributeValue: string;\n}\n\ninterface PlacementEventRule {\n eventAttributeKey: string;\n conditions: EventAttributeCondition[];\n}\n\ninterface EventAttributeMapping {\n value: string;\n map: string;\n conditions?: EventAttributeCondition[];\n}\n\ninterface PlacementEventMappingEntry {\n jsmap: string;\n value: string;\n}\n\ninterface RoktExtensionEntry {\n value: string;\n}\n\ninterface RoktSelection {\n context?: {\n sessionId?: Promise;\n };\n then?: (callback: (sel: RoktSelection) => void) => Promise;\n catch?: (callback: () => void) => void;\n}\n\ninterface RoktLauncher {\n selectPlacements(options: Record): RoktSelection | Promise;\n hashAttributes(attributes: Record): Promise>;\n use(extensionName: string): Promise;\n}\n\ninterface RoktGlobal {\n createLauncher(options: Record): Promise;\n createLocalLauncher(options: Record): RoktLauncher;\n currentLauncher?: RoktLauncher;\n setExtensionData(data: Record): void;\n}\n\n// FilteredUser is the IMParticleUser shape we receive after kit filtering.\n// `getMPID` and `getUserIdentities` are inherited from the SDK's `User` base type.\ntype FilteredUser = IMParticleUser;\n\n// TODO: Replace with `IIdentitySearchResult` from `@mparticle/web-sdk` once\n// a version that exports it is published (currently on a feature branch in\n// mParticle/mparticle-web-sdk PR #1255). The shape below is intentionally\n// structurally identical so the swap is a one-line import change.\ninterface WorkspaceIdSyncResult {\n httpCode: number;\n body?: {\n context?: string | null;\n mpid?: string;\n matched_identities?: Record;\n is_ephemeral?: boolean;\n is_logged_in?: boolean;\n };\n}\n\n// TODO: Replace with `IdentitySearchCallback`-compatible reference from\n// `@mparticle/web-sdk` once published (mirrors `SDKIdentityApi.search`).\ntype WorkspaceIdSyncSearcher = (\n apiKey: string,\n knownIdentities: IUserIdentities,\n callback: (result: WorkspaceIdSyncResult) => void,\n) => void;\n\ninterface KitFilters {\n userAttributeFilters?: string[];\n filterUserAttributes?: (attributes: Record, filters?: string[]) => Record;\n filteredUser?: FilteredUser | null;\n}\n\ninterface RoktManager {\n attachKit(kit: RoktKit): void | Promise;\n flushOnShoppableAdsReadyMessageQueue?(kit: RoktKit): void;\n filters?: KitFilters;\n domain?: string;\n launcherOptions?: Record;\n getLocalSessionAttributes?(): Record;\n setLocalSessionAttribute?(key: string, value: unknown): void;\n}\n\ninterface MParticleInstance {\n setIntegrationAttribute(moduleId: number, attrs: Record): void;\n}\n\ninterface OptimizelyState {\n getActiveExperimentIds(): string[];\n getVariationMap(): Record;\n}\n\ninterface OptimizelyGlobal {\n get(key: 'state'): OptimizelyState;\n}\n\n// Our view of the mParticle global with Rokt-specific extensions.\n// We access window.mParticle via an explicit cast (see `mp()` helper below)\n// rather than augmenting Window to avoid conflicts with @mparticle/web-sdk declarations.\ninterface MParticleExtended {\n Rokt: RoktManager;\n addForwarder(config: ForwarderRegistration): void;\n getVersion(): string;\n generateHash(value: string): string | number;\n logEvent(name: string, type: number, attrs?: Record): void;\n EventType: { Other: number };\n getInstance(): MParticleInstance;\n getDeviceId?(): string;\n sessionManager?: { getSession?(): string; getSessionId?(): string };\n _getActiveForwarders(): Array<{ name: string }>;\n config?: { isLocalLauncherEnabled?: boolean; isLoggingEnabled?: boolean };\n captureTiming?(metricName: string): void;\n forwarder?: RoktKit;\n loggedEvents?: Array>;\n _registerErrorReportingService?(service: ErrorReportingService): void;\n _registerLoggingService?(service: LoggingService): void;\n Identity?: { search?: WorkspaceIdSyncSearcher };\n}\n\ninterface TestHelpers {\n generateLauncherScript: (domain: string | undefined, extensions: string[]) => string;\n generateThankYouElementScript: (domain: string | undefined) => string;\n extractRoktExtensionConfig: (settingsString?: string) => RoktExtensionConfig;\n hashEventMessage: (messageType: number, eventType: number, eventName: string) => string | number;\n parseSettingsString: (settingsString?: string) => T[];\n generateMappedEventLookup: (placementEventMapping: PlacementEventMappingEntry[]) => Record;\n generateMappedEventAttributeLookup: (mapping: EventAttributeMapping[]) => Record;\n sendAdBlockMeasurementSignals: (domain: string | undefined, version: string | null) => void;\n createAutoRemovedIframe: (src: string) => void;\n djb2: (str: string) => number;\n setAllowedOriginHashes: (hashes: number[]) => void;\n ReportingTransport: typeof ReportingTransport;\n ErrorReportingService: typeof ErrorReportingService;\n LoggingService: typeof LoggingService;\n RateLimiter: typeof RateLimiter;\n ErrorCodes: typeof ErrorCodes;\n WSDKErrorSeverity: typeof WSDKErrorSeverity;\n}\n\ninterface ForwarderRegistration {\n name: string;\n constructor: new () => RoktKit;\n getId: () => number;\n}\n\ninterface ReportingConfig {\n loggingUrl?: string;\n errorUrl?: string;\n integrationDomain?: string;\n isLoggingEnabled: boolean;\n}\n\ninterface ErrorReport {\n message: string;\n code?: string;\n severity?: string;\n stackTrace?: string;\n}\n\n// A log-delivery failure. statusCode is set when the request reached the server\n// and returned a non-2xx status (server-side); it is absent for network-level\n// failures such as ad-blockers, offline, or CORS rejections (client-side).\ninterface DeliveryError extends Error {\n statusCode?: number;\n}\n\ninterface LogEntry {\n message: string;\n code?: string;\n}\n\ninterface RoktExtensionConfig {\n roktExtensionsQueryParams: string[];\n legacyRoktExtensions: string[];\n loadThankYouElement: boolean;\n}\n\ndeclare global {\n interface Window {\n Rokt?: RoktGlobal;\n __rokt_li_guid__?: string;\n optimizely?: OptimizelyGlobal;\n // mParticle is declared as any to avoid conflicts with @mparticle/web-sdk type declarations.\n // We use the typed mp() accessor for all internal accesses.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n mParticle: any;\n }\n}\n\n// ============================================================\n// Module-level constants\n// ============================================================\n\nconst name = 'Rokt';\nconst moduleId = 181;\nconst EVENT_NAME_SELECT_PLACEMENTS = 'selectPlacements';\nconst ADBLOCK_CONTROL_DOMAIN = 'apps.roktecommerce.com';\nconst INIT_LOG_SAMPLING_RATE = 0.1;\nconst ROKT_THANK_YOU_JOURNEY_EXTENSION = 'ThankYouPageJourney';\nconst ROKT_INTEGRATION_SCRIPT_ID = 'rokt-launcher';\nconst ROKT_THANK_YOU_ELEMENT_SCRIPT_ID = 'rokt-thank-you-element';\nconst USER_IDENTIFIED_IN_WORKSPACE_KEY = 'userIdentifiedInWorkspace';\n\nconst MESSAGE_TYPE_PAGE_VIEW = 3; // mParticle MessageType.PageView\nconst MESSAGE_TYPE_SESSION_END = 2; // mParticle MessageType.SessionEnd\nconst PAGE_EVENTS_KEY = 'page_events';\nconst PAGE_VIEW_ATTRIBUTES_KEY = 'page_view_attributes';\nconst MPARTICLE_SESSION_ID_KEY = 'mparticle_session_id';\nconst MPARTICLE_DEVICE_ID_KEY = 'mparticle_device_id';\n\n// Bound on how long selectPlacements will wait for an in-flight Workspace\n// IDSync search before proceeding without the userIdentifiedInWorkspace flag.\n// Long enough to cover the typical /v1/search round-trip (~50ms); short enough that a\n// stalled search never blocks placement rendering on a thank-you page.\nconst WORKSPACE_SEARCH_SELECT_TIMEOUT_MS = 500;\n\n// ============================================================\n// Reporting service constants\n// ============================================================\n\nconst ErrorCodes = {\n UNKNOWN_ERROR: 'UNKNOWN_ERROR',\n UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION',\n IDENTITY_REQUEST: 'IDENTITY_REQUEST',\n LOG_DELIVERY_FAILURE: 'LOG_DELIVERY_FAILURE',\n} as const;\n\nconst WSDKErrorSeverity = {\n ERROR: 'ERROR',\n INFO: 'INFO',\n WARNING: 'WARNING',\n} as const;\n\nconst DEFAULT_ROKT_DOMAIN = 'apps.rokt-api.com';\nconst LOGGING_ENDPOINT = '/v1/log';\nconst ERROR_ENDPOINT = '/v1/errors';\nconst RATE_LIMIT_PER_SEVERITY = 10;\n\n// ============================================================\n// Helper: typed accessor for window.mParticle\n// We use an explicit cast here to avoid conflicts with @mparticle/web-sdk\n// type declarations while still providing full type safety for our usages.\n// ============================================================\n\nfunction mp(): MParticleExtended {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (window as any).mParticle as MParticleExtended;\n}\n\n// ============================================================\n// Module-level utility functions\n// ============================================================\n\nfunction generateLauncherScript(domain: string | undefined, extensions: string[]): string {\n const launcherPath = '/wsdk/integrations/launcher.js';\n const baseUrl = [generateBaseUrl(domain), launcherPath].join('');\n\n if (!extensions || extensions.length === 0) {\n return baseUrl;\n }\n return baseUrl + '?extensions=' + extensions.join(',');\n}\n\nfunction generateThankYouElementScript(domain: string | undefined) {\n const thankYouElementPath = '/rokt-elements/rokt-element-thank-you.js';\n return [generateBaseUrl(domain), thankYouElementPath].join('');\n}\n\nfunction generateBaseUrl(domain: string | undefined) {\n const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN;\n\n if (resolvedDomain.includes('://')) {\n return resolvedDomain.replace(/\\/+$/, '');\n }\n\n const protocol = 'https://';\n\n return [protocol, resolvedDomain].join('');\n}\n\nfunction generateReportingUrl(configuredUrl: string | undefined, domain: string | undefined, endpoint: string): string {\n if (configuredUrl) {\n if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://')) {\n return configuredUrl;\n }\n return 'https://' + configuredUrl;\n }\n\n const hasNonHttpScheme = domain?.includes('://') && !/^https?:\\/\\//i.test(domain);\n const reportingDomain = hasNonHttpScheme ? undefined : domain;\n\n return generateBaseUrl(reportingDomain) + endpoint;\n}\n\nfunction loadRoktScript(\n scriptId: string,\n source: string,\n handlers?: { onLoad?: () => void; onError?: (e: Event | string) => void },\n): void {\n if (document.getElementById(scriptId)) return; // resolves the preexisting script issue\n\n const target = document.head || document.body;\n const script = document.createElement('script');\n script.id = scriptId;\n script.type = 'text/javascript';\n script.src = source;\n script.async = true;\n script.crossOrigin = 'anonymous';\n (script as HTMLScriptElement & { fetchPriority: string }).fetchPriority = 'high';\n if (handlers?.onLoad) script.onload = handlers.onLoad;\n if (handlers?.onError) script.onerror = handlers.onError;\n target.appendChild(script);\n}\n\nfunction parseSettingsString(settingsString?: string): T[] {\n if (!settingsString) {\n return [];\n }\n try {\n return JSON.parse(settingsString.replace(/"/g, '\"')) as T[];\n } catch (_error) {\n console.error('Settings string contains invalid JSON');\n }\n return [];\n}\n\nfunction extractRoktExtensionConfig(settingsString?: string): RoktExtensionConfig {\n const settings = settingsString ? parseSettingsString(settingsString) : [];\n const roktExtensionsQueryParams: string[] = [];\n const legacyRoktExtensions: string[] = [];\n let loadThankYouElement = false;\n\n for (let i = 0; i < settings.length; i++) {\n const extensionName = settings[i].value;\n if (extensionName === 'thank-you-journey') {\n loadThankYouElement = true;\n legacyRoktExtensions.push(ROKT_THANK_YOU_JOURNEY_EXTENSION);\n } else {\n roktExtensionsQueryParams.push(extensionName);\n }\n }\n\n return {\n roktExtensionsQueryParams,\n legacyRoktExtensions,\n loadThankYouElement,\n };\n}\n\nasync function registerLegacyExtensions(legacyExtensions: string[], launcher: RoktLauncher | null) {\n const extensions: Promise[] = [];\n if (launcher) {\n for (const extension of legacyExtensions) {\n extensions.push(launcher.use(extension));\n }\n }\n\n return Promise.all(extensions);\n}\n\nfunction generateMappedEventLookup(placementEventMapping: PlacementEventMappingEntry[]): Record {\n if (!placementEventMapping) {\n return {};\n }\n\n const mappedEvents: Record = {};\n for (let i = 0; i < placementEventMapping.length; i++) {\n const mapping = placementEventMapping[i];\n mappedEvents[mapping.jsmap] = mapping.value;\n }\n return mappedEvents;\n}\n\nfunction generateMappedEventAttributeLookup(\n placementEventAttributeMapping: EventAttributeMapping[],\n): Record {\n const mappedAttributeKeys: Record = {};\n if (!Array.isArray(placementEventAttributeMapping)) {\n return mappedAttributeKeys;\n }\n for (let i = 0; i < placementEventAttributeMapping.length; i++) {\n const mapping = placementEventAttributeMapping[i];\n if (!mapping || !isString(mapping.value) || !isString(mapping.map)) {\n continue;\n }\n\n const mappedAttributeKey = mapping.value;\n const eventAttributeKey = mapping.map;\n\n if (!mappedAttributeKeys[mappedAttributeKey]) {\n mappedAttributeKeys[mappedAttributeKey] = [];\n }\n\n mappedAttributeKeys[mappedAttributeKey].push({\n eventAttributeKey: eventAttributeKey,\n conditions: Array.isArray(mapping.conditions) ? mapping.conditions : [],\n });\n }\n return mappedAttributeKeys;\n}\n\nfunction hashEventMessage(messageType: number, eventType: number, eventName: string): string | number {\n return mp().generateHash([messageType, eventType, eventName].join(''));\n}\n\nfunction generateIntegrationName(customIntegrationName?: string): string {\n const coreSdkVersion = mp().getVersion();\n const kitVersion = process.env.PACKAGE_VERSION;\n let integrationName = 'mParticle_' + 'wsdkv_' + coreSdkVersion + '_kitv_' + kitVersion;\n\n if (customIntegrationName) {\n integrationName += '_' + customIntegrationName;\n }\n return integrationName;\n}\n\nfunction djb2(str: string): number {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) + hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return hash;\n}\n\nfunction createAutoRemovedIframe(src: string): void {\n const iframe = document.createElement('iframe');\n iframe.style.display = 'none';\n iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');\n iframe.src = src;\n iframe.onload = function () {\n iframe.onload = null;\n if (iframe.parentNode) {\n iframe.parentNode.removeChild(iframe);\n }\n };\n const target = document.body || document.head;\n if (target) {\n target.appendChild(iframe);\n }\n}\n\nfunction sendAdBlockMeasurementSignals(domain: string | undefined, version: string | null): void {\n const originHash = djb2(window.location.origin);\n const allowedOriginHashes = RoktKit._allowedOriginHashes;\n if (allowedOriginHashes.indexOf(originHash) === -1) {\n return;\n }\n\n if (Math.random() >= INIT_LOG_SAMPLING_RATE) {\n return;\n }\n\n const guid = window.__rokt_li_guid__;\n if (!guid) {\n return;\n }\n\n if (domain && domain.includes('://') && !/^https:\\/\\//i.test(domain)) {\n return;\n }\n\n const pageUrl = window.location.href.split('?')[0].split('#')[0];\n const params =\n 'version=' +\n encodeURIComponent(version ?? '') +\n '&launcherInstanceGuid=' +\n encodeURIComponent(guid) +\n '&pageUrl=' +\n encodeURIComponent(pageUrl);\n\n const existingBaseUrl = domain ? generateBaseUrl(domain) : 'https://apps.rokt.com';\n createAutoRemovedIframe(existingBaseUrl + '/v1/wsdk-init/index.html?' + params);\n\n createAutoRemovedIframe(\n 'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true',\n );\n}\n\n// ============================================================\n// Reporting helpers\n// ============================================================\n\nfunction _isDebugModeEnabled(): boolean {\n return typeof window !== 'undefined' && !!window.location?.search?.toLowerCase().includes('mp_enable_logging=true');\n}\n\nfunction _getReportingUrl(): string | undefined {\n return typeof window !== 'undefined' ? window.location?.href : undefined;\n}\n\nfunction _getUserAgent(): string | undefined {\n return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined;\n}\n\nclass RateLimiter {\n private _logCount: Record = {};\n\n incrementAndCheck(severity: string): boolean {\n const count = this._logCount[severity] || 0;\n const newCount = count + 1;\n this._logCount[severity] = newCount;\n return newCount > RATE_LIMIT_PER_SEVERITY;\n }\n}\n\nclass ReportingTransport {\n private _isEnabled: boolean;\n private _integrationName: string;\n private _launcherInstanceGuid: string | undefined;\n private _accountId: string | null;\n private _rateLimiter: RateLimiter;\n private readonly _reporter = 'mp-wsdk';\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid: string | undefined,\n accountId: string | null | undefined,\n rateLimiter?: RateLimiter,\n ) {\n const isLoggingEnabled = config.isLoggingEnabled;\n this._integrationName = integrationName || '';\n this._launcherInstanceGuid = launcherInstanceGuid;\n this._accountId = accountId || null;\n this._rateLimiter = rateLimiter || new RateLimiter();\n this._isEnabled = _isDebugModeEnabled() || isLoggingEnabled;\n }\n\n send(\n url: string,\n severity: string,\n msg: string,\n code?: string,\n stackTrace?: string,\n onError?: (error: DeliveryError) => void,\n ): void {\n if (!this._isEnabled || this._rateLimiter.incrementAndCheck(severity)) {\n return;\n }\n\n try {\n const logRequest = {\n additionalInformation: {\n message: msg,\n version: this._integrationName,\n },\n severity,\n code: code || ErrorCodes.UNKNOWN_ERROR,\n url: _getReportingUrl(),\n deviceInfo: _getUserAgent(),\n stackTrace,\n reporter: this._reporter,\n integration: this._integrationName,\n };\n\n const headers: Record = {\n Accept: 'text/plain;charset=UTF-8',\n 'Content-Type': 'application/json',\n 'rokt-launcher-version': this._integrationName,\n 'rokt-wsdk-version': 'joint',\n };\n\n if (this._launcherInstanceGuid) {\n headers['rokt-launcher-instance-guid'] = this._launcherInstanceGuid;\n }\n if (this._accountId) {\n headers['rokt-account-id'] = this._accountId;\n }\n\n fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(logRequest),\n })\n .then((response: Response) => {\n // fetch only rejects on network failures; an HTTP 5xx resolves with\n // ok === false. Surface server-side failures so they are not swallowed.\n if (!response.ok) {\n const serverError: DeliveryError = new Error('HTTP ' + response.status + ' from log endpoint');\n serverError.statusCode = response.status;\n throw serverError;\n }\n })\n .catch((error: DeliveryError) => {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error);\n });\n } catch (error) {\n console.error('ReportingTransport: Failed to send log', error);\n if (onError) onError(error as DeliveryError);\n }\n }\n}\n\nclass ErrorReportingService {\n private _transport: ReportingTransport;\n private _errorUrl: string;\n\n constructor(\n config: ReportingConfig,\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._errorUrl = generateReportingUrl(config?.errorUrl, config?.integrationDomain, ERROR_ENDPOINT);\n }\n\n report(error: ErrorReport | null | undefined): void {\n if (!error) return;\n const severity = error.severity || WSDKErrorSeverity.ERROR;\n this._transport.send(this._errorUrl, severity, error.message, error.code, error.stackTrace);\n }\n}\n\nclass LoggingService {\n private _transport: ReportingTransport;\n private _loggingUrl: string;\n private _errorReportingService: { report: (e: ErrorReport) => void };\n\n constructor(\n config: ReportingConfig,\n errorReportingService: { report: (e: ErrorReport) => void },\n integrationName: string | null | undefined,\n launcherInstanceGuid?: string,\n accountId?: string | null,\n rateLimiter?: RateLimiter,\n ) {\n this._transport = new ReportingTransport(config, integrationName, launcherInstanceGuid, accountId, rateLimiter);\n this._loggingUrl = generateReportingUrl(config?.loggingUrl, config?.integrationDomain, LOGGING_ENDPOINT);\n this._errorReportingService = errorReportingService;\n }\n\n log(entry: LogEntry | null | undefined): void {\n if (!entry) return;\n this._transport.send(\n this._loggingUrl,\n WSDKErrorSeverity.INFO,\n entry.message,\n entry.code,\n undefined,\n (error: DeliveryError) => {\n if (this._errorReportingService) {\n // A failed log POST is not itself an SDK error. Network-level failures\n // (ad-blockers, offline, CORS) are client-side noise and reported as a\n // WARNING; only a server-side non-2xx response stays at ERROR severity.\n const isServerSide = typeof error.statusCode === 'number';\n this._errorReportingService.report({\n message: 'LoggingService: Failed to send log: ' + error.message,\n code: ErrorCodes.LOG_DELIVERY_FAILURE,\n severity: isServerSide ? WSDKErrorSeverity.ERROR : WSDKErrorSeverity.WARNING,\n });\n }\n },\n );\n }\n}\n\nfunction buildPageEvent(event: SDKEvent): PageEvent {\n const pageUrl = sanitizeUrl(window.location.href);\n const pageTitle = event.EventAttributes?.title || document.title;\n const canonicalUrl = readCanonicalUrl();\n const activeTimeOnSite = event.ActiveTimeOnSite;\n\n return {\n pageUrl,\n sourceMessageId: event.SourceMessageId,\n timestamp: event.Timestamp,\n ...(pageTitle ? { pageTitle } : {}),\n ...(canonicalUrl !== undefined ? { canonicalUrl } : {}),\n ...(Number.isFinite(activeTimeOnSite) ? { activeTimeOnSite } : {}),\n };\n}\n\n// ============================================================\n// RoktKit class\n// ============================================================\n\nclass RoktKit implements KitInterface {\n // Static field for allowed origin hashes (mutable by testHelpers)\n public static _allowedOriginHashes: number[] = [-553112570, 549508659];\n\n private static readonly PERFORMANCE_MARKS = {\n RoktScriptAppended: 'mp:RoktScriptAppended',\n };\n\n private static readonly EMAIL_SHA256_KEY = 'emailsha256';\n\n // Public fields (accessed by tests and the mParticle framework)\n public name = name;\n public id = moduleId;\n public moduleId = moduleId;\n public isInitialized = false;\n public launcher: RoktLauncher | null = null;\n public filters: KitFilters = {};\n public userAttributes: Record = {};\n // Flag set by the Workspace IDSync flow on a 200 response. Stored on the\n // kit instance and merged into placement attributes inside selectPlacements.\n public userIdentifiedInWorkspace = false;\n public testHelpers: TestHelpers | null = null;\n public placementEventMappingLookup: Record = {};\n public placementEventAttributeMappingLookup: Record = {};\n public integrationName: string | null = null;\n public domain?: string;\n public errorReportingService: ErrorReportingService | null = null;\n public loggingService: LoggingService | null = null;\n\n // Private fields\n private _mappedEmailSha256Key?: string;\n private _onboardingExpProvider?: string;\n private _thankYouElementOnLoadCallback: (() => void) | null = null;\n private _isThankYouElementLoaded = false;\n private _workspaceIdSyncApiKey?: string;\n\n // Held during a search dispatch so the next selectPlacements call;\n // can wait for the HTTP response before reading userIdentifiedInWorkspace;\n // — otherwise the first placement call ships without the flag.\n private _workspaceSearchInFlightPromise: Promise | null = null;\n // Stable serialization of the identifier set sent in the most recent\n // successful search dispatch. If a subsequent identification arrives with\n // an identical set, we skip the network call (the flag is still correct\n // from the prior search). Keyed over the full IUserIdentities map — not\n // just email — so partners passing hashed email through `other`/`other2-10`\n // or any other identifier benefit from the same dedupe. Cleared on logout\n // so a re-login re-evaluates fresh.\n private _workspaceLastSearchedIdentitiesKey?: string;\n\n // ---- Private helpers ----\n\n private getEventAttributeValue(event: SDKEvent, eventAttributeKey: string): unknown {\n const attributes = event && event.EventAttributes;\n if (!attributes) {\n return null;\n }\n\n if (typeof attributes[eventAttributeKey] === 'undefined') {\n return null;\n }\n\n return attributes[eventAttributeKey];\n }\n\n private doesEventAttributeConditionMatch(condition: EventAttributeCondition, actualValue: unknown): boolean {\n if (!condition || !isString(condition.operator)) {\n return false;\n }\n\n const operator = condition.operator.toLowerCase();\n const expectedValue = condition.attributeValue;\n\n if (operator === 'exists') {\n return actualValue !== null;\n }\n\n if (actualValue == null) {\n return false;\n }\n\n if (operator === 'equals') {\n return String(actualValue) === String(expectedValue);\n }\n\n if (operator === 'contains') {\n return String(actualValue).indexOf(String(expectedValue)) !== -1;\n }\n\n return false;\n }\n\n private doesEventMatchRule(event: SDKEvent, rule: PlacementEventRule): boolean {\n if (!rule || !isString(rule.eventAttributeKey)) {\n return false;\n }\n\n const conditions = rule.conditions;\n if (!Array.isArray(conditions)) {\n return false;\n }\n\n const actualValue = this.getEventAttributeValue(event, rule.eventAttributeKey);\n\n if (conditions.length === 0) {\n return actualValue !== null;\n }\n for (let i = 0; i < conditions.length; i++) {\n if (!this.doesEventAttributeConditionMatch(conditions[i], actualValue)) {\n return false;\n }\n }\n\n return true;\n }\n\n private applyPlacementEventAttributeMapping(event: SDKEvent): void {\n const mappedAttributeKeys = Object.keys(this.placementEventAttributeMappingLookup);\n for (let i = 0; i < mappedAttributeKeys.length; i++) {\n const mappedAttributeKey = mappedAttributeKeys[i];\n const rulesForMappedAttributeKey = this.placementEventAttributeMappingLookup[mappedAttributeKey];\n if (isEmpty(rulesForMappedAttributeKey)) {\n continue;\n }\n\n // Require ALL rules for the same key to match (AND).\n let allMatch = true;\n for (let j = 0; j < rulesForMappedAttributeKey.length; j++) {\n if (!this.doesEventMatchRule(event, rulesForMappedAttributeKey[j])) {\n allMatch = false;\n break;\n }\n }\n if (!allMatch) {\n continue;\n }\n\n mp().Rokt.setLocalSessionAttribute?.(mappedAttributeKey, true);\n }\n }\n\n private capturePageView(event: SDKEvent): void {\n let pageUrl: string | undefined;\n\n try {\n pageUrl = sanitizeUrl(window.location.href);\n\n const pageViews = loadPageViews(this.loggingService);\n const pageView = buildPageEvent(event);\n pageViews.push(pageView);\n\n const requested = Math.min(pageViews.length, PAGE_VIEWS_MAX_COUNT);\n const stored = writePageViews(pageViews);\n if (stored === 0) {\n const reason = isLocalStorageAvailable() ? 'quota' : 'ls_unavailable';\n this.loggingService?.log({\n message: `Rokt Kit: Failed to persist page view for ${pageUrl} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n } else if (stored < requested) {\n this.loggingService?.log({\n message: `Rokt Kit: Page view storage reduced from ${requested} to ${stored} record(s) under quota pressure [reason: quota_eviction]`,\n code: 'PAGE_VIEW_QUOTA_EVICTION',\n });\n }\n } catch (err) {\n const reason = isLocalStorageAvailable() ? 'exception' : 'ls_unavailable';\n const errMessage = err instanceof Error ? err.message : String(err);\n this.loggingService?.log({\n message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${errMessage} [reason: ${reason}]`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n }\n\n private isLauncherReadyToAttach(): boolean {\n return !!window.Rokt && isFunction(window.Rokt.createLauncher);\n }\n\n /**\n * Returns the user identities from the filtered user, if any.\n */\n private returnUserIdentities(filteredUser: FilteredUser | null | undefined): Record {\n if (!filteredUser || !filteredUser.getUserIdentities) {\n return {};\n }\n\n const userIdentities: IUserIdentities = filteredUser.getUserIdentities().userIdentities;\n\n return this.replaceOtherIdentityWithEmailsha256(userIdentities);\n }\n\n private returnLocalSessionAttributes(): Record {\n if (!mp().Rokt || typeof mp().Rokt.getLocalSessionAttributes !== 'function') {\n return {};\n }\n return mp().Rokt.getLocalSessionAttributes!();\n }\n\n private replaceOtherIdentityWithEmailsha256(userIdentities: IUserIdentities): Record {\n const newUserIdentities: Record = { ...(userIdentities || {}) };\n const key = this._mappedEmailSha256Key;\n if (key && userIdentities[key as keyof IUserIdentities]) {\n newUserIdentities[RoktKit.EMAIL_SHA256_KEY] = userIdentities[key as keyof IUserIdentities] as string;\n }\n if (key) {\n delete newUserIdentities[key];\n }\n\n return newUserIdentities;\n }\n\n private logSelectPlacementsEvent(attributes: unknown): void {\n if (!window.mParticle || typeof mp().logEvent !== 'function') {\n return;\n }\n\n if (!isObject(attributes)) {\n return;\n }\n\n const EVENT_TYPE_OTHER = mp().EventType.Other;\n\n mp().logEvent(EVENT_NAME_SELECT_PLACEMENTS, EVENT_TYPE_OTHER, attributes as Record);\n }\n\n private setRoktSessionId(sessionId: string): void {\n if (!sessionId || typeof sessionId !== 'string') {\n return;\n }\n try {\n const mpInstance = mp().getInstance();\n if (mpInstance && isFunction(mpInstance.setIntegrationAttribute)) {\n mpInstance.setIntegrationAttribute(moduleId, {\n roktSessionId: sessionId,\n });\n }\n } catch (_e) {\n // Best effort — never let this break the partner page\n }\n }\n\n private readMpSessionId(): string | undefined {\n // The public mParticle.sessionManager facade exposes only getSession(), which already returns\n // the session id. getSessionId() lives on the internal _SessionManager and has never been\n // re-exported, so prefer it if a future core adds it and fall back to getSession() until then.\n const sessionManager = mp()?.sessionManager;\n const readSessionId = sessionManager?.getSessionId ?? sessionManager?.getSession;\n if (!isFunction(readSessionId)) {\n return undefined;\n }\n\n return readSessionId.call(sessionManager) || undefined;\n }\n\n private readMpDeviceId(): string | undefined {\n // The device application stamp (`das`) outlives the session id: core clears the session on\n // timeout, cross-tab rotation and endSession(), but never the device id, which lives in\n // localStorage/cookie for cookieExpiration days (365 by default) and survives login/logout.\n // Read it per call anyway — a partner can reassign it at any time via setDeviceId().\n return mp()?.getDeviceId?.() || undefined;\n }\n\n private attachLauncher(\n accountId: string,\n launcherOptions: Record,\n legacyRoktExtensions: string[] = [],\n ): void {\n const options: Record = {\n accountId,\n ...(launcherOptions || {}),\n };\n\n let launcherPromise: Promise;\n if (this.isPartnerInLocalLauncherTestGroup()) {\n launcherPromise = Promise.resolve(window.Rokt!.createLocalLauncher(options));\n } else {\n launcherPromise = window.Rokt!.createLauncher(options);\n }\n\n launcherPromise\n .then(async (launcher) => {\n await registerLegacyExtensions(legacyRoktExtensions, launcher);\n this.initRoktLauncher(launcher);\n })\n .catch((err: unknown) => {\n console.error('Error creating Rokt launcher:', err);\n });\n }\n\n private initRoktLauncher(launcher: RoktLauncher): void {\n // Assign the launcher to a global variable for later access\n if (window.Rokt) {\n window.Rokt.currentLauncher = launcher;\n }\n // Locally cache the launcher and filters\n this.launcher = launcher;\n\n const roktFilters = mp().Rokt?.filters;\n\n if (!roktFilters) {\n console.warn('Rokt Kit: No filters have been set.');\n } else {\n this.filters = roktFilters;\n if (!roktFilters.filteredUser) {\n console.warn('Rokt Kit: No filtered user has been set.');\n } else {\n this._workspaceSearchInFlightPromise = this.search(roktFilters.filteredUser);\n }\n }\n\n // Kit must be initialized before attaching to the Rokt manager\n this.isInitialized = true;\n\n sendAdBlockMeasurementSignals(this.domain, this.integrationName);\n\n // Attaches the kit to the Rokt manager\n mp().Rokt.attachKit(this);\n }\n\n private fetchOptimizely(): Record {\n const forwarders = mp()\n ._getActiveForwarders()\n .filter((forwarder) => forwarder.name === 'Optimizely');\n\n try {\n if (forwarders.length > 0 && window.optimizely) {\n const optimizelyState = window.optimizely.get('state');\n if (!optimizelyState || !optimizelyState.getActiveExperimentIds) {\n return {};\n }\n const activeExperimentIds = optimizelyState.getActiveExperimentIds();\n const activeExperiments = activeExperimentIds.reduce((acc: Record, expId: string) => {\n acc['rokt.custom.optimizely.experiment.' + expId + '.variationId'] =\n optimizelyState.getVariationMap()[expId].id;\n return acc;\n }, {});\n return activeExperiments;\n }\n } catch (error) {\n console.error('Error fetching Optimizely attributes:', error);\n }\n return {};\n }\n\n private isKitReady(): boolean {\n return !!(this.isInitialized && this.launcher);\n }\n\n // When the partner has opted out of targeting (noTargeting launcher option),\n // the kit must not collect behavioral targeting signals such as page views.\n private isTargetingDisabled(): boolean {\n return (mp().Rokt?.launcherOptions as Record | undefined)?.noTargeting === true;\n }\n\n private isPartnerInLocalLauncherTestGroup(): boolean {\n return !!(mp().config && mp().config!.isLocalLauncherEnabled && this.isAssignedToSampleGroup());\n }\n\n private isAssignedToSampleGroup(): boolean {\n const LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD = 0.5;\n return Math.random() > LOCAL_LAUNCHER_TEST_GROUP_THRESHOLD;\n }\n\n private captureTiming(metricName: string): void {\n if (window && mp() && mp().captureTiming && metricName) {\n mp().captureTiming!(metricName);\n }\n }\n\n // ---- Public methods (mParticle Kit Callbacks) ----\n\n /**\n * Initializes the Rokt forwarder with settings from the mParticle server.\n */\n public init(\n settings: Record,\n _service: unknown,\n testMode: boolean,\n _trackerId: unknown,\n filteredUserAttributes?: Record,\n ): string {\n const kitSettings = settings as unknown as RoktKitSettings;\n const accountId = kitSettings.accountId;\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredUserAttributes);\n this._onboardingExpProvider = kitSettings.onboardingExpProvider;\n\n const placementEventMapping = parseSettingsString(kitSettings.placementEventMapping);\n this.placementEventMappingLookup = generateMappedEventLookup(placementEventMapping);\n\n const placementEventAttributeMapping = parseSettingsString(\n kitSettings.placementEventAttributeMapping,\n );\n this.placementEventAttributeMappingLookup = generateMappedEventAttributeLookup(placementEventAttributeMapping);\n\n // Set dynamic OTHER_IDENTITY based on server settings\n if (kitSettings.hashedEmailUserIdentityType) {\n this._mappedEmailSha256Key = kitSettings.hashedEmailUserIdentityType.toLowerCase();\n }\n\n this._workspaceIdSyncApiKey = isString(kitSettings.workspaceIdSyncApiKey)\n ? kitSettings.workspaceIdSyncApiKey\n : undefined;\n\n const domain = mp().Rokt?.domain;\n const { roktExtensionsQueryParams, legacyRoktExtensions, loadThankYouElement } = extractRoktExtensionConfig(\n kitSettings.roktExtensions,\n );\n const launcherOptions: Record = {\n ...((mp().Rokt?.launcherOptions as Record) || {}),\n };\n this.integrationName = generateIntegrationName(launcherOptions.integrationName as string | undefined);\n launcherOptions.integrationName = this.integrationName;\n\n this.domain = domain;\n\n const reportingConfig: ReportingConfig = {\n loggingUrl: kitSettings.loggingUrl,\n errorUrl: kitSettings.errorUrl,\n integrationDomain: domain,\n isLoggingEnabled: mp().config?.isLoggingEnabled === true,\n };\n const errorReportingService = new ErrorReportingService(\n reportingConfig,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n const loggingService = new LoggingService(\n reportingConfig,\n errorReportingService,\n this.integrationName,\n window.__rokt_li_guid__,\n kitSettings.accountId,\n );\n\n this.errorReportingService = errorReportingService;\n this.loggingService = loggingService;\n\n if (this.isTargetingDisabled()) {\n try {\n clearPageViews();\n clearUtmParams();\n } catch (err) {\n this.errorReportingService?.report({\n message: 'Rokt Kit: Failed to clear page views when targeting is disabled',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n severity: WSDKErrorSeverity.INFO,\n stackTrace: err instanceof Error ? err.stack : undefined,\n });\n }\n }\n\n if (mp()._registerErrorReportingService) {\n mp()._registerErrorReportingService!(errorReportingService);\n }\n if (mp()._registerLoggingService) {\n mp()._registerLoggingService!(loggingService);\n }\n\n if (testMode) {\n this.testHelpers = {\n generateLauncherScript: generateLauncherScript,\n generateThankYouElementScript: generateThankYouElementScript,\n extractRoktExtensionConfig: extractRoktExtensionConfig,\n hashEventMessage: hashEventMessage,\n parseSettingsString: parseSettingsString,\n generateMappedEventLookup: generateMappedEventLookup,\n generateMappedEventAttributeLookup: generateMappedEventAttributeLookup,\n sendAdBlockMeasurementSignals: sendAdBlockMeasurementSignals,\n createAutoRemovedIframe: createAutoRemovedIframe,\n djb2: djb2,\n setAllowedOriginHashes: (hashes: number[]) => {\n RoktKit._allowedOriginHashes = hashes;\n },\n ReportingTransport: ReportingTransport,\n ErrorReportingService: ErrorReportingService,\n LoggingService: LoggingService,\n RateLimiter: RateLimiter,\n ErrorCodes: ErrorCodes,\n WSDKErrorSeverity: WSDKErrorSeverity,\n };\n this.attachLauncher(accountId, launcherOptions);\n return 'Successfully initialized: ' + name;\n }\n\n if (loadThankYouElement) {\n mp().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this);\n loadRoktScript(ROKT_THANK_YOU_ELEMENT_SCRIPT_ID, generateThankYouElementScript(domain), {\n onLoad: () => {\n this._isThankYouElementLoaded = true;\n if (this._thankYouElementOnLoadCallback) {\n this._thankYouElementOnLoadCallback();\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt Thank You Element script:', error);\n },\n });\n }\n\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n loadRoktScript(ROKT_INTEGRATION_SCRIPT_ID, generateLauncherScript(domain, roktExtensionsQueryParams), {\n onLoad: () => {\n if (this.isLauncherReadyToAttach()) {\n this.attachLauncher(accountId, launcherOptions, legacyRoktExtensions);\n } else {\n console.error('Rokt object is not available after script load.');\n }\n },\n onError: (error) => {\n console.error('Error loading Rokt launcher script:', error);\n },\n });\n\n this.captureTiming(RoktKit.PERFORMANCE_MARKS.RoktScriptAppended);\n }\n\n return 'Successfully initialized: ' + name;\n }\n\n public process(event: SDKEvent): string {\n if (!this.isTargetingDisabled()) {\n if (event.EventDataType === MESSAGE_TYPE_PAGE_VIEW) {\n captureUtmParams(this.loggingService);\n this.capturePageView(event);\n }\n\n if (event.EventDataType === MESSAGE_TYPE_SESSION_END) {\n migrateLegacyPageViewStorage(this.loggingService);\n clearPageViews();\n clearUtmParams();\n }\n }\n\n // The forwarding work below (LSA mapping) depends on the launcher, so guard\n // it here and surface the not-ready signal to the core SDK.\n if (!this.isKitReady()) {\n return 'Kit not ready for forwarder: ' + name;\n }\n\n if (isFunction(mp().Rokt?.setLocalSessionAttribute)) {\n if (!isEmpty(this.placementEventAttributeMappingLookup)) {\n this.applyPlacementEventAttributeMapping(event);\n }\n\n if (!isEmpty(this.placementEventMappingLookup)) {\n const hashedEvent = hashEventMessage(event.EventDataType, event.EventCategory, event.EventName ?? '');\n if (this.placementEventMappingLookup[String(hashedEvent)]) {\n mp().Rokt.setLocalSessionAttribute?.(this.placementEventMappingLookup[String(hashedEvent)], true);\n }\n }\n }\n\n return 'Successfully sent to forwarder: ' + name;\n }\n\n public setExtensionData(partnerExtensionData: Record): void {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return;\n }\n\n window.Rokt!.setExtensionData(partnerExtensionData);\n }\n\n public setUserAttribute(key: string, value: unknown): string {\n if (!isSelectPlacementsAttributePersistenceDenied(key)) {\n this.userAttributes[key] = value;\n }\n return 'Successfully set user attribute for forwarder: ' + name;\n }\n\n public removeUserAttribute(key: string): string {\n delete this.userAttributes[key];\n return 'Successfully removed user attribute for forwarder: ' + name;\n }\n\n private handleIdentityComplete(user: IMParticleUser, callbackName: string): string {\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(user.getAllUserAttributes());\n return 'Successfully called ' + callbackName + ' for forwarder: ' + name;\n }\n\n public onUserIdentified(user: IMParticleUser): string {\n const filteredUser = user as FilteredUser;\n this.filters.filteredUser = filteredUser;\n this._workspaceSearchInFlightPromise = this.search(filteredUser);\n return this.handleIdentityComplete(user, 'onUserIdentified');\n }\n\n private search(filteredUser: FilteredUser): Promise {\n const apiKey = this._workspaceIdSyncApiKey;\n if (!apiKey) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n const search = mp().Identity?.search;\n if (typeof search !== 'function') {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n const userIdentities: IUserIdentities | null = filteredUser.getUserIdentities\n ? filteredUser.getUserIdentities().userIdentities\n : null;\n\n // Forward every non-empty string identifier the user has — email,\n // customerid, other/other2-10 (commonly used for hashed email),\n // mobile_number, facebook, etc. The host SDK's Identity.search accepts\n // the full IUserIdentities surface and the server validates it.\n const knownIdentities: Record = {};\n if (userIdentities) {\n for (const key of Object.keys(userIdentities) as Array) {\n const value = userIdentities[key];\n if (isString(value) && value.length > 0) {\n knownIdentities[key] = value;\n }\n }\n }\n\n const identityKeys = Object.keys(knownIdentities);\n if (identityKeys.length === 0) {\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return Promise.resolve();\n }\n\n // Stable cache key: sort keys so insertion-order differences don't\n // cause false misses. The values are partner-supplied strings; no\n // hashing needed — equality on this serialization is sufficient.\n const identitiesKey = identityKeys\n .sort()\n .map((k) => `${k}=${knownIdentities[k]}`)\n .join('&');\n\n // Same identifier set as the last successful dispatch → skip the\n // network call. The current flag value still reflects the correct\n // match status.\n if (identitiesKey === this._workspaceLastSearchedIdentitiesKey) {\n return this._workspaceSearchInFlightPromise || Promise.resolve();\n }\n\n // New / different identifier set → reset and re-search. Cache the key\n // up front so a second concurrent invocation with the same set also\n // dedupes.\n this.userIdentifiedInWorkspace = false;\n this._workspaceLastSearchedIdentitiesKey = identitiesKey;\n\n return new Promise((resolve) => {\n try {\n search(apiKey, knownIdentities as IUserIdentities, (result: WorkspaceIdSyncResult) => {\n if (result?.httpCode === 200) {\n this.userIdentifiedInWorkspace = true;\n }\n resolve();\n });\n } catch (err) {\n console.error('Rokt Kit: Workspace IDSync search failed', err);\n // Dispatch failed — clear the cache so the same identifier set\n // can retry on the next identification rather than being stuck\n // behind a poisoned entry that short-circuits future searches.\n this._workspaceLastSearchedIdentitiesKey = undefined;\n resolve();\n }\n });\n }\n\n public onLoginComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onLoginComplete');\n }\n\n public onLogoutComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n // Anonymous sessions must not carry the previous user's match forward.\n // Clear the flag explicitly here. Also clear the identities cache so a\n // re-login (possibly with the same identifiers) dispatches a fresh\n // search rather than reusing a stale answer.\n this.userIdentifiedInWorkspace = false;\n this._workspaceSearchInFlightPromise = null;\n this._workspaceLastSearchedIdentitiesKey = undefined;\n return this.handleIdentityComplete(user, 'onLogoutComplete');\n }\n\n public onModifyComplete(user: IMParticleUser, _filteredIdentityRequest: unknown): string {\n return this.handleIdentityComplete(user, 'onModifyComplete');\n }\n\n /**\n * Selects placements for Rokt Web SDK with merged attributes, filters, and experimentation options.\n *\n * If a Workspace IDSync search is in flight from a recent onUserIdentified\n * call, this method waits up to `WORKSPACE_SEARCH_SELECT_TIMEOUT_MS` for it\n * to settle so the first placement call can include the\n * `userIdentifiedInWorkspace` flag without racing the network response.\n * The timeout protects against a stalled or slow search blocking placement\n * rendering — if it fires, selectPlacements proceeds without the flag.\n *\n * Implementation note: this method stays non-async deliberately. First,\n * the public return type is `RoktSelection | Promise |\n * undefined` — a superset of the `RoktSelection | Promise`\n * shape declared for `RoktLauncher.selectPlacements` above (line ~70).\n * Marking this `async` would narrow it to `Promise` and silently change the contract for callers that read\n * the result synchronously. Second, `RoktSelection` has an optional\n * `then?` member, so TS treats it as ambiguously promise-like and\n * rejects it as the awaited return of an async function (TS1058) —\n * working around that would require a cast or wrapping every return in\n * `Promise.resolve(...)`. The inner work runs in `_dispatchPlacements`;\n * this wrapper just gates it on the in-flight search via `Promise.race`.\n */\n public selectPlacements(options: Record): RoktSelection | Promise | undefined {\n if (this._workspaceSearchInFlightPromise) {\n const inFlight = this._workspaceSearchInFlightPromise;\n return Promise.race([\n inFlight,\n new Promise((resolve) => setTimeout(resolve, WORKSPACE_SEARCH_SELECT_TIMEOUT_MS)),\n ]).then(() => this._dispatchPlacements(options)) as Promise;\n }\n return this._dispatchPlacements(options);\n }\n\n private _dispatchPlacements(options: Record): RoktSelection | Promise | undefined {\n const attributes = ((options && (options.attributes as Record)) || {}) as Record;\n const cachedUserAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(this.userAttributes);\n const placementAttributes: Record = { ...cachedUserAttributes, ...attributes };\n\n const filters = this.filters || {};\n const userAttributeFilters = (filters.userAttributeFilters as string[]) || [];\n const filteredUser = filters.filteredUser || null;\n const mpid = filteredUser ? filteredUser.getMPID() : null;\n\n let filteredAttributes: Record;\n\n if (!filters) {\n console.warn('Rokt Kit: No filters available, using user attributes');\n filteredAttributes = placementAttributes;\n } else if (filters.filterUserAttributes) {\n filteredAttributes = filters.filterUserAttributes(placementAttributes, userAttributeFilters);\n } else {\n filteredAttributes = placementAttributes;\n }\n\n this.userAttributes = removeSelectPlacementsAttributePersistenceDeniedAttributes(filteredAttributes);\n\n const optimizelyAttributes = this._onboardingExpProvider === 'Optimizely' ? this.fetchOptimizely() : {};\n\n const filteredUserIdentities = this.returnUserIdentities(filteredUser);\n\n const sessionAttributes = this.returnLocalSessionAttributes();\n const pageEvents = buildPageEvents(loadPageViews(this.loggingService));\n const utmParams = loadUtmParams();\n const mpSessionId = this.readMpSessionId();\n const mpDeviceId = this.readMpDeviceId();\n\n const selectPlacementsAttributes: Record = {\n ...(filteredUserIdentities as Record),\n ...filteredAttributes,\n ...optimizelyAttributes,\n ...sessionAttributes,\n ...(pageEvents.length ? { [PAGE_EVENTS_KEY]: JSON.stringify(pageEvents) } : {}),\n ...(utmParams ? { [PAGE_VIEW_ATTRIBUTES_KEY]: JSON.stringify(utmParams) } : {}),\n ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}),\n ...(mpSessionId ? { [MPARTICLE_SESSION_ID_KEY]: mpSessionId } : {}),\n ...(mpDeviceId ? { [MPARTICLE_DEVICE_ID_KEY]: mpDeviceId } : {}),\n mpid,\n };\n\n const selectPlacementsOptions: Record = { ...options, attributes: selectPlacementsAttributes };\n\n const selection = this.launcher!.selectPlacements(selectPlacementsOptions);\n\n // After selection resolves, sync the Rokt session ID back to mParticle, then log\n const logSelection = () => this.logSelectPlacementsEvent(selectPlacementsAttributes);\n\n void Promise.resolve(selection)\n .then((sel) => sel?.context?.sessionId?.then((sessionId) => this.setRoktSessionId(sessionId)))\n .catch(() => undefined)\n .finally(logSelection);\n\n return selection;\n }\n\n /**\n * Passes attributes to the Rokt Web SDK for client-side hashing.\n */\n public hashAttributes(attributes: Record): Promise> | null {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return null;\n }\n return this.launcher!.hashAttributes(attributes);\n }\n\n /**\n * Enables optional Integration Launcher extensions before selecting placements.\n *\n * @deprecated This functionality has been internalized and will be removed in a future release.\n */\n public use(extensionName: string): Promise {\n if (!this.isKitReady()) {\n console.error('Rokt Kit: Not initialized');\n return Promise.reject(new Error('Rokt Kit: Not initialized'));\n }\n if (!extensionName || !isString(extensionName)) {\n return Promise.reject(new Error('Rokt Kit: Invalid extension name'));\n }\n return this.launcher!.use(extensionName);\n }\n\n /**\n * Registers a callback to be invoked once rokt-thank-you-element.js becomes available.\n */\n public onShoppableAdsReady(callback: () => void) {\n if (this._isThankYouElementLoaded) {\n callback();\n } else {\n this._thankYouElementOnLoadCallback = callback;\n }\n }\n}\n\n// ============================================================\n// Kit registration\n// ============================================================\n\nfunction getId(): number {\n return moduleId;\n}\n\nfunction register(config: { kits?: Record }): void {\n if (!config) {\n window.console.log('You must pass a config object to register the kit ' + name);\n return;\n }\n if (!isObject(config)) {\n window.console.log(\"'config' must be an object. You passed in a \" + typeof config);\n return;\n }\n\n if (isObject(config.kits)) {\n (config.kits as Record)[name] = {\n constructor: RoktKit,\n };\n } else {\n config.kits = {};\n config.kits[name] = {\n constructor: RoktKit,\n };\n }\n window.console.log('Successfully registered ' + name + ' to your mParticle configuration');\n}\n\nif (typeof window !== 'undefined' && window.mParticle && mp().addForwarder) {\n mp().addForwarder({\n name: name,\n constructor: RoktKit,\n getId: getId,\n });\n}\n\nexport { register };\nexport type { LoggingService };\n"],"names":["SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_LIST","SELECT_PLACEMENTS_ATTRIBUTE_PERSISTENCE_DENY_SET","isSelectPlacementsAttributePersistenceDenied","key","removeSelectPlacementsAttributePersistenceDeniedAttributes","attributes","filteredAttributes","sourceAttributes","attributeKeys","i","isObject","value","isString","isFunction","isEmpty","sanitizeUrl","href","url","LS_PROBE_KEY","isLocalStorageAvailable","readJSON","stored","writeJSON","removeKey","readNamespacedField","namespaceKey","field","blob","writeNamespacedField","next","removeNamespacedField","LS_NAMESPACE_KEY","LS_PAGE_VIEWS_FIELD","LS_UTM_PARAMS_FIELD","LEGACY_PAGE_VIEWS_KEY","PAGE_VIEWS_MAX_COUNT","UTM_KEYS","capPageViews","views","migrateLegacyPageViewStorage","loggingService","legacyViews","loadPageViews","writePageViews","pageViews","toWrite","clearPageViews","buildPageEvents","pageView","index","activeTimeOnSite","hasActiveTime","nextActiveTimeOnSite","hasNextActiveTimeOnSite","diff","captureUtmParams","search","params","captured","reason","loadUtmParams","clearUtmParams","readCanonicalUrl","name","moduleId","EVENT_NAME_SELECT_PLACEMENTS","ADBLOCK_CONTROL_DOMAIN","INIT_LOG_SAMPLING_RATE","ROKT_THANK_YOU_JOURNEY_EXTENSION","ROKT_INTEGRATION_SCRIPT_ID","ROKT_THANK_YOU_ELEMENT_SCRIPT_ID","USER_IDENTIFIED_IN_WORKSPACE_KEY","MESSAGE_TYPE_PAGE_VIEW","MESSAGE_TYPE_SESSION_END","PAGE_EVENTS_KEY","PAGE_VIEW_ATTRIBUTES_KEY","MPARTICLE_SESSION_ID_KEY","MPARTICLE_DEVICE_ID_KEY","WORKSPACE_SEARCH_SELECT_TIMEOUT_MS","ErrorCodes","WSDKErrorSeverity","DEFAULT_ROKT_DOMAIN","LOGGING_ENDPOINT","ERROR_ENDPOINT","RATE_LIMIT_PER_SEVERITY","mp","generateLauncherScript","domain","extensions","baseUrl","generateBaseUrl","generateThankYouElementScript","resolvedDomain","generateReportingUrl","configuredUrl","endpoint","reportingDomain","loadRoktScript","scriptId","source","handlers","target","script","parseSettingsString","settingsString","extractRoktExtensionConfig","settings","roktExtensionsQueryParams","legacyRoktExtensions","loadThankYouElement","extensionName","registerLegacyExtensions","legacyExtensions","launcher","extension","generateMappedEventLookup","placementEventMapping","mappedEvents","mapping","generateMappedEventAttributeLookup","placementEventAttributeMapping","mappedAttributeKeys","mappedAttributeKey","eventAttributeKey","hashEventMessage","messageType","eventType","eventName","generateIntegrationName","customIntegrationName","integrationName","djb2","str","hash","createAutoRemovedIframe","src","iframe","sendAdBlockMeasurementSignals","version","originHash","RoktKit","guid","pageUrl","existingBaseUrl","_isDebugModeEnabled","_getReportingUrl","_getUserAgent","RateLimiter","severity","newCount","ReportingTransport","config","launcherInstanceGuid","accountId","rateLimiter","isLoggingEnabled","msg","code","stackTrace","onError","logRequest","headers","response","serverError","error","ErrorReportingService","LoggingService","errorReportingService","entry","isServerSide","buildPageEvent","event","pageTitle","canonicalUrl","_RoktKit","condition","actualValue","operator","expectedValue","rule","conditions","rulesForMappedAttributeKey","allMatch","j","requested","err","errMessage","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","sessionManager","readSessionId","launcherOptions","options","launcherPromise","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","sessionAttributes","pageEvents","utmParams","mpSessionId","mpDeviceId","selectPlacementsAttributes","selectPlacementsOptions","selection","logSelection","sel","callback","getId","register"],"mappings":"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"} \ No newline at end of file diff --git a/kits/rokt/src/Rokt-Kit.ts b/kits/rokt/src/Rokt-Kit.ts index afef3243d..389e03595 100644 --- a/kits/rokt/src/Rokt-Kit.ts +++ b/kits/rokt/src/Rokt-Kit.ts @@ -1501,7 +1501,7 @@ class RoktKit implements KitInterface { ...optimizelyAttributes, ...sessionAttributes, ...(pageEvents.length ? { [PAGE_EVENTS_KEY]: JSON.stringify(pageEvents) } : {}), - ...(utmParams ? { [PAGE_VIEW_ATTRIBUTES_KEY]: utmParams } : {}), + ...(utmParams ? { [PAGE_VIEW_ATTRIBUTES_KEY]: JSON.stringify(utmParams) } : {}), ...(this.userIdentifiedInWorkspace ? { [USER_IDENTIFIED_IN_WORKSPACE_KEY]: true } : {}), ...(mpSessionId ? { [MPARTICLE_SESSION_ID_KEY]: mpSessionId } : {}), ...(mpDeviceId ? { [MPARTICLE_DEVICE_ID_KEY]: mpDeviceId } : {}), diff --git a/kits/rokt/test/src/tests.spec.ts b/kits/rokt/test/src/tests.spec.ts index b3aba2975..525c59ee0 100644 --- a/kits/rokt/test/src/tests.spec.ts +++ b/kits/rokt/test/src/tests.spec.ts @@ -6607,6 +6607,56 @@ describe('Rokt Forwarder', () => { ]); }); + it('surfaces captured UTM params through selectPlacements as stringified page_view_attributes', async () => { + const originalLocation = window.location; + Object.defineProperty(window, 'location', { + value: new URL( + 'https://www.example.com/?utm_source=google&utm_medium=cpc&utm_campaign=spring', + ), + writable: true, + configurable: true, + }); + + try { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + (window as any).mParticle._Store.localSessionAttributes = {}; + (window as any).mParticle.forwarder.process({ + EventName: 'Home Page', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + SourceMessageId: 'source-message-id-utm', + Timestamp: 1712345678000, + }); + + await (window as any).mParticle.forwarder.selectPlacements({ attributes: {} }); + + const forwardedAttributes = (window as any).mParticle.Rokt.selectPlacementsOptions.attributes; + expect(typeof forwardedAttributes.page_view_attributes).toBe('string'); + expect(JSON.parse(forwardedAttributes.page_view_attributes)).toEqual({ + utm_source: 'google', + utm_medium: 'cpc', + utm_campaign: 'spring', + }); + } finally { + Object.defineProperty(window, 'location', { + value: originalLocation, + writable: true, + configurable: true, + }); + } + }); + it('carries pageTitle and canonicalUrl through selectPlacements when stored', async () => { seedStoredPageViews([ {