Skip to content

Release: 2.29.1 - #236

Merged
uc-brunosilva merged 3 commits into
masterfrom
release/2.29.1
Aug 6, 2026
Merged

uc-brunosilva merged 3 commits into
masterfrom
release/2.29.1

Conversation

@uc-brunosilva

Copy link
Copy Markdown
Collaborator

No description provided.

uc-brunosilva and others added 3 commits August 6, 2026 10:38
… 2.29.1

UsercentricsCore.denyAll and denyAllForTCF gained a new
unsavedServiceDecisions parameter in the native iOS SDK 2.29.1 (statistical
exception support). The Kotlin common interface defaults it to null, but
that default isn't carried over to the generated Swift/ObjC interop, so the
RN wrapper failed to compile against the bumped native SDK version.

Pass nil from RNUsercentricsModule.swift for both call sites, preserving
the existing public JS API and behavior (nil means no unsaved service
decisions are considered, matching pre-2.29.1 semantics per
UsercentricsSDKImpl.denyAll). Updated the FakeUsercentricsManager test
mock to match the new protocol signature.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Usercentrics 2.29.1 added a required isExempt parameter to several native
init signatures used by test mocks (UsercentricsService, ServiceConsentTemplate,
SubConsentTemplate, UsercentricsCategory). Update CMPData+Mock.swift to pass
isExempt: false, matching pre-2.29.1 (non-exempt) semantics.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@codeant-ai

codeant-ai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Skipping CodeAnt AI review — this PR is a back-merge between long-lived branches (release/2.29.1 → master). The diff here has already been reviewed when the underlying commits landed on the source branch, so re-running analysis would produce duplicate findings on already-reviewed code.

If you want to analyze this anyway (e.g. you resolved conflicts with new logic), comment @codeant-ai : review and CodeAnt will start a review.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@uc-brunosilva, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 6 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 16da336e-0136-41bb-b350-12a77413eb46

📥 Commits

Reviewing files that changed from the base of the PR and between fe65f38 and a1f00c8.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • sample/ios/Podfile.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • CHANGELOG.md
  • CLAUDE.md
  • android/build.gradle.kts
  • ios/Manager/UsercentricsManager.swift
  • ios/RNUsercentricsModule.swift
  • package.json
  • sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift
  • sample/ios/sampleTests/Mock/CMPData+Mock.swift

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Release 2.29.1: bump native SDKs and fix iOS interop build

⚙️ Configuration changes 🐞 Bug fix 📝 Documentation 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Bump React Native wrapper and native Android/iOS Usercentrics dependencies to 2.29.1.
• Fix iOS bridge compilation by passing newly-required denyAll parameters as nil.
• Update iOS test fakes/mocks for new native SDK initializer and protocol signatures.
Diagram

graph TD
  JS(("JS API")) --> RN["RNUsercentricsModule (iOS)"] --> MGR["UsercentricsManager"] --> CORE[("UsercentricsCore iOS SDK 2.29.1")]
  RN -->|"denyAll* passes nil"| MGR
  AND["android/build.gradle.kts"] -->|"usercentricsVersion=2.29.1"| AAR[("Android SDK 2.29.1")]
  POD["sample/ios/Podfile.lock"] -->|"UsercentricsUI=2.29.1"| CORE
  subgraph Legend
    direction LR
    _api(("App/JS")) ~~~ _mod["Bridge/Module"] ~~~ _sdk[("Native SDK")]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Expose unsavedServiceDecisions in the JS API
  • ➕ Allows RN consumers to leverage statistical-exception behavior explicitly
  • ➕ Avoids hard-coding nil in the bridge
  • ➖ Breaking/expanding public API surface for a release bump
  • ➖ Requires cross-platform API design and documentation
2. Add Swift overloads/defaults for denyAll* at the manager layer
  • ➕ Centralizes defaulting logic (nil) away from RN module call sites
  • ➕ Keeps JS API stable while future-proofing additional call sites
  • ➖ More indirection for minimal gain with only two call sites today
  • ➖ Still requires keeping protocol signatures in sync
3. Pin iOS native SDK below 2.29.1 temporarily
  • ➕ Avoids bridge changes in the short term
  • ➕ Can buy time if upstream SDK is unstable
  • ➖ Blocks adopting 2.29.1 fixes/features
  • ➖ Not viable for a 2.29.1 release tag

Recommendation: Keep the PR’s approach: pass nil for the new unsavedServiceDecisions parameter and update mocks to match new native signatures. This preserves the existing JS API/behavior while restoring iOS compilation against Usercentrics 2.29.1; exposing the parameter can be a separate feature PR if needed.

Files changed (10) +205 / -81

Bug fix (2) +9 / -8
UsercentricsManager.swiftAlign iOS manager API with 2.29.1 denyAll signatures +6/-6

Align iOS manager API with 2.29.1 denyAll signatures

• Extends the UsercentricsManager protocol and implementation to accept the newly-required unsavedServiceDecisions argument for denyAll and denyAllForTCF, forwarding it to UsercentricsCore.

ios/Manager/UsercentricsManager.swift

RNUsercentricsModule.swiftPass nil for new denyAll unsavedServiceDecisions parameter +3/-2

Pass nil for new denyAll unsavedServiceDecisions parameter

• Updates both denyAll and denyAllForTCF bridge call sites to provide unsavedServiceDecisions: nil, keeping the JS API unchanged while compiling against native SDK 2.29.1.

ios/RNUsercentricsModule.swift

Tests (2) +12 / -4
FakeUsercentricsManager.swiftUpdate fake manager for new denyAll method parameters +6/-2

Update fake manager for new denyAll method parameters

• Adjusts the test double to match the updated UsercentricsManager protocol by adding unsavedServiceDecisions plumbing for denyAll and denyAllForTCF.

sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift

CMPData+Mock.swiftAdd isExempt to iOS SDK mock initializers +6/-2

Add isExempt to iOS SDK mock initializers

• Updates mock constructors for multiple native SDK types to pass isExempt: false, matching the new required initializer argument introduced in Usercentrics 2.29.1.

sample/ios/sampleTests/Mock/CMPData+Mock.swift

Documentation (2) +115 / -0
CHANGELOG.mdAdd 2.29.1 changelog entry +20/-0

Add 2.29.1 changelog entry

• Adds release notes for 2.29.1 at the top of the changelog, including the Unity isExempt propagation feature and carrying forward 2.29.0 notes below.

CHANGELOG.md

CLAUDE.mdDocument repo and release bump procedure +95/-0

Document repo and release bump procedure

• Introduces a Claude Code guidance file describing the repo purpose, the expected release workflow, versioned files to bump, and CI/test expectations.

CLAUDE.md

Other (4) +69 / -69
build.gradle.ktsBump Android Usercentrics dependency to 2.29.1 +1/-1

Bump Android Usercentrics dependency to 2.29.1

• Updates the pinned Usercentrics Android SDK version constant from 2.28.2 to 2.29.1.

android/build.gradle.kts

package-lock.jsonRegenerate lockfile for 2.29.1 release +2/-2

Regenerate lockfile for 2.29.1 release

• Updates the root package-lock version fields to 2.29.1 to match the package version bump.

package-lock.json

package.jsonBump npm package and iOS package versions to 2.29.1 +2/-2

Bump npm package and iOS package versions to 2.29.1

• Updates version and iosPackageVersion from 2.28.2 to 2.29.1 for the release.

package.json

Podfile.lockBump sample iOS pods to Usercentrics 2.29.1 +64/-64

Bump sample iOS pods to Usercentrics 2.29.1

• Updates the sample app lockfile to react-native-usercentrics 2.29.1 and Usercentrics/UsercentricsUI 2.29.1, including expected checksum churn.

sample/ios/Podfile.lock

@pantoaibot

pantoaibot Bot commented Aug 6, 2026

Copy link
Copy Markdown

PR Summary:

Bump release to 2.29.1, add release notes and repo guidance; add support for passing per-service "unsavedServiceDecisions" through native denyAll APIs and update tests/mocks.

Changes:

  • CHANGELOG.md: added 2.29.1 release notes (features/fixes/chores summary).
  • New file CLAUDE.md: repository release/repo guidance and release checklist.
  • Version bumps:
    • package.json: version and iosPackageVersion -> 2.29.1
    • android/build.gradle.kts: usercentricsVersion -> "2.29.1"
  • iOS native bridge (ios/Manager/UsercentricsManager.swift):
    • Added optional unsavedServiceDecisions: [String: KotlinBoolean]? parameter to denyAllForTCF and denyAll in the protocol and implementation, and forwarded it to UsercentricsCore.shared.
  • RN bridge (ios/RNUsercentricsModule.swift):
    • Updated denyAllForTCF and denyAll calls to include the new unsavedServiceDecisions parameter (currently passed as nil).
    • Small parameter formatting fix for denyAllForTCF call.
  • Tests / sample mocks updated:
    • sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift: added storage and handling for unsavedServiceDecisions in denyAllForTCF and denyAll; updated method signatures.
    • sample/ios/sampleTests/Mock/CMPData+Mock.swift: added isExempt fields to several mock initializers (ServiceConsentTemplate, SubConsentTemplate, UsercentricsCategory, and CMPData mock).
  • No functional behavior changes in RN bridge (new service decision params are optional and passed nil), but native API surface expanded — downstream/native implementors should be aware of the new optional parameter.

Reviewed by Panto AI

Comment thread package.json
Comment thread android/build.gradle.kts
Comment thread ios/Manager/UsercentricsManager.swift
Comment thread ios/RNUsercentricsModule.swift
@pantoaibot

pantoaibot Bot commented Aug 6, 2026

Copy link
Copy Markdown

Reviewed up to commit:a1f00c885304e0dabfc8a5285c5dab2db6c28021

Additional Suggestion
Others - You modified iOS-native Manager APIs to accept unsavedServiceDecisions, but the RN codegen spec (RNUsercentricsModuleSpec.kt) and Android RN bridge still use the older signatures. If the new parameter is intended to be part of the public JS API, update the codegen spec and Android bridge to match, then regenerate codegen artifacts. If it is intentionally iOS-internal only, add a comment in the spec/release notes clarifying that the JS API is unchanged to avoid confusion.
// android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt

@ReactMethod
abstract fun denyAll(
    consentType: Double,
    unsavedServiceDecisions: ReadableMap?,
    promise: Promise
)

@ReactMethod
abstract fun denyAllForTCF(
    fromLayer: Double,
    consentType: Double,
    unsavedPurposeLIDecisions: ReadableArray,
    unsavedVendorLIDecisions: ReadableArray,
    unsavedServiceDecisions: ReadableMap?,
    promise: Promise
)
// android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt

@ReactMethod
override fun denyAllForTCF(
    fromLayer: Double,
    consentType: Double,
    unsavedPurposeLIDecisions: ReadableArray,
    unsavedVendorLIDecisions: ReadableArray,
    unsavedServiceDecisions: ReadableMap?,
    promise: Promise
) {
    promise.resolve(
        usercentricsProxy.instance.denyAllForTCF(
            TCFDecisionUILayer.values()[fromLayer.toInt()],
            UsercentricsConsentType.values()[consentType.toInt()],
            unsavedPurposeLIDecisions.deserializePurposeLIDecisionsMap(),
            unsavedVendorLIDecisions.deserializePurposeLIDecisionsMap(),
            unsavedServiceDecisions.deserializeServiceDecisionsMap()
        ).toWritableArray()
    )
}

@ReactMethod
override fun denyAll(
    consentType: Double,
    unsavedServiceDecisions: ReadableMap?,
    promise: Promise
) {
    promise.resolve(
        usercentricsProxy.instance.denyAll(
            UsercentricsConsentType.values()[consentType.toInt()],
            unsavedServiceDecisions.deserializeServiceDecisionsMap()
        ).toWritableArray()
    )
}

// helper (same file or appropriate extension file)
private fun ReadableMap?.deserializeServiceDecisionsMap(): Map<String, KotlinBoolean>? {
    if (this == null || this.entryIterator.hasNext().not()) return null
    val result = mutableMapOf<String, KotlinBoolean>()
    val iterator = this.entryIterator
    while (iterator.hasNext()) {
        val entry = iterator.next()
        val key = entry.key
        val value = entry.value as? Boolean ?: continue
        result[key] = KotlinBoolean(value)
    }
    return result
}

Reviewed by Panto AI

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Breaking public Swift protocol 🐞 Bug ⚙ Maintainability
Description
This PR changes required method signatures on the public UsercentricsManager protocol
(denyAll/denyAllForTCF) while releasing a patch version (2.29.1), which will fail compilation
for any downstream conformer still implementing the old signatures. The repository’s own
FakeUsercentricsManager had to be updated to compile, indicating real conformance breakage for
external test doubles/custom implementations too.
Code

ios/Manager/UsercentricsManager.swift[R36-37]

+    func denyAllForTCF(fromLayer: TCFDecisionUILayer, consentType: UsercentricsConsentType, unsavedPurposeLIDecisions: [KotlinInt: KotlinBoolean]?, unsavedVendorLIDecisions: [KotlinInt: KotlinBoolean]?, unsavedServiceDecisions: [String: KotlinBoolean]?) -> [UsercentricsServiceConsent]
+    func denyAll(consentType: UsercentricsConsentType, unsavedServiceDecisions: [String: KotlinBoolean]?) -> [UsercentricsServiceConsent]
Evidence
The package is bumped to 2.29.1 while the iOS code changes required method signatures on a public
protocol. The in-repo fake manager was updated to match the new requirements, demonstrating that
older conformers would fail to compile after upgrading.

package.json[1-11]
ios/Manager/UsercentricsManager.swift[5-37]
sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift[169-190]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`UsercentricsManager` is declared `public`, and this PR modifies protocol requirements by adding new parameters to `denyAll` and `denyAllForTCF`. This is a **source-breaking change** for any downstream app/test target that conforms to `UsercentricsManager`.

## Issue Context
Because this PR also bumps the package version to **2.29.1** (a patch release), consumers may reasonably expect a non-breaking update. The repo’s own test fake (`FakeUsercentricsManager`) needed updates just to conform, showing that existing conformers will not compile without changes.

## Fix Focus Areas
- ios/Manager/UsercentricsManager.swift[5-46]

## Suggested fix approach
Choose one of these compatibility-preserving options:

1) **Provide backward-compatible overloads via protocol defaults**
- Re-introduce the old protocol methods (the previous signatures without `unsavedServiceDecisions`).
- Keep the new methods too, but provide default implementations in a `public extension UsercentricsManager` so existing conformers can continue implementing only the old methods and still compile.
 - Default implementation of the *new* methods should call the old ones (dropping the new parameter by using `nil`/ignoring it).
 - Alternatively, default implementation of the *old* methods can call the new ones with `nil`.

2) **Avoid changing the existing protocol**
- Create a new protocol (e.g., `UsercentricsManagerV2`) containing the new methods.
- Keep `UsercentricsManager` unchanged, and have the implementation conform to both.
- Update internal call sites to use V2 where needed.

If you intentionally want a breaking API change, then **don’t ship it as 2.29.1**; bump to a version that matches your breaking-change policy.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread ios/Manager/UsercentricsManager.swift
@uc-brunosilva
uc-brunosilva merged commit d1b6582 into master Aug 6, 2026
19 checks passed
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