Skip to content

feat(MSDK-3172): Consume and expose DPS metadata in AppSDK#193

Open
uc-christiansousa wants to merge 1 commit intomasterfrom
feat/MSDK-3172/consume-and-expose-dps-metadata-in-app-sdk
Open

feat(MSDK-3172): Consume and expose DPS metadata in AppSDK#193
uc-christiansousa wants to merge 1 commit intomasterfrom
feat/MSDK-3172/consume-and-expose-dps-metadata-in-app-sdk

Conversation

@uc-christiansousa
Copy link
Contributor

@uc-christiansousa uc-christiansousa commented Mar 20, 2026

CodeAnt-AI Description

Expose DPS metadata retrieval by template ID to JavaScript

What Changed

  • Added a new getDpsMetadata(templateId) API that returns DPS metadata for a given template ID (object) or null when absent
  • Wired the API through native layers on Android and iOS so JS callers can request metadata and receive a plain dictionary
  • Added unit tests (native and JS) covering valid metadata, null response, and empty-object responses

Impact

✅ Retrieve DPS metadata by template ID
✅ Null-safe metadata responses for missing templates
✅ Tests verify metadata access and edge cases

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Summary by CodeRabbit

New Features

  • Added getDpsMetadata(templateId) method to retrieve metadata for a specified template ID. Returns metadata object or null if unavailable. Now available on iOS and Android platforms.

@codeant-ai
Copy link

codeant-ai bot commented Mar 20, 2026

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

A new getDpsMetadata API method is added across the entire React Native SDK stack, including native bridge implementations for both iOS and Android, TypeScript interfaces, a JavaScript wrapper, and comprehensive unit test coverage.

Changes

Cohort / File(s) Summary
Android Native Bridge
android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt, android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt
Added getDpsMetadata(templateId, promise) method declarations and implementations; delegates to proxy instance and resolves promise with metadata map or null.
iOS Native Manager
ios/Manager/UsercentricsManager.swift
Extended UsercentricsManager protocol with getDpsMetadata(templateId) method; implemented in UsercentricsManagerImplementation via delegation to UsercentricsCore.
iOS Native Module Bridge
ios/RNUsercentricsModule.swift, ios/RNUsercentricsModuleSpec.h
Added getDpsMetadata React Native promise-based method declaration and implementation; calls native manager and resolves with NSDictionary or null.
iOS Test Fixtures
example/ios/exampleTests/Fake/FakeUsercentricsManager.swift, sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift
Added fake getDpsMetadata method with storage properties for test configuration; captures templateId and returns configured response.
iOS Unit Tests
example/ios/exampleTests/RNUsercentricsModuleTests.swift, sample/ios/sampleTests/RNUsercentricsModuleTests.swift
Added three test cases each: validates successful metadata mapping, null response handling, and empty metadata behavior; all assertions include template ID passthrough verification.
TypeScript Interfaces
src/NativeUsercentrics.ts, src/fabric/NativeUsercentricsModule.ts
Added getDpsMetadata(templateId) method signature returning Promise<Record<string, unknown> | null> in both TurboModule specs.
TypeScript Implementation & Tests
src/Usercentrics.tsx, src/__tests__/index.test.ts
Added getDpsMetadata public API method with isReady check; mocked native bridge in tests with three test cases covering null, object, and empty-map scenarios.

Sequence Diagram(s)

sequenceDiagram
    participant JS as JavaScript Client
    participant RNBridge as React Native Bridge
    participant NativeManager as Native Manager<br/>(iOS/Android)
    participant Core as Usercentrics Core

    JS->>RNBridge: getDpsMetadata(templateId)
    activate RNBridge
    RNBridge->>NativeManager: getDpsMetadata(templateId)
    activate NativeManager
    NativeManager->>Core: getDpsMetadata(templateId)
    activate Core
    Core-->>NativeManager: [metadata] or null
    deactivate Core
    NativeManager-->>RNBridge: [metadata] or null
    deactivate NativeManager
    RNBridge-->>JS: Promise<metadata | null>
    deactivate RNBridge
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested labels

size:M

Suggested reviewers

  • uc-brunosouza
  • uc-brunosilva
  • islameldesoky95

Poem

🐰 A new method hops through the stack,
From scripts to native, swift as a track,
getDpsMetadata bridges the way,
Hopping through promises, bright as the day!
Tests all pass—let's celebrate, hooray! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and specifically describes the main change: consuming and exposing DPS metadata in the AppSDK, which aligns with the comprehensive changes across Android, iOS, and TypeScript implementations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/MSDK-3172/consume-and-expose-dps-metadata-in-app-sdk
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

Tip

You can customize the tone of the review comments and chat replies.

Configure the tone_instructions setting to customize the tone of the review comments and chat replies. For example, you can set the tone to Act like a strict teacher, Act like a pirate and more.

@qodo-code-review
Copy link

Review Summary by Qodo

Add getDpsMetadata method to consume and expose DPS metadata

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add getDpsMetadata method to retrieve DPS metadata by template ID
• Implement method across Android and iOS native modules
• Add comprehensive unit tests for valid, null, and empty metadata cases
• Expose method through TypeScript interfaces and Usercentrics SDK
Diagram
flowchart LR
  A["Native Layer<br/>Android/iOS"] -->|getDpsMetadata| B["Manager Implementation<br/>UsercentricsManager"]
  B -->|expose| C["React Native Module<br/>RNUsercentricsModule"]
  C -->|bridge| D["TypeScript API<br/>Usercentrics.tsx"]
  D -->|return| E["Metadata Dictionary<br/>Record or null"]
Loading

Grey Divider

File Changes

1. android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt ✨ Enhancement +10/-0

Add getDpsMetadata React method for Android

android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt


2. android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt ✨ Enhancement +3/-0

Add getDpsMetadata abstract method specification

android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt


3. ios/Manager/UsercentricsManager.swift ✨ Enhancement +5/-0

Add getDpsMetadata protocol method to manager

ios/Manager/UsercentricsManager.swift


View more (11)
4. ios/Manager/UsercentricsManagerImplementation.swift ✨ Enhancement +0/-0

Implement getDpsMetadata delegation to core

ios/Manager/UsercentricsManagerImplementation.swift


5. ios/RNUsercentricsModule.swift ✨ Enhancement +5/-0

Add getDpsMetadata React method for iOS

ios/RNUsercentricsModule.swift


6. ios/RNUsercentricsModuleSpec.h ✨ Enhancement +4/-0

Add getDpsMetadata method signature header

ios/RNUsercentricsModuleSpec.h


7. src/NativeUsercentrics.ts ✨ Enhancement +1/-0

Add getDpsMetadata to native module interface

src/NativeUsercentrics.ts


8. src/fabric/NativeUsercentricsModule.ts ✨ Enhancement +1/-0

Add getDpsMetadata to Fabric module interface

src/fabric/NativeUsercentricsModule.ts


9. src/Usercentrics.tsx ✨ Enhancement +5/-0

Add getDpsMetadata public API method

src/Usercentrics.tsx


10. src/__tests__/index.test.ts 🧪 Tests +32/-0

Add unit tests for getDpsMetadata functionality

src/tests/index.test.ts


11. example/ios/exampleTests/Fake/FakeUsercentricsManager.swift 🧪 Tests +7/-0

Add mock getDpsMetadata for example tests

example/ios/exampleTests/Fake/FakeUsercentricsManager.swift


12. example/ios/exampleTests/RNUsercentricsModuleTests.swift 🧪 Tests +37/-0

Add getDpsMetadata test cases for example app

example/ios/exampleTests/RNUsercentricsModuleTests.swift


13. sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift 🧪 Tests +7/-0

Add mock getDpsMetadata for sample tests

sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift


14. sample/ios/sampleTests/RNUsercentricsModuleTests.swift 🧪 Tests +37/-0

Add getDpsMetadata test cases for sample app

sample/ios/sampleTests/RNUsercentricsModuleTests.swift


Grey Divider

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 20, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Action required

1. Metadata serialization loses fields 🐞 Bug ✓ Correctness
Description
Android getDpsMetadata resolves SDK metadata via Map.toWritableMap(), but that converter ignores
nulls and unsupported Number types (e.g., Long/Float) and does unsafe nested-map casts, which can
lead to missing metadata fields or runtime exceptions when DPS metadata contains non-Int/Double
values.
Code

android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt[R89-95]

+    override fun getDpsMetadata(templateId: String, promise: Promise) {
+        val metadata = usercentricsProxy.instance.getDpsMetadata(templateId)
+        if (metadata == null) {
+            promise.resolve(null)
+        } else {
+            promise.resolve(metadata.toWritableMap())
+        }
Evidence
The new method returns whatever the SDK provides as a dynamic map, but the chosen serialization
helper only supports a narrow set of value types and does not handle nulls. The repo already
contains a more robust dynamic-map serializer for GPP that supports null + generic Number,
highlighting the gap for DPS metadata.

android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt[88-96]
android/src/main/java/com/usercentrics/reactnative/extensions/ReadableMapExtensions.kt[74-115]
android/src/main/java/com/usercentrics/reactnative/extensions/GppDataExtensions.kt[17-46]

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

### Issue description
`getDpsMetadata` converts the SDK-returned metadata with `Map&lt;String, Any?&gt;.toWritableMap()`.

That converter:
- does not write `null` values (it drops keys)
- does not support generic `Number` (only `Int`/`Double`), so values like `Long`/`Float` are dropped
- uses unsafe casts for nested maps (`value as Map&lt;String, Any&gt;`) which can throw at runtime

This can cause missing fields or bridge crashes for real-world DPS metadata.

### Issue Context
The repository already includes a robust dynamic serialization approach in `GppDataExtensions.kt` (handles `null`, `Number`, `Iterable`, arrays, and has safe key handling). DPS metadata is similarly dynamic and should use the same robustness.

### Fix Focus Areas
- android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt[88-96]
- android/src/main/java/com/usercentrics/reactnative/extensions/ReadableMapExtensions.kt[74-115]
- android/src/main/java/com/usercentrics/reactnative/extensions/GppDataExtensions.kt[17-46]

### Implementation notes
- Prefer extracting a shared `Any?.toWritableValue()` / `Map&lt;*, *&gt;.toWritableMap()` / `Iterable&lt;*&gt;.toWritableArray()` utility (based on `GppDataExtensions.kt`) and use it for DPS metadata.
- Ensure `null` values become `putNull` / `pushNull` rather than being dropped.
- Normalize `Number` similarly to `GppDataExtensions.normalizeNumber` to avoid losing integer-ness.
- Avoid unchecked casts for nested maps; convert keys via `key?.toString() ?: continue`.

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


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@codeant-ai codeant-ai bot added the size:L This PR changes 100-499 lines, ignoring generated files label Mar 20, 2026
@codeant-ai
Copy link

codeant-ai bot commented Mar 20, 2026

Sequence Diagram

This PR adds a new getDpsMetadata API to the App SDK and wires it end to end from JavaScript to the native Usercentrics core layer. The flow returns either a metadata object for a template id or null when no metadata is available.

sequenceDiagram
    participant App
    participant UsercentricsAPI
    participant NativeModule
    participant UsercentricsCore

    App->>UsercentricsAPI: Request DPS metadata with template id
    UsercentricsAPI->>NativeModule: Ensure ready and call getDpsMetadata
    NativeModule->>UsercentricsCore: Fetch DPS metadata for template id
    UsercentricsCore-->>NativeModule: Metadata map or null
    alt Metadata found
        NativeModule-->>UsercentricsAPI: Resolve metadata object
    else No metadata
        NativeModule-->>UsercentricsAPI: Resolve null
    end
    UsercentricsAPI-->>App: Return DPS metadata result
Loading

Generated by CodeAnt AI

@pantoaibot
Copy link

pantoaibot bot commented Mar 20, 2026

PR Summary:

Add support to retrieve DPS (data processor) metadata by templateId from native SDKs and expose it through the React Native bridge and TypeScript API.

  • Overview

    • New API: getDpsMetadata(templateId) added across native iOS/Android, TurboModule/fabric and TypeScript wrappers; returns a nullable map/object with DPS metadata.
    • Non-breaking, additive change (nullable return).
  • Android

    • android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt
      • Added @ReactMethod getDpsMetadata(templateId: String, promise: Promise) that calls usercentricsProxy.instance.getDpsMetadata and resolves either null or a WritableMap.
    • android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt
      • Declared abstract fun getDpsMetadata(templateId: String, promise: Promise).
  • iOS

    • ios/Manager/UsercentricsManager.swift
      • Protocol and implementation extended with func getDpsMetadata(templateId: String) -> [String: Any]? that calls UsercentricsCore.shared.getDpsMetadata.
    • ios/RNUsercentricsModule.swift
      • Exposed @objc getDpsMetadata(_:resolve:reject:) which resolves the returned metadata as NSDictionary? to JS.
    • ios/RNUsercentricsModuleSpec.h
      • Added getDpsMetadata signature for the ObjC spec header.
  • JS / TypeScript

    • src/NativeUsercentrics.ts and src/fabric/NativeUsercentricsModule.ts
      • TurboModule spec updated to include getDpsMetadata(templateId): Promise<Object | null>.
    • src/Usercentrics.tsx
      • Added getDpsMetadata wrapper that awaits isReady and calls the native module.
    • src/tests/index.test.ts
      • Jest tests added to validate getDpsMetadata behavior for valid data, null, and empty object cases.
    • RN NativeModules mock updated to include getDpsMetadata.
  • Tests / Mocks

    • example/ios/exampleTests and sample/ios/sampleTests:
      • FakeUsercentricsManager.swift updated to add getDpsMetadataResponse/getDpsMetadataTemplateId and method.
      • Unit tests added to verify expected behavior (valid data, null, empty map) for both example and sample test suites.
  • Notes

    • The metadata is forwarded as a platform-native dictionary (NSDictionary / WritableMap) and exposed to JS as a plain object or null.
    • No dependency or behavior changes besides the added getter; backwards-compatible.

Reviewed by Panto AI

Comment on lines +88 to +96
@ReactMethod
override fun getDpsMetadata(templateId: String, promise: Promise) {
val metadata = usercentricsProxy.instance.getDpsMetadata(templateId)
if (metadata == null) {
promise.resolve(null)
} else {
promise.resolve(metadata.toWritableMap())
}
}
Copy link

Choose a reason for hiding this comment

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

[CRITICAL_BUG] Wrap the new getDpsMetadata implementation in a try/catch and reject the promise on failure. Converting native Maps to WritableMap (metadata.toWritableMap()) can throw if values are not directly serializable to the bridge. Example actionable fixes: (1) surround the conversion with try { ... } catch (e: Exception) { promise.reject(e) } or (2) defensively validate/normalize the map values before calling toWritableMap(). This prevents unhandled exceptions that would crash the bridge or leave the JS promise unresolved.

@ReactMethod
override fun getDpsMetadata(templateId: String, promise: Promise) {
    try {
        val metadata = usercentricsProxy.instance.getDpsMetadata(templateId)
        if (metadata == null) {
            promise.resolve(null)
        } else {
            promise.resolve(metadata.toWritableMap())
        }
    } catch (e: Exception) {
        promise.reject("usercentrics_getDpsMetadata_error", e.message, e)
    }
}

Comment on lines +162 to +165
@objc func getDpsMetadata(_ templateId: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
let metadata = usercentricsManager.getDpsMetadata(templateId: templateId)
resolve(metadata as NSDictionary?)
}
Copy link

Choose a reason for hiding this comment

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

[CRITICAL_BUG] Avoid force/unsafe bridging when resolving the metadata. resolve(metadata as NSDictionary?) may crash or produce unexpected results if the dictionary contains values that aren't bridgeable to Objective-C. Convert safely, e.g. guard let metadata = usercentricsManager.getDpsMetadata(templateId: templateId) else { resolve(nil); return } then create an NSDictionary via NSDictionary(dictionary: metadata) or use JSONSerialization to ensure bridgeable types. Also consider catching exceptions and rejecting with an error when conversion fails.

@objc func getDpsMetadata(_ templateId: String,
                         resolve: @escaping RCTPromiseResolveBlock,
                         reject: @escaping RCTPromiseRejectBlock) -> Void {
    guard let metadata = usercentricsManager.getDpsMetadata(templateId: templateId) else {
        resolve(nil)
        return
    }

    // Ensure only bridgeable Foundation types are passed to React Native
    if JSONSerialization.isValidJSONObject(metadata) {
        resolve(metadata as NSDictionary)
    } else {
        // Fallback: attempt to sanitize via JSON round‑trip
        do {
            let data = try JSONSerialization.data(withJSONObject: metadata, options: [])
            if let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
                resolve(jsonObject as NSDictionary)
            } else {
                reject("usercentrics_reactNative_getDpsMetadata_error",
                       "Failed to serialize DPS metadata",
                       nil)
            }
        } catch {
            reject("usercentrics_reactNative_getDpsMetadata_error",
                   "Failed to serialize DPS metadata: \(error.localizedDescription)",
                   error)
        }
    }
}

Comment on lines +63 to +65
@ReactMethod
abstract fun getDpsMetadata(templateId: String, promise: Promise)

Copy link

Choose a reason for hiding this comment

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

[REFACTORING] You added a new abstract method to the TurboModule spec. Make sure to run the native codegen/prepare steps so generated JNI and TurboModule bindings are updated accordingly (e.g. run the project prepare/script that triggers generate-codegen-jni or run yarn prepare). Without regenerating, native binding mismatches can cause runtime crashes or missing methods in the bridge.

getGPPData(): Promise<GppData>;
getGPPString(): Promise<string | null>;
getABTestingVariant(): Promise<string>;
getDpsMetadata(templateId: string): Promise<Record<string, unknown> | null>;
Copy link

Choose a reason for hiding this comment

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

[REFACTORING] Type mismatch/consistency: you added getDpsMetadata(templateId: string): Promise<Record<string, unknown> | null>. The fabric TurboModule spec uses Promise<Object | null>. Align the types across both files to a single, specific shape (prefer Record<string, unknown> | null) to keep type safety consistent and avoid confusion when consuming the API.

// src/fabric/NativeUsercentricsModule.ts
export interface Spec extends TurboModule {
  // ...existing methods...
-  getDpsMetadata(templateId: string): Promise<Object | null>;
+  getDpsMetadata(templateId: string): Promise<Record<string, unknown> | null>;
}

getGPPData(): Promise<Object>;
getGPPString(): Promise<string | null>;
getABTestingVariant(): Promise<string>;
getDpsMetadata(templateId: string): Promise<Object | null>;
Copy link

Choose a reason for hiding this comment

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

[REFACTORING] Use a consistent, explicit type for the new method signature instead of generic Object. Change getDpsMetadata(templateId: string): Promise<Object | null> to use the same type as the JS spec (e.g. Promise<Record<string, unknown> | null>) so TS types match between the TurboModule spec and the public TS declaration.

// src/fabric/NativeUsercentricsModule.ts
export interface Spec extends TurboModule {
  // ...
  getABTestingVariant(): Promise<string>;
  getDpsMetadata(templateId: string): Promise<Record<string, unknown> | null>;
  // ...
}

setGPPConsent: jest.fn(),
track: jest.fn(),
reset: jest.fn(),
getDpsMetadata: jest.fn(),
Copy link

Choose a reason for hiding this comment

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

[VALIDATION] You added getDpsMetadata to the NativeModules mock. The JS implementation awaits RNUsercentricsModule.isReady() before calling the method; please ensure RNUsercentricsModule.isReady is mocked to a resolved value (e.g. jest.fn().mockResolvedValue(undefined)) in tests that call getDpsMetadata so the await doesn't produce surprising behavior. Also, if your production code prefers TurboModuleRegistry.get over NativeModules, make sure tests mock the TurboModule path as well (or explicitly import the same module path your code uses).

// At top-level in src/__tests__/index.test.ts, after defining RNUsercentricsModule mock
beforeEach(() => {
  RNUsercentricsModule.isReady.mockResolvedValue(undefined);
});

// Or, inside each DPS metadata test:
RNUsercentricsModule.isReady.mockResolvedValueOnce(undefined);

// Additionally, if your production code ever switches to TurboModuleRegistry:
jest.mock('../fabric/NativeUsercentricsModule', () => {
  return {
    __esModule: true,
    default: {
      isReady: jest.fn().mockResolvedValue(undefined),
      getDpsMetadata: jest.fn(),
      // ...other mocked methods as needed
    },
  };
});

Comment on lines +103 to +106
getDpsMetadata: async (templateId: string): Promise<Record<string, unknown> | null> => {
await RNUsercentricsModule.isReady();
return RNUsercentricsModule.getDpsMetadata(templateId);
},
Copy link

Choose a reason for hiding this comment

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

[REFACTORING] Public wrapper getDpsMetadata is added — ensure its returned runtime type is documented in public typings and that callers know it can be null. Also consider normalizing the returned value (e.g. return {} instead of null) only if that matches product requirements; otherwise keep current null semantics but document them.

// src/Usercentrics.tsx
export interface UsercentricsPublicAPI {
  // ...existing methods
  /**
   * Returns DPS metadata for the given template.
   *
   * When metadata is available, a flat key/value object is returned.
   * When no metadata exists for the given templateId, this resolves to `null`.
   */
  getDpsMetadata(templateId: string): Promise<Record<string, unknown> | null>;
}

export const Usercentrics: UsercentricsPublicAPI = {
  // ...existing methods
  getDpsMetadata: async (
    templateId: string,
  ): Promise<Record<string, unknown> | null> => {
    await RNUsercentricsModule.isReady();
    const metadata = await RNUsercentricsModule.getDpsMetadata(templateId);
    // keep native null semantics; callers must handle `null`
    return metadata;
  },
};

@pantoaibot
Copy link

pantoaibot bot commented Mar 20, 2026

Reviewed up to commit:8c529d1bb006b4275633046aefe94f9d09c866c2

Reviewed by Panto AI

Comment on lines +89 to +95
override fun getDpsMetadata(templateId: String, promise: Promise) {
val metadata = usercentricsProxy.instance.getDpsMetadata(templateId)
if (metadata == null) {
promise.resolve(null)
} else {
promise.resolve(metadata.toWritableMap())
}

Choose a reason for hiding this comment

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

Action required

1. Metadata serialization loses fields 🐞 Bug ✓ Correctness

Android getDpsMetadata resolves SDK metadata via Map.toWritableMap(), but that converter ignores
nulls and unsupported Number types (e.g., Long/Float) and does unsafe nested-map casts, which can
lead to missing metadata fields or runtime exceptions when DPS metadata contains non-Int/Double
values.
Agent Prompt
### Issue description
`getDpsMetadata` converts the SDK-returned metadata with `Map<String, Any?>.toWritableMap()`.

That converter:
- does not write `null` values (it drops keys)
- does not support generic `Number` (only `Int`/`Double`), so values like `Long`/`Float` are dropped
- uses unsafe casts for nested maps (`value as Map<String, Any>`) which can throw at runtime

This can cause missing fields or bridge crashes for real-world DPS metadata.

### Issue Context
The repository already includes a robust dynamic serialization approach in `GppDataExtensions.kt` (handles `null`, `Number`, `Iterable`, arrays, and has safe key handling). DPS metadata is similarly dynamic and should use the same robustness.

### Fix Focus Areas
- android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt[88-96]
- android/src/main/java/com/usercentrics/reactnative/extensions/ReadableMapExtensions.kt[74-115]
- android/src/main/java/com/usercentrics/reactnative/extensions/GppDataExtensions.kt[17-46]

### Implementation notes
- Prefer extracting a shared `Any?.toWritableValue()` / `Map<*, *>.toWritableMap()` / `Iterable<*>.toWritableArray()` utility (based on `GppDataExtensions.kt`) and use it for DPS metadata.
- Ensure `null` values become `putNull` / `pushNull` rather than being dropped.
- Normalize `Number` similarly to `GppDataExtensions.normalizeNumber` to avoid losing integer-ness.
- Avoid unchecked casts for nested maps; convert keys via `key?.toString() ?: continue`.

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


getDpsMetadata: async (templateId: string): Promise<Record<string, unknown> | null> => {
await RNUsercentricsModule.isReady();
return RNUsercentricsModule.getDpsMetadata(templateId);
Copy link

Choose a reason for hiding this comment

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

Suggestion: This new call assumes getDpsMetadata always exists on the native module, but on iOS legacy bridge builds the method is not exported, so this will throw undefined is not a function at runtime. Guard the method before calling it and fail with a controlled error (or safe fallback) instead of invoking an undefined function. [possible bug]

Severity Level: Major ⚠️
-`Usercentrics.getDpsMetadata()` crashes on legacy iOS bridge.
- ⚠️ DPS metadata feature unavailable for legacy iOS consumers.
- ⚠️ Runtime failure occurs after successful `isReady()` call.
Suggested change
return RNUsercentricsModule.getDpsMetadata(templateId);
if (typeof RNUsercentricsModule.getDpsMetadata !== 'function') {
throw new Error('Usercentrics React Native SDK: getDpsMetadata is not available in this native build.');
}
Steps of Reproduction ✅
1. Build iOS with legacy bridge (non-new-architecture); JS resolves module through
fallback at `src/Usercentrics.tsx:25` and `src/NativeUsercentrics.ts:74`
(`TurboModuleRegistry.get(...) || NativeModules.RNUsercentricsModule`).

2. Call exported API `Usercentrics.getDpsMetadata("template123")` (public export at
`src/index.tsx:1`, implementation at `src/Usercentrics.tsx:103-105`).

3. On iOS legacy bridge, `ios/RNUsercentricsModule.mm:10-118` defines exported methods via
`RCT_EXTERN_METHOD(...)`, and this file has no `getDpsMetadata` export entry.

4. Because legacy `NativeModules.RNUsercentricsModule` lacks that function, call site
`src/Usercentrics.tsx:105` invokes `undefined`, causing runtime `TypeError:
...getDpsMetadata is not a function`.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/Usercentrics.tsx
**Line:** 105:105
**Comment:**
	*Possible Bug: This new call assumes `getDpsMetadata` always exists on the native module, but on iOS legacy bridge builds the method is not exported, so this will throw `undefined is not a function` at runtime. Guard the method before calling it and fail with a controlled error (or safe fallback) instead of invoking an undefined function.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
👍 | 👎

@codeant-ai
Copy link

codeant-ai bot commented Mar 20, 2026

CodeAnt AI finished reviewing your PR.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
example/ios/exampleTests/RNUsercentricsModuleTests.swift (1)

566-601: Add descriptive messages to XCTFail calls.

Static analysis flagged missing assertion messages. Adding descriptions helps identify which assertion failed when debugging test failures.

🔧 Proposed fix
   func testGetDpsMetadataWithValidData() {
     fakeUsercentrics.getDpsMetadataResponse = ["partner": "appsflyer", "source": "campaign_1"]
     module.getDpsMetadata("template123") { result in
       guard let result = result as? NSDictionary else {
-        XCTFail()
+        XCTFail("Expected NSDictionary result")
         return
       }
       XCTAssertEqual("appsflyer", result["partner"] as! String)
       XCTAssertEqual("campaign_1", result["source"] as! String)
     } reject: { _, _, _ in
       XCTFail("Should not go here")
     }
     XCTAssertEqual("template123", fakeUsercentrics.getDpsMetadataTemplateId)
   }
   func testGetDpsMetadataWithEmptyMap() {
     fakeUsercentrics.getDpsMetadataResponse = [:]
     module.getDpsMetadata("template123") { result in
       guard let result = result as? NSDictionary else {
-        XCTFail()
+        XCTFail("Expected NSDictionary result")
         return
       }
       XCTAssertEqual(0, result.count)
     } reject: { _, _, _ in
       XCTFail("Should not go here")
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@example/ios/exampleTests/RNUsercentricsModuleTests.swift` around lines 566 -
601, Tests have XCTFail calls without descriptive messages which makes failures
hard to diagnose; update the XCTFail usages in testGetDpsMetadataWithValidData,
testGetDpsMetadataWhenNull, and testGetDpsMetadataWithEmptyMap to include clear
descriptions (e.g., for reject closures use "Unexpected rejection in
testGetDpsMetadataWithValidData/testGetDpsMetadataWhenNull/testGetDpsMetadataWithEmptyMap",
and for guard failure use "Expected NSDictionary result in
testGetDpsMetadataWithValidData"); ensure each XCTFail call across these
functions includes a concise message identifying the test and failure reason.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt`:
- Around line 88-96: The getDpsMetadata ReactMethod references a non-existent
Usercentrics SDK method and will crash; either remove the entire getDpsMetadata
method from RNUsercentricsModule or replace its implementation by calling a
supported API (e.g., usercentricsProxy.instance.getCMPData() or
usercentricsProxy.instance.getConsents()) after confirming which API returns the
equivalent DPS metadata with Usercentrics support, then convert that result to a
WritableMap (using metadata.toWritableMap() or equivalent) and resolve the
promise; if you cannot confirm immediately, remove the method to prevent runtime
crashes and open a follow-up to reintroduce it once Usercentrics confirms the
correct API.

In `@sample/ios/sampleTests/RNUsercentricsModuleTests.swift`:
- Around line 570-572: Update the bare XCTFail() calls in
RNUsercentricsModuleTests.swift to include descriptive failure messages so
failures are actionable; specifically, modify the guard blocks that check "guard
let result = result as? NSDictionary else { XCTFail(); return }" (and the
similar guard at the other occurrence) to call XCTFail(...) with a short message
such as "expected 'result' to be NSDictionary but was nil or wrong type" or
test-specific context so the test output identifies what went wrong.

---

Nitpick comments:
In `@example/ios/exampleTests/RNUsercentricsModuleTests.swift`:
- Around line 566-601: Tests have XCTFail calls without descriptive messages
which makes failures hard to diagnose; update the XCTFail usages in
testGetDpsMetadataWithValidData, testGetDpsMetadataWhenNull, and
testGetDpsMetadataWithEmptyMap to include clear descriptions (e.g., for reject
closures use "Unexpected rejection in
testGetDpsMetadataWithValidData/testGetDpsMetadataWhenNull/testGetDpsMetadataWithEmptyMap",
and for guard failure use "Expected NSDictionary result in
testGetDpsMetadataWithValidData"); ensure each XCTFail call across these
functions includes a concise message identifying the test and failure reason.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c20c5ab4-9c6b-4591-bf9a-1596ddd9e455

📥 Commits

Reviewing files that changed from the base of the PR and between a3f7a22 and 8c529d1.

📒 Files selected for processing (13)
  • android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt
  • android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt
  • example/ios/exampleTests/Fake/FakeUsercentricsManager.swift
  • example/ios/exampleTests/RNUsercentricsModuleTests.swift
  • ios/Manager/UsercentricsManager.swift
  • ios/RNUsercentricsModule.swift
  • ios/RNUsercentricsModuleSpec.h
  • sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift
  • sample/ios/sampleTests/RNUsercentricsModuleTests.swift
  • src/NativeUsercentrics.ts
  • src/Usercentrics.tsx
  • src/__tests__/index.test.ts
  • src/fabric/NativeUsercentricsModule.ts

Comment on lines +88 to +96
@ReactMethod
override fun getDpsMetadata(templateId: String, promise: Promise) {
val metadata = usercentricsProxy.instance.getDpsMetadata(templateId)
if (metadata == null) {
promise.resolve(null)
} else {
promise.resolve(metadata.toWritableMap())
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for any documentation or usage of getDpsMetadata in the codebase
rg -n "getDpsMetadata" --type-add 'kotlin:*.kt' --type kotlin

Repository: Usercentrics/react-native-sdk

Length of output: 529


🏁 Script executed:

find . -name "build.gradle*" -type f | head -20

Repository: Usercentrics/react-native-sdk

Length of output: 288


🏁 Script executed:

rg -n "usercentrics" --type-add 'gradle:*.gradle' --type gradle -i | head -30

Repository: Usercentrics/react-native-sdk

Length of output: 1278


🏁 Script executed:

rg -n "2\.25\." --type-add 'gradle:*.gradle' --type gradle

Repository: Usercentrics/react-native-sdk

Length of output: 138


🏁 Script executed:

cat -n android/build.gradle.kts | head -100

Repository: Usercentrics/react-native-sdk

Length of output: 3728


🏁 Script executed:

rg -n "usercentrics-ui\|usercentrics_version" android/build.gradle.kts

Repository: Usercentrics/react-native-sdk

Length of output: 55


🏁 Script executed:

rg -n "usercentricsProxy" --type kotlin

Repository: Usercentrics/react-native-sdk

Length of output: 20394


🏁 Script executed:

find . -name "UsercentricsProxy*" -type f

Repository: Usercentrics/react-native-sdk

Length of output: 150


🏁 Script executed:

rg -n "interface UsercentricsProxy\|class.*UsercentricsProxy" --type kotlin -A 5

Repository: Usercentrics/react-native-sdk

Length of output: 55


🏁 Script executed:

rg -n "getDpsMetadata" --type kotlin -B 2 -A 2

Repository: Usercentrics/react-native-sdk

Length of output: 1292


🏁 Script executed:

cat -n android/src/main/java/com/usercentrics/reactnative/api/UsercentricsProxy.kt

Repository: Usercentrics/react-native-sdk

Length of output: 2289


🏁 Script executed:

rg -n "getDpsMetadata" --type kotlin -B 5 -A 5

Repository: Usercentrics/react-native-sdk

Length of output: 2599


🏁 Script executed:

find . -name "*Test*.kt" -type f -exec grep -l "getDpsMetadata" {} \;

Repository: Usercentrics/react-native-sdk

Length of output: 55


🌐 Web query:

Usercentrics Android SDK 2.25.1 getDpsMetadata API changelog

💡 Result:

No specific changelog entry found for the getDpsMetadata API in Usercentrics Android SDK version 2.25.1. The release notes for 2.25.1 (released March 2, 2026) mention only "UI improvements and fixes" and "Patch with security fixes". No mention of getDpsMetadata or DPS-related API changes in 2.25.1, 2.25.0, or recent versions. Official API documentation lists methods like getCMPData, getConsents, but no getDpsMetadata. DPS (Data Processing Services) metadata is likely accessed via UsercentricsService.deviceStorage in getCMPData response, which received TCF Vendor Device Storage enhancements in 2.25.1 (new fields: sdks, specialPurposes, optOut in disclosures).

Citations:


🌐 Web query:

Usercentrics SDK getDpsMetadata method documentation

💡 Result:

No official documentation for a "getDpsMetadata" method was found in Usercentrics SDKs across browser, mobile (iOS/Android/Flutter/Unity/React Native), or related APIs after extensive searches of official docs.usercentrics.com pages, pub.dev packages, and GitHub repos. Usercentrics SDKs provide similar functionality through methods like: - getServices or getServicesBaseInfo / getServicesFullInfo in browser SDK (returns Service[] with data processing service details) - getCMPData in Apps SDK Core API (includes services: [UsercentricsService]) - consents (Future<List>) in Flutter SDK "DPS" refers to Data Processing Services in Usercentrics terminology. If this is from a private/internal SDK version or custom wrapper, check your specific implementation or contact Usercentrics support. Primary docs: https://docs.usercentrics.com/

Citations:


Remove getDpsMetadata method or verify API existence with Usercentrics support.

The getDpsMetadata(templateId: String) method is not documented in the official Usercentrics Android SDK v2.25.1 API. Official documentation and recent changelogs (including 2.25.1 released March 2, 2026) do not list this method. Similar functionality appears to be accessed through getCMPData() or getConsents() instead. Calling this non-existent method at runtime will cause a crash. Verify with Usercentrics whether this API exists in v2.25.1 or if an alternative method should be used.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt`
around lines 88 - 96, The getDpsMetadata ReactMethod references a non-existent
Usercentrics SDK method and will crash; either remove the entire getDpsMetadata
method from RNUsercentricsModule or replace its implementation by calling a
supported API (e.g., usercentricsProxy.instance.getCMPData() or
usercentricsProxy.instance.getConsents()) after confirming which API returns the
equivalent DPS metadata with Usercentrics support, then convert that result to a
WritableMap (using metadata.toWritableMap() or equivalent) and resolve the
promise; if you cannot confirm immediately, remove the method to prevent runtime
crashes and open a follow-up to reintroduce it once Usercentrics confirms the
correct API.

Comment on lines +570 to +572
guard let result = result as? NSDictionary else {
XCTFail()
return
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add assertion messages to XCTFail() calls.

Two XCTFail() calls have no message, which hurts debugging clarity (also matches SwiftLint warning).

Suggested patch
-      guard let result = result as? NSDictionary else {
-        XCTFail()
+      guard let result = result as? NSDictionary else {
+        XCTFail("Expected NSDictionary result for non-empty DPS metadata")
         return
       }
@@
-      guard let result = result as? NSDictionary else {
-        XCTFail()
+      guard let result = result as? NSDictionary else {
+        XCTFail("Expected NSDictionary result for empty DPS metadata map")
         return
       }

Also applies to: 594-596

🧰 Tools
🪛 SwiftLint (0.63.2)

[Warning] 571-571: An XCTFail call should include a description of the assertion

(xctfail_message)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sample/ios/sampleTests/RNUsercentricsModuleTests.swift` around lines 570 -
572, Update the bare XCTFail() calls in RNUsercentricsModuleTests.swift to
include descriptive failure messages so failures are actionable; specifically,
modify the guard blocks that check "guard let result = result as? NSDictionary
else { XCTFail(); return }" (and the similar guard at the other occurrence) to
call XCTFail(...) with a short message such as "expected 'result' to be
NSDictionary but was nil or wrong type" or test-specific context so the test
output identifies what went wrong.

@qodo-code-review
Copy link

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: test-ios

Failed stage: Run tests [❌]

Failed test name: ""

Failure summary:

The GitHub Action failed during the iOS build/test step (xcodebuild exited with code 65) because the
build did not compile successfully.
- The key compiler error is repeated multiple times: Cannot find
type 'GppSectionChangePayload' in scope, which indicates a missing/undefined Swift type during
compilation.
- The build failure is reported under EmitSwiftModule normal arm64 (in target
'react-native-usercentrics' from project 'Pods'), suggesting the Swift module for the
react-native-usercentrics pod failed to compile due to that missing type.
- As a result, tests were
cancelled: Testing cancelled because the build failed. and the job ends with ** TEST FAILED **.
-
Numerous Run script build phase 'Create Symlinks to Header Folders' will be run during every
build... messages are warnings about script phase outputs and are not the root cause of the failure.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

965:  Installing React-RCTText (0.81.4)
966:  Installing React-RCTVibration (0.81.4)
967:  Installing React-RuntimeApple (0.81.4)
968:  Installing React-RuntimeCore (0.81.4)
969:  Installing React-RuntimeHermes (0.81.4)
970:  Installing React-callinvoker (0.81.4)
971:  Installing React-cxxreact (0.81.4)
972:  Installing React-debug (0.81.4)
973:  Installing React-defaultsnativemodule (0.81.4)
974:  Installing React-domnativemodule (0.81.4)
975:  Installing React-featureflags (0.81.4)
976:  Installing React-featureflagsnativemodule (0.81.4)
977:  Installing React-graphics (0.81.4)
978:  Installing React-hermes (0.81.4)
979:  Installing React-idlecallbacksnativemodule (0.81.4)
980:  Installing React-jserrorhandler (0.81.4)
981:  Installing React-jsi (0.81.4)
...

1219:  ▸ Copying ExecutionContextManager.h
1220:  ▸ Copying ExecutionContext.h
1221:  ▸ Copying ConsoleMessage.h
1222:  ▸ Copying Base64.h
1223:  ▸ Copying React-jsiexecutor-umbrella.h
1224:  ▸ Copying JSINativeModules.h
1225:  ▸ Copying JSIExecutor.h
1226:  ▸ Copying threadsafe.h
1227:  ▸ Copying jsilib.h
1228:  ▸ Copying jsi.h
1229:  ▸ Copying jsi-inl.h
1230:  ▸ Copying instrumentation.h
1231:  ▸ Copying decorator.h
1232:  ▸ Copying React-jsi-umbrella.h
1233:  ▸ Copying JSIDynamic.h
1234:  ▸ Copying React-jserrorhandler-umbrella.h
1235:  ▸ Copying React-idlecallbacksnativemodule-umbrella.h
1236:  ▸ Copying React-hermes-umbrella.h
1237:  ▸ Copying HermesExecutorFactory.h
1238:  ▸ Copying React-graphics-umbrella.h
1239:  ▸ Copying React-featureflagsnativemodule-umbrella.h
1240:  ▸ Copying React-featureflags-umbrella.h
1241:  ▸ Copying React-domnativemodule-umbrella.h
1242:  ▸ Copying React-defaultsnativemodule-umbrella.h
1243:  ▸ Copying React-debug-umbrella.h
1244:  ▸ Copying TraceSection.h
1245:  ▸ Copying SystraceSection.h
1246:  ▸ Copying SharedProxyCxxModule.h
1247:  ▸ Copying RecoverableError.h
1248:  ▸ Copying ReactNativeVersion.h
...

1251:  ▸ Copying RAMBundleRegistry.h
1252:  ▸ Copying NativeToJsBridge.h
1253:  ▸ Copying NativeModule.h
1254:  ▸ Copying MoveWrapper.h
1255:  ▸ Copying ModuleRegistry.h
1256:  ▸ Copying MethodCall.h
1257:  ▸ Copying MessageQueueThread.h
1258:  ▸ Copying JsArgumentHelpers.h
1259:  ▸ Copying JsArgumentHelpers-inl.h
1260:  ▸ Copying JSModulesUnbundle.h
1261:  ▸ Copying JSIndexedRAMBundle.h
1262:  ▸ Copying JSExecutor.h
1263:  ▸ Copying JSBundleType.h
1264:  ▸ Copying JSBigString.h
1265:  ▸ Copying Instance.h
1266:  ▸ Copying ErrorUtils.h
1267:  ▸ Copying CxxNativeModule.h
...

1610:  ▸ Copying RCTI18nUtil.h
1611:  ▸ Copying RCTI18nManager.h
1612:  ▸ Copying RCTHTTPRequestHandler.h
1613:  ▸ Copying RCTGIFImageDecoder.h
1614:  ▸ Copying RCTFrameUpdate.h
1615:  ▸ Copying RCTFrameAnimation.h
1616:  ▸ Copying RCTFont.h
1617:  ▸ Copying RCTFileRequestHandler.h
1618:  ▸ Copying RCTFileReaderModule.h
1619:  ▸ Copying RCTFPSGraph.h
1620:  ▸ Copying RCTExceptionsManager.h
1621:  ▸ Copying RCTEventEmitter.h
1622:  ▸ Copying RCTEventDispatcherProtocol.h
1623:  ▸ Copying RCTEventDispatcher.h
1624:  ▸ Copying RCTEventAnimation.h
1625:  ▸ Copying RCTErrorInfo.h
1626:  ▸ Copying RCTErrorCustomizer.h
1627:  ▸ Copying RCTDynamicTypeRamp.h
...

1833:  ▸ Compiling SocketRocket-dummy.m
1834:  ▸ Compiling SRWebSocket.m
1835:  ▸ Compiling SRURLUtilities.m
1836:  ▸ Compiling SRSecurityPolicy.m
1837:  ▸ Compiling SRSIMDHelpers.m
1838:  ▸ Compiling SRRunLoopThread.m
1839:  ▸ Compiling SRRandom.m
1840:  ▸ Compiling SRProxyConnect.m
1841:  ▸ Compiling SRPinningSecurityPolicy.m
1842:  ▸ Compiling SRMutex.m
1843:  ▸ Compiling SRLog.m
1844:  ▸ Compiling SRIOConsumerPool.m
1845:  ▸ Compiling SRIOConsumer.m
1846:  ▸ Compiling SRHash.m
1847:  ▸ Compiling SRHTTPConnectMessage.m
1848:  ▸ Compiling SRError.m
1849:  ▸ Compiling SRDelegateController.m
...

2238:  ▸ Compiling RCTModalManager.m
2239:  ▸ Compiling RCTModalHostViewManager.m
2240:  ▸ Compiling RCTModalHostViewController.m
2241:  ▸ Compiling RCTModalHostView.m
2242:  ▸ Compiling RCTLayoutAnimationGroup.m
2243:  ▸ Compiling RCTLayoutAnimation.m
2244:  ▸ Compiling RCTLayout.m
2245:  ▸ Compiling RCTKeyCommands.m
2246:  ▸ Compiling RCTJSThread.m
2247:  ▸ Compiling RCTJSStackFrame.m
2248:  ▸ Compiling RCTImageSource.m
2249:  ▸ Compiling RCTI18nUtil.m
2250:  ▸ Compiling RCTFrameUpdate.m
2251:  ▸ Compiling RCTEventEmitter.m
2252:  ▸ Compiling RCTEventDispatcher.m
2253:  ▸ Compiling RCTErrorInfo.m
2254:  ▸ Compiling RCTDisplayLink.m
...

2292:  ▸ Compiling RCTConvert+Text.mm
2293:  ▸ Compiling RCTBaseTextViewManager.mm
2294:  ▸ Compiling RCTBaseTextShadowView.mm
2295:  ▸ Compiling RCTBaseTextInputViewManager.mm
2296:  ▸ Compiling RCTBaseTextInputView.mm
2297:  ▸ Compiling RCTBaseTextInputShadowView.mm
2298:  ▸ Compiling RCTBackedTextInputDelegateAdapter.mm
2299:  ▸ Compiling RCTActivityIndicatorView.m
2300:  ▸ Compiling RCTText_vers.c
2301:  ▸ Compiling React-RCTText-dummy.m
2302:  ▸ Compiling RCTTypedModuleConstants.mm
2303:  ▸ Compiling RCTConvertHelpers.mm
2304:  ▸ Compiling NSTextStorage+FontScaling.m
2305:  ▸ Compiling RCTTypeSafety_vers.c
2306:  ▸ Touching ReactCommon.framework (in target 'ReactCommon' from project 'Pods')
2307:  ▸ Processing React-jserrorhandler-Info.plist
2308:  ▸ Compiling StackTraceParser.cpp
2309:  ▸ Compiling JsErrorHandler.cpp
2310:  ▸ Compiling RCTTypeSafety-dummy.m
2311:  ▸ Compiling React_jserrorhandler_vers.c
2312:  ▸ Touching React.framework (in target 'React-Core' from project 'Pods')
2313:  ▸ Processing react-native-safe-area-context-Info.plist
2314:  ▸ Processing React-RCTText-Info.plist
2315:  ▸ Processing React-NativeModulesApple-Info.plist
2316:  ▸ Processing RCTTypeSafety-Info.plist
2317:  ▸ Touching react_native_safe_area_context.framework (in target 'react-native-safe-area-context' from project 'Pods')
2318:  ▸ Compiling RCTTurboModuleManager.mm
2319:  ▸ Compiling RCTTurboModule.mm
2320:  ▸ Compiling React-jserrorhandler-dummy.m
2321:  ▸ Compiling RCTInteropTurboModule.mm
2322:  ▸ Compiling React_NativeModulesApple_vers.c
2323:  ▸ Running script 'Create Symlinks to Header Folders'
2324:  ▸ Touching RCTText.framework (in target 'React-RCTText' from project 'Pods')
2325:  ▸ Touching React_jserrorhandler.framework (in target 'React-jserrorhandler' from project 'Pods')
2326:  ▸ Touching RCTTypeSafety.framework (in target 'RCTTypeSafety' from project 'Pods')
...

2822:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/ComponentDescriptors.cpp (in target 'ReactCodegen' from project 'Pods')
2823:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/ComponentDescriptors.cpp (in target 'ReactCodegen' from project 'Pods')
2824:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/EventEmitters.cpp (in target 'ReactCodegen' from project 'Pods')
2825:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/EventEmitters.cpp (in target 'ReactCodegen' from project 'Pods')
2826:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/EventEmitters.cpp (in target 'ReactCodegen' from project 'Pods')
2827:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/Props.cpp (in target 'ReactCodegen' from project 'Pods')
2828:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/Props.cpp (in target 'ReactCodegen' from project 'Pods')
2829:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/Props.cpp (in target 'ReactCodegen' from project 'Pods')
2830:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/ShadowNodes.cpp (in target 'ReactCodegen' from project 'Pods')
2831:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/ShadowNodes.cpp (in target 'ReactCodegen' from project 'Pods')
2832:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/ShadowNodes.cpp (in target 'ReactCodegen' from project 'Pods')
2833:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/States.cpp (in target 'ReactCodegen' from project 'Pods')
2834:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/States.cpp (in target 'ReactCodegen' from project 'Pods')
2835:  Skipping duplicate build file in Compile Sources build phase: /Users/runner/work/react-native-sdk/react-native-sdk/sample/ios/build/generated/ios/react/renderer/components/safeareacontext/States.cpp (in target 'ReactCodegen' from project 'Pods')
2836:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'ReactCodegen' from project 'Pods')
2837:  Testing failed:
2838:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-utils' from project 'Pods')
2839:  Cannot find type 'GppSectionChangePayload' in scope
2840:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-runtimescheduler' from project 'Pods')
2841:  Cannot find type 'GppSectionChangePayload' in scope
2842:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-runtimeexecutor' from project 'Pods')
2843:  Cannot find type 'GppSectionChangePayload' in scope
2844:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-rendererdebug' from project 'Pods')
2845:  Cannot find type 'GppSectionChangePayload' in scope
2846:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-renderercss' from project 'Pods')
2847:  Cannot find type 'GppSectionChangePayload' in scope
2848:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-rendererconsistency' from project 'Pods')
2849:  Cannot find type 'GppSectionChangePayload' in scope
2850:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-performancetimeline' from project 'Pods')
2851:  Testing cancelled because the build failed.
2852:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-microtasksnativemodule' from project 'Pods')
2853:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-jsitooling' from project 'Pods')
2854:  ** TEST FAILED **
2855:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-jsinspectortracing' from project 'Pods')
2856:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-jsinspectornetwork' from project 'Pods')
2857:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-jsinspectorcdp' from project 'Pods')
2858:  The following build commands failed:
2859:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-jserrorhandler' from project 'Pods')
2860:  EmitSwiftModule normal arm64 (in target 'react-native-usercentrics' from project 'Pods')
...

2867:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-debug' from project 'Pods')
2868:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-defaultsnativemodule' from project 'Pods')
2869:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-RuntimeHermes' from project 'Pods')
2870:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-RuntimeCore' from project 'Pods')
2871:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-RuntimeApple' from project 'Pods')
2872:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-RCTRuntime' from project 'Pods')
2873:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-RCTFBReactNativeSpec' from project 'Pods')
2874:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-NativeModulesApple' from project 'Pods')
2875:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-Mapbuffer' from project 'Pods')
2876:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-ImageManager' from project 'Pods')
2877:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-FabricImage' from project 'Pods')
2878:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-FabricComponents' from project 'Pods')
2879:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'React-Fabric' from project 'Pods')
2880:  Run script build phase 'Create Symlinks to Header Folders' will be run during every build because it does not specify any outputs. To address this issue, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'RCT-Folly' from project 'Pods')
2881:  Testing workspace sample with scheme sample
2882:  (3 failures)
2883:  ##[error]Process completed with exit code 65.
2884:  ##[group]Run actions/upload-artifact@v4

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

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant