-
Notifications
You must be signed in to change notification settings - Fork 16
feat(MSDK-4525): add controllerId to React Native bridge options #239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,20 @@ export class UsercentricsOptions { | |
| networkMode?: NetworkMode; | ||
| consentMediation?: Boolean; | ||
| initTimeoutMillis?: number; | ||
| /** | ||
| * Optional controllerId to inject at SDK initialisation. | ||
| * | ||
| * Use this to preserve user identity across login/logout flows that clear local consent | ||
| * storage. Store the controllerId (via `Usercentrics.getControllerId()`) server-side after | ||
| * the first successful init, then pass it here on every subsequent login. The SDK will skip | ||
| * generating a new ID and use this value instead. It is persisted to local storage, so | ||
| * subsequent re-initialisations without this option continue to use it. | ||
| * | ||
| * The value must be a 64-character lowercase hexadecimal string (the format produced | ||
| * internally by the SDK). Invalid values are ignored with a warning log and the SDK falls | ||
| * back to its normal ID resolution (stored → generated). | ||
|
Comment on lines
+13
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: The public contract now states that every controller ID must be a 64-character lowercase hexadecimal value, but this repository already exposes controller IDs with a different format, including the mixed-case 40-character value in the existing user-session fixture. Consumers restoring an existing ID obtained from Severity Level: Major
|
||
| */ | ||
| controllerId?: string; | ||
|
Comment on lines
+13
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [VALIDATION] The docstring documents that controllerId must be a 64-character lowercase hex string, but there is no client-side validation in the JS/TS layer. Please add a light validation (regex) in the constructor or where the options are serialized to the native bridge and either: 1) reject/throw for obviously invalid values; or 2) log a clear warning and drop the invalid value before sending to native. Also add a unit test that passes an invalid controllerId (wrong length / invalid characters) and asserts it is not forwarded to the native module (or that a warning is emitted). This provides faster feedback to integrators instead of relying only on the native SDK to ignore invalid values. export class UsercentricsOptions {
// ...existing fields...
/**
* Optional controllerId to inject at SDK initialisation.
*
* The value must be a 64-character lowercase hexadecimal string (the format produced
* internally by the SDK). Invalid values are ignored with a warning log and the SDK falls
* back to its normal ID resolution (stored → generated).
*/
controllerId?: string;
private static readonly CONTROLLER_ID_REGEX = /^[0-9a-f]{64}$/;
constructor({
settingsId = "",
ruleSetId = "",
defaultLanguage = undefined,
loggerLevel = undefined,
timeoutMillis = undefined,
version = undefined,
networkMode = undefined,
consentMediation = undefined,
initTimeoutMillis = undefined,
controllerId = undefined,
bannerCustomization = undefined,
}: {
settingsId?: string;
ruleSetId?: string;
defaultLanguage?: string;
loggerLevel?: UsercentricsLoggerLevel;
timeoutMillis?: number;
version?: string;
networkMode?: NetworkMode;
consentMediation?: Boolean;
initTimeoutMillis?: number;
controllerId?: string;
bannerCustomization?: BannerInitCustomization;
}) {
this.settingsId = settingsId;
this.ruleSetId = ruleSetId;
this.defaultLanguage = defaultLanguage;
this.loggerLevel = loggerLevel;
this.timeoutMillis = timeoutMillis;
this.version = version;
this.networkMode = networkMode;
this.consentMediation = consentMediation;
this.initTimeoutMillis = initTimeoutMillis;
if (controllerId == null) {
this.controllerId = undefined;
} else if (UsercentricsOptions.CONTROLLER_ID_REGEX.test(controllerId)) {
this.controllerId = controllerId;
} else {
// eslint-disable-next-line no-console
console.warn(
"[UsercentricsOptions] Ignoring invalid controllerId. Expected 64-char lowercase hex string."
);
this.controllerId = undefined;
}
this.bannerCustomization = bannerCustomization;
}
}
// And in src/__tests__/index.test.ts add something like:
test('controllerId invalid format is dropped and warns', () => {
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
const options = new UsercentricsOptions({
settingsId: 'abc',
ruleSetId: 'qwer',
// invalid: too short and contains non-hex character
controllerId: 'XYZ',
});
expect(options.controllerId).toBeUndefined();
expect(warnSpy).toHaveBeenCalledWith(
'[UsercentricsOptions] Ignoring invalid controllerId. Expected 64-char lowercase hex string.'
);
warnSpy.mockRestore();
}); |
||
| /** | ||
| * @deprecated bannerCustomization is deprecated and will be removed in a future release. | ||
| * Configure banner appearance via the Usercentrics dashboard instead. | ||
|
|
@@ -26,6 +40,7 @@ export class UsercentricsOptions { | |
| networkMode = undefined, | ||
| consentMediation = undefined, | ||
| initTimeoutMillis = undefined, | ||
| controllerId = undefined, | ||
| bannerCustomization = undefined | ||
| }: { | ||
| settingsId?: string, | ||
|
|
@@ -37,6 +52,7 @@ export class UsercentricsOptions { | |
| networkMode?: NetworkMode, | ||
| consentMediation?: Boolean, | ||
| initTimeoutMillis?: number, | ||
| controllerId?: string, | ||
| bannerCustomization?: BannerInitCustomization | ||
| }) { | ||
| this.settingsId = settingsId; | ||
|
|
@@ -48,6 +64,7 @@ export class UsercentricsOptions { | |
| this.networkMode = networkMode | ||
| this.consentMediation = consentMediation | ||
| this.initTimeoutMillis = initTimeoutMillis | ||
| this.controllerId = controllerId | ||
| this.bannerCustomization = bannerCustomization | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🔎 Supported by static analysis
🏁 Script executed:
Repository: Usercentrics/react-native-sdk
Length of output: 5266
🏁 Script executed:
Repository: Usercentrics/react-native-sdk
Length of output: 50387
🌐 Web query:
Usercentrics Android SDK 2.30.0 UsercentricsOptions controllerId💡 Result:
In the Usercentrics Android SDK, the controllerId is a unique identifier generated by Usercentrics to track a specific user's consent history [1][2]. While you can access the current controllerId via the SDK settings after initialization [3][4], it is not a parameter configured directly within UsercentricsOptions [1]. UsercentricsOptions is used during SDK initialization to define global configuration settings, such as the settingsId, default language, and other initialization parameters [1][5]. The controllerId is not passed into UsercentricsOptions to initialize the SDK; rather, it is handled through specific session management methods [3][4]. To utilize a controllerId for cross-device or session persistence, you have two primary methods: 1. Restore Session (Recommended): Use the restoreUserSession method after initializing the SDK to load a user's existing consent history by passing the controllerId [2][3][4]. 2. Retrieve Current ID: After the SDK is initialized, you can retrieve the currently active controllerId from the settings object using usercentrics.getSettings.controllerId [3][4]. SDK version 2.30.0, released in August 2026, continues to support these established patterns for session and consent management [6][7]. If you need to reset the user's session (e.g., upon logout), you can call clearUserSession, which will cause a new controllerId to be generated upon the next initialization [3][8].
Citations:
🌐 Web query:
Usercentrics iOS SDK 2.30.0 UsercentricsOptions controllerId💡 Result:
In the current Usercentrics Apps SDK (v2), the controllerId is not a property of the UsercentricsOptions class [1]. The UsercentricsOptions class is primarily used for SDK initialization and configuration, accepting parameters such as settingsID, defaultLanguage, version, timeoutMillis, loggerLevel, rulesetId, and consentMediation [1]. To manage or restore a user's consent session via the controllerId, you should follow these patterns: 1. Retrieval: You can obtain the current controllerId after initialization by calling UsercentricsCore.shared.getControllerId [2][1]. 2. Restoration: To restore a user's session (e.g., across platforms), you use the dedicated restoreUserSession method rather than passing the ID through initial configuration options [2][1]: UsercentricsCore.shared.restoreUserSession(controllerId: controllerId) { status in // Handle restored consent status } onFailure: { error in // Handle error } If you are referencing legacy SDK documentation or migration guides, note that passing a controllerId during initialization was a pattern in earlier versions, but it has been replaced by the explicit restoreUserSession workflow in the modern v2+ SDK architecture [3][2].
Citations:
Remove the unsupported
controllerIdassignments.UsercentricsOptionsin the resolved v2 Android and iOS SDKs does not declarecontrollerId. The assignments in both adapters can therefore fail compilation. UserestoreUserSession(controllerId:)for session restoration instead.📍 Affects 2 files
android/src/main/java/com/usercentrics/reactnative/extensions/UserOptionsExtensions.kt#L59-L62(this comment)ios/Extensions/UsercentricsOptions+Dict.swift#L44-L47🤖 Prompt for AI Agents