Skip to content

refactor: migrate identity module to TS#1248

Open
jaissica12 wants to merge 3 commits into
developmentfrom
refactor/SDKE-1103-migrate-identity-module-to-ts
Open

refactor: migrate identity module to TS#1248
jaissica12 wants to merge 3 commits into
developmentfrom
refactor/SDKE-1103-migrate-identity-module-to-ts

Conversation

@jaissica12
Copy link
Copy Markdown
Contributor

@jaissica12 jaissica12 commented Apr 13, 2026

Background

  • The identity.js module was one of the remaining JavaScript files in the SDK. As part of the ongoing TypeScript migration effort (SDKE-1103), it needed to be converted to TypeScript to improve type safety and maintainability. This is a direct migration with no behavior, API, or breaking changes.

What Has Changed

  • Renamed src/identity.js to src/identity.ts with type annotations added to all functions, parameters, and variables
  • Corrected pre-existing type mismatches in identity.interfaces.ts, identityApiClient.ts, persistence.interfaces.ts, store.ts, and mp-instance.ts where interfaces didn't match actual runtime behavior
  • Updated test files to align with corrected interface types
  • No runtime logic, public API, or deprecated behavior was changed — compiled output is functionally identical

Testing

  • All existing Karma + Mocha integration tests pass
  • All existing Jest unit tests pass
  • Manual end-to-end testing performed via rokt-web-playground with local SDK build, covering:
    • SDK initialization and identify callback (httpCode 200)
    • Login with multiple identity types (email, customerid, facebook, mobile_number)
    • Modify with no-op (httpCode 400 — expected) and actual changes (httpCode 200)
    • Logout → anonymous MPID transition (ephemeral, is_logged_in: false)
    • Anonymous user: page views, commerce events, user attributes all fire with correct anonymous MPID and empty identities
    • Re-login from anonymous state restores known MPID with full identity set
    • User attribute set/remove with forwarder callbacks (Rokt Kit)
    • Session end/start across identity transitions
    • All event batches uploaded successfully (202) with correct MPID and identity payloads

Screenshots/Video

Screenshot 2026-05-20 at 4 01 44 PM Screenshot 2026-05-20 at 4 02 06 PM Screenshot 2026-05-20 at 4 02 42 PM Screenshot 2026-05-20 at 4 03 04 PM

Checklist

  • I have performed a self-review of my own code.
  • I have made corresponding changes to the documentation.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have tested this locally.

Additional Notes

  • The main self = this pattern in the Identity constructor (~31 usages) was intentionally left as-is for a follow-up refactor to arrow functions, to keep this PR focused on the JS→TS migration only.
  • varconst/let replacements and removal of unnecessary type assertions were included as part of SonarCloud compliance.

Reference Issue (For employees only. Ignore if you are an outside contributor)

@jaissica12 jaissica12 force-pushed the refactor/SDKE-1103-migrate-identity-module-to-ts branch from 54ee61d to 6013f98 Compare May 12, 2026 21:20
@jaissica12 jaissica12 force-pushed the refactor/SDKE-1103-migrate-identity-module-to-ts branch from 6013f98 to 1cdacb3 Compare May 12, 2026 21:36
@sonarqubecloud
Copy link
Copy Markdown

@jaissica12 jaissica12 marked this pull request as ready for review May 20, 2026 19:58
@jaissica12 jaissica12 requested a review from a team as a code owner May 20, 2026 19:58
@cursor
Copy link
Copy Markdown

cursor Bot commented May 20, 2026

PR Summary

Medium Risk
Touches the SDK’s identity/login/modify/logout and persistence interfaces; while intended as a type-only migration, small signature/shape tweaks (e.g., request field names and optional params) could surface integration mismatches at compile/runtime boundaries.

Overview
Migrates the core Identity module from JS to TypeScript (identity.ts), adding explicit types across identity flows (identify/login/logout/modify, user object methods, aliasing, and search) and replacing many untyped var usages with typed const/let.

Adjusts several public/internal type contracts to match runtime behavior, including identity request shapes (context now Context | null, request_timestamp_ms naming), broader identity/attribute value typing, identity caching callback types, and updated client/persistence/store/mp-instance interfaces (e.g., sendIdentityRequest accepting modify requests and optional knownIdentities, persistence firstSeen/lastSeen types, and _IdentityAPIClient typed as IIdentityApiClient). Tests are updated accordingly.

Reviewed by Cursor Bugbot for commit 85a0f3c. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8f4c21b. Configure here.

Comment thread src/identity.ts
const aliasRequestMessage = mpInstance._Identity.IdentityRequest.createAliasNetworkRequest(
aliasRequest
);
) as IAliasRequest;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incorrect type cast masks alias network request shape

Medium Severity

The return value of createAliasNetworkRequest (which has fields like request_id, request_type, api_key, data) is cast as IAliasRequest, but IAliasRequest has a completely different shape (destinationMpid, sourceMpid, startTime, endTime). This incorrect assertion propagates through sendAliasRequest, whose parameter is also typed as IAliasRequest. While no runtime breakage occurs today because the object is only JSON-stringified, the misleading type could cause silent undefined values if anyone later accesses aliasRequest.destinationMpid inside sendAliasRequest trusting the declared type.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8f4c21b. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Will address this in follow-up branch fix/SDKE-1103-alias-network-request-type by introducing IAliasNetworkRequest interface and updates sendAliasRequest + tests to use it.

@sonarqubecloud
Copy link
Copy Markdown

Comment thread src/identity-utils.ts
UserIdentities,
IdentityCallback,
} from '@mparticle/web-sdk';
import { IdentityCallback } from './identity-user-interfaces';
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Clean up the imports

Comment thread src/identity-utils.ts
identityApiData: IdentityApiData,
identityMethod: string,
knownIdentities: IKnownIdentities,
knownIdentities: IKnownIdentities | UserIdentities,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not sure if these overlap cleanly

environment: Environment;
request_id: string;
request_timestamp_unixtime_ms: number;
request_timestamp_ms: number;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why are we renaming this?

previousIdentities: UserIdentities,
newIdentitie: UserIdentities
): IIdentityAPIIdentityChangeData;
newIdentities: UserIdentities
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

How long has this typo been here? 😓

): IUserAttributeChangeEvent;
createUserIdentityChange(
identityType: SDKIdentityTypeEnum,
identityType: SDKIdentityTypeEnum | string,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think we should use string but really limit this to known types

Comment thread src/identity.ts
aliasRequest.destinationMpid
);
var aliasRequestMessage = mpInstance._Identity.IdentityRequest.createAliasNetworkRequest(
const aliasRequestMessage = mpInstance._Identity.IdentityRequest.createAliasNetworkRequest(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This cast hides a real mismatch and is worth fixing before merge.

createAliasNetworkRequest returns the network wire shape:

{ request_id, request_type: 'alias', environment, data: { destination_mpid, source_mpid, start_unixtime_ms, end_unixtime_ms, device_application_stamp } }

But IAliasRequest is:

{ destinationMpid, sourceMpid, startTime, endTime, scope? }

Those are completely different shapes. The as IAliasRequest cast tells the compiler "trust me, it's an IAliasRequest" and from there sendAliasRequest(aliasRequest: IAliasRequest) is happy. At runtime sendAliasRequest just does JSON.stringify(aliasRequest) (identityApiClient.ts:113) so the actual wire format is still right, but the types are lying.

callback: IdentityCallback,
method: IdentityAPIMethod
): IdentityPreProcessResult;
createAliasNetworkRequest(aliasRequest: IAliasRequest): object;
Copy link
Copy Markdown

@crisryantan crisryantan May 21, 2026

Choose a reason for hiding this comment

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

Tied to the earlier comment. These three methods all return object, which is barely better than any. The migration goal is type safety, so this is a missed opportunity.

If you do above for createAliasNetworkRequest, the same pattern applies here, declare proper interfaces for the native shapes and use them. convertToNative returning object | void is especially confusing because void is meaningless as a return type union with anything else (it means "ignore the return value"), and the actual code returns undefined explicitly. IdentityNativeRequest | undefined would be clearer.

Happy to defer to a follow-up if you want to keep this PR scoped, but please file a ticket so it does not slip.

Comment thread src/identity.ts
) {
if (forwarder.logOut) {
forwarder.logOut(evt);
const fwd = forwarder as unknown as Record<string, Function>;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Why the double-cast to Record<string, Function>? That tells the compiler "this thing is a string-keyed bag of arbitrary functions" which is the loosest possible cast and erases all type information from forwarder.

I checked ConfiguredKit in forwarders.interfaces.ts does not have a logOut method. So either:

  1. The old JS code (if (forwarder.logOut)) was always-falsy defensive code that never actually fired. If that is the case, this whole block can be deleted.
  2. There is a logOut method present at runtime on some kit implementations that the ConfiguredKit interface does not describe. If that is the case, add logOut?: (evt: SDKEvent) => void to ConfiguredKit and the cast disappears.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants