diff --git a/kits/rokt/dist/Rokt-Kit.common.js b/kits/rokt/dist/Rokt-Kit.common.js index c174b6984..c74c3e21c 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 ae=["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"],ce=new Set(ae);function X(i){return ce.has(i.toLowerCase())}function b(i){const e={},t=i||{},n=Object.keys(t);for(let r=0;rr.length<=1?!1:(r.shift(),!0);let s=JSON.stringify(r).length>n;for(;s&&o();)s=JSON.stringify(r).length>n;let c=U(i,e,r);for(;!c&&o();)c=U(i,e,r);return c}const S="mp-rokt-kit",k="pageViews",x="mpPageViews",de=100*1024;function ie(i){const e=N(x);if(e===null)return;if(!(te(S,k)!==void 0)&&Array.isArray(e)&&!U(S,k,e)){i?.log({message:"Rokt Kit: Failed to migrate legacy page-view storage; retaining legacy key for retry",code:"PAGE_VIEW_CAPTURE_FAILED"});return}ee(x)}function Y(i){ie(i);const e=te(S,k);return Array.isArray(e)?e:[]}function he(i){return ue(S,k,i,de)}function G(){le(S,k)}function ge(i){return i.map((e,t)=>{const n=e.activeTimeOnSite,r=n!==void 0&&Number.isFinite(n),s=i[t+1]?.activeTimeOnSite,c=s!==void 0&&Number.isFinite(s),u=r&&c?s-n:void 0;return{pageUrl:e.pageUrl,sourceMessageId:e.sourceMessageId,timestamp:e.timestamp,...e.pageTitle!==void 0?{pageTitle:e.pageTitle}:{},...e.canonicalUrl!==void 0?{canonicalUrl:e.canonicalUrl}:{},...r?{activeTimeOnSite:n}:{},...u!==void 0&&u>=0?{activeTimeOnPage:u}:{}}})}function pe(){const e=document.querySelector('link[rel="canonical"]')?.href;if(e)return M(e)}const d="Rokt",L=181,fe="selectPlacements",me="apps.roktecommerce.com",Ee=.1,_e="ThankYouPageJourney",ye="rokt-launcher",Ie="rokt-thank-you-element",Se="userIdentifiedInWorkspace",ke=3,Ae=2,Re="page_events",ve=500,K={UNKNOWN_ERROR:"UNKNOWN_ERROR",UNHANDLED_EXCEPTION:"UNHANDLED_EXCEPTION",IDENTITY_REQUEST:"IDENTITY_REQUEST",LOG_DELIVERY_FAILURE:"LOG_DELIVERY_FAILURE"},_={ERROR:"ERROR",INFO:"INFO",WARNING:"WARNING"},we="apps.rokt-api.com",be="/v1/log",Le="/v1/errors",Te=10;function a(){return window.mParticle}function W(i,e){const n=[D(i),"/wsdk/integrations/launcher.js"].join("");return!e||e.length===0?n:n+"?extensions="+e.join(",")}function j(i){return[D(i),"/rokt-elements/rokt-element-thank-you.js"].join("")}function D(i){return["https://",typeof i<"u"?i:we].join("")}function ne(i,e,t){return i?i.startsWith("http://")||i.startsWith("https://")?i:"https://"+i:D(e)+t}function H(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 T(i){if(!i)return[];try{return JSON.parse(i.replace(/"/g,'"'))}catch{console.error("Settings string contains invalid JSON")}return[]}function V(i){const e=i?T(i):[],t=[],n=[];let r=!1;for(let o=0;o=Ee)return;const r=window.__rokt_li_guid__;if(!r)return;const o=window.location.href.split("?")[0].split("#")[0],s="version="+encodeURIComponent(e??"")+"&launcherInstanceGuid="+encodeURIComponent(r)+"&pageUrl="+encodeURIComponent(o);C("https://"+(i||"apps.rokt.com")+"/v1/wsdk-init/index.html?"+s),C("https://"+me+"/v1/wsdk-init/index.html?"+s+"&isControl=true")}function Pe(){return typeof window<"u"&&!!window.location?.search?.toLowerCase().includes("mp_enable_logging=true")}function Ue(){return typeof window<"u"?window.location?.href:void 0}function Ce(){return typeof window<"u"?window.navigator?.userAgent:void 0}class oe{constructor(){this._logCount={}}incrementAndCheck(e){const n=(this._logCount[e]||0)+1;return this._logCount[e]=n,n>Te}}class F{constructor(e,t,n,r,o){this._reporter="mp-wsdk";const s=e.isLoggingEnabled;this._integrationName=t||"",this._launcherInstanceGuid=n,this._accountId=r||null,this._rateLimiter=o||new oe,this._isEnabled=Pe()||s}send(e,t,n,r,o,s){if(!(!this._isEnabled||this._rateLimiter.incrementAndCheck(t)))try{const c={additionalInformation:{message:n,version:this._integrationName},severity:t,code:r||K.UNKNOWN_ERROR,url:Ue(),deviceInfo:Ce(),stackTrace:o,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),s&&s(l)})}catch(c){console.error("ReportingTransport: Failed to send log",c),s&&s(c)}}}class Q{constructor(e,t,n,r,o){this._transport=new F(e,t,n,r,o),this._errorUrl=ne(e?.errorUrl,e?.integrationDomain,Le)}report(e){if(!e)return;const t=e.severity||_.ERROR;this._transport.send(this._errorUrl,t,e.message,e.code,e.stackTrace)}}class ${constructor(e,t,n,r,o,s){this._transport=new F(e,n,r,o,s),this._loggingUrl=ne(e?.loggingUrl,e?.integrationDomain,be),this._errorReportingService=t}log(e){e&&this._transport.send(this._loggingUrl,_.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:K.LOG_DELIVERY_FAILURE,severity:n?_.ERROR:_.WARNING})}})}}function Me(i){const e=M(window.location.href),t=i.EventAttributes?.title||document.title,n=pe(),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=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||!m(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||!m(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 o=0;o{await Ne(n,c),this.initRoktLauncher(c)}).catch(c=>{console.error("Error creating Rokt launcher:",c)})}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,q(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((o,s)=>(o["rokt.custom.optimizely.experiment."+s+".variationId"]=t.getVariationMap()[s].id,o),{})}}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,o){const s=e,c=s.accountId;this.userAttributes=b(o),this._onboardingExpProvider=s.onboardingExpProvider;const u=T(s.placementEventMapping);this.placementEventMappingLookup=z(u);const l=T(s.placementEventAttributeMapping);this.placementEventAttributeMappingLookup=J(l),s.hashedEmailUserIdentityType&&(this._mappedEmailSha256Key=s.hashedEmailUserIdentityType.toLowerCase()),this._workspaceIdSyncApiKey=m(s.workspaceIdSyncApiKey)?s.workspaceIdSyncApiKey:void 0;const g=a().Rokt?.domain,{roktExtensionsQueryParams:O,legacyRoktExtensions:A,loadThankYouElement:R}=V(s.roktExtensions),p={...a().Rokt?.launcherOptions||{}};this.integrationName=Oe(p.integrationName),p.integrationName=this.integrationName,this.domain=g;const v={loggingUrl:s.loggingUrl,errorUrl:s.errorUrl,integrationDomain:g,isLoggingEnabled:a().config?.isLoggingEnabled===!0},E=new Q(v,this.integrationName,window.__rokt_li_guid__,s.accountId),w=new $(v,E,this.integrationName,window.__rokt_li_guid__,s.accountId);if(this.errorReportingService=E,this.loggingService=w,this.isTargetingDisabled())try{G()}catch(h){this.errorReportingService?.report({message:"Rokt Kit: Failed to clear page views when targeting is disabled",code:"PAGE_VIEW_CAPTURE_FAILED",severity:_.INFO,stackTrace:h instanceof Error?h.stack:void 0})}return a()._registerErrorReportingService&&a()._registerErrorReportingService(E),a()._registerLoggingService&&a()._registerLoggingService(w),n?(this.testHelpers={generateLauncherScript:W,generateThankYouElementScript:j,extractRoktExtensionConfig:V,hashEventMessage:B,parseSettingsString:T,generateMappedEventLookup:z,generateMappedEventAttributeLookup:J,sendAdBlockMeasurementSignals:q,createAutoRemovedIframe:C,djb2:re,setAllowedOriginHashes:h=>{f._allowedOriginHashes=h},ReportingTransport:F,ErrorReportingService:Q,LoggingService:$,RateLimiter:oe,ErrorCodes:K,WSDKErrorSeverity:_},this.attachLauncher(c,p),"Successfully initialized: "+d):(R&&(a().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this),H(Ie,j(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,p,A):(H(ye,W(g,O),{onLoad:()=>{this.isLauncherReadyToAttach()?this.attachLauncher(c,p,A):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===ke&&this.capturePageView(e),e.EventDataType===Ae&&(ie(this.loggingService),G())),!this.isKitReady())return"Kit not ready for forwarder: "+d;if(typeof a().Rokt?.setLocalSessionAttribute=="function"&&(P(this.placementEventAttributeMappingLookup)||this.applyPlacementEventAttributeMapping(e),!P(this.placementEventMappingLookup))){const t=B(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 X(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,o={};if(r)for(const u of Object.keys(r)){const l=r[u];m(l)&&l.length>0&&(o[u]=l)}const s=Object.keys(o);if(s.length===0)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const c=s.sort().map(u=>`${u}=${o[u]}`).join("&");return c===this._workspaceLastSearchedIdentitiesKey?this._workspaceSearchInFlightPromise||Promise.resolve():(this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=c,new Promise(u=>{try{n(t,o,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,ve))]).then(()=>this._dispatchPlacements(e))}return this._dispatchPlacements(e)}_dispatchPlacements(e){const t=e&&e.attributes||{},r={...b(this.userAttributes),...t},o=this.filters||{},s=o.userAttributeFilters||[],c=o.filteredUser||null,u=c?c.getMPID():null;let l;o?o.filterUserAttributes?l=o.filterUserAttributes(r,s):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():{},O=this.returnUserIdentities(c),A=this.returnLocalSessionAttributes(),R=ge(Y(this.loggingService)),p={...O,...l,...g,...A,...R.length?{[Re]:JSON.stringify(R)}:{},...this.userIdentifiedInWorkspace?{[Se]:!0}:{},mpid:u},v={...e,attributes:p},E=this.launcher.selectPlacements(v),w=()=>this.logSelectPlacementsEvent(p);return Promise.resolve(E).then(h=>h?.context?.sessionId?.then(se=>this.setRoktSessionId(se))).catch(()=>{}).finally(w),E}hashAttributes(e){return this.isKitReady()?this.launcher.hashAttributes(e):(console.error("Rokt Kit: Not initialized"),null)}use(e){return this.isKitReady()?!e||!m(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 I=f;function Ke(){return L}function De(i){if(!i){window.console.log("You must pass a config object to register the kit "+d);return}if(!y(i)){window.console.log("'config' must be an object. You passed in a "+typeof i);return}y(i.kits)?i.kits[d]={constructor:I}:(i.kits={},i.kits[d]={constructor:I}),window.console.log("Successfully registered "+d+" to your mParticle configuration")}typeof window<"u"&&window.mParticle&&a().addForwarder&&a().addForwarder({name:d,constructor:I,getId:Ke});exports.register=De; //# 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..a5cdecaaf 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":"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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 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\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\nexport function writeNamespacedFieldWithinBudget(\n namespaceKey: string,\n field: string,\n records: unknown[],\n maxLength: number,\n): boolean {\n // Operate on a copy so the caller's array isn't trimmed as a side effect.\n const remaining = records.slice();\n\n const evictOldest = (): boolean => {\n if (remaining.length <= 1) {\n return false;\n }\n remaining.shift();\n return true;\n };\n\n // Two limits: our own soft cap (maxLength), then the browser's hard quota,\n // which is shared across the origin and only surfaces when setItem throws.\n let overBudget = JSON.stringify(remaining).length > maxLength;\n while (overBudget && evictOldest()) {\n overBudget = JSON.stringify(remaining).length > maxLength;\n }\n\n let written = writeNamespacedField(namespaceKey, field, remaining);\n while (!written && evictOldest()) {\n written = writeNamespacedField(namespaceKey, field, remaining);\n }\n\n return written;\n}\n","import type { LoggingService } from './Rokt-Kit';\nimport {\n readJSON,\n removeKey,\n readNamespacedField,\n writeNamespacedField,\n removeNamespacedField,\n writeNamespacedFieldWithinBudget,\n} from './storage';\nimport { sanitizeUrl } from './utils';\n\nconst LS_NAMESPACE_KEY = 'mp-rokt-kit';\nconst LS_PAGE_VIEWS_FIELD = 'pageViews';\nconst LEGACY_PAGE_VIEWS_KEY = 'mpPageViews';\nconst PAGE_VIEWS_MAX_LENGTH = 100 * 1024;\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\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 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; retaining legacy key for retry',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n return;\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[]): boolean {\n return writeNamespacedFieldWithinBudget(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, pageViews, PAGE_VIEWS_MAX_LENGTH);\n}\n\nexport function clearPageViews(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n}\n\nexport function buildPageEvents(pageViews: PageEvent[]): PageEvent[] {\n return pageViews.map((pageView, index) => {\n const activeTimeOnSite = pageView.activeTimeOnSite;\n const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite);\n\n const next = pageViews[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 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 buildPageEvents,\n migrateLegacyPageViewStorage,\n loadPageViews,\n writePageViews,\n clearPageViews,\n readCanonicalUrl,\n} from './pageViewStorage';\n\nimport { isObject, isString, isEmpty, 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 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\nconst MESSAGE_TYPE_PAGE_VIEW = 3; // mParticle MessageType.PageView\nconst MESSAGE_TYPE_SESSION_END = 2; // mParticle MessageType.SessionEnd\nconst PAGE_EVENTS_KEY = 'page_events';\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 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 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\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 if (!writePageViews(pageViews)) {\n this.loggingService?.log({\n message: `Rokt Kit: Failed to persist page view for ${pageUrl}`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n } catch (err) {\n this.loggingService?.log({\n message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\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 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 // 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 } 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 this.capturePageView(event);\n }\n\n if (event.EventDataType === MESSAGE_TYPE_SESSION_END) {\n migrateLegacyPageViewStorage(this.loggingService);\n clearPageViews();\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 (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 sessionAttributes = this.returnLocalSessionAttributes();\n const pageEvents = buildPageEvents(loadPageViews(this.loggingService));\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 ...(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 };\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","isEmpty","sanitizeUrl","href","url","readJSON","stored","writeJSON","removeKey","readNamespacedField","namespaceKey","field","blob","writeNamespacedField","next","removeNamespacedField","writeNamespacedFieldWithinBudget","records","maxLength","remaining","evictOldest","overBudget","written","LS_NAMESPACE_KEY","LS_PAGE_VIEWS_FIELD","LEGACY_PAGE_VIEWS_KEY","PAGE_VIEWS_MAX_LENGTH","migrateLegacyPageViewStorage","loggingService","legacyViews","loadPageViews","writePageViews","pageViews","clearPageViews","buildPageEvents","pageView","index","activeTimeOnSite","hasActiveTime","nextActiveTimeOnSite","hasNextActiveTimeOnSite","diff","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","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","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","params","_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","err","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","launcherOptions","mpSessionId","options","launcherPromise","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","search","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","sessionAttributes","pageEvents","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..861bc5ec5 100644 --- a/kits/rokt/dist/Rokt-Kit.esm.js +++ b/kits/rokt/dist/Rokt-Kit.esm.js @@ -1,4 +1,5 @@ -const B = [ +const ae = [ + "active_time_on_site_ms", "billingaddress1", "billingaddress2", "billingcity", @@ -22,184 +23,282 @@ const B = [ "shippingstate", "shippingzipcode", "totalprice" -], J = new Set(B); -function G(n) { - return J.has(n.toLowerCase()); +], ce = new Set(ae); +function X(i) { + return ce.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 o = n[r]; + X(o) || (e[o] = t[o]); } - 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 y(i) { + return typeof i == "object" && i !== null && !Array.isArray(i); +} +function m(i) { + return typeof i == "string"; +} +function P(i) { + return i == null ? !0 : typeof i == "object" ? Object.keys(i).length === 0 : !1; +} +function M(i) { + try { + const e = new URL(i); + return e.search = "", e.toString(); + } catch { + return i; + } +} +function N(i) { + try { + const e = window.localStorage.getItem(i); + return e === null ? null : JSON.parse(e); + } catch { + return null; + } +} +function Z(i, e) { + try { + return window.localStorage.setItem(i, JSON.stringify(e)), !0; + } catch { + return !1; + } +} +function ee(i) { + try { + window.localStorage.removeItem(i); + } catch { + } +} +function te(i, e) { + const t = N(i); + return y(t) ? t[e] : void 0; +} +function U(i, e, t) { + const n = N(i), r = y(n) ? { ...n } : {}; + return r[e] = t, Z(i, r); +} +function le(i, e) { + const t = N(i); + if (!y(t) || !(e in t)) + return; + const n = { ...t }; + delete n[e], Object.keys(n).length === 0 ? ee(i) : Z(i, n); +} +function ue(i, e, t, n) { + const r = t.slice(), o = () => r.length <= 1 ? !1 : (r.shift(), !0); + let s = JSON.stringify(r).length > n; + for (; s && o(); ) + s = JSON.stringify(r).length > n; + let c = U(i, e, r); + for (; !c && o(); ) + c = U(i, e, r); + return c; +} +const S = "mp-rokt-kit", k = "pageViews", x = "mpPageViews", de = 100 * 1024; +function ie(i) { + const e = N(x); + if (e === null) + return; + if (!(te(S, k) !== void 0) && Array.isArray(e) && !U(S, k, e)) { + i?.log({ + message: "Rokt Kit: Failed to migrate legacy page-view storage; retaining legacy key for retry", + code: "PAGE_VIEW_CAPTURE_FAILED" + }); + return; + } + ee(x); +} +function Y(i) { + ie(i); + const e = te(S, k); + return Array.isArray(e) ? e : []; +} +function he(i) { + return ue(S, k, i, de); +} +function G() { + le(S, k); +} +function ge(i) { + return i.map((e, t) => { + const n = e.activeTimeOnSite, r = n !== void 0 && Number.isFinite(n), s = i[t + 1]?.activeTimeOnSite, c = s !== void 0 && Number.isFinite(s), u = r && c ? s - n : void 0; + return { + pageUrl: e.pageUrl, + sourceMessageId: e.sourceMessageId, + timestamp: e.timestamp, + ...e.pageTitle !== void 0 ? { pageTitle: e.pageTitle } : {}, + ...e.canonicalUrl !== void 0 ? { canonicalUrl: e.canonicalUrl } : {}, + ...r ? { activeTimeOnSite: n } : {}, + ...u !== void 0 && u >= 0 ? { activeTimeOnPage: u } : {} + }; + }); +} +function pe() { + const e = document.querySelector('link[rel="canonical"]')?.href; + if (e) + return M(e); +} +const d = "Rokt", L = 181, fe = "selectPlacements", me = "apps.roktecommerce.com", Ee = 0.1, _e = "ThankYouPageJourney", ye = "rokt-launcher", Ie = "rokt-thank-you-element", Se = "userIdentifiedInWorkspace", ke = 3, Ae = 2, Re = "page_events", ve = 500, K = { 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" -}, rt = "apps.rokt-api.com", st = "/v1/log", ot = "/v1/errors", at = 10; +}, we = "apps.rokt-api.com", be = "/v1/log", Le = "/v1/errors", Te = 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 W(i, e) { + const n = [D(i), "/wsdk/integrations/launcher.js"].join(""); + return !e || e.length === 0 ? n : n + "?extensions=" + e.join(","); } -function K(n) { - return [P(n), "/rokt-elements/rokt-element-thank-you.js"].join(""); +function j(i) { + return [D(i), "/rokt-elements/rokt-element-thank-you.js"].join(""); } -function P(n) { - return ["https://", typeof n < "u" ? n : rt].join(""); +function D(i) { + return ["https://", typeof i < "u" ? i : we].join(""); } -function z(n, t, e) { - return n ? n.startsWith("http://") || n.startsWith("https://") ? n : "https://" + n : P(t) + e; +function ne(i, e, t) { + return i ? i.startsWith("http://") || i.startsWith("https://") ? i : "https://" + i : D(e) + t; } -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 H(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 T(n) { - return n != null && typeof n == "object" && Array.isArray(n) === !1; -} -function L(n) { - if (!n) +function T(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 V(i) { + const e = i ? T(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 o = 0; o < e.length; o++) { + const s = e[o].value; + s === "thank-you-journey" ? (r = !0, n.push(_e)) : t.push(s); } 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 Ne(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 J(i) { + const e = {}; + if (!Array.isArray(i)) + return e; + for (let t = 0; t < i.length; t++) { + const n = i[t]; + if (!n || !m(n.value) || !m(n.map)) continue; - const r = i.value, s = i.map; - t[r] || (t[r] = []), t[r].push({ - eventAttributeKey: s, - conditions: Array.isArray(i.conditions) ? i.conditions : [] + const r = n.value, o = n.map; + e[r] || (e[r] = []), e[r].push({ + eventAttributeKey: o, + conditions: Array.isArray(n.conditions) ? n.conditions : [] }); } - return t; + return e; } -function F(n, t, e) { - return a().generateHash([n, t, e].join("")); +function B(i, e, t) { + return a().generateHash([i, e, t].join("")); } -function k(n) { - return n == null ? !0 : typeof n == "object" ? Object.keys(n).length === 0 : Array.isArray(n) ? n.length === 0 : !1; +function Oe(i) { + let n = "mParticle_wsdkv_" + a().getVersion() + "_kitv_" + "1.30.2"; + return i && (n += "_" + i), n; } -function m(n) { - return typeof n == "string"; +function re(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 lt(n) { - let i = "mParticle_wsdkv_" + a().getVersion() + "_kitv_" + "1.28.3"; - return n && (i += "_" + n), i; -} -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 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 C(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 q(i, e) { + const t = re(window.location.origin); + if (I._allowedOriginHashes.indexOf(t) === -1 || Math.random() >= Ee) 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); - N("https://" + (n || "apps.rokt.com") + "/v1/wsdk-init/index.html?" + o), N( - "https://" + X + "/v1/wsdk-init/index.html?" + o + "&isControl=true" + const o = window.location.href.split("?")[0].split("#")[0], s = "version=" + encodeURIComponent(e ?? "") + "&launcherInstanceGuid=" + encodeURIComponent(r) + "&pageUrl=" + encodeURIComponent(o); + C("https://" + (i || "apps.rokt.com") + "/v1/wsdk-init/index.html?" + s), C( + "https://" + me + "/v1/wsdk-init/index.html?" + s + "&isControl=true" ); } -function ut() { +function Pe() { return typeof window < "u" && !!window.location?.search?.toLowerCase().includes("mp_enable_logging=true"); } -function dt() { +function Ue() { return typeof window < "u" ? window.location?.href : void 0; } -function ht() { +function Ce() { return typeof window < "u" ? window.navigator?.userAgent : void 0; } -class q { +class oe { 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 > Te; } } -class C { - constructor(t, e, i, r, s) { +class F { + constructor(e, t, n, r, o) { 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 s = e.isLoggingEnabled; + this._integrationName = t || "", this._launcherInstanceGuid = n, this._accountId = r || null, this._rateLimiter = o || new oe(), this._isEnabled = Pe() || s; } - send(t, e, i, r, s, o) { - if (!(!this._isEnabled || this._rateLimiter.incrementAndCheck(e))) + send(e, t, n, r, o, s) { + 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(), - stackTrace: s, + severity: t, + code: r || K.UNKNOWN_ERROR, + url: Ue(), + deviceInfo: Ce(), + stackTrace: o, reporter: this._reporter, integration: this._integrationName }, u = { @@ -208,99 +307,126 @@ 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); + console.error("ReportingTransport: Failed to send log", l), s && s(l); }); } catch (c) { - console.error("ReportingTransport: Failed to send log", c), o && o(c); + console.error("ReportingTransport: Failed to send log", c), s && s(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 Q { + constructor(e, t, n, r, o) { + this._transport = new F(e, t, n, r, o), this._errorUrl = ne(e?.errorUrl, e?.integrationDomain, Le); } - 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 || _.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 $ { + constructor(e, t, n, r, o, s) { + this._transport = new F(e, n, r, o, s), this._loggingUrl = ne(e?.loggingUrl, e?.integrationDomain, be), this._errorReportingService = t; } - log(t) { - t && this._transport.send( + log(e) { + e && this._transport.send( this._loggingUrl, - I.INFO, - t.message, - t.code, + _.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: K.LOG_DELIVERY_FAILURE, + severity: n ? _.ERROR : _.WARNING }); } } ); } } -const p = class p { +function Me(i) { + const e = M(window.location.href), t = i.EventAttributes?.title || document.title, n = pe(), 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 = 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 || !m(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 || !m(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 o = 0; o < n.length; o++) + if (!this.doesEventAttributeConditionMatch(n[o], 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], o = this.placementEventAttributeMappingLookup[r]; + if (P(o)) continue; - let o = !0; - for (let c = 0; c < s.length; c++) - if (!this.doesEventMatchRule(t, s[c])) { - o = !1; + let s = !0; + for (let c = 0; c < o.length; c++) + if (!this.doesEventMatchRule(e, o[c])) { + s = !1; break; } - o && a().Rokt.setLocalSessionAttribute?.(r, !0); + s && a().Rokt.setLocalSessionAttribute?.(r, !0); + } + } + capturePageView(e) { + let t; + try { + t = M(window.location.href); + const n = Y(this.loggingService), r = Me(e); + n.push(r), he(n) || this.loggingService?.log({ + message: `Rokt Kit: Failed to persist page view for ${t}`, + code: "PAGE_VIEW_CAPTURE_FAILED" + }); + } catch (n) { + this.loggingService?.log({ + message: `Rokt Kit: Failed to capture page view for ${t}: ${n instanceof Error ? n.message : String(n)}`, + code: "PAGE_VIEW_CAPTURE_FAILED" + }); } } isLauncherReadyToAttach() { @@ -309,198 +435,214 @@ const p = class p { /** * 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[f.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" || !y(e)) return; - const e = a().EventType.Other; - a().logEvent(Q, e, t); + const t = a().EventType.Other; + a().logEvent(fe, 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 && typeof t.setIntegrationAttribute == "function" && 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 || {}, + attachLauncher(e, t, n = []) { + const r = a() && a().sessionManager && typeof a().sessionManager.getSession == "function" ? a().sessionManager.getSession() : void 0, o = { + accountId: e, + ...t || {}, ...r ? { mpSessionId: r } : {} }; - 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); + let s; + this.isPartnerInLocalLauncherTestGroup() ? s = Promise.resolve(window.Rokt.createLocalLauncher(o)) : s = window.Rokt.createLauncher(o), s.then(async (c) => { + await Ne(n, 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, 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, q(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((o, s) => (o["rokt.custom.optimizely.experiment." + s + ".variationId"] = t.getVariationMap()[s].id, o), {}); } - } 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( - o.placementEventAttributeMapping + init(e, t, n, r, o) { + const s = e, c = s.accountId; + this.userAttributes = b(o), this._onboardingExpProvider = s.onboardingExpProvider; + const u = T(s.placementEventMapping); + this.placementEventMappingLookup = z(u); + const l = T( + s.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 = { + this.placementEventAttributeMappingLookup = J(l), s.hashedEmailUserIdentityType && (this._mappedEmailSha256Key = s.hashedEmailUserIdentityType.toLowerCase()), this._workspaceIdSyncApiKey = m(s.workspaceIdSyncApiKey) ? s.workspaceIdSyncApiKey : void 0; + const g = a().Rokt?.domain, { roktExtensionsQueryParams: O, legacyRoktExtensions: A, loadThankYouElement: R } = V( + s.roktExtensions + ), p = { ...a().Rokt?.launcherOptions || {} }; - this.integrationName = lt(g.integrationName), g.integrationName = this.integrationName, this.domain = h; - const _ = { - loggingUrl: o.loggingUrl, - errorUrl: o.errorUrl, - integrationDomain: h, + this.integrationName = Oe(p.integrationName), p.integrationName = this.integrationName, this.domain = g; + const v = { + loggingUrl: s.loggingUrl, + errorUrl: s.errorUrl, + integrationDomain: g, isLoggingEnabled: a().config?.isLoggingEnabled === !0 - }, y = new H( - _, + }, E = new Q( + v, this.integrationName, window.__rokt_li_guid__, - o.accountId - ), S = new W( - _, - y, + s.accountId + ), w = new $( + v, + E, this.integrationName, window.__rokt_li_guid__, - o.accountId + s.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 = E, this.loggingService = w, this.isTargetingDisabled()) + try { + G(); + } catch (h) { + this.errorReportingService?.report({ + message: "Rokt Kit: Failed to clear page views when targeting is disabled", + code: "PAGE_VIEW_CAPTURE_FAILED", + severity: _.INFO, + stackTrace: h instanceof Error ? h.stack : void 0 + }); + } + return a()._registerErrorReportingService && a()._registerErrorReportingService(E), a()._registerLoggingService && a()._registerLoggingService(w), n ? (this.testHelpers = { + generateLauncherScript: W, + generateThankYouElementScript: j, + extractRoktExtensionConfig: V, + hashEventMessage: B, + parseSettingsString: T, + generateMappedEventLookup: z, + generateMappedEventAttributeLookup: J, + sendAdBlockMeasurementSignals: q, + createAutoRemovedIframe: C, + djb2: re, + setAllowedOriginHashes: (h) => { + f._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: F, + ErrorReportingService: Q, + LoggingService: $, + RateLimiter: oe, + ErrorCodes: K, + WSDKErrorSeverity: _ + }, this.attachLauncher(c, p), "Successfully initialized: " + d) : (R && (a().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this), H(Ie, j(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, p, A) : (H(ye, W(g, O), { onLoad: () => { - this.isLauncherReadyToAttach() ? this.attachLauncher(c, g, R) : console.error("Rokt object is not available after script load."); + this.isLauncherReadyToAttach() ? this.attachLauncher(c, p, A) : 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(f.PERFORMANCE_MARKS.RoktScriptAppended)), "Successfully initialized: " + d); } - process(t) { - if (!this.isKitReady()) + process(e) { + if (this.isTargetingDisabled() || (e.EventDataType === ke && this.capturePageView(e), e.EventDataType === Ae && (ie(this.loggingService), G())), !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 (typeof a().Rokt?.setLocalSessionAttribute == "function" && (P(this.placementEventAttributeMappingLookup) || this.applyPlacementEventAttributeMapping(e), !P(this.placementEventMappingLookup))) { + const t = B(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 X(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, o = {}; if (r) for (const u of Object.keys(r)) { const l = r[u]; - m(l) && l.length > 0 && (s[u] = l); + m(l) && l.length > 0 && (o[u] = l); } - const o = Object.keys(s); - if (o.length === 0) + const s = Object.keys(o); + if (s.length === 0) return this.userIdentifiedInWorkspace = !1, this._workspaceLastSearchedIdentitiesKey = void 0, Promise.resolve(); - const c = o.sort().map((u) => `${u}=${s[u]}`).join("&"); + const c = s.sort().map((u) => `${u}=${o[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, o, (l) => { l?.httpCode === 200 && (this.userIdentifiedInWorkspace = !0), u(); }); } catch (l) { @@ -508,14 +650,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 +682,81 @@ 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, ve)) + ]).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 }, o = this.filters || {}, s = o.userAttributeFilters || [], c = o.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, + o ? o.filterUserAttributes ? l = o.filterUserAttributes(r, s) : 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() : {}, O = this.returnUserIdentities(c), A = this.returnLocalSessionAttributes(), R = ge(Y(this.loggingService)), p = { + ...O, ...l, - ...h, - ...R, - ...this.userIdentifiedInWorkspace ? { [it]: !0 } : {}, + ...g, + ...A, + ...R.length ? { [Re]: JSON.stringify(R) } : {}, + ...this.userIdentifiedInWorkspace ? { [Se]: !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), _; + }, v = { ...e, attributes: p }, E = this.launcher.selectPlacements(v), w = () => this.logSelectPlacementsEvent(p); + return Promise.resolve(E).then((h) => h?.context?.sessionId?.then((se) => this.setRoktSessionId(se))).catch(() => { + }).finally(w), E; } /** * 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 || !m(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 = { +f._allowedOriginHashes = [-553112570, 549508659], f.PERFORMANCE_MARKS = { RoktScriptAppended: "mp:RoktScriptAppended" -}, p.EMAIL_SHA256_KEY = "emailsha256"; -let E = p; -function pt() { - return b; +}, f.EMAIL_SHA256_KEY = "emailsha256"; +let I = f; +function Ke() { + return L; } -function gt(n) { - if (!n) { +function De(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 (!y(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 + y(i.kits) ? i.kits[d] = { + constructor: I + } : (i.kits = {}, i.kits[d] = { + constructor: I }), 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: I, + getId: Ke }); export { - gt as register + De 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..1d52fe764 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 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\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\nexport function writeNamespacedFieldWithinBudget(\n namespaceKey: string,\n field: string,\n records: unknown[],\n maxLength: number,\n): boolean {\n // Operate on a copy so the caller's array isn't trimmed as a side effect.\n const remaining = records.slice();\n\n const evictOldest = (): boolean => {\n if (remaining.length <= 1) {\n return false;\n }\n remaining.shift();\n return true;\n };\n\n // Two limits: our own soft cap (maxLength), then the browser's hard quota,\n // which is shared across the origin and only surfaces when setItem throws.\n let overBudget = JSON.stringify(remaining).length > maxLength;\n while (overBudget && evictOldest()) {\n overBudget = JSON.stringify(remaining).length > maxLength;\n }\n\n let written = writeNamespacedField(namespaceKey, field, remaining);\n while (!written && evictOldest()) {\n written = writeNamespacedField(namespaceKey, field, remaining);\n }\n\n return written;\n}\n","import type { LoggingService } from './Rokt-Kit';\nimport {\n readJSON,\n removeKey,\n readNamespacedField,\n writeNamespacedField,\n removeNamespacedField,\n writeNamespacedFieldWithinBudget,\n} from './storage';\nimport { sanitizeUrl } from './utils';\n\nconst LS_NAMESPACE_KEY = 'mp-rokt-kit';\nconst LS_PAGE_VIEWS_FIELD = 'pageViews';\nconst LEGACY_PAGE_VIEWS_KEY = 'mpPageViews';\nconst PAGE_VIEWS_MAX_LENGTH = 100 * 1024;\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\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 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; retaining legacy key for retry',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n return;\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[]): boolean {\n return writeNamespacedFieldWithinBudget(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, pageViews, PAGE_VIEWS_MAX_LENGTH);\n}\n\nexport function clearPageViews(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n}\n\nexport function buildPageEvents(pageViews: PageEvent[]): PageEvent[] {\n return pageViews.map((pageView, index) => {\n const activeTimeOnSite = pageView.activeTimeOnSite;\n const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite);\n\n const next = pageViews[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 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 buildPageEvents,\n migrateLegacyPageViewStorage,\n loadPageViews,\n writePageViews,\n clearPageViews,\n readCanonicalUrl,\n} from './pageViewStorage';\n\nimport { isObject, isString, isEmpty, 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 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\nconst MESSAGE_TYPE_PAGE_VIEW = 3; // mParticle MessageType.PageView\nconst MESSAGE_TYPE_SESSION_END = 2; // mParticle MessageType.SessionEnd\nconst PAGE_EVENTS_KEY = 'page_events';\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 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 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\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 if (!writePageViews(pageViews)) {\n this.loggingService?.log({\n message: `Rokt Kit: Failed to persist page view for ${pageUrl}`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n } catch (err) {\n this.loggingService?.log({\n message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\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 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 // 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 } 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 this.capturePageView(event);\n }\n\n if (event.EventDataType === MESSAGE_TYPE_SESSION_END) {\n migrateLegacyPageViewStorage(this.loggingService);\n clearPageViews();\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 (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 sessionAttributes = this.returnLocalSessionAttributes();\n const pageEvents = buildPageEvents(loadPageViews(this.loggingService));\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 ...(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 };\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","isEmpty","sanitizeUrl","href","url","readJSON","stored","writeJSON","removeKey","readNamespacedField","namespaceKey","field","blob","writeNamespacedField","next","removeNamespacedField","writeNamespacedFieldWithinBudget","records","maxLength","remaining","evictOldest","overBudget","written","LS_NAMESPACE_KEY","LS_PAGE_VIEWS_FIELD","LEGACY_PAGE_VIEWS_KEY","PAGE_VIEWS_MAX_LENGTH","migrateLegacyPageViewStorage","loggingService","legacyViews","loadPageViews","writePageViews","pageViews","clearPageViews","buildPageEvents","pageView","index","activeTimeOnSite","hasActiveTime","nextActiveTimeOnSite","hasNextActiveTimeOnSite","diff","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","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","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","params","_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","err","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","launcherOptions","mpSessionId","options","launcherPromise","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","search","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","sessionAttributes","pageEvents","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..ab5a082e4 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(O){"use strict";const ae=["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"],ce=new Set(ae);function x(i){return ce.has(i.toLowerCase())}function A(i){const e={},t=i||{},n=Object.keys(t);for(let r=0;rr.length<=1?!1:(r.shift(),!0);let s=JSON.stringify(r).length>n;for(;s&&o();)s=JSON.stringify(r).length>n;let c=C(i,e,r);for(;!c&&o();)c=C(i,e,r);return c}const S="mp-rokt-kit",k="pageViews",H="mpPageViews",de=100*1024;function V(i){const e=R(H);if(e===null)return;if(!(j(S,k)!==void 0)&&Array.isArray(e)&&!C(S,k,e)){i?.log({message:"Rokt Kit: Failed to migrate legacy page-view storage; retaining legacy key for retry",code:"PAGE_VIEW_CAPTURE_FAILED"});return}W(H)}function z(i){V(i);const e=j(S,k);return Array.isArray(e)?e:[]}function he(i){return ue(S,k,i,de)}function J(){le(S,k)}function ge(i){return i.map((e,t)=>{const n=e.activeTimeOnSite,r=n!==void 0&&Number.isFinite(n),s=i[t+1]?.activeTimeOnSite,c=s!==void 0&&Number.isFinite(s),u=r&&c?s-n:void 0;return{pageUrl:e.pageUrl,sourceMessageId:e.sourceMessageId,timestamp:e.timestamp,...e.pageTitle!==void 0?{pageTitle:e.pageTitle}:{},...e.canonicalUrl!==void 0?{canonicalUrl:e.canonicalUrl}:{},...r?{activeTimeOnSite:n}:{},...u!==void 0&&u>=0?{activeTimeOnPage:u}:{}}})}function pe(){const e=document.querySelector('link[rel="canonical"]')?.href;if(e)return U(e)}const d="Rokt",v=181,fe="selectPlacements",me="apps.roktecommerce.com",Ee=.1,_e="ThankYouPageJourney",ye="rokt-launcher",Ie="rokt-thank-you-element",Se="userIdentifiedInWorkspace",ke=3,Ae=2,Re="page_events",ve=500,M={UNKNOWN_ERROR:"UNKNOWN_ERROR",UNHANDLED_EXCEPTION:"UNHANDLED_EXCEPTION",IDENTITY_REQUEST:"IDENTITY_REQUEST",LOG_DELIVERY_FAILURE:"LOG_DELIVERY_FAILURE"},_={ERROR:"ERROR",INFO:"INFO",WARNING:"WARNING"},we="apps.rokt-api.com",be="/v1/log",Le="/v1/errors",Te=10;function a(){return window.mParticle}function B(i,e){const n=[K(i),"/wsdk/integrations/launcher.js"].join("");return!e||e.length===0?n:n+"?extensions="+e.join(",")}function q(i){return[K(i),"/rokt-elements/rokt-element-thank-you.js"].join("")}function K(i){return["https://",typeof i<"u"?i:we].join("")}function Q(i,e,t){return i?i.startsWith("http://")||i.startsWith("https://")?i:"https://"+i:K(e)+t}function $(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 w(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?w(i):[],t=[],n=[];let r=!1;for(let o=0;o=Ee)return;const r=window.__rokt_li_guid__;if(!r)return;const o=window.location.href.split("?")[0].split("#")[0],s="version="+encodeURIComponent(e??"")+"&launcherInstanceGuid="+encodeURIComponent(r)+"&pageUrl="+encodeURIComponent(o);D("https://"+(i||"apps.rokt.com")+"/v1/wsdk-init/index.html?"+s),D("https://"+me+"/v1/wsdk-init/index.html?"+s+"&isControl=true")}function Pe(){return typeof window<"u"&&!!window.location?.search?.toLowerCase().includes("mp_enable_logging=true")}function Ue(){return typeof window<"u"?window.location?.href:void 0}function Ce(){return typeof window<"u"?window.navigator?.userAgent:void 0}class re{constructor(){this._logCount={}}incrementAndCheck(e){const n=(this._logCount[e]||0)+1;return this._logCount[e]=n,n>Te}}class F{constructor(e,t,n,r,o){this._reporter="mp-wsdk";const s=e.isLoggingEnabled;this._integrationName=t||"",this._launcherInstanceGuid=n,this._accountId=r||null,this._rateLimiter=o||new re,this._isEnabled=Pe()||s}send(e,t,n,r,o,s){if(!(!this._isEnabled||this._rateLimiter.incrementAndCheck(t)))try{const c={additionalInformation:{message:n,version:this._integrationName},severity:t,code:r||M.UNKNOWN_ERROR,url:Ue(),deviceInfo:Ce(),stackTrace:o,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),s&&s(l)})}catch(c){console.error("ReportingTransport: Failed to send log",c),s&&s(c)}}}class oe{constructor(e,t,n,r,o){this._transport=new F(e,t,n,r,o),this._errorUrl=Q(e?.errorUrl,e?.integrationDomain,Le)}report(e){if(!e)return;const t=e.severity||_.ERROR;this._transport.send(this._errorUrl,t,e.message,e.code,e.stackTrace)}}class se{constructor(e,t,n,r,o,s){this._transport=new F(e,n,r,o,s),this._loggingUrl=Q(e?.loggingUrl,e?.integrationDomain,be),this._errorReportingService=t}log(e){e&&this._transport.send(this._loggingUrl,_.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:M.LOG_DELIVERY_FAILURE,severity:n?_.ERROR:_.WARNING})}})}}function Me(i){const e=U(window.location.href),t=i.EventAttributes?.title||document.title,n=pe(),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 p=class p{constructor(){this.name=d,this.id=v,this.moduleId=v,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||!m(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||!m(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 o=0;o{await Ne(n,c),this.initRoktLauncher(c)}).catch(c=>{console.error("Error creating Rokt launcher:",c)})}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,ne(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((o,s)=>(o["rokt.custom.optimizely.experiment."+s+".variationId"]=t.getVariationMap()[s].id,o),{})}}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,o){const s=e,c=s.accountId;this.userAttributes=A(o),this._onboardingExpProvider=s.onboardingExpProvider;const u=w(s.placementEventMapping);this.placementEventMappingLookup=Z(u);const l=w(s.placementEventAttributeMapping);this.placementEventAttributeMappingLookup=ee(l),s.hashedEmailUserIdentityType&&(this._mappedEmailSha256Key=s.hashedEmailUserIdentityType.toLowerCase()),this._workspaceIdSyncApiKey=m(s.workspaceIdSyncApiKey)?s.workspaceIdSyncApiKey:void 0;const g=a().Rokt?.domain,{roktExtensionsQueryParams:Y,legacyRoktExtensions:b,loadThankYouElement:L}=X(s.roktExtensions),f={...a().Rokt?.launcherOptions||{}};this.integrationName=Oe(f.integrationName),f.integrationName=this.integrationName,this.domain=g;const T={loggingUrl:s.loggingUrl,errorUrl:s.errorUrl,integrationDomain:g,isLoggingEnabled:a().config?.isLoggingEnabled===!0},I=new oe(T,this.integrationName,window.__rokt_li_guid__,s.accountId),N=new se(T,I,this.integrationName,window.__rokt_li_guid__,s.accountId);if(this.errorReportingService=I,this.loggingService=N,this.isTargetingDisabled())try{J()}catch(h){this.errorReportingService?.report({message:"Rokt Kit: Failed to clear page views when targeting is disabled",code:"PAGE_VIEW_CAPTURE_FAILED",severity:_.INFO,stackTrace:h instanceof Error?h.stack:void 0})}return a()._registerErrorReportingService&&a()._registerErrorReportingService(I),a()._registerLoggingService&&a()._registerLoggingService(N),n?(this.testHelpers={generateLauncherScript:B,generateThankYouElementScript:q,extractRoktExtensionConfig:X,hashEventMessage:te,parseSettingsString:w,generateMappedEventLookup:Z,generateMappedEventAttributeLookup:ee,sendAdBlockMeasurementSignals:ne,createAutoRemovedIframe:D,djb2:ie,setAllowedOriginHashes:h=>{p._allowedOriginHashes=h},ReportingTransport:F,ErrorReportingService:oe,LoggingService:se,RateLimiter:re,ErrorCodes:M,WSDKErrorSeverity:_},this.attachLauncher(c,f),"Successfully initialized: "+d):(L&&(a().Rokt.flushOnShoppableAdsReadyMessageQueue?.(this),$(Ie,q(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,b):($(ye,B(g,Y),{onLoad:()=>{this.isLauncherReadyToAttach()?this.attachLauncher(c,f,b):console.error("Rokt object is not available after script load.")},onError:h=>{console.error("Error loading Rokt launcher script:",h)}}),this.captureTiming(p.PERFORMANCE_MARKS.RoktScriptAppended)),"Successfully initialized: "+d)}process(e){if(this.isTargetingDisabled()||(e.EventDataType===ke&&this.capturePageView(e),e.EventDataType===Ae&&(V(this.loggingService),J())),!this.isKitReady())return"Kit not ready for forwarder: "+d;if(typeof a().Rokt?.setLocalSessionAttribute=="function"&&(P(this.placementEventAttributeMappingLookup)||this.applyPlacementEventAttributeMapping(e),!P(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 x(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=A(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,o={};if(r)for(const u of Object.keys(r)){const l=r[u];m(l)&&l.length>0&&(o[u]=l)}const s=Object.keys(o);if(s.length===0)return this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=void 0,Promise.resolve();const c=s.sort().map(u=>`${u}=${o[u]}`).join("&");return c===this._workspaceLastSearchedIdentitiesKey?this._workspaceSearchInFlightPromise||Promise.resolve():(this.userIdentifiedInWorkspace=!1,this._workspaceLastSearchedIdentitiesKey=c,new Promise(u=>{try{n(t,o,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,ve))]).then(()=>this._dispatchPlacements(e))}return this._dispatchPlacements(e)}_dispatchPlacements(e){const t=e&&e.attributes||{},r={...A(this.userAttributes),...t},o=this.filters||{},s=o.userAttributeFilters||[],c=o.filteredUser||null,u=c?c.getMPID():null;let l;o?o.filterUserAttributes?l=o.filterUserAttributes(r,s):l=r:(console.warn("Rokt Kit: No filters available, using user attributes"),l=r),this.userAttributes=A(l);const g=this._onboardingExpProvider==="Optimizely"?this.fetchOptimizely():{},Y=this.returnUserIdentities(c),b=this.returnLocalSessionAttributes(),L=ge(z(this.loggingService)),f={...Y,...l,...g,...b,...L.length?{[Re]:JSON.stringify(L)}:{},...this.userIdentifiedInWorkspace?{[Se]:!0}:{},mpid:u},T={...e,attributes:f},I=this.launcher.selectPlacements(T),N=()=>this.logSelectPlacementsEvent(f);return Promise.resolve(I).then(h=>h?.context?.sessionId?.then(Fe=>this.setRoktSessionId(Fe))).catch(()=>{}).finally(N),I}hashAttributes(e){return this.isKitReady()?this.launcher.hashAttributes(e):(console.error("Rokt Kit: Not initialized"),null)}use(e){return this.isKitReady()?!e||!m(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}};p._allowedOriginHashes=[-553112570,549508659],p.PERFORMANCE_MARKS={RoktScriptAppended:"mp:RoktScriptAppended"},p.EMAIL_SHA256_KEY="emailsha256";let y=p;function Ke(){return v}function De(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:y}:(i.kits={},i.kits[d]={constructor:y}),window.console.log("Successfully registered "+d+" to your mParticle configuration")}return typeof window<"u"&&window.mParticle&&a().addForwarder&&a().addForwarder({name:d,constructor:y,getId:Ke}),O.register=De,Object.defineProperty(O,Symbol.toStringTag,{value:"Module"}),O})({}); //# 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..da492de51 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 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\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\nexport function writeNamespacedFieldWithinBudget(\n namespaceKey: string,\n field: string,\n records: unknown[],\n maxLength: number,\n): boolean {\n // Operate on a copy so the caller's array isn't trimmed as a side effect.\n const remaining = records.slice();\n\n const evictOldest = (): boolean => {\n if (remaining.length <= 1) {\n return false;\n }\n remaining.shift();\n return true;\n };\n\n // Two limits: our own soft cap (maxLength), then the browser's hard quota,\n // which is shared across the origin and only surfaces when setItem throws.\n let overBudget = JSON.stringify(remaining).length > maxLength;\n while (overBudget && evictOldest()) {\n overBudget = JSON.stringify(remaining).length > maxLength;\n }\n\n let written = writeNamespacedField(namespaceKey, field, remaining);\n while (!written && evictOldest()) {\n written = writeNamespacedField(namespaceKey, field, remaining);\n }\n\n return written;\n}\n","import type { LoggingService } from './Rokt-Kit';\nimport {\n readJSON,\n removeKey,\n readNamespacedField,\n writeNamespacedField,\n removeNamespacedField,\n writeNamespacedFieldWithinBudget,\n} from './storage';\nimport { sanitizeUrl } from './utils';\n\nconst LS_NAMESPACE_KEY = 'mp-rokt-kit';\nconst LS_PAGE_VIEWS_FIELD = 'pageViews';\nconst LEGACY_PAGE_VIEWS_KEY = 'mpPageViews';\nconst PAGE_VIEWS_MAX_LENGTH = 100 * 1024;\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\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 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; retaining legacy key for retry',\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n return;\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[]): boolean {\n return writeNamespacedFieldWithinBudget(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, pageViews, PAGE_VIEWS_MAX_LENGTH);\n}\n\nexport function clearPageViews(): void {\n removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD);\n}\n\nexport function buildPageEvents(pageViews: PageEvent[]): PageEvent[] {\n return pageViews.map((pageView, index) => {\n const activeTimeOnSite = pageView.activeTimeOnSite;\n const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite);\n\n const next = pageViews[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 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 buildPageEvents,\n migrateLegacyPageViewStorage,\n loadPageViews,\n writePageViews,\n clearPageViews,\n readCanonicalUrl,\n} from './pageViewStorage';\n\nimport { isObject, isString, isEmpty, 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 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\nconst MESSAGE_TYPE_PAGE_VIEW = 3; // mParticle MessageType.PageView\nconst MESSAGE_TYPE_SESSION_END = 2; // mParticle MessageType.SessionEnd\nconst PAGE_EVENTS_KEY = 'page_events';\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 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 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\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 if (!writePageViews(pageViews)) {\n this.loggingService?.log({\n message: `Rokt Kit: Failed to persist page view for ${pageUrl}`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\n }\n } catch (err) {\n this.loggingService?.log({\n message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n code: 'PAGE_VIEW_CAPTURE_FAILED',\n });\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 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 // 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 } 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 this.capturePageView(event);\n }\n\n if (event.EventDataType === MESSAGE_TYPE_SESSION_END) {\n migrateLegacyPageViewStorage(this.loggingService);\n clearPageViews();\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 (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 sessionAttributes = this.returnLocalSessionAttributes();\n const pageEvents = buildPageEvents(loadPageViews(this.loggingService));\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 ...(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 };\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","isEmpty","sanitizeUrl","href","url","readJSON","stored","writeJSON","removeKey","readNamespacedField","namespaceKey","field","blob","writeNamespacedField","next","removeNamespacedField","writeNamespacedFieldWithinBudget","records","maxLength","remaining","evictOldest","overBudget","written","LS_NAMESPACE_KEY","LS_PAGE_VIEWS_FIELD","LEGACY_PAGE_VIEWS_KEY","PAGE_VIEWS_MAX_LENGTH","migrateLegacyPageViewStorage","loggingService","legacyViews","loadPageViews","writePageViews","pageViews","clearPageViews","buildPageEvents","pageView","index","activeTimeOnSite","hasActiveTime","nextActiveTimeOnSite","hasNextActiveTimeOnSite","diff","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","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","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","params","_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","err","filteredUser","userIdentities","newUserIdentities","EVENT_TYPE_OTHER","sessionId","mpInstance","launcherOptions","mpSessionId","options","launcherPromise","roktFilters","forwarders","forwarder","optimizelyState","acc","expId","metricName","_service","testMode","_trackerId","filteredUserAttributes","kitSettings","reportingConfig","hashes","hashedEvent","partnerExtensionData","user","callbackName","apiKey","search","knownIdentities","identityKeys","identitiesKey","k","resolve","result","_filteredIdentityRequest","inFlight","placementAttributes","filters","userAttributeFilters","mpid","optimizelyAttributes","filteredUserIdentities","sessionAttributes","pageEvents","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 3246b2fe7..937cc4fd8 100644 --- a/kits/rokt/src/Rokt-Kit.ts +++ b/kits/rokt/src/Rokt-Kit.ts @@ -24,6 +24,18 @@ import { removeSelectPlacementsAttributePersistenceDeniedAttributes, } from './selectPlacementsAttributePersistence'; +import { + PageEvent, + buildPageEvents, + migrateLegacyPageViewStorage, + loadPageViews, + writePageViews, + clearPageViews, + readCanonicalUrl, +} from './pageViewStorage'; + +import { isObject, isString, isEmpty, sanitizeUrl } from './utils'; + interface RoktKitSettings { accountId: string; roktExtensions?: string; @@ -61,17 +73,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; @@ -257,15 +258,6 @@ 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'; // Bound on how long selectPlacements will wait for an in-flight Workspace @@ -311,27 +303,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(''); @@ -385,10 +356,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 +447,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; @@ -759,6 +698,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,31 +864,22 @@ 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(); + if (!writePageViews(pageViews)) { + this.loggingService?.log({ + message: `Rokt Kit: Failed to persist page view for ${pageUrl}`, + code: 'PAGE_VIEW_CAPTURE_FAILED', + }); } - - writePageViewsStorage(pageViews); } catch (err) { - this.errorReportingService?.report({ - message: `Rokt Kit: Failed to capture page view for ${pageUrl}`, + this.loggingService?.log({ + message: `Rokt Kit: Failed to capture page view for ${pageUrl}: ${ + err instanceof Error ? err.message : String(err) + }`, code: 'PAGE_VIEW_CAPTURE_FAILED', - severity: WSDKErrorSeverity.INFO, - stackTrace: err instanceof Error ? err.stack : undefined, }); } } @@ -962,34 +908,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; @@ -1217,7 +1135,7 @@ class RoktKit implements KitInterface { if (this.isTargetingDisabled()) { try { - clearPageViewsStorage(); + clearPageViews(); } catch (err) { this.errorReportingService?.report({ message: 'Rokt Kit: Failed to clear page views when targeting is disabled', @@ -1305,16 +1223,8 @@ class RoktKit implements KitInterface { } 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(); } } @@ -1533,7 +1443,7 @@ 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 selectPlacementsAttributes: Record = { ...(filteredUserIdentities as Record), @@ -1639,3 +1549,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..e52ee7787 --- /dev/null +++ b/kits/rokt/src/pageViewStorage.ts @@ -0,0 +1,94 @@ +import type { LoggingService } from './Rokt-Kit'; +import { + readJSON, + removeKey, + readNamespacedField, + writeNamespacedField, + removeNamespacedField, + writeNamespacedFieldWithinBudget, +} from './storage'; +import { sanitizeUrl } from './utils'; + +const LS_NAMESPACE_KEY = 'mp-rokt-kit'; +const LS_PAGE_VIEWS_FIELD = 'pageViews'; +const LEGACY_PAGE_VIEWS_KEY = 'mpPageViews'; +const PAGE_VIEWS_MAX_LENGTH = 100 * 1024; + +export interface PageEvent { + pageUrl: string; + sourceMessageId: string; + timestamp: number; + pageTitle?: string; + canonicalUrl?: string; + activeTimeOnSite?: number; + activeTimeOnPage?: number; +} + +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) { + 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; retaining legacy key for retry', + code: 'PAGE_VIEW_CAPTURE_FAILED', + }); + return; + } + } + + 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[]): boolean { + return writeNamespacedFieldWithinBudget(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD, pageViews, PAGE_VIEWS_MAX_LENGTH); +} + +export function clearPageViews(): void { + removeNamespacedField(LS_NAMESPACE_KEY, LS_PAGE_VIEWS_FIELD); +} + +export function buildPageEvents(pageViews: PageEvent[]): PageEvent[] { + return pageViews.map((pageView, index) => { + const activeTimeOnSite = pageView.activeTimeOnSite; + const hasActiveTime = activeTimeOnSite !== undefined && Number.isFinite(activeTimeOnSite); + + const next = pageViews[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 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..6a125c662 --- /dev/null +++ b/kits/rokt/src/storage.ts @@ -0,0 +1,85 @@ +import { isObject } from './utils'; + +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); + } +} + +export function writeNamespacedFieldWithinBudget( + namespaceKey: string, + field: string, + records: unknown[], + maxLength: number, +): boolean { + // Operate on a copy so the caller's array isn't trimmed as a side effect. + const remaining = records.slice(); + + const evictOldest = (): boolean => { + if (remaining.length <= 1) { + return false; + } + remaining.shift(); + return true; + }; + + // Two limits: our own soft cap (maxLength), then the browser's hard quota, + // which is shared across the origin and only surfaces when setItem throws. + let overBudget = JSON.stringify(remaining).length > maxLength; + while (overBudget && evictOldest()) { + overBudget = JSON.stringify(remaining).length > maxLength; + } + + let written = writeNamespacedField(namespaceKey, field, remaining); + while (!written && evictOldest()) { + written = writeNamespacedField(namespaceKey, field, remaining); + } + + return written; +} diff --git a/kits/rokt/src/utils.ts b/kits/rokt/src/utils.ts new file mode 100644 index 000000000..dbeebf4aa --- /dev/null +++ b/kits/rokt/src/utils.ts @@ -0,0 +1,28 @@ +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 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..88f69e713 --- /dev/null +++ b/kits/rokt/test/src/pageViewStorage.spec.ts @@ -0,0 +1,116 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { readJSON, writeNamespacedField } from '../../src/storage'; +import { migrateLegacyPageViewStorage, loadPageViews, writePageViews, clearPageViews } from '../../src/pageViewStorage'; +import type { LoggingService } from '../../src/Rokt-Kit'; + +const NAMESPACE_KEY = 'mp-rokt-kit'; +const PAGE_VIEWS_FIELD = 'pageViews'; +const LEGACY_PAGE_VIEWS_KEY = 'mpPageViews'; + +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('retains 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); + + expect(window.localStorage.getItem(LEGACY_PAGE_VIEWS_KEY)).not.toBeNull(); + expect(logger.log).toHaveBeenCalledWith(expect.objectContaining({ code: 'PAGE_VIEW_CAPTURE_FAILED' })); + }); + }); + + 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 true', () => { + expect(writePageViews([pageView('home')])).toBe(true); + expect(loadPageViews(null)).toEqual([pageView('home')]); + }); + + it('evicts oldest-first to stay within the byte budget', () => { + const oversizedUrl = 'https://example.com/' + 'a'.repeat(5000); + const views = Array.from({ length: 30 }, (_, i) => ({ + pageUrl: oversizedUrl, + sourceMessageId: 'seed-' + i, + timestamp: i, + })); + + expect(writePageViews(views)).toBe(true); + + const stored = loadPageViews(null); + expect(JSON.stringify(stored).length).toBeLessThanOrEqual(100 * 1024); + expect(stored.length).toBeLessThan(30); + expect(stored[stored.length - 1].sourceMessageId).toBe('seed-29'); + }); + }); + + 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'); + }); + }); +}); diff --git a/kits/rokt/test/src/storage.spec.ts b/kits/rokt/test/src/storage.spec.ts new file mode 100644 index 000000000..5f51fa8db --- /dev/null +++ b/kits/rokt/test/src/storage.spec.ts @@ -0,0 +1,220 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { + readJSON, + writeJSON, + removeKey, + readNamespacedField, + writeNamespacedField, + removeNamespacedField, + writeNamespacedFieldWithinBudget, +} 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('writeNamespacedFieldWithinBudget', () => { + const NAMESPACE_KEY = 'mp-rokt-kit'; + const BUDGET = 1024; + + it('writes all records unchanged when under budget', () => { + const records = [{ id: 1 }, { id: 2 }]; + expect(writeNamespacedFieldWithinBudget(NAMESPACE_KEY, 'pageViews', records, BUDGET)).toBe(true); + expect(records).toHaveLength(2); + expect(readNamespacedField(NAMESPACE_KEY, 'pageViews')).toEqual([{ id: 1 }, { id: 2 }]); + }); + + it('evicts oldest-first until the serialized size is within budget', () => { + const big = 'x'.repeat(300); + const records = [ + { id: 'a', v: big }, + { id: 'b', v: big }, + { id: 'c', v: big }, + { id: 'd', v: big }, + ]; + expect(writeNamespacedFieldWithinBudget(NAMESPACE_KEY, 'pageViews', records, BUDGET)).toBe(true); + + const stored = readNamespacedField(NAMESPACE_KEY, 'pageViews') as { id: string }[]; + expect(JSON.stringify(stored).length).toBeLessThanOrEqual(BUDGET); + expect(stored[stored.length - 1].id).toBe('d'); + expect(stored.map((r) => r.id)).not.toContain('a'); + }); + + it('keeps at least the newest record even when it alone exceeds the budget', () => { + const records = [{ id: 'newest', v: 'x'.repeat(BUDGET * 2) }]; + expect(writeNamespacedFieldWithinBudget(NAMESPACE_KEY, 'pageViews', records, BUDGET)).toBe(true); + expect(readNamespacedField(NAMESPACE_KEY, 'pageViews')).toEqual([{ id: 'newest', v: 'x'.repeat(BUDGET * 2) }]); + }); + + it('evicts and retries when writes fail, then persists', () => { + let calls = 0; + const realSetItem = Storage.prototype.setItem; + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(function (this: Storage, key: string, value: string) { + calls += 1; + if (calls <= 2) { + throw new DOMException('quota', 'QuotaExceededError'); + } + return realSetItem.call(this, key, value); + }); + + const records = [{ id: 'a' }, { id: 'b' }, { id: 'c' }, { id: 'd' }]; + expect(writeNamespacedFieldWithinBudget(NAMESPACE_KEY, 'pageViews', records, BUDGET)).toBe(true); + + const stored = readNamespacedField(NAMESPACE_KEY, 'pageViews') as { id: string }[]; + // 2 failed writes evict the oldest twice (a, then b), leaving [c, d]. + expect(stored.map((r) => r.id)).toEqual(['c', 'd']); + }); + + it('returns false when even a single record cannot be written', () => { + vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { + throw new DOMException('quota', 'QuotaExceededError'); + }); + const records = [{ id: 'a' }, { id: 'b' }]; + expect(writeNamespacedFieldWithinBudget(NAMESPACE_KEY, 'pageViews', records, BUDGET)).toBe(false); + expect(records).toEqual([{ id: 'a' }, { id: 'b' }]); + }); + }); +}); diff --git a/kits/rokt/test/src/tests.spec.ts b/kits/rokt/test/src/tests.spec.ts index dc18813c7..636dbf3e9 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 */ @@ -5638,10 +5639,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 +5686,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 +5866,12 @@ describe('Rokt Forwarder', () => { expect(readStoredPageViews()).toBeNull(); }); - it('caps the stored history at 25 records, evicting oldest first', async () => { + // The budget is a code constant (PAGE_VIEWS_MAX_LENGTH = 100 * 1024), + // measured as JSON string length. Not exported, so tests reference the + // literal value. + const PAGE_VIEWS_MAX_LENGTH = 100 * 1024; + + it('caps the stored history by byte budget, evicting oldest first', async () => { await (window as any).mParticle.forwarder.init( { accountId: '123456', @@ -5761,22 +5884,61 @@ describe('Rokt Forwarder', () => { await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + // Pre-seed a history that already exceeds the byte budget, using long + // synthetic URLs so a handful of records is enough (~5KB each × 30 ≈ + // 150KB). Seeding directly avoids ~1000 process() calls to reach 100KB. + const bigUrl = 'https://example.com/' + 'a'.repeat(5000); + 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: bigUrl, sourceMessageId: 'seed-' + i, timestamp: 1712345678000 + i }); } + seedStoredPageViews(seed); + + // One more capture triggers byte-budget eviction on write. + (window as any).mParticle.forwarder.process({ + EventName: 'Newest', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + SourceMessageId: 'newest', + Timestamp: 1712345678999, + ActiveTimeOnSite: 1, + }); + + const stored = readStoredPageViews(); + expect(JSON.stringify(stored).length).toBeLessThanOrEqual(PAGE_VIEWS_MAX_LENGTH); + expect(stored.length).toBeLessThan(31); + expect(stored[stored.length - 1].sourceMessageId).toBe('newest'); + expect(stored[0].sourceMessageId).not.toBe('seed-0'); + }); + + it('retains at least the newest page view even if an older record alone exceeds the budget', async () => { + await (window as any).mParticle.forwarder.init( + { + accountId: '123456', + }, + reportService.cb, + true, + null, + {}, + ); + + await waitForCondition(() => (window as any).mParticle.Rokt.attachKitCalled); + + const hugeUrl = 'https://example.com/' + 'a'.repeat(PAGE_VIEWS_MAX_LENGTH + 1); + seedStoredPageViews([{ pageUrl: hugeUrl, 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(); - // 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.length).toBe(1); + expect(stored[0].sourceMessageId).toBe('newest'); }); it('clears the stored page-view history on a SessionEnd event', async () => { @@ -5815,6 +5977,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 +6176,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 +6190,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 +6212,69 @@ 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('evicts oldest and retries when the browser quota is exceeded, then persists', 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); + + // writeNamespacedField swallows the quota error and returns false, so + // failing the first 3 writes drives writePageViews's evict-and-retry. + let calls = 0; + const realSetItem = Storage.prototype.setItem; + const setItemSpy = vi.spyOn(Storage.prototype, 'setItem').mockImplementation(function ( + this: Storage, + key: string, + value: string, + ) { + calls += 1; + if (calls <= 3) { + throw new DOMException('quota', 'QuotaExceededError'); + } + return realSetItem.call(this, key, value); + }); + + try { + (window as any).mParticle.forwarder.process({ + EventName: 'Newest', + EventCategory: EventType.Unknown, + EventDataType: MessageType.PageView, + SourceMessageId: 'newest', + Timestamp: 1712345678999, + ActiveTimeOnSite: 1, + }); + } finally { + setItemSpy.mockRestore(); + } + + const stored = readStoredPageViews(); + // 5 seed + 1 newest = 6, minus 3 evicted across the 3 failed retries = 3. + expect(stored.length).toBe(3); + expect(stored[stored.length - 1].sourceMessageId).toBe('newest'); + expect(stored[0].sourceMessageId).toBe('seed-3'); + }); + it('captures page views independently of setLocalSessionAttribute availability', async () => { await (window as any).mParticle.forwarder.init( { @@ -5989,6 +6352,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 +6557,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 +6598,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 +6634,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. diff --git a/kits/rokt/test/src/utils.spec.ts b/kits/rokt/test/src/utils.spec.ts new file mode 100644 index 000000000..9c53956c7 --- /dev/null +++ b/kits/rokt/test/src/utils.spec.ts @@ -0,0 +1,65 @@ +import { describe, it, expect } from 'vitest'; +import { isObject, isString, isEmpty } 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('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); + }); + }); +});