Skip to content

Commit cfbcd1a

Browse files
authored
1.6 Release Candidate 1 (#752)
* add clipboard button for inboxid to example app * update upstream library versions * libxmtp 1.6 feature related updates * update package version and release action --------- Co-authored-by: cameronvoell <[email protected]>
1 parent 157c889 commit cfbcd1a

File tree

17 files changed

+436
-66
lines changed

17 files changed

+436
-66
lines changed

.github/workflows/release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ jobs:
5858
if: steps.release-type.outputs.type == 'dev'
5959
run: |
6060
CURRENT_VERSION="${{ steps.current-version.outputs.current_version }}"
61-
if [[ ! $CURRENT_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+-dev$ ]]; then
62-
echo "Error: For dev releases, package version must be in format MAJOR.MINOR.PATCH-dev"
61+
if [[ ! $CURRENT_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+-(dev|rc[0-9]+)$ ]]; then
62+
echo "Error: For dev releases, package version must be in format MAJOR.MINOR.PATCH-dev or MAJOR.MINOR.PATCH-rc{number}"
6363
echo "Current version is $CURRENT_VERSION"
64-
echo "Please update package.json version to follow the dev format (e.g., 1.0.0-dev)"
64+
echo "Please update package.json version to follow the dev format (e.g., 1.0.0-dev or 1.0.0-rc1)"
6565
exit 1
6666
fi
6767

android/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ repositories {
9595
dependencies {
9696
implementation project(':expo-modules-core')
9797
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
98-
implementation "org.xmtp:android:4.6.0-dev.606cdda"
98+
implementation "org.xmtp:android:4.6.1-rc1"
9999
implementation 'com.google.code.gson:gson:2.10.1'
100100
implementation 'com.facebook.react:react-native:0.71.3'
101101
implementation "com.daveanthonythomas.moshipack:moshipack:1.0.1"
@@ -107,7 +107,7 @@ dependencies {
107107
// implementation 'io.grpc:grpc-protobuf-lite:1.62.2'
108108
// implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0'
109109
// implementation 'org.web3j:crypto:4.9.4'
110-
// implementation "net.java.dev.jna:jna:5.14.0@aar"
110+
// implementation "net.java.dev.jna:jna:5.17.0@aar"
111111
// api 'com.google.protobuf:protobuf-kotlin-lite:3.22.3'
112112
// api 'org.xmtp:proto-kotlin:3.72.4'
113113
}

android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ import org.xmtp.android.library.ConsentState
5151
import org.xmtp.android.library.Conversation
5252
import org.xmtp.android.library.Conversations
5353
import org.xmtp.android.library.Conversations.ConversationFilterType
54+
import org.xmtp.android.library.ForkRecoveryOptions
55+
import org.xmtp.android.library.ForkRecoveryPolicy
5456
import org.xmtp.android.library.PreEventCallback
5557
import org.xmtp.android.library.PreferenceType
5658
import org.xmtp.android.library.SendOptions
@@ -167,20 +169,22 @@ class XMTPModule : Module() {
167169
return reactContext
168170
}
169171

170-
private fun apiEnvironments(env: String, customLocalUrl: String? = null, appVersion: String? = null): ClientOptions.Api {
172+
private fun apiEnvironments(env: String, customLocalUrl: String? = null, appVersion: String? = null, gatewayHost: String? = null): ClientOptions.Api {
171173
return when (env) {
172174
"local" -> {
173175
if (customLocalUrl.isNullOrBlank()) {
174176
ClientOptions.Api(
175177
env = XMTPEnvironment.LOCAL,
176178
isSecure = false,
177179
appVersion = appVersion,
180+
gatewayHost = gatewayHost,
178181
)
179182
} else {
180183
ClientOptions.Api(
181184
env = XMTPEnvironment.LOCAL.withValue(customLocalUrl),
182185
isSecure = false,
183186
appVersion = appVersion,
187+
gatewayHost = gatewayHost,
184188
)
185189
}
186190
}
@@ -189,12 +193,14 @@ class XMTPModule : Module() {
189193
env = XMTPEnvironment.PRODUCTION,
190194
isSecure = true,
191195
appVersion = appVersion,
196+
gatewayHost = gatewayHost,
192197
)
193198

194199
else -> ClientOptions.Api(
195200
env = XMTPEnvironment.DEV,
196201
isSecure = true,
197202
appVersion = appVersion,
203+
gatewayHost = gatewayHost,
198204
)
199205
}
200206
}
@@ -220,14 +226,20 @@ class XMTPModule : Module() {
220226
else -> "https://message-history.dev.ephemera.network/"
221227
}
222228
return ClientOptions(
223-
api = apiEnvironments(authOptions.environment, authOptions.customLocalUrl, authOptions.appVersion),
229+
api = apiEnvironments(
230+
authOptions.environment,
231+
authOptions.customLocalUrl,
232+
authOptions.appVersion,
233+
authOptions.gatewayHost,
234+
),
224235
preAuthenticateToInboxCallback = preAuthenticateToInboxCallback,
225236
appContext = context,
226237
dbEncryptionKey = encryptionKeyBytes,
227238
dbDirectory = authOptions.dbDirectory,
228239
historySyncUrl = historySyncUrl,
229240
deviceSyncEnabled = authOptions.deviceSyncEnabled,
230241
debugEventsEnabled = authOptions.debugEventsEnabled,
242+
forkRecoveryOptions = authOptions.forkRecoveryOptions
231243
)
232244
}
233245

@@ -970,20 +982,20 @@ class XMTPModule : Module() {
970982
}
971983
}
972984

973-
AsyncFunction("getHmacKeys") Coroutine { inboxId: String ->
985+
AsyncFunction("getHmacKeys") Coroutine { installationId: String ->
974986
withContext(Dispatchers.IO) {
975987
logV("getHmacKeys")
976-
val client = clients[inboxId] ?: throw XMTPException("No client")
988+
val client = clients[installationId] ?: throw XMTPException("No client")
977989
val hmacKeys = client.conversations.getHmacKeys()
978990
logV("$hmacKeys")
979991
hmacKeys.toByteArray().map { it.toInt() and 0xFF }
980992
}
981993
}
982994

983-
AsyncFunction("getAllPushTopics") Coroutine { inboxId: String ->
995+
AsyncFunction("getAllPushTopics") Coroutine { installationId: String ->
984996
withContext(Dispatchers.IO) {
985997
logV("getAllPushTopics")
986-
val client = clients[inboxId] ?: throw XMTPException("No client")
998+
val client = clients[installationId] ?: throw XMTPException("No client")
987999
client.conversations.allPushTopics()
9881000
}
9891001
}
@@ -1354,7 +1366,7 @@ class XMTPModule : Module() {
13541366
val client = clients[installationId] ?: throw XMTPException("No client")
13551367
val consentStates = consentStringStates?.let { ConsentWrapper.getConsentStates(it) }
13561368
val numGroupsSyncedInt: Int =
1357-
client.conversations.syncAllConversations(consentStates).toInt()
1369+
client.conversations.syncAllConversations(consentStates).numSynced.toInt()
13581370
numGroupsSyncedInt
13591371
}
13601372
}
@@ -1854,6 +1866,16 @@ class XMTPModule : Module() {
18541866
}
18551867
}
18561868

1869+
AsyncFunction("leaveGroup") Coroutine { clientInstallationId: String, groupId: String ->
1870+
withContext(Dispatchers.IO) {
1871+
logV("leaveGroup")
1872+
val client = clients[clientInstallationId] ?: throw XMTPException("No client")
1873+
val group = client.conversations.findGroup(groupId)
1874+
?: throw XMTPException("no group found for $groupId")
1875+
group.leaveGroup()
1876+
}
1877+
}
1878+
18571879
Function("subscribeToPreferenceUpdates") { installationId: String ->
18581880
logV("subscribeToPreferenceUpdates")
18591881

android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/AuthParamsWrapper.kt

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package expo.modules.xmtpreactnativesdk.wrappers
22

3+
import com.google.gson.JsonArray
34
import com.google.gson.JsonParser
5+
import org.xmtp.android.library.ForkRecoveryOptions
6+
import org.xmtp.android.library.ForkRecoveryPolicy
47
import org.xmtp.android.library.SignerType
8+
import java.math.BigInteger
59

610
class AuthParamsWrapper(
711
val environment: String,
@@ -11,10 +15,71 @@ class AuthParamsWrapper(
1115
val deviceSyncEnabled: Boolean,
1216
val debugEventsEnabled: Boolean,
1317
val appVersion: String?,
18+
val gatewayHost: String?,
19+
val forkRecoveryOptions: ForkRecoveryOptions?
1420
) {
1521
companion object {
22+
private fun createForkRecoveryOptions(
23+
enableRecoveryRequestsString: String?,
24+
groupsToRequestRecovery: JsonArray?,
25+
disableRecoveryResponse: Boolean?,
26+
workerIntervalNs: BigInteger?
27+
): ForkRecoveryOptions? {
28+
// If none of the fork recovery options are provided, return null
29+
if (enableRecoveryRequestsString == null &&
30+
groupsToRequestRecovery == null &&
31+
disableRecoveryResponse == null &&
32+
workerIntervalNs == null) {
33+
return null
34+
}
35+
36+
// Convert groupsToRequestRecovery JsonArray to List<String>
37+
val groupsList = groupsToRequestRecovery?.map { it.asString } ?: emptyList()
38+
39+
//convert BigInt to ULong safely
40+
val workerIntervalNsLong = workerIntervalNs?.let { bigInt ->
41+
try {
42+
if (bigInt <= BigInteger.valueOf(Long.MAX_VALUE)) {
43+
bigInt.toLong().toULong()
44+
} else {
45+
ULong.MAX_VALUE // Clamp to max value if too large
46+
}
47+
} catch (e: Exception) {
48+
null
49+
}
50+
}
51+
52+
return ForkRecoveryOptions(
53+
enableRecoveryRequests = convertToForkRecoveryPolicy(enableRecoveryRequestsString),
54+
groupsToRequestRecovery = groupsList,
55+
disableRecoveryResponses = disableRecoveryResponse,
56+
workerIntervalNs = workerIntervalNsLong
57+
)
58+
}
59+
60+
private fun convertToForkRecoveryPolicy(enableRecoveryRequestsString: String?): ForkRecoveryPolicy {
61+
return when (enableRecoveryRequestsString) {
62+
"none" -> ForkRecoveryPolicy.None
63+
"all" -> ForkRecoveryPolicy.All
64+
"groups" -> ForkRecoveryPolicy.AllowlistedGroups
65+
else -> ForkRecoveryPolicy.None
66+
}
67+
}
68+
1669
fun authParamsFromJson(authParams: String): AuthParamsWrapper {
1770
val jsonOptions = JsonParser.parseString(authParams).asJsonObject
71+
val enableRecoveryRequestsString = if (jsonOptions.has("enableRecoveryRequests")) jsonOptions.get("enableRecoveryRequests").asString else null
72+
val groupsToRequestRecovery = if (jsonOptions.has("groupsToRequestRecovery")) jsonOptions.get("groupsToRequestRecovery").asJsonArray else null
73+
val disableRecoveryResponse = if (jsonOptions.has("disableRecoveryResponses")) jsonOptions.get("disableRecoveryResponses").asBoolean else null
74+
val workerIntervalNs = if (jsonOptions.has("workerIntervalNs")) jsonOptions.get("workerIntervalNs").asBigInteger else null
75+
76+
val forkRecoveryOptions = createForkRecoveryOptions(
77+
enableRecoveryRequestsString,
78+
groupsToRequestRecovery,
79+
disableRecoveryResponse,
80+
workerIntervalNs
81+
)
82+
1883
return AuthParamsWrapper(
1984
jsonOptions.get("environment").asString,
2085
if (jsonOptions.has("dbDirectory")) jsonOptions.get("dbDirectory").asString else null,
@@ -23,7 +88,9 @@ class AuthParamsWrapper(
2388
if (jsonOptions.has("deviceSyncEnabled")) jsonOptions.get("deviceSyncEnabled").asBoolean else true,
2489
if (jsonOptions.has("debugEventsEnabled")) jsonOptions.get("debugEventsEnabled").asBoolean else false,
2590
if (jsonOptions.has("appVersion")) jsonOptions.get("appVersion").asString else null,
26-
)
91+
if (jsonOptions.has("gatewayHost")) jsonOptions.get("gatewayHost").asString else null,
92+
forkRecoveryOptions
93+
)
2794
}
2895
}
2996
}

0 commit comments

Comments
 (0)