@@ -184,16 +184,16 @@ export default class RoktManager {
184184 this . captureTiming ( PerformanceMarkType . JointSdkSelectPlacements ) ;
185185 }
186186
187- if ( ! this . isReady ( ) ) {
187+ // Queue if kit isn't ready OR if identity is in flight
188+ if ( ! this . isReady ( ) || this . store ?. identityCallInFlight ) {
188189 return this . deferredCall < IRoktSelection > ( 'selectPlacements' , options ) ;
189190 }
190191
191192 try {
192193 const { attributes } = options ;
193194 const sandboxValue = attributes ?. sandbox || null ;
194195 const mappedAttributes = this . mapPlacementAttributes ( attributes , this . placementAttributesMapping ) ;
195-
196- // Get current user identities
196+
197197 this . currentUser = this . identityService . getCurrentUser ( ) ;
198198 const currentUserIdentities = this . currentUser ?. getUserIdentities ( ) ?. userIdentities || { } ;
199199
@@ -204,9 +204,16 @@ export default class RoktManager {
204204 let newHashedEmail : string | undefined ;
205205
206206 // Hashed email identity is valid if it is set to Other-Other10
207- if ( this . mappedEmailShaIdentityType && IdentityType . getIdentityType ( this . mappedEmailShaIdentityType ) !== false ) {
207+ const isValidHashedEmailIdentityType =
208+ this . mappedEmailShaIdentityType &&
209+ IdentityType . getIdentityType ( this . mappedEmailShaIdentityType ) !== false ;
210+
211+ if ( isValidHashedEmailIdentityType ) {
208212 currentHashedEmail = currentUserIdentities [ this . mappedEmailShaIdentityType ] ;
209- newHashedEmail = mappedAttributes [ 'emailsha256' ] as string || mappedAttributes [ this . mappedEmailShaIdentityType ] as string || undefined ;
213+ newHashedEmail =
214+ ( mappedAttributes [ 'emailsha256' ] as string ) ||
215+ ( mappedAttributes [ this . mappedEmailShaIdentityType ] as string ) ||
216+ undefined ;
210217 }
211218
212219 const emailChanged = this . hasIdentityChanged ( currentEmail , newEmail ) ;
@@ -242,14 +249,37 @@ export default class RoktManager {
242249 this . logger . error ( 'Failed to identify user with new email: ' + JSON . stringify ( error ) ) ;
243250 }
244251 }
252+
253+ // Refresh current user identities to ensure we have the latest values before building enrichedAttributes
254+ this . currentUser = this . identityService . getCurrentUser ( ) ;
255+ const finalUserIdentities = this . currentUser ?. getUserIdentities ( ) ?. userIdentities || { } ;
245256
246257 this . setUserAttributes ( mappedAttributes ) ;
247258
248- const enrichedAttributes = {
259+ const enrichedAttributes : RoktAttributes = {
249260 ...mappedAttributes ,
250261 ...( sandboxValue !== null ? { sandbox : sandboxValue } : { } ) ,
251262 } ;
252263
264+ // Propagate email from current user identities if not already in attributes
265+ if ( finalUserIdentities . email && ! enrichedAttributes . email ) {
266+ enrichedAttributes . email = finalUserIdentities . email ;
267+ }
268+
269+ // Propagate emailsha256 from current user identities if not already in attributes
270+ if ( isValidHashedEmailIdentityType ) {
271+ const hashedEmail = finalUserIdentities [ this . mappedEmailShaIdentityType ] ;
272+ if (
273+ hashedEmail &&
274+ ! enrichedAttributes . emailsha256 &&
275+ ! enrichedAttributes [ this . mappedEmailShaIdentityType ]
276+ ) {
277+ enrichedAttributes . emailsha256 = hashedEmail ;
278+ }
279+ }
280+
281+ this . filters . filteredUser = this . currentUser || this . filters . filteredUser || null ;
282+
253283 const enrichedOptions = {
254284 ...options ,
255285 attributes : enrichedAttributes ,
@@ -405,14 +435,27 @@ export default class RoktManager {
405435 return mappedAttributes ;
406436 }
407437
438+ public onIdentityComplete ( ) : void {
439+ if ( this . isReady ( ) ) {
440+ this . currentUser = this . identityService . getCurrentUser ( ) ;
441+ // Process any queued selectPlacements calls that were waiting for identity
442+ this . processMessageQueue ( ) ;
443+ }
444+ }
445+
408446 private processMessageQueue ( ) : void {
409447 if ( ! this . isReady ( ) || this . messageQueue . size === 0 ) {
410448 return ;
411449 }
412450
413451 this . logger ?. verbose ( `RoktManager: Processing ${ this . messageQueue . size } queued messages` ) ;
414452
415- this . messageQueue . forEach ( ( message ) => {
453+ const messagesToProcess = Array . from ( this . messageQueue . values ( ) ) ;
454+
455+ // Clear the queue immediately to prevent re-processing
456+ this . messageQueue . clear ( ) ;
457+
458+ messagesToProcess . forEach ( ( message ) => {
416459 if ( ! ( message . methodName in this ) || ! isFunction ( this [ message . methodName ] ) ) {
417460 this . logger ?. error ( `RoktManager: Method ${ message . methodName } not found` ) ;
418461
@@ -421,18 +464,32 @@ export default class RoktManager {
421464
422465 this . logger ?. verbose ( `RoktManager: Processing queued message: ${ message . methodName } with payload: ${ JSON . stringify ( message . payload ) } ` ) ;
423466
467+ // Capture resolve/reject functions before async processing
468+ const resolve = message . resolve ;
469+ const reject = message . reject ;
470+
471+ const handleError = ( error : unknown ) => {
472+ const errorMessage = error instanceof Error ? error . message : String ( error ) ;
473+ this . logger ?. error ( `RoktManager: Error processing message '${ message . methodName } ': ${ errorMessage } ` ) ;
474+ if ( reject ) {
475+ reject ( error ) ;
476+ }
477+ } ;
478+
424479 try {
425480 const result = ( this [ message . methodName ] as Function ) ( message . payload ) ;
426- this . completePendingPromise ( message . messageId , result ) ;
481+ // Handle both sync and async methods
482+ Promise . resolve ( result )
483+ . then ( ( resolvedResult ) => {
484+ if ( resolve ) {
485+ resolve ( resolvedResult ) ;
486+ }
487+ } )
488+ . catch ( handleError ) ;
427489 } catch ( error ) {
428- const errorMessage = error instanceof Error ? error . message : String ( error ) ;
429- this . logger ?. error ( `RoktManager: Error processing message '${ message . methodName } ': ${ errorMessage } ` ) ;
430- this . completePendingPromise ( message . messageId , Promise . reject ( error ) ) ;
490+ handleError ( error ) ;
431491 }
432492 } ) ;
433-
434- // Clear the queue after processing all messages
435- this . messageQueue . clear ( ) ;
436493 }
437494
438495 private queueMessage ( message : IRoktMessage ) : void {
@@ -453,22 +510,6 @@ export default class RoktManager {
453510 } ) ;
454511 }
455512
456- private completePendingPromise ( messageId : string | undefined , resultOrError : any ) : void {
457- if ( ! messageId || ! this . messageQueue . has ( messageId ) ) {
458- return ;
459- }
460-
461- const message = this . messageQueue . get ( messageId ) ! ;
462-
463- if ( message . resolve ) {
464- Promise . resolve ( resultOrError )
465- . then ( ( result ) => message . resolve ! ( result ) )
466- . catch ( ( error ) => message . reject ! ( error ) ) ;
467- }
468-
469- this . messageQueue . delete ( messageId ) ;
470- }
471-
472513 /**
473514 * Hashes a string input using SHA-256 and returns the hex digest
474515 * Uses the Web Crypto API for secure hashing
0 commit comments