Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 8 additions & 53 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
"@types/jest": "^29.5.1",
"@types/jest-expect-message": "^1.1.0",
"@types/mocha": "^9.0.0",
"@types/mparticle__web-sdk": "^2.16.1",
"@types/mparticle__web-sdk": "^2.66.0",
"@types/node": "^20.1.0",
"babel-preset-minify": "^0.5.1",
"browser-sync": "^2.26.3",
Expand Down
50 changes: 46 additions & 4 deletions src/identity-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,48 @@ const getExpireTimestamp = (maxAge: number = ONE_DAY_IN_SECONDS): number =>
const parseIdentityResponse = (responseText: string): IdentityResultBody =>
responseText ? JSON.parse(responseText) : ({} as IdentityResultBody);

type Sha256IdentityAlias = 'email_sha256' | 'mobile_sha256';

const SHA256_IDENTITY_ALIASES: Readonly<
Record<Sha256IdentityAlias, keyof UserIdentities>
> = {
email_sha256: 'other',
mobile_sha256: 'other2',
};
Comment thread
cursor[bot] marked this conversation as resolved.

type UserIdentitiesWithAliases = UserIdentities &
Partial<Record<Sha256IdentityAlias, string | null>>;

export const normalizeUserIdentityKeys = (
userIdentities: UserIdentitiesWithAliases
): UserIdentities => {
const normalized: UserIdentitiesWithAliases = { ...userIdentities };
(Object.keys(SHA256_IDENTITY_ALIASES) as Sha256IdentityAlias[]).forEach(
(alias) => {
if (alias in normalized) {
const value = normalized[alias];
delete normalized[alias];
normalized[SHA256_IDENTITY_ALIASES[alias]] = value;
}
}
);
return normalized;
};

Comment thread
cursor[bot] marked this conversation as resolved.
// Compare two identity objects by key and value, independent of
// object key insertion order. The two sides come from different sources
// (numeric IdentityType iteration vs. partner-provided / alias-normalized
// order)
const identitiesEqual = (
a?: UserIdentities,
b?: UserIdentities
): boolean => {
const aKeys = Object.keys(a ?? {});
const bKeys = Object.keys(b ?? {});
if (aKeys.length !== bKeys.length) return false;
return aKeys.every((key) => a[key] === b[key]);
};

export const hasIdentityRequestChanged = (
currentUser: IMParticleUser,
newIdentityRequest: IdentityApiData
Expand All @@ -300,11 +342,11 @@ export const hasIdentityRequestChanged = (
const currentUserIdentities =
currentUser.getUserIdentities().userIdentities;

const newIdentities = newIdentityRequest.userIdentities;

return (
JSON.stringify(currentUserIdentities) !== JSON.stringify(newIdentities)
const newIdentities = normalizeUserIdentityKeys(
newIdentityRequest.userIdentities
);
Comment thread
cursor[bot] marked this conversation as resolved.

return !identitiesEqual(currentUserIdentities, newIdentities);
};

/**
Expand Down
13 changes: 12 additions & 1 deletion src/identity.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import Constants, { HTTP_OK } from './constants';

Check failure on line 1 in src/identity.js

View workflow job for this annotation

GitHub Actions / Core Tests / Core SDK Tests

Declaration emit for this file requires using private name 'mParticleUserCart'. An explicit type annotation may unblock declaration emit.

Check failure on line 1 in src/identity.js

View workflow job for this annotation

GitHub Actions / Core Tests / Core SDK Tests

Declaration emit for this file requires using private name 'mParticleUser'. An explicit type annotation may unblock declaration emit.
import Types, { IdentityType } from './types';
import {
cacheOrClearIdCache,
createKnownIdentities,
executeSearchRequest,
normalizeUserIdentityKeys,
tryCacheIdentity,
} from './identity-utils';
import AudienceManager from './audienceManager';
Expand Down Expand Up @@ -35,11 +36,21 @@
);

// First, remove any falsy identity values and warn about them
const cleanedIdentityApiData = mpInstance._Helpers.Validators.removeFalsyIdentityValues(
const removedFalsyIdentityData = mpInstance._Helpers.Validators.removeFalsyIdentityValues(
identityApiData,
mpInstance.Logger
);

// Normalize convenience aliases (email_sha256 → other, mobile_sha256 → other2)
const cleanedIdentityApiData = removedFalsyIdentityData?.userIdentities
? {
...removedFalsyIdentityData,
userIdentities: normalizeUserIdentityKeys(
removedFalsyIdentityData.userIdentities
),
}
: removedFalsyIdentityData;

var identityValidationResult = mpInstance._Helpers.Validators.validateIdentities(
cleanedIdentityApiData,
method
Expand Down
10 changes: 5 additions & 5 deletions src/sdkRuntimeModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,9 @@ export interface SDKProductAction {
}

export interface SDKProduct {
Sku?: string;
Name?: string;
Price?: number;
Sku: string;
Name: string;
Price: number;
Quantity?: number;
Brand?: string;
Variant?: string;
Expand All @@ -173,7 +173,7 @@ export interface SDKProduct {
TotalAmount?: number;

// https://go.mparticle.com/work/SQDSDKS-4801
Attributes?: Record<string, unknown> | null;
Attributes?: Record<string, unknown>;
}

// https://go.mparticle.com/work/SQDSDKS-6949
Expand Down Expand Up @@ -306,7 +306,7 @@ export const LogLevelType = {
// Currently, this extends MPConfiguration in @types/mparticle__web-sdk
// and the two will be merged in once the Store module is refactored
export interface SDKInitConfig
extends Omit<MPConfiguration, 'dataPlan' | 'logLevel'> {
extends Omit<MPConfiguration, 'dataPlan' | 'logLevel' | 'identityCallback'> {
Copy link
Copy Markdown
Member

@rmi22186 rmi22186 May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was required due to build issues with definitelytyped - the local SDK is actually typed more strongly and is more accurate than DT's definition. Once we deprecated DT, this will be resolved.

dataPlan?: DataPlanConfig | KitBlockerDataPlan; // TODO: These should be eventually split into two different attributes
logLevel?: LogLevelType;

Expand Down
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ export const IdentityType = {
return IdentityType.PhoneNumber2;
case 'phone_number_3':
return IdentityType.PhoneNumber3;
case 'email_sha256':
return IdentityType.Other;
case 'mobile_sha256':
return IdentityType.Other2;
default:
return false;
}
Expand Down
Loading
Loading