Skip to content

Conversation

@jayant-dhingra-cb
Copy link
Collaborator

Changes for all the code for React Native version 1

jayant-dhingra-cb and others added 30 commits October 14, 2025 22:11
*SDK version migrated from 3.2.1 to 3.3 in both Android and iOS.
*All the submodules are now pointing to the main branch.
*Create an error for all unimplemented functions since we are not releasing p2p in v1.0.0
- Add collection change listener tests
- Add document change listener tests
- Add custom bug fix tests
- Update CblReactnativeModule.kt for Android
- Update CblReactNativeEngine.tsx
- Update iOS Swift bridge code
- Update test navigation sections
- Update cblite-js tests
- Add collection-change-listener test component
- Add custom-bug-fix test component
- Add document-change-listener test component
- Update CblReactNativeEngine with latest changes
- Update Android module with latest changes
- Resolve merge conflicts in Podfile.lock
- Implement collection_GetFullName method in CblReactnativeModule for both Android and iOS.
- Update CblReactNativeEngine to include collection_GetFullName functionality.
- Modify various components to utilize the new fullName method for collections.
- Expand tsconfig.build.json to exclude additional directories.
- Add listenerToken_Remove method to CblReactNativeEngine
- Update Android native module with listener token removal
- Update iOS native module with listener token removal
- Update listener test files to use new token-based removal
- Add listener token plan documentation
- Update Android CblReactnativeModule.kt
- Update iOS CblReactnative.swift
- Remove listener-token-plan.md (no longer needed)
chore: update submodule reference for cblite-js-tests
# Conflicts:
#	expo-example/app/tests/replicator-listeners-new.tsx
#	expo-example/cblite-js-tests
#	expo-example/hooks/useTestsNavigationSections.tsx
#	src/cblite-js
chore: update submodules to support_col_db_property branch
@gemini-code-assist
Copy link

Summary of Changes

Hello @jayant-dhingra-cb, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request marks a major version update to 1.0.0 for the React Native library, integrating the latest Couchbase Lite SDKs (3.3.0) for both Android and iOS. Key architectural improvements include a unified listener management system with a new ListenerToken API, and the introduction of a flexible Log Sinks API for console, file, and custom logging. Replicator configuration has been modernized to support collection arrays, and a new collection.fullName() method is available. These updates are thoroughly supported by an expanded test suite and updated example application to ensure stability and ease of use.

Highlights

  • Couchbase Lite SDK Upgrade: The underlying Couchbase Lite SDKs for both Android and iOS have been upgraded to version 3.3.0, bringing the latest features and improvements.
  • Unified Listener Management: A significant refactoring has been implemented to unify how various change listeners (collection, document, query, and replicator) are managed. This introduces a new ListenerToken API for adding and removing listeners, simplifying their lifecycle.
  • New Log Sinks API: A comprehensive Log Sinks API has been added, allowing developers to configure and manage logging output to the console, files, or custom callbacks with fine-grained control over log levels and domains.
  • Enhanced Replicator Configuration: The replicator configuration has been updated to use an array of CollectionConfiguration objects, aligning with the latest SDK capabilities and providing more flexibility.
  • New collection.fullName() Method: A new asynchronous method, collection.fullName(), has been introduced to retrieve the fully qualified name of a collection directly from the native layer.
  • Expanded Test Suite and Examples: Numerous new test screens and example implementations have been added to demonstrate and validate the new listener management, log sinks, and replicator configuration changes.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a major refactoring for listener management, new logging capabilities via a LogSinks API, and updates dependencies. The listener management has been centralized, which is a great improvement for maintainability. However, there are a few critical issues that need to be addressed, including a typo in a ProGuard file that could break release builds, and unsafe type casting in the new logging functionality that could lead to runtime crashes. Additionally, the use of GlobalScope for coroutines should be replaced with a lifecycle-aware scope to prevent potential memory leaks.


# Keep our React Native module
-keep class com.cblreactnative.** { *; }
-keep class cbl.js.kotiln.** { *; }

Choose a reason for hiding this comment

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

critical

There is a typo in the package name. It should be cbl.js.kotlin instead of cbl.js.kotiln. This will cause ProGuard to not keep the necessary classes, leading to crashes in release builds due to obfuscation.

-keep class cbl.js.kotlin.** { *; }

val intLevel = level?.toInt()

// Convert ReadableMap? to Map<String, Any>?
val configMap = config?.toHashMap()?.mapValues { it.value as Any }

Choose a reason for hiding this comment

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

high

The unsafe cast it.value as Any can lead to a TypeCastException at runtime if a value in the ReadableMap is null. The toHashMap() method on ReadableMap can produce a map with nullable values (HashMap<String, Any?>). Casting a null value to a non-nullable type Any will cause a crash.

To prevent this, you should safely handle potential null values before passing the map to LogSinksManager.setFileSink.

Suggested change
val configMap = config?.toHashMap()?.mapValues { it.value as Any }
val configMap = config?.toHashMap()?.filterValues { it != null } as? Map<String, Any>

scopeName: String,
promise: Promise
) {
GlobalScope.launch(Dispatchers.IO) {

Choose a reason for hiding this comment

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

medium

Using GlobalScope to launch coroutines is discouraged as it can lead to memory leaks. Coroutines launched in GlobalScope are not tied to any component's lifecycle and will not be automatically cancelled. This can cause them to continue running even after the component that launched them is destroyed.

A better approach is to create a CoroutineScope that is tied to the lifecycle of this CblReactnativeModule. You can create a scope with a SupervisorJob and cancel it in the onCatalystInstanceDestroy method of the module.

This comment also applies to other uses of GlobalScope in this file, such as in listenerToken_Remove, logsinks_SetConsole, logsinks_SetFile, and logsinks_SetCustom.

}
} else {
val errorMsg = "No listener found for token $changeListenerToken"
android.util.Log.e("CblReactnative", "::KOTLIN DEBUG:: listenerToken_Remove: $errorMsg")

Choose a reason for hiding this comment

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

medium

Using Log.e for debugging messages that are not critical errors can clutter the error logs and make it harder to identify actual problems. For a 'listener not found' scenario, which is an expected client-side condition, Log.w (warning) or Log.d (debug) would be more appropriate. Additionally, it's good practice to ensure such debug logs are stripped from production builds.

Suggested change
android.util.Log.e("CblReactnative", "::KOTLIN DEBUG:: listenerToken_Remove: $errorMsg")
android.util.Log.w("CblReactnative", "::KOTLIN DEBUG:: listenerToken_Remove: $errorMsg")

Comment on lines 32 to 43
// Test 3: Test error handling with a fake collection
results.push('');
results.push('=== TEST 3: Error Handling ===');
results.push('Testing with valid collection (should succeed)');
try {
const testFullName = await collection.fullName();
results.push(`✅ No error thrown for valid collection`);
results.push(` Got: "${testFullName}"`);
} catch (error: any) {
results.push(`❌ Unexpected error: ${error.message}`);
results.push(` Code: ${error.code || 'N/A'}`);
}

Choose a reason for hiding this comment

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

medium

The test case description for 'Test 3' says it will test error handling with a fake collection, but the implementation uses the valid collection object passed into the function. This means the error path is not actually being tested. To properly test error handling, you should attempt to call .fullName() on an invalid or destroyed collection object and assert that it throws the expected error.

- Fix ProGuard typo: cbl.js.kotiln -> cbl.js.kotlin
- Fix nullable value handling in LogSinksManager.setFileSink
- Change Log.e to Log.w for non-critical listener debug message
- Update test case comment for clarity
pasin
pasin previously approved these changes Jan 8, 2026
Fixed an issue where passing an empty encryption key would cause a
callback error. Empty encryption keys are now properly handled on both
iOS and Android platforms to remove database encryption as intended.

- iOS: Removed validation that rejected empty strings, convert empty
  strings to nil before passing to DatabaseManager
- Android: Convert empty strings to null before passing to DatabaseManager

This prevents the "callback was already invoked" error and allows users
to remove encryption by providing an empty key value.
Temporarily disabled these test navigation items in the expo-example app.
pasin
pasin previously approved these changes Jan 9, 2026
Remove unused commented code for connecting to Sync Gateway from collection change listener test.
@jayant-dhingra-cb jayant-dhingra-cb merged commit 16d9e10 into main Jan 12, 2026
5 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.

5 participants