Skip to content

Commit 60c1ca6

Browse files
fix: SDKE-846 - User Identity through selectPlacements (#1146)
1 parent 17e4115 commit 60c1ca6

3 files changed

Lines changed: 763 additions & 96 deletions

File tree

src/identity.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,7 +1372,6 @@ export default function Identity(mpInstance) {
13721372
: {};
13731373
let mpidIsNotInCookies;
13741374
let identityApiResult;
1375-
13761375
let newUser;
13771376
let newIdentitiesByType = {};
13781377

@@ -1577,9 +1576,7 @@ export default function Identity(mpInstance) {
15771576
}
15781577
mpInstance._Store.isInitialized = true;
15791578

1580-
if (mpInstance._RoktManager.isReady()) {
1581-
mpInstance._RoktManager.currentUser = mpInstance.Identity.getCurrentUser();
1582-
}
1579+
mpInstance._RoktManager.onIdentityComplete();
15831580

15841581
mpInstance._preInit.readyQueue = processReadyQueue(
15851582
mpInstance._preInit.readyQueue

src/roktManager.ts

Lines changed: 71 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)