From 2fd4169f8846fa688b9812b865486c17c9a70f8e Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 25 Nov 2024 14:56:06 -0800 Subject: [PATCH 01/12] do the ios side --- android/build.gradle | 2 +- example/ios/Podfile.lock | 8 +-- ios/XMTPModule.swift | 108 ++++++++++++++++++++++++++++-------- ios/XMTPReactNative.podspec | 2 +- 4 files changed, 91 insertions(+), 29 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 1403dc5f..812c6841 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -98,7 +98,7 @@ repositories { dependencies { implementation project(':expo-modules-core') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}" - implementation "org.xmtp:android:3.0.8" + implementation "org.xmtp:android:3.0.10" implementation 'com.google.code.gson:gson:2.10.1' implementation 'com.facebook.react:react-native:0.71.3' implementation "com.daveanthonythomas.moshipack:moshipack:1.0.1" diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 2cdbd55f..cf4baccd 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -441,7 +441,7 @@ PODS: - RNSVG (13.14.0): - React-Core - SwiftProtobuf (1.28.2) - - XMTP (3.0.8): + - XMTP (3.0.10): - Connect-Swift (= 1.0.0) - CryptoSwift (= 1.8.3) - CSecp256k1 (~> 0.2) @@ -450,7 +450,7 @@ PODS: - CSecp256k1 (~> 0.2) - ExpoModulesCore - MessagePacker - - XMTP (= 3.0.8) + - XMTP (= 3.0.10) - Yoga (1.14.0) DEPENDENCIES: @@ -747,8 +747,8 @@ SPEC CHECKSUMS: RNScreens: 218801c16a2782546d30bd2026bb625c0302d70f RNSVG: d00c8f91c3cbf6d476451313a18f04d220d4f396 SwiftProtobuf: 4dbaffec76a39a8dc5da23b40af1a5dc01a4c02d - XMTP: f8ee66c4aacc5750ab0f67f5bb86c05cd2513185 - XMTPReactNative: 8cda2ca09be81cee8c26d986db65fc6faef57bea + XMTP: 22bd60ccd58801953c1bbc7619b0046b2eef5b97 + XMTPReactNative: 48e8bbbb9c1800cd507121bd9918aa4a571e8237 Yoga: e71803b4c1fff832ccf9b92541e00f9b873119b9 PODFILE CHECKSUM: 0e6fe50018f34e575d38dc6a1fdf1f99c9596cdd diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index 06c39289..4aa5b248 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -223,9 +223,11 @@ public class XMTPModule: Module { AsyncFunction("create") { ( address: String, hasAuthenticateToInboxCallback: Bool?, - dbEncryptionKey: [UInt8], authParams: String, walletParams: String + dbEncryptionKey: [UInt8], authParams: String, + walletParams: String ) in - let walletOptions = WalletParamsWrapper.walletParamsFromJson(walletParams) + let walletOptions = WalletParamsWrapper.walletParamsFromJson( + walletParams) let signer = ReactNativeSigner( module: self, address: address, walletType: walletOptions.walletType, @@ -271,13 +273,15 @@ public class XMTPModule: Module { key: client.inboxID, client: client) return try ClientWrapper.encodeToObj(client) } - - AsyncFunction("revokeAllOtherInstallations") { (inboxId: String, walletParams: String) in + + AsyncFunction("revokeAllOtherInstallations") { + (inboxId: String, walletParams: String) in guard let client = await clientsManager.getClient(key: inboxId) else { throw Error.noClient } - let walletOptions = WalletParamsWrapper.walletParamsFromJson(walletParams) + let walletOptions = WalletParamsWrapper.walletParamsFromJson( + walletParams) let signer = ReactNativeSigner( module: self, address: client.address, walletType: walletOptions.walletType, @@ -288,13 +292,15 @@ public class XMTPModule: Module { try await client.revokeAllOtherInstallations(signingKey: signer) self.signer = nil } - - AsyncFunction("addAccount") { (inboxId: String, newAddress: String, walletParams: String) in + + AsyncFunction("addAccount") { + (inboxId: String, newAddress: String, walletParams: String) in guard let client = await clientsManager.getClient(key: inboxId) else { throw Error.noClient } - let walletOptions = WalletParamsWrapper.walletParamsFromJson(walletParams) + let walletOptions = WalletParamsWrapper.walletParamsFromJson( + walletParams) let signer = ReactNativeSigner( module: self, address: newAddress, walletType: walletOptions.walletType, @@ -305,13 +311,15 @@ public class XMTPModule: Module { try await client.addAccount(newAccount: signer) self.signer = nil } - - AsyncFunction("removeAccount") { (inboxId: String, addressToRemove: String, walletParams: String) in + + AsyncFunction("removeAccount") { + (inboxId: String, addressToRemove: String, walletParams: String) in guard let client = await clientsManager.getClient(key: inboxId) else { throw Error.noClient } - let walletOptions = WalletParamsWrapper.walletParamsFromJson(walletParams) + let walletOptions = WalletParamsWrapper.walletParamsFromJson( + walletParams) let signer = ReactNativeSigner( module: self, address: client.address, walletType: walletOptions.walletType, @@ -319,7 +327,8 @@ public class XMTPModule: Module { blockNumber: walletOptions.blockNumber) self.signer = signer - try await client.removeAccount(recoveryAccount: signer, addressToRemove: addressToRemove) + try await client.removeAccount( + recoveryAccount: signer, addressToRemove: addressToRemove) self.signer = nil } @@ -337,14 +346,15 @@ public class XMTPModule: Module { let signature = try client.signWithInstallationKey(message: message) return [UInt8](signature) } - + AsyncFunction("verifySignature") { (inboxId: String, message: String, signature: [UInt8]) -> Bool in guard let client = await clientsManager.getClient(key: inboxId) else { throw Error.noClient } - return try client.verifySignature(message: message, signature: Data(signature)) + return try client.verifySignature( + message: message, signature: Data(signature)) } AsyncFunction("canMessage") { @@ -517,7 +527,8 @@ public class XMTPModule: Module { for conversation in conversations { let encodedConversationContainer = try await ConversationWrapper.encode( - conversation, client: client, conversationParams: params) + conversation, client: client, conversationParams: params + ) results.append(encodedConversationContainer) } return results @@ -1398,7 +1409,7 @@ public class XMTPModule: Module { throw Error.noClient } - try await client.syncConsent() + try await client.preferences.syncConsent() } AsyncFunction("setConsentState") { @@ -1414,9 +1425,9 @@ public class XMTPModule: Module { let resolvedEntryType = try getEntryType(type: entryType) let resolvedConsentState = try getConsentState(state: consentType) - try await client.preferences.consentList.setConsentState( + try await client.preferences.setConsentState( entries: [ - ConsentListEntry( + ConsentRecord( value: value, entryType: resolvedEntryType, consentType: resolvedConsentState @@ -1432,7 +1443,7 @@ public class XMTPModule: Module { throw Error.noClient } return try await ConsentWrapper.consentStateToString( - state: client.preferences.consentList.addressState( + state: client.preferences.addressState( address: address)) } @@ -1443,7 +1454,7 @@ public class XMTPModule: Module { throw Error.noClient } return try await ConsentWrapper.consentStateToString( - state: client.preferences.consentList.inboxIdState( + state: client.preferences.inboxIdState( inboxId: peerInboxId)) } @@ -1454,7 +1465,7 @@ public class XMTPModule: Module { throw Error.noClient } return try await ConsentWrapper.consentStateToString( - state: client.preferences.consentList.conversationState( + state: client.preferences.conversationState( conversationId: conversationId)) } @@ -1496,6 +1507,13 @@ public class XMTPModule: Module { state: getConsentState(state: state)) } + AsyncFunction("subscribeToConsent") { + (inboxId: String) in + + try await subscribeToConsent( + inboxId: inboxId) + } + AsyncFunction("subscribeToConversations") { (inboxId: String, type: String) in @@ -1514,6 +1532,11 @@ public class XMTPModule: Module { try await subscribeToMessages(inboxId: inboxId, id: id) } + AsyncFunction("unsubscribeFromConsent") { (inboxId: String) in + await subscriptionsManager.get(getConsentKey(inboxId: inboxId))? + .cancel() + } + AsyncFunction("unsubscribeFromConversations") { (inboxId: String) in await subscriptionsManager.get( getConversationsKey(inboxId: inboxId))?.cancel() @@ -1706,11 +1729,46 @@ public class XMTPModule: Module { let authOptions = AuthParamsWrapper.authParamsFromJson(authParams) return XMTP.ClientOptions( - api: createApiClient(env: authOptions.environment, appVersion: authOptions.appVersion), + api: createApiClient( + env: authOptions.environment, appVersion: authOptions.appVersion + ), preAuthenticateToInboxCallback: preAuthenticateToInboxCallback, - dbEncryptionKey: dbEncryptionKey, dbDirectory: authOptions.dbDirectory, + dbEncryptionKey: dbEncryptionKey, + dbDirectory: authOptions.dbDirectory, historySyncUrl: authOptions.historySyncUrl) } + + func subscribeToConsent(inboxId: String) + async throws + { + guard let client = await clientsManager.getClient(key: inboxId) else { + return + } + + await subscriptionsManager.get(getConsentKey(inboxId: inboxId))? + .cancel() + await subscriptionsManager.set( + getConsentKey(inboxId: inboxId), + Task { + do { + for try await consent in await client.preferences + .streamConsent() + { + try sendEvent( + "consent", + [ + "inboxId": inboxId, + "consent": ConsentWrapper.encodeToObj( + consent, client: client), + ]) + } + } catch { + print("Error in consent subscription: \(error)") + await subscriptionsManager.get( + getConsentKey(inboxId: inboxId))?.cancel() + } + }) + } func subscribeToConversations(inboxId: String, type: ConversationType) async throws @@ -1830,6 +1888,10 @@ public class XMTPModule: Module { await subscriptionsManager.get(converation.cacheKey(inboxId))? .cancel() } + + func getConsentKey(inboxId: String) -> String { + return "consent:\(inboxId)" + } func getMessagesKey(inboxId: String) -> String { return "messages:\(inboxId)" diff --git a/ios/XMTPReactNative.podspec b/ios/XMTPReactNative.podspec index 1be2289e..26f28970 100644 --- a/ios/XMTPReactNative.podspec +++ b/ios/XMTPReactNative.podspec @@ -26,6 +26,6 @@ Pod::Spec.new do |s| s.source_files = "**/*.{h,m,swift}" s.dependency "MessagePacker" - s.dependency "XMTP", "= 3.0.8" + s.dependency "XMTP", "= 3.0.10" s.dependency 'CSecp256k1', '~> 0.2' end From b0e98ef340edbe105d379e62d025895f3ac39449 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 25 Nov 2024 15:04:25 -0800 Subject: [PATCH 02/12] do the android side --- .../modules/xmtpreactnativesdk/XMTPModule.kt | 54 ++++++++++++++++--- .../wrappers/ConsentWrapper.kt | 30 +++++++++++ ios/Wrappers/ConsentWrapper.swift | 4 +- ios/XMTPModule.swift | 3 +- src/lib/ConsentListEntry.ts | 12 ++--- 5 files changed, 87 insertions(+), 16 deletions(-) create mode 100644 android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ConsentWrapper.kt diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 0a9db884..3f0d9a18 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -13,6 +13,7 @@ import expo.modules.kotlin.modules.Module import expo.modules.kotlin.modules.ModuleDefinition import expo.modules.xmtpreactnativesdk.wrappers.AuthParamsWrapper import expo.modules.xmtpreactnativesdk.wrappers.ClientWrapper +import expo.modules.xmtpreactnativesdk.wrappers.ConsentWrapper import expo.modules.xmtpreactnativesdk.wrappers.ContentJson import expo.modules.xmtpreactnativesdk.wrappers.ConversationWrapper import expo.modules.xmtpreactnativesdk.wrappers.ConversationParamsWrapper @@ -35,7 +36,7 @@ import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext import org.xmtp.android.library.Client import org.xmtp.android.library.ClientOptions -import org.xmtp.android.library.ConsentListEntry +import org.xmtp.android.library.ConsentRecord import org.xmtp.android.library.ConsentState import org.xmtp.android.library.Conversation import org.xmtp.android.library.Conversations.* @@ -206,6 +207,7 @@ class XMTPModule : Module() { "conversation", "message", "conversationMessage", + "consent", ) Function("address") { inboxId: String -> @@ -1144,16 +1146,16 @@ class XMTPModule : Module() { AsyncFunction("syncConsent") Coroutine { inboxId: String -> withContext(Dispatchers.IO) { val client = clients[inboxId] ?: throw XMTPException("No client") - client.syncConsent() + client.preferences.syncConsent() } } AsyncFunction("setConsentState") Coroutine { inboxId: String, value: String, entryType: String, consentType: String -> withContext(Dispatchers.IO) { val client = clients[inboxId] ?: throw XMTPException("No client") - client.preferences.consentList.setConsentState( + client.preferences.setConsentState( listOf( - ConsentListEntry( + ConsentRecord( value, getEntryType(entryType), getConsentState(consentType) @@ -1166,21 +1168,21 @@ class XMTPModule : Module() { AsyncFunction("consentAddressState") Coroutine { inboxId: String, peerAddress: String -> withContext(Dispatchers.IO) { val client = clients[inboxId] ?: throw XMTPException("No client") - consentStateToString(client.preferences.consentList.addressState(peerAddress)) + consentStateToString(client.preferences.addressState(peerAddress)) } } AsyncFunction("consentInboxIdState") Coroutine { inboxId: String, peerInboxId: String -> withContext(Dispatchers.IO) { val client = clients[inboxId] ?: throw XMTPException("No client") - consentStateToString(client.preferences.consentList.inboxIdState(peerInboxId)) + consentStateToString(client.preferences.inboxIdState(peerInboxId)) } } AsyncFunction("consentConversationIdState") Coroutine { inboxId: String, conversationId: String -> withContext(Dispatchers.IO) { val client = clients[inboxId] ?: throw XMTPException("No client") - consentStateToString(client.preferences.consentList.conversationState(conversationId)) + consentStateToString(client.preferences.conversationState(conversationId)) } } @@ -1204,6 +1206,12 @@ class XMTPModule : Module() { } } + Function("subscribeToConsent") { inboxId: String -> + logV("subscribeToConsent") + + subscribeToConsent(inboxId = inboxId) + } + Function("subscribeToConversations") { inboxId: String, type: String -> logV("subscribeToConversations") @@ -1225,6 +1233,11 @@ class XMTPModule : Module() { } } + Function("unsubscribeFromConsent") { inboxId: String -> + logV("unsubscribeFromConsent") + subscriptions[getConsentKey(inboxId)]?.cancel() + } + Function("unsubscribeFromConversations") { inboxId: String -> logV("unsubscribeFromConversations") subscriptions[getConversationsKey(inboxId)]?.cancel() @@ -1341,6 +1354,29 @@ class XMTPModule : Module() { } } + private fun subscribeToConsent(inboxId: String) { + val client = clients[inboxId] ?: throw XMTPException("No client") + + subscriptions[getConsentKey(client.inboxId)]?.cancel() + subscriptions[getConsentKey(client.inboxId)] = + CoroutineScope(Dispatchers.IO).launch { + try { + client.preferences.streamConsent().collect { consent -> + sendEvent( + "consent", + mapOf( + "inboxId" to inboxId, + "consent" to ConsentWrapper.encodeMap(consent) + ) + ) + } + } catch (e: Exception) { + Log.e("XMTPModule", "Error in group subscription: $e") + subscriptions[getConsentKey(client.inboxId)]?.cancel() + } + } + } + private fun subscribeToConversations(inboxId: String, type: ConversationType) { val client = clients[inboxId] ?: throw XMTPException("No client") @@ -1414,6 +1450,10 @@ class XMTPModule : Module() { } } + private fun getConsentKey(inboxId: String): String { + return "consent:$inboxId" + } + private fun getMessagesKey(inboxId: String): String { return "messages:$inboxId" } diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ConsentWrapper.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ConsentWrapper.kt new file mode 100644 index 00000000..1b6d984a --- /dev/null +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ConsentWrapper.kt @@ -0,0 +1,30 @@ +package expo.modules.xmtpreactnativesdk.wrappers + +import com.google.gson.GsonBuilder +import org.xmtp.android.library.ConsentRecord +import org.xmtp.android.library.ConsentState + +class ConsentWrapper { + + companion object { + fun encode(model: ConsentRecord): String { + val gson = GsonBuilder().create() + val message = encodeMap(model) + return gson.toJson(message) + } + + fun encodeMap(model: ConsentRecord): Map = mapOf( + "type" to model.entryType.name.lowercase(), + "value" to model.value.lowercase(), + "state" to consentStateToString(model.consentType), + ) + + fun consentStateToString(state: ConsentState): String { + return when (state) { + ConsentState.ALLOWED -> "allowed" + ConsentState.DENIED -> "denied" + ConsentState.UNKNOWN -> "unknown" + } + } + } +} \ No newline at end of file diff --git a/ios/Wrappers/ConsentWrapper.swift b/ios/Wrappers/ConsentWrapper.swift index c683925a..2eb85e2a 100644 --- a/ios/Wrappers/ConsentWrapper.swift +++ b/ios/Wrappers/ConsentWrapper.swift @@ -2,7 +2,7 @@ import Foundation import XMTP struct ConsentWrapper { - static func encodeToObj(_ entry: XMTP.ConsentListEntry) throws -> [String: Any] { + static func encodeToObj(_ entry: XMTP.ConsentRecord) throws -> [String: Any] { return [ "type": entry.entryType.rawValue, "value": entry.value, @@ -10,7 +10,7 @@ struct ConsentWrapper { ] } - static func encode(_ entry: XMTP.ConsentListEntry) throws -> String { + static func encode(_ entry: XMTP.ConsentRecord) throws -> String { let obj = try encodeToObj(entry) let data = try JSONSerialization.data(withJSONObject: obj) guard let result = String(data: data, encoding: .utf8) else { diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index 4aa5b248..a7c4519d 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -89,7 +89,8 @@ public class XMTPModule: Module { "preAuthenticateToInboxCallback", "conversation", "message", - "conversationMessage" + "conversationMessage", + "consent" ) AsyncFunction("address") { (inboxId: String) -> String in diff --git a/src/lib/ConsentListEntry.ts b/src/lib/ConsentListEntry.ts index 2393fc09..ac93b1be 100644 --- a/src/lib/ConsentListEntry.ts +++ b/src/lib/ConsentListEntry.ts @@ -1,15 +1,15 @@ export type ConsentState = 'allowed' | 'denied' | 'unknown' -export type ConsentListEntryType = 'address' | 'conversation_id' | 'inbox_id' +export type ConsentType = 'address' | 'conversation_id' | 'inbox_id' -export class ConsentListEntry { +export class ConsentRecord { value: string - entryType: ConsentListEntryType + entryType: ConsentType permissionType: ConsentState constructor( value: string, - entryType: ConsentListEntryType, + entryType: ConsentType, permissionType: ConsentState ) { this.value = value @@ -17,8 +17,8 @@ export class ConsentListEntry { this.permissionType = permissionType } - static from(json: string): ConsentListEntry { + static from(json: string): ConsentRecord { const entry = JSON.parse(json) - return new ConsentListEntry(entry.value, entry.type, entry.state) + return new ConsentRecord(entry.value, entry.type, entry.state) } } From fefbcdba3851eb0fa0c04e44134b624c4cfa25cd Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 25 Nov 2024 15:09:45 -0800 Subject: [PATCH 03/12] update the react native side --- example/src/tests/groupTests.ts | 10 +++++----- src/index.ts | 18 +++++++++++------- .../{ConsentListEntry.ts => ConsentRecord.ts} | 0 src/lib/Conversation.ts | 2 +- src/lib/Dm.ts | 2 +- src/lib/Group.ts | 2 +- src/lib/Member.ts | 2 +- src/lib/PrivatePreferences.ts | 2 +- 8 files changed, 21 insertions(+), 17 deletions(-) rename src/lib/{ConsentListEntry.ts => ConsentRecord.ts} (100%) diff --git a/example/src/tests/groupTests.ts b/example/src/tests/groupTests.ts index e8b04e71..c97455b6 100644 --- a/example/src/tests/groupTests.ts +++ b/example/src/tests/groupTests.ts @@ -13,8 +13,8 @@ import { Group, GroupUpdatedContent, GroupUpdatedCodec, - ConsentListEntry, DecodedMessage, + ConsentRecord, } from '../../../src/index' export const groupTests: Test[] = [] @@ -1185,7 +1185,7 @@ test('can group consent', async () => { ) await bo.preferences.setConsentState( - new ConsentListEntry(group.id, 'conversation_id', 'denied') + new ConsentRecord(group.id, 'conversation_id', 'denied') ) const isDenied = await bo.preferences.conversationConsentState(group.id) assert(isDenied === 'denied', `bo group should be denied but was ${isDenied}`) @@ -1219,7 +1219,7 @@ test('can allow and deny a inbox id', async () => { ) await bo.preferences.setConsentState( - new ConsentListEntry(alix.inboxId, 'inbox_id', 'allowed') + new ConsentRecord(alix.inboxId, 'inbox_id', 'allowed') ) let alixMember = (await boGroup.members()).find( @@ -1243,7 +1243,7 @@ test('can allow and deny a inbox id', async () => { ) await bo.preferences.setConsentState( - new ConsentListEntry(alix.inboxId, 'inbox_id', 'denied') + new ConsentRecord(alix.inboxId, 'inbox_id', 'denied') ) alixMember = (await boGroup.members()).find( @@ -1261,7 +1261,7 @@ test('can allow and deny a inbox id', async () => { ) await bo.preferences.setConsentState( - new ConsentListEntry(alix.address, 'address', 'allowed') + new ConsentRecord(alix.address, 'address', 'allowed') ) isAddressAllowed = await bo.preferences.addressConsentState(alix.address) diff --git a/src/index.ts b/src/index.ts index 5fce15be..3375a32d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,11 +3,7 @@ import { EventEmitter, NativeModulesProxy } from 'expo-modules-core' import { Client } from '.' import XMTPModule from './XMTPModule' import { Address, InboxId, XMTPEnvironment } from './lib/Client' -import { - ConsentListEntry, - ConsentListEntryType, - ConsentState, -} from './lib/ConsentListEntry' +import { ConsentRecord, ConsentState, ConsentType } from './lib/ConsentRecord' import { DecryptedLocalAttachment, EncryptedLocalAttachment, @@ -957,7 +953,7 @@ export async function syncConsent(inboxId: InboxId): Promise { export async function setConsentState( inboxId: InboxId, value: string, - entryType: ConsentListEntryType, + entryType: ConsentType, consentType: ConsentState ): Promise { return await XMTPModule.setConsentState( @@ -1001,6 +997,10 @@ export async function updateConversationConsent( return XMTPModule.updateConversationConsent(inboxId, conversationId, state) } +export function subscribeToConsent(inboxId: InboxId) { + return XMTPModule.subscribeToConsent(inboxId) +} + export function subscribeToConversations( inboxId: InboxId, type: ConversationType @@ -1022,6 +1022,10 @@ export async function subscribeToMessages( return await XMTPModule.subscribeToMessages(inboxId, id) } +export function unsubscribeFromConsent(inboxId: InboxId) { + return XMTPModule.unsubscribeFromConsent(inboxId) +} + export function unsubscribeFromConversations(inboxId: InboxId) { return XMTPModule.unsubscribeFromConversations(inboxId) } @@ -1075,7 +1079,7 @@ export { Client } from './lib/Client' export * from './lib/ContentCodec' export { Conversation, ConversationVersion } from './lib/Conversation' export { XMTPPush } from './lib/XMTPPush' -export { ConsentListEntry, DecodedMessage, MessageDeliveryStatus, ConsentState } +export { ConsentRecord, DecodedMessage, MessageDeliveryStatus, ConsentState } export { Group } from './lib/Group' export { Dm } from './lib/Dm' export { Member } from './lib/Member' diff --git a/src/lib/ConsentListEntry.ts b/src/lib/ConsentRecord.ts similarity index 100% rename from src/lib/ConsentListEntry.ts rename to src/lib/ConsentRecord.ts diff --git a/src/lib/Conversation.ts b/src/lib/Conversation.ts index 0b8db1a1..11521972 100644 --- a/src/lib/Conversation.ts +++ b/src/lib/Conversation.ts @@ -1,4 +1,4 @@ -import { ConsentState } from './ConsentListEntry' +import { ConsentState } from './ConsentRecord' import { ConversationSendPayload, MessageId, MessagesOptions } from './types' import { DefaultContentTypes } from './types/DefaultContentType' import * as XMTP from '../index' diff --git a/src/lib/Dm.ts b/src/lib/Dm.ts index f78daf86..005201b9 100644 --- a/src/lib/Dm.ts +++ b/src/lib/Dm.ts @@ -1,5 +1,5 @@ import { InboxId } from './Client' -import { ConsentState } from './ConsentListEntry' +import { ConsentState } from './ConsentRecord' import { ConversationVersion, ConversationBase } from './Conversation' import { DecodedMessage } from './DecodedMessage' import { Member } from './Member' diff --git a/src/lib/Group.ts b/src/lib/Group.ts index 7eff0a36..9b709d27 100644 --- a/src/lib/Group.ts +++ b/src/lib/Group.ts @@ -1,5 +1,5 @@ import { InboxId } from './Client' -import { ConsentState } from './ConsentListEntry' +import { ConsentState } from './ConsentRecord' import { ConversationBase, ConversationVersion } from './Conversation' import { DecodedMessage } from './DecodedMessage' import { Member } from './Member' diff --git a/src/lib/Member.ts b/src/lib/Member.ts index 416431be..514a037b 100644 --- a/src/lib/Member.ts +++ b/src/lib/Member.ts @@ -1,5 +1,5 @@ import { Address, InboxId } from './Client' -import { ConsentState } from './ConsentListEntry' +import { ConsentState } from './ConsentRecord' export type PermissionLevel = 'member' | 'admin' | 'super_admin' diff --git a/src/lib/PrivatePreferences.ts b/src/lib/PrivatePreferences.ts index f78baca7..b019fb48 100644 --- a/src/lib/PrivatePreferences.ts +++ b/src/lib/PrivatePreferences.ts @@ -1,5 +1,5 @@ import { Address, Client, InboxId } from './Client' -import { ConsentListEntry, ConsentState } from './ConsentListEntry' +import { ConsentListEntry, ConsentState } from './ConsentRecord' import * as XMTPModule from '../index' import { ConversationId } from '../index' import { getAddress } from '../utils/address' From f0eb4a7c8287c3130ff72ed36d4e5b7afb8ac400 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 25 Nov 2024 15:20:43 -0800 Subject: [PATCH 04/12] fix: add consent streaming --- src/lib/ConsentRecord.ts | 10 +++---- src/lib/PrivatePreferences.ts | 51 +++++++++++++++++++++++++++++++---- src/lib/types/EventTypes.ts | 4 +++ 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/lib/ConsentRecord.ts b/src/lib/ConsentRecord.ts index ac93b1be..607b8b34 100644 --- a/src/lib/ConsentRecord.ts +++ b/src/lib/ConsentRecord.ts @@ -5,16 +5,12 @@ export type ConsentType = 'address' | 'conversation_id' | 'inbox_id' export class ConsentRecord { value: string entryType: ConsentType - permissionType: ConsentState + state: ConsentState - constructor( - value: string, - entryType: ConsentType, - permissionType: ConsentState - ) { + constructor(value: string, entryType: ConsentType, state: ConsentState) { this.value = value this.entryType = entryType - this.permissionType = permissionType + this.state = state } static from(json: string): ConsentRecord { diff --git a/src/lib/PrivatePreferences.ts b/src/lib/PrivatePreferences.ts index b019fb48..db881b79 100644 --- a/src/lib/PrivatePreferences.ts +++ b/src/lib/PrivatePreferences.ts @@ -1,11 +1,13 @@ import { Address, Client, InboxId } from './Client' -import { ConsentListEntry, ConsentState } from './ConsentRecord' +import { ConsentRecord, ConsentState } from './ConsentRecord' +import { EventTypes } from './types/EventTypes' import * as XMTPModule from '../index' import { ConversationId } from '../index' import { getAddress } from '../utils/address' export default class PrivatePreferences { client: Client + private subscriptions: { [key: string]: { remove: () => void } } = {} constructor(client: Client) { this.client = client @@ -31,16 +33,55 @@ export default class PrivatePreferences { ) } - async setConsentState(consentEntry: ConsentListEntry): Promise { + async setConsentState(consentRecord: ConsentRecord): Promise { return await XMTPModule.setConsentState( this.client.inboxId, - consentEntry.value, - consentEntry.entryType, - consentEntry.permissionType + consentRecord.value, + consentRecord.entryType, + consentRecord.permissionType ) } async syncConsent(): Promise { return await XMTPModule.syncConsent(this.client.inboxId) } + + /** + * This method streams consent. + * @returns {Promise} A Promise that resolves to an array of ConsentRecord objects. + */ + async streamConsent( + callback: (consent: ConsentRecord) => Promise + ): Promise { + XMTPModule.subscribeToConsent(this.client.inboxId) + const subscription = XMTPModule.emitter.addListener( + EventTypes.Consent, + async ({ + inboxId, + consent, + }: { + inboxId: string + consent: ConsentRecord + }) => { + if (inboxId !== this.client.inboxId) { + return + } + return await callback( + new ConsentRecord(consent.value, consent.entryType, consent.state) + ) + } + ) + this.subscriptions[EventTypes.Consent] = subscription + } + + /** + * Cancels the stream for new consent records. + */ + cancelStreamConsent() { + if (this.subscriptions[EventTypes.Consent]) { + this.subscriptions[EventTypes.Consent].remove() + delete this.subscriptions[EventTypes.Consent] + } + XMTPModule.unsubscribeFromConsent(this.client.inboxId) + } } diff --git a/src/lib/types/EventTypes.ts b/src/lib/types/EventTypes.ts index f6cbed4b..9f2c0d3f 100644 --- a/src/lib/types/EventTypes.ts +++ b/src/lib/types/EventTypes.ts @@ -17,4 +17,8 @@ export enum EventTypes { * A new message is sent to a specific conversation */ ConversationMessage = 'conversationMessage', + /** + * A inboxId or conversation has been approved or denied + */ + Consent = 'consent', } From 12410205d510569284a4f950de729496f316797f Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 25 Nov 2024 15:23:03 -0800 Subject: [PATCH 05/12] fix swift compiler --- ios/XMTPModule.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index a7c4519d..bcfd1c79 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -1760,7 +1760,7 @@ public class XMTPModule: Module { [ "inboxId": inboxId, "consent": ConsentWrapper.encodeToObj( - consent, client: client), + consent), ]) } } catch { From 7dc349f0adfe5b9d25961b2b3eee9a646a5279b4 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 25 Nov 2024 15:25:17 -0800 Subject: [PATCH 06/12] fix another lint issue --- src/lib/PrivatePreferences.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/PrivatePreferences.ts b/src/lib/PrivatePreferences.ts index db881b79..cdce5f58 100644 --- a/src/lib/PrivatePreferences.ts +++ b/src/lib/PrivatePreferences.ts @@ -38,7 +38,7 @@ export default class PrivatePreferences { this.client.inboxId, consentRecord.value, consentRecord.entryType, - consentRecord.permissionType + consentRecord.state ) } From 234674699bd2df5eb9911964d9e611ca4e539e99 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 26 Nov 2024 09:19:53 -0800 Subject: [PATCH 07/12] update android to installation based ids --- .../modules/xmtpreactnativesdk/XMTPModule.kt | 430 +++++++++--------- 1 file changed, 215 insertions(+), 215 deletions(-) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 3f0d9a18..a4d2db31 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -129,8 +129,8 @@ data class SignatureRequest( var message: String, ) -fun Conversation.cacheKey(inboxId: String): String { - return "${inboxId}:${topic}" +fun Conversation.cacheKey(installationId: String): String { + return "${installationId}:${topic}" } class XMTPModule : Module() { @@ -210,63 +210,63 @@ class XMTPModule : Module() { "consent", ) - Function("address") { inboxId: String -> + Function("address") { installationId: String -> logV("address") - val client = clients[inboxId] + val client = clients[installationId] client?.address ?: "No Client." } - Function("inboxId") { inboxId: String -> + Function("inboxId") { installationId: String -> logV("inboxId") - val client = clients[inboxId] + val client = clients[installationId] client?.inboxId ?: "No Client." } - AsyncFunction("findInboxIdFromAddress") Coroutine { inboxId: String, address: String -> + AsyncFunction("findInboxIdFromAddress") Coroutine { installationId: String, address: String -> withContext(Dispatchers.IO) { logV("findInboxIdFromAddress") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") client.inboxIdFromAddress(address) } } - AsyncFunction("deleteLocalDatabase") { inboxId: String -> - logV(inboxId) + AsyncFunction("deleteLocalDatabase") { installationId: String -> + logV(installationId) logV(clients.toString()) - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") client.deleteLocalDatabase() } - Function("dropLocalDatabaseConnection") { inboxId: String -> - val client = clients[inboxId] ?: throw XMTPException("No client") + Function("dropLocalDatabaseConnection") { installationId: String -> + val client = clients[installationId] ?: throw XMTPException("No client") client.dropLocalDatabaseConnection() } - AsyncFunction("reconnectLocalDatabase") Coroutine { inboxId: String -> + AsyncFunction("reconnectLocalDatabase") Coroutine { installationId: String -> withContext(Dispatchers.IO) { - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") client.reconnectLocalDatabase() } } - AsyncFunction("requestMessageHistorySync") Coroutine { inboxId: String -> + AsyncFunction("requestMessageHistorySync") Coroutine { installationId: String -> withContext(Dispatchers.IO) { - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") client.requestMessageHistorySync() } } - AsyncFunction("getInboxState") Coroutine { inboxId: String, refreshFromNetwork: Boolean -> + AsyncFunction("getInboxState") Coroutine { installationId: String, refreshFromNetwork: Boolean -> withContext(Dispatchers.IO) { - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val inboxState = client.inboxState(refreshFromNetwork) InboxStateWrapper.encode(inboxState) } } - AsyncFunction("getInboxStates") Coroutine { inboxId: String, refreshFromNetwork: Boolean, inboxIds: List -> + AsyncFunction("getInboxStates") Coroutine { installationId: String, refreshFromNetwork: Boolean, inboxIds: List -> withContext(Dispatchers.IO) { - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val inboxStates = client.inboxStatesForInboxIds(refreshFromNetwork, inboxIds) inboxStates.map { InboxStateWrapper.encode(it) } } @@ -302,7 +302,7 @@ class XMTPModule : Module() { val randomClient = Client().create(account = privateKey, options = options) ContentJson.Companion - clients[randomClient.inboxId] = randomClient + clients[randomClient.installationId] = randomClient ClientWrapper.encodeToObj(randomClient) } } @@ -325,7 +325,7 @@ class XMTPModule : Module() { hasAuthInboxCallback, ) val client = Client().create(account = reactSigner, options = options) - clients[client.inboxId] = client + clients[client.installationId] = client ContentJson.Companion signer = null sendEvent("authed", ClientWrapper.encodeToObj(client)) @@ -341,15 +341,15 @@ class XMTPModule : Module() { ) val client = Client().build(address = address, options = options) ContentJson.Companion - clients[client.inboxId] = client + clients[client.installationId] = client ClientWrapper.encodeToObj(client) } } - AsyncFunction("revokeAllOtherInstallations") Coroutine { inboxId: String, walletParams: String -> + AsyncFunction("revokeAllOtherInstallations") Coroutine { installationId: String, walletParams: String -> withContext(Dispatchers.IO) { logV("revokeAllOtherInstallations") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val walletOptions = WalletParamsWrapper.walletParamsFromJson(walletParams) val reactSigner = ReactNativeSigner( @@ -366,10 +366,10 @@ class XMTPModule : Module() { } } - AsyncFunction("addAccount") Coroutine { inboxId: String, newAddress: String, walletParams: String -> + AsyncFunction("addAccount") Coroutine { installationId: String, newAddress: String, walletParams: String -> withContext(Dispatchers.IO) { logV("addAccount") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val walletOptions = WalletParamsWrapper.walletParamsFromJson(walletParams) val reactSigner = ReactNativeSigner( @@ -386,10 +386,10 @@ class XMTPModule : Module() { } } - AsyncFunction("removeAccount") Coroutine { inboxId: String, addressToRemove: String, walletParams: String -> + AsyncFunction("removeAccount") Coroutine { installationId: String, addressToRemove: String, walletParams: String -> withContext(Dispatchers.IO) { logV("removeAccount") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val walletOptions = WalletParamsWrapper.walletParamsFromJson(walletParams) val reactSigner = ReactNativeSigner( @@ -406,28 +406,28 @@ class XMTPModule : Module() { } } - AsyncFunction("dropClient") Coroutine { inboxId: String -> + AsyncFunction("dropClient") Coroutine { installationId: String -> withContext(Dispatchers.IO) { logV("dropClient") - clients.remove(inboxId) + clients.remove(installationId) Unit } } - AsyncFunction("signWithInstallationKey") Coroutine { inboxId: String, message: String -> + AsyncFunction("signWithInstallationKey") Coroutine { installationId: String, message: String -> withContext(Dispatchers.IO) { logV("signWithInstallationKey") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val signature = client.signWithInstallationKey(message) signature.map { it.toInt() and 0xFF } } } - AsyncFunction("verifySignature") Coroutine { inboxId: String, message: String, signature: List -> + AsyncFunction("verifySignature") Coroutine { installationId: String, message: String, signature: List -> withContext(Dispatchers.IO) { logV("verifySignature") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val signatureBytes = signature.foldIndexed(ByteArray(signature.size)) { i, a, v -> a.apply { set(i, v.toByte()) } @@ -436,10 +436,10 @@ class XMTPModule : Module() { } } - AsyncFunction("canMessage") Coroutine { inboxId: String, peerAddresses: List -> + AsyncFunction("canMessage") Coroutine { installationId: String, peerAddresses: List -> withContext(Dispatchers.IO) { logV("canMessage") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") client.canMessage(peerAddresses) } } @@ -458,7 +458,7 @@ class XMTPModule : Module() { } } - AsyncFunction("encryptAttachment") { inboxId: String, fileJson: String -> + AsyncFunction("encryptAttachment") { installationId: String, fileJson: String -> logV("encryptAttachment") val file = DecryptedLocalAttachment.fromJson(fileJson) val uri = Uri.parse(file.fileUri) @@ -484,7 +484,7 @@ class XMTPModule : Module() { ).toJson() } - AsyncFunction("decryptAttachment") { inboxId: String, encryptedFileJson: String -> + AsyncFunction("decryptAttachment") { installationId: String, encryptedFileJson: String -> logV("decryptAttachment") val encryptedFile = EncryptedLocalAttachment.fromJson(encryptedFileJson) val encryptedData = appContext.reactContext?.contentResolver @@ -510,10 +510,10 @@ class XMTPModule : Module() { ).toJson() } - AsyncFunction("listGroups") Coroutine { inboxId: String, groupParams: String?, sortOrder: String?, limit: Int?, consentState: String? -> + AsyncFunction("listGroups") Coroutine { installationId: String, groupParams: String?, sortOrder: String?, limit: Int?, consentState: String? -> withContext(Dispatchers.IO) { logV("listGroups") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val params = ConversationParamsWrapper.conversationParamsFromJson(groupParams ?: "") val order = getConversationSortOrder(sortOrder ?: "") val consent = consentState?.let { getConsentState(it) } @@ -528,10 +528,10 @@ class XMTPModule : Module() { } } - AsyncFunction("listDms") Coroutine { inboxId: String, groupParams: String?, sortOrder: String?, limit: Int?, consentState: String? -> + AsyncFunction("listDms") Coroutine { installationId: String, groupParams: String?, sortOrder: String?, limit: Int?, consentState: String? -> withContext(Dispatchers.IO) { logV("listDms") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val params = ConversationParamsWrapper.conversationParamsFromJson(groupParams ?: "") val order = getConversationSortOrder(sortOrder ?: "") val consent = consentState?.let { getConsentState(it) } @@ -546,10 +546,10 @@ class XMTPModule : Module() { } } - AsyncFunction("listConversations") Coroutine { inboxId: String, conversationParams: String?, sortOrder: String?, limit: Int?, consentState: String? -> + AsyncFunction("listConversations") Coroutine { installationId: String, conversationParams: String?, sortOrder: String?, limit: Int?, consentState: String? -> withContext(Dispatchers.IO) { logV("listConversations") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val params = ConversationParamsWrapper.conversationParamsFromJson(conversationParams ?: "") val order = getConversationSortOrder(sortOrder ?: "") @@ -562,10 +562,10 @@ class XMTPModule : Module() { } } - AsyncFunction("conversationMessages") Coroutine { inboxId: String, conversationId: String, limit: Int?, beforeNs: Long?, afterNs: Long?, direction: String? -> + AsyncFunction("conversationMessages") Coroutine { installationId: String, conversationId: String, limit: Int?, beforeNs: Long?, afterNs: Long?, direction: String? -> withContext(Dispatchers.IO) { logV("conversationMessages") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversation(conversationId) conversation?.messages( limit = limit, @@ -578,10 +578,10 @@ class XMTPModule : Module() { } } - AsyncFunction("findMessage") Coroutine { inboxId: String, messageId: String -> + AsyncFunction("findMessage") Coroutine { installationId: String, messageId: String -> withContext(Dispatchers.IO) { logV("findMessage") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val message = client.findMessage(messageId) message?.let { DecodedMessageWrapper.encode(it.decode()) @@ -589,10 +589,10 @@ class XMTPModule : Module() { } } - AsyncFunction("findGroup") Coroutine { inboxId: String, groupId: String -> + AsyncFunction("findGroup") Coroutine { installationId: String, groupId: String -> withContext(Dispatchers.IO) { logV("findGroup") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) group?.let { GroupWrapper.encode(client, it) @@ -600,10 +600,10 @@ class XMTPModule : Module() { } } - AsyncFunction("findConversation") Coroutine { inboxId: String, conversationId: String -> + AsyncFunction("findConversation") Coroutine { installationId: String, conversationId: String -> withContext(Dispatchers.IO) { logV("findConversation") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversation(conversationId) conversation?.let { ConversationWrapper.encode(client, conversation) @@ -611,10 +611,10 @@ class XMTPModule : Module() { } } - AsyncFunction("findConversationByTopic") Coroutine { inboxId: String, topic: String -> + AsyncFunction("findConversationByTopic") Coroutine { installationId: String, topic: String -> withContext(Dispatchers.IO) { logV("findConversationByTopic") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversationByTopic(topic) conversation?.let { ConversationWrapper.encode(client, conversation) @@ -622,10 +622,10 @@ class XMTPModule : Module() { } } - AsyncFunction("findDmByInboxId") Coroutine { inboxId: String, peerInboxId: String -> + AsyncFunction("findDmByInboxId") Coroutine { installationId: String, peerInboxId: String -> withContext(Dispatchers.IO) { logV("findDmByInboxId") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val dm = client.findDmByInboxId(peerInboxId) dm?.let { DmWrapper.encode(client, dm) @@ -633,10 +633,10 @@ class XMTPModule : Module() { } } - AsyncFunction("findDmByAddress") Coroutine { inboxId: String, peerAddress: String -> + AsyncFunction("findDmByAddress") Coroutine { installationId: String, peerAddress: String -> withContext(Dispatchers.IO) { logV("findDmByAddress") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val dm = client.findDmByAddress(peerAddress) dm?.let { DmWrapper.encode(client, dm) @@ -644,10 +644,10 @@ class XMTPModule : Module() { } } - AsyncFunction("sendMessage") Coroutine { inboxId: String, id: String, contentJson: String -> + AsyncFunction("sendMessage") Coroutine { installationId: String, id: String, contentJson: String -> withContext(Dispatchers.IO) { logV("sendMessage") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversation(id) ?: throw XMTPException("no conversation found for $id") val sending = ContentJson.fromJson(contentJson) @@ -658,20 +658,20 @@ class XMTPModule : Module() { } } - AsyncFunction("publishPreparedMessages") Coroutine { inboxId: String, id: String -> + AsyncFunction("publishPreparedMessages") Coroutine { installationId: String, id: String -> withContext(Dispatchers.IO) { logV("publishPreparedMessages") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversation(id) ?: throw XMTPException("no conversation found for $id") conversation.publishMessages() } } - AsyncFunction("prepareMessage") Coroutine { inboxId: String, id: String, contentJson: String -> + AsyncFunction("prepareMessage") Coroutine { installationId: String, id: String, contentJson: String -> withContext(Dispatchers.IO) { logV("prepareMessage") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversation(id) ?: throw XMTPException("no conversation found for $id") val sending = ContentJson.fromJson(contentJson) @@ -682,19 +682,19 @@ class XMTPModule : Module() { } } - AsyncFunction("findOrCreateDm") Coroutine { inboxId: String, peerAddress: String -> + AsyncFunction("findOrCreateDm") Coroutine { installationId: String, peerAddress: String -> withContext(Dispatchers.IO) { logV("findOrCreateDm") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val dm = client.conversations.findOrCreateDm(peerAddress) DmWrapper.encode(client, dm) } } - AsyncFunction("createGroup") Coroutine { inboxId: String, peerAddresses: List, permission: String, groupOptionsJson: String -> + AsyncFunction("createGroup") Coroutine { installationId: String, peerAddresses: List, permission: String, groupOptionsJson: String -> withContext(Dispatchers.IO) { logV("createGroup") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val permissionLevel = when (permission) { "admin_only" -> GroupPermissionPreconfiguration.ADMIN_ONLY else -> GroupPermissionPreconfiguration.ALL_MEMBERS @@ -713,10 +713,10 @@ class XMTPModule : Module() { } } - AsyncFunction("createGroupCustomPermissions") Coroutine { inboxId: String, peerAddresses: List, permissionPolicySetJson: String, groupOptionsJson: String -> + AsyncFunction("createGroupCustomPermissions") Coroutine { installationId: String, peerAddresses: List, permissionPolicySetJson: String, groupOptionsJson: String -> withContext(Dispatchers.IO) { logV("createGroup") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val createGroupParams = CreateGroupParamsWrapper.createGroupParamsFromJson(groupOptionsJson) val permissionPolicySet = @@ -736,20 +736,20 @@ class XMTPModule : Module() { } - AsyncFunction("listMemberInboxIds") Coroutine { inboxId: String, id: String -> + AsyncFunction("listMemberInboxIds") Coroutine { installationId: String, id: String -> withContext(Dispatchers.IO) { logV("listMembers") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversation(id) ?: throw XMTPException("no conversation found for $id") conversation.members().map { it.inboxId } } } - AsyncFunction("dmPeerInboxId") Coroutine { inboxId: String, dmId: String -> + AsyncFunction("dmPeerInboxId") Coroutine { installationId: String, dmId: String -> withContext(Dispatchers.IO) { logV("dmPeerInboxId") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversation(dmId) ?: throw XMTPException("no conversation found for $dmId") val dm = (conversation as Conversation.Dm).dm @@ -757,358 +757,358 @@ class XMTPModule : Module() { } } - AsyncFunction("listConversationMembers") Coroutine { inboxId: String, conversationId: String -> + AsyncFunction("listConversationMembers") Coroutine { installationId: String, conversationId: String -> withContext(Dispatchers.IO) { logV("listConversationMembers") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversation(conversationId) ?: throw XMTPException("no conversation found for $conversationId") conversation.members().map { MemberWrapper.encode(it) } } } - AsyncFunction("syncConversations") Coroutine { inboxId: String -> + AsyncFunction("syncConversations") Coroutine { installationId: String -> withContext(Dispatchers.IO) { logV("syncConversations") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") client.conversations.sync() } } - AsyncFunction("syncAllConversations") Coroutine { inboxId: String -> + AsyncFunction("syncAllConversations") Coroutine { installationId: String -> withContext(Dispatchers.IO) { logV("syncAllConversations") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val numGroupsSyncedInt: Int = client.conversations.syncAllConversations().toInt() numGroupsSyncedInt } } - AsyncFunction("syncConversation") Coroutine { inboxId: String, id: String -> + AsyncFunction("syncConversation") Coroutine { installationId: String, id: String -> withContext(Dispatchers.IO) { logV("syncConversation") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversation(id) ?: throw XMTPException("no conversation found for $id") conversation.sync() } } - AsyncFunction("addGroupMembers") Coroutine { inboxId: String, groupId: String, peerAddresses: List -> + AsyncFunction("addGroupMembers") Coroutine { installationId: String, groupId: String, peerAddresses: List -> withContext(Dispatchers.IO) { logV("addGroupMembers") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.addMembers(peerAddresses) } } - AsyncFunction("removeGroupMembers") Coroutine { inboxId: String, groupId: String, peerAddresses: List -> + AsyncFunction("removeGroupMembers") Coroutine { installationId: String, groupId: String, peerAddresses: List -> withContext(Dispatchers.IO) { logV("removeGroupMembers") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.removeMembers(peerAddresses) } } - AsyncFunction("addGroupMembersByInboxId") Coroutine { inboxId: String, groupId: String, peerInboxIds: List -> + AsyncFunction("addGroupMembersByInboxId") Coroutine { installationId: String, groupId: String, peerInboxIds: List -> withContext(Dispatchers.IO) { logV("addGroupMembersByInboxId") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.addMembersByInboxId(peerInboxIds) } } - AsyncFunction("removeGroupMembersByInboxId") Coroutine { inboxId: String, groupId: String, peerInboxIds: List -> + AsyncFunction("removeGroupMembersByInboxId") Coroutine { installationId: String, groupId: String, peerInboxIds: List -> withContext(Dispatchers.IO) { logV("removeGroupMembersByInboxId") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.removeMembersByInboxId(peerInboxIds) } } - AsyncFunction("groupName") Coroutine { inboxId: String, groupId: String -> + AsyncFunction("groupName") Coroutine { installationId: String, groupId: String -> withContext(Dispatchers.IO) { logV("groupName") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.name } } - AsyncFunction("updateGroupName") Coroutine { inboxId: String, groupId: String, groupName: String -> + AsyncFunction("updateGroupName") Coroutine { installationId: String, groupId: String, groupName: String -> withContext(Dispatchers.IO) { logV("updateGroupName") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.updateGroupName(groupName) } } - AsyncFunction("groupImageUrlSquare") Coroutine { inboxId: String, groupId: String -> + AsyncFunction("groupImageUrlSquare") Coroutine { installationId: String, groupId: String -> withContext(Dispatchers.IO) { logV("groupImageUrlSquare") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.imageUrlSquare } } - AsyncFunction("updateGroupImageUrlSquare") Coroutine { inboxId: String, groupId: String, groupImageUrl: String -> + AsyncFunction("updateGroupImageUrlSquare") Coroutine { installationId: String, groupId: String, groupImageUrl: String -> withContext(Dispatchers.IO) { logV("updateGroupImageUrlSquare") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.updateGroupImageUrlSquare(groupImageUrl) } } - AsyncFunction("groupDescription") Coroutine { inboxId: String, groupId: String -> + AsyncFunction("groupDescription") Coroutine { installationId: String, groupId: String -> withContext(Dispatchers.IO) { logV("groupDescription") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.description } } - AsyncFunction("updateGroupDescription") Coroutine { inboxId: String, groupId: String, groupDescription: String -> + AsyncFunction("updateGroupDescription") Coroutine { installationId: String, groupId: String, groupDescription: String -> withContext(Dispatchers.IO) { logV("updateGroupDescription") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.updateGroupDescription(groupDescription) } } - AsyncFunction("groupPinnedFrameUrl") Coroutine { inboxId: String, groupId: String -> + AsyncFunction("groupPinnedFrameUrl") Coroutine { installationId: String, groupId: String -> withContext(Dispatchers.IO) { logV("groupPinnedFrameUrl") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.pinnedFrameUrl } } - AsyncFunction("updateGroupPinnedFrameUrl") Coroutine { inboxId: String, groupId: String, pinnedFrameUrl: String -> + AsyncFunction("updateGroupPinnedFrameUrl") Coroutine { installationId: String, groupId: String, pinnedFrameUrl: String -> withContext(Dispatchers.IO) { logV("updateGroupPinnedFrameUrl") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.updateGroupPinnedFrameUrl(pinnedFrameUrl) } } - AsyncFunction("isGroupActive") Coroutine { inboxId: String, groupId: String -> + AsyncFunction("isGroupActive") Coroutine { installationId: String, groupId: String -> withContext(Dispatchers.IO) { logV("isGroupActive") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.isActive() } } - AsyncFunction("addedByInboxId") Coroutine { inboxId: String, groupId: String -> + AsyncFunction("addedByInboxId") Coroutine { installationId: String, groupId: String -> withContext(Dispatchers.IO) { logV("addedByInboxId") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.addedByInboxId() } } - AsyncFunction("creatorInboxId") Coroutine { inboxId: String, groupId: String -> + AsyncFunction("creatorInboxId") Coroutine { installationId: String, groupId: String -> withContext(Dispatchers.IO) { logV("creatorInboxId") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.creatorInboxId() } } - AsyncFunction("isAdmin") Coroutine { clientInboxId: String, groupId: String, inboxId: String -> + AsyncFunction("isAdmin") Coroutine { clientInstallationId: String, groupId: String, inboxId: String -> withContext(Dispatchers.IO) { logV("isGroupAdmin") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.isAdmin(inboxId) } } - AsyncFunction("isSuperAdmin") Coroutine { clientInboxId: String, groupId: String, inboxId: String -> + AsyncFunction("isSuperAdmin") Coroutine { clientInstallationId: String, groupId: String, inboxId: String -> withContext(Dispatchers.IO) { logV("isSuperAdmin") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.isSuperAdmin(inboxId) } } - AsyncFunction("listAdmins") Coroutine { inboxId: String, groupId: String -> + AsyncFunction("listAdmins") Coroutine { installationId: String, groupId: String -> withContext(Dispatchers.IO) { logV("listAdmins") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.listAdmins() } } - AsyncFunction("listSuperAdmins") Coroutine { inboxId: String, groupId: String -> + AsyncFunction("listSuperAdmins") Coroutine { installationId: String, groupId: String -> withContext(Dispatchers.IO) { logV("listSuperAdmins") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.listSuperAdmins() } } - AsyncFunction("addAdmin") Coroutine { clientInboxId: String, groupId: String, inboxId: String -> + AsyncFunction("addAdmin") Coroutine { clientInstallationId: String, groupId: String, inboxId: String -> withContext(Dispatchers.IO) { logV("addAdmin") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.addAdmin(inboxId) } } - AsyncFunction("addSuperAdmin") Coroutine { clientInboxId: String, groupId: String, inboxId: String -> + AsyncFunction("addSuperAdmin") Coroutine { clientInstallationId: String, groupId: String, inboxId: String -> withContext(Dispatchers.IO) { logV("addSuperAdmin") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.addSuperAdmin(inboxId) } } - AsyncFunction("removeAdmin") Coroutine { clientInboxId: String, groupId: String, inboxId: String -> + AsyncFunction("removeAdmin") Coroutine { clientInstallationId: String, groupId: String, inboxId: String -> withContext(Dispatchers.IO) { logV("removeAdmin") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.removeAdmin(inboxId) } } - AsyncFunction("removeSuperAdmin") Coroutine { clientInboxId: String, groupId: String, inboxId: String -> + AsyncFunction("removeSuperAdmin") Coroutine { clientInstallationId: String, groupId: String, inboxId: String -> withContext(Dispatchers.IO) { logV("removeSuperAdmin") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.removeSuperAdmin(inboxId) } } - AsyncFunction("updateAddMemberPermission") Coroutine { clientInboxId: String, groupId: String, newPermission: String -> + AsyncFunction("updateAddMemberPermission") Coroutine { clientInstallationId: String, groupId: String, newPermission: String -> withContext(Dispatchers.IO) { logV("updateAddMemberPermission") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.updateAddMemberPermission(getPermissionOption(newPermission)) } } - AsyncFunction("updateRemoveMemberPermission") Coroutine { clientInboxId: String, groupId: String, newPermission: String -> + AsyncFunction("updateRemoveMemberPermission") Coroutine { clientInstallationId: String, groupId: String, newPermission: String -> withContext(Dispatchers.IO) { logV("updateRemoveMemberPermission") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.updateRemoveMemberPermission(getPermissionOption(newPermission)) } } - AsyncFunction("updateAddAdminPermission") Coroutine { clientInboxId: String, groupId: String, newPermission: String -> + AsyncFunction("updateAddAdminPermission") Coroutine { clientInstallationId: String, groupId: String, newPermission: String -> withContext(Dispatchers.IO) { logV("updateAddAdminPermission") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.updateAddAdminPermission(getPermissionOption(newPermission)) } } - AsyncFunction("updateRemoveAdminPermission") Coroutine { clientInboxId: String, groupId: String, newPermission: String -> + AsyncFunction("updateRemoveAdminPermission") Coroutine { clientInstallationId: String, groupId: String, newPermission: String -> withContext(Dispatchers.IO) { logV("updateRemoveAdminPermission") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.updateRemoveAdminPermission(getPermissionOption(newPermission)) } } - AsyncFunction("updateGroupNamePermission") Coroutine { clientInboxId: String, groupId: String, newPermission: String -> + AsyncFunction("updateGroupNamePermission") Coroutine { clientInstallationId: String, groupId: String, newPermission: String -> withContext(Dispatchers.IO) { logV("updateGroupNamePermission") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.updateGroupNamePermission(getPermissionOption(newPermission)) } } - AsyncFunction("updateGroupImageUrlSquarePermission") Coroutine { clientInboxId: String, groupId: String, newPermission: String -> + AsyncFunction("updateGroupImageUrlSquarePermission") Coroutine { clientInstallationId: String, groupId: String, newPermission: String -> withContext(Dispatchers.IO) { logV("updateGroupImageUrlSquarePermission") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.updateGroupImageUrlSquarePermission(getPermissionOption(newPermission)) } } - AsyncFunction("updateGroupDescriptionPermission") Coroutine { clientInboxId: String, groupId: String, newPermission: String -> + AsyncFunction("updateGroupDescriptionPermission") Coroutine { clientInstallationId: String, groupId: String, newPermission: String -> withContext(Dispatchers.IO) { logV("updateGroupDescriptionPermission") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.updateGroupDescriptionPermission(getPermissionOption(newPermission)) } } - AsyncFunction("updateGroupPinnedFrameUrlPermission") Coroutine { clientInboxId: String, groupId: String, newPermission: String -> + AsyncFunction("updateGroupPinnedFrameUrlPermission") Coroutine { clientInstallationId: String, groupId: String, newPermission: String -> withContext(Dispatchers.IO) { logV("updateGroupPinnedFrameUrlPermission") - val client = clients[clientInboxId] ?: throw XMTPException("No client") + val client = clients[clientInstallationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") group.updateGroupPinnedFrameUrlPermission(getPermissionOption(newPermission)) } } - AsyncFunction("permissionPolicySet") Coroutine { inboxId: String, groupId: String -> + AsyncFunction("permissionPolicySet") Coroutine { installationId: String, groupId: String -> withContext(Dispatchers.IO) { logV("groupImageUrlSquare") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val group = client.findGroup(groupId) ?: throw XMTPException("no group found for $groupId") val permissionPolicySet = group.permissionPolicySet() @@ -1116,10 +1116,10 @@ class XMTPModule : Module() { } } - AsyncFunction("processMessage") Coroutine { inboxId: String, id: String, encryptedMessage: String -> + AsyncFunction("processMessage") Coroutine { installationId: String, id: String, encryptedMessage: String -> withContext(Dispatchers.IO) { logV("processMessage") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversation(id) ?: throw XMTPException("no conversation found for $id") val message = conversation.processMessage(Base64.decode(encryptedMessage, NO_WRAP)) @@ -1127,10 +1127,10 @@ class XMTPModule : Module() { } } - AsyncFunction("processWelcomeMessage") Coroutine { inboxId: String, encryptedMessage: String -> + AsyncFunction("processWelcomeMessage") Coroutine { installationId: String, encryptedMessage: String -> withContext(Dispatchers.IO) { logV("processWelcomeMessage") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.conversations.fromWelcome( @@ -1143,16 +1143,16 @@ class XMTPModule : Module() { } } - AsyncFunction("syncConsent") Coroutine { inboxId: String -> + AsyncFunction("syncConsent") Coroutine { installationId: String -> withContext(Dispatchers.IO) { - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") client.preferences.syncConsent() } } - AsyncFunction("setConsentState") Coroutine { inboxId: String, value: String, entryType: String, consentType: String -> + AsyncFunction("setConsentState") Coroutine { installationId: String, value: String, entryType: String, consentType: String -> withContext(Dispatchers.IO) { - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") client.preferences.setConsentState( listOf( ConsentRecord( @@ -1165,40 +1165,40 @@ class XMTPModule : Module() { } } - AsyncFunction("consentAddressState") Coroutine { inboxId: String, peerAddress: String -> + AsyncFunction("consentAddressState") Coroutine { installationId: String, peerAddress: String -> withContext(Dispatchers.IO) { - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") consentStateToString(client.preferences.addressState(peerAddress)) } } - AsyncFunction("consentInboxIdState") Coroutine { inboxId: String, peerInboxId: String -> + AsyncFunction("consentInboxIdState") Coroutine { installationId: String, peerInboxId: String -> withContext(Dispatchers.IO) { - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") consentStateToString(client.preferences.inboxIdState(peerInboxId)) } } - AsyncFunction("consentConversationIdState") Coroutine { inboxId: String, conversationId: String -> + AsyncFunction("consentConversationIdState") Coroutine { installationId: String, conversationId: String -> withContext(Dispatchers.IO) { - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") consentStateToString(client.preferences.conversationState(conversationId)) } } - AsyncFunction("conversationConsentState") Coroutine { inboxId: String, conversationId: String -> + AsyncFunction("conversationConsentState") Coroutine { installationId: String, conversationId: String -> withContext(Dispatchers.IO) { - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversation(conversationId) ?: throw XMTPException("no group found for $conversationId") consentStateToString(conversation.consentState()) } } - AsyncFunction("updateConversationConsent") Coroutine { inboxId: String, conversationId: String, state: String -> + AsyncFunction("updateConversationConsent") Coroutine { installationId: String, conversationId: String, state: String -> withContext(Dispatchers.IO) { logV("updateConversationConsent") - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversation(conversationId) ?: throw XMTPException("no group found for $conversationId") @@ -1206,53 +1206,53 @@ class XMTPModule : Module() { } } - Function("subscribeToConsent") { inboxId: String -> + Function("subscribeToConsent") { installationId: String -> logV("subscribeToConsent") - subscribeToConsent(inboxId = inboxId) + subscribeToConsent(installationId = installationId) } - Function("subscribeToConversations") { inboxId: String, type: String -> + Function("subscribeToConversations") { installationId: String, type: String -> logV("subscribeToConversations") - subscribeToConversations(inboxId = inboxId, getStreamType(type)) + subscribeToConversations(installationId = installationId, getStreamType(type)) } - Function("subscribeToAllMessages") { inboxId: String, type: String -> + Function("subscribeToAllMessages") { installationId: String, type: String -> logV("subscribeToAllMessages") - subscribeToAllMessages(inboxId = inboxId, getStreamType(type)) + subscribeToAllMessages(installationId = installationId, getStreamType(type)) } - AsyncFunction("subscribeToMessages") Coroutine { inboxId: String, id: String -> + AsyncFunction("subscribeToMessages") Coroutine { installationId: String, id: String -> withContext(Dispatchers.IO) { logV("subscribeToMessages") subscribeToMessages( - inboxId = inboxId, + installationId = installationId, id = id ) } } - Function("unsubscribeFromConsent") { inboxId: String -> + Function("unsubscribeFromConsent") { installationId: String -> logV("unsubscribeFromConsent") - subscriptions[getConsentKey(inboxId)]?.cancel() + subscriptions[getConsentKey(installationId)]?.cancel() } - Function("unsubscribeFromConversations") { inboxId: String -> + Function("unsubscribeFromConversations") { installationId: String -> logV("unsubscribeFromConversations") - subscriptions[getConversationsKey(inboxId)]?.cancel() + subscriptions[getConversationsKey(installationId)]?.cancel() } - Function("unsubscribeFromAllMessages") { inboxId: String -> + Function("unsubscribeFromAllMessages") { installationId: String -> logV("unsubscribeFromAllMessages") - subscriptions[getMessagesKey(inboxId)]?.cancel() + subscriptions[getMessagesKey(installationId)]?.cancel() } - AsyncFunction("unsubscribeFromMessages") Coroutine { inboxId: String, id: String -> + AsyncFunction("unsubscribeFromMessages") Coroutine { installationId: String, id: String -> withContext(Dispatchers.IO) { logV("unsubscribeFromMessages") unsubscribeFromMessages( - inboxId = inboxId, + installationId = installationId, id = id ) } @@ -1354,41 +1354,41 @@ class XMTPModule : Module() { } } - private fun subscribeToConsent(inboxId: String) { - val client = clients[inboxId] ?: throw XMTPException("No client") + private fun subscribeToConsent(installationId: String) { + val client = clients[installationId] ?: throw XMTPException("No client") - subscriptions[getConsentKey(client.inboxId)]?.cancel() - subscriptions[getConsentKey(client.inboxId)] = + subscriptions[getConsentKey(installationId)]?.cancel() + subscriptions[getConsentKey(installationId)] = CoroutineScope(Dispatchers.IO).launch { try { client.preferences.streamConsent().collect { consent -> sendEvent( "consent", mapOf( - "inboxId" to inboxId, + "installationId" to installationId, "consent" to ConsentWrapper.encodeMap(consent) ) ) } } catch (e: Exception) { Log.e("XMTPModule", "Error in group subscription: $e") - subscriptions[getConsentKey(client.inboxId)]?.cancel() + subscriptions[getConsentKey(installationId)]?.cancel() } } } - private fun subscribeToConversations(inboxId: String, type: ConversationType) { - val client = clients[inboxId] ?: throw XMTPException("No client") + private fun subscribeToConversations(installationId: String, type: ConversationType) { + val client = clients[installationId] ?: throw XMTPException("No client") - subscriptions[getConversationsKey(client.inboxId)]?.cancel() - subscriptions[getConversationsKey(client.inboxId)] = + subscriptions[getConversationsKey(installationId)]?.cancel() + subscriptions[getConversationsKey(installationId)] = CoroutineScope(Dispatchers.IO).launch { try { client.conversations.stream(type).collect { conversation -> sendEvent( "conversation", mapOf( - "inboxId" to inboxId, + "installationId" to installationId, "conversation" to ConversationWrapper.encodeToObj( client, conversation @@ -1398,46 +1398,46 @@ class XMTPModule : Module() { } } catch (e: Exception) { Log.e("XMTPModule", "Error in group subscription: $e") - subscriptions[getConversationsKey(client.inboxId)]?.cancel() + subscriptions[getConversationsKey(installationId)]?.cancel() } } } - private fun subscribeToAllMessages(inboxId: String, type: ConversationType) { - val client = clients[inboxId] ?: throw XMTPException("No client") + private fun subscribeToAllMessages(installationId: String, type: ConversationType) { + val client = clients[installationId] ?: throw XMTPException("No client") - subscriptions[getMessagesKey(inboxId)]?.cancel() - subscriptions[getMessagesKey(inboxId)] = CoroutineScope(Dispatchers.IO).launch { + subscriptions[getMessagesKey(installationId)]?.cancel() + subscriptions[getMessagesKey(installationId)] = CoroutineScope(Dispatchers.IO).launch { try { client.conversations.streamAllMessages(type).collect { message -> sendEvent( "message", mapOf( - "inboxId" to inboxId, + "installationId" to installationId, "message" to DecodedMessageWrapper.encodeMap(message), ) ) } } catch (e: Exception) { Log.e("XMTPModule", "Error in all group messages subscription: $e") - subscriptions[getMessagesKey(inboxId)]?.cancel() + subscriptions[getMessagesKey(installationId)]?.cancel() } } } - private suspend fun subscribeToMessages(inboxId: String, id: String) { - val client = clients[inboxId] ?: throw XMTPException("No client") + private suspend fun subscribeToMessages(installationId: String, id: String) { + val client = clients[installationId] ?: throw XMTPException("No client") val conversation = client.findConversation(id) ?: throw XMTPException("no conversation found for $id") - subscriptions[conversation.cacheKey(inboxId)]?.cancel() - subscriptions[conversation.cacheKey(inboxId)] = + subscriptions[conversation.cacheKey(installationId)]?.cancel() + subscriptions[conversation.cacheKey(installationId)] = CoroutineScope(Dispatchers.IO).launch { try { conversation.streamMessages().collect { message -> sendEvent( "conversationMessage", mapOf( - "inboxId" to inboxId, + "installationId" to installationId, "message" to DecodedMessageWrapper.encodeMap(message), "conversationId" to id, ) @@ -1445,30 +1445,30 @@ class XMTPModule : Module() { } } catch (e: Exception) { Log.e("XMTPModule", "Error in messages subscription: $e") - subscriptions[conversation.cacheKey(inboxId)]?.cancel() + subscriptions[conversation.cacheKey(installationId)]?.cancel() } } } - private fun getConsentKey(inboxId: String): String { - return "consent:$inboxId" + private fun getConsentKey(installationId: String): String { + return "consent:$installationId" } - private fun getMessagesKey(inboxId: String): String { - return "messages:$inboxId" + private fun getMessagesKey(installationId: String): String { + return "messages:$installationId" } - private fun getConversationsKey(inboxId: String): String { - return "conversations:$inboxId" + private fun getConversationsKey(installationId: String): String { + return "conversations:$installationId" } private fun unsubscribeFromMessages( - inboxId: String, + installationId: String, id: String, ) { - val client = clients[inboxId] ?: throw XMTPException("No client") + val client = clients[installationId] ?: throw XMTPException("No client") val convo = client.findConversation(id) ?: return - subscriptions[convo.cacheKey(inboxId)]?.cancel() + subscriptions[convo.cacheKey(installationId)]?.cancel() } private fun logV(msg: String) { From 762cd1b372227f75d31cf502ef3732becf3bca4e Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 26 Nov 2024 09:33:28 -0800 Subject: [PATCH 08/12] update react native to be installation based --- src/index.ts | 368 +++++++++++++++++++--------------- src/lib/Client.ts | 71 ++++--- src/lib/Conversations.ts | 24 +-- src/lib/Dm.ts | 41 ++-- src/lib/Group.ts | 111 ++++++---- src/lib/PrivatePreferences.ts | 23 ++- 6 files changed, 375 insertions(+), 263 deletions(-) diff --git a/src/index.ts b/src/index.ts index 3375a32d..7ed81248 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,7 @@ import { EventEmitter, NativeModulesProxy } from 'expo-modules-core' import { Client } from '.' import XMTPModule from './XMTPModule' -import { Address, InboxId, XMTPEnvironment } from './lib/Client' +import { Address, InboxId, InstallationId, XMTPEnvironment } from './lib/Client' import { ConsentRecord, ConsentState, ConsentType } from './lib/ConsentRecord' import { DecryptedLocalAttachment, @@ -47,43 +47,50 @@ export function inboxId(): InboxId { } export async function findInboxIdFromAddress( - inboxId: InboxId, + installationId: InstallationId, address: string ): Promise { - return XMTPModule.findInboxIdFromAddress(inboxId, address) + return XMTPModule.findInboxIdFromAddress(installationId, address) } -export async function deleteLocalDatabase(inboxId: InboxId) { - return XMTPModule.deleteLocalDatabase(inboxId) +export async function deleteLocalDatabase(installationId: InstallationId) { + return XMTPModule.deleteLocalDatabase(installationId) } -export async function dropLocalDatabaseConnection(inboxId: InboxId) { - return XMTPModule.dropLocalDatabaseConnection(inboxId) +export async function dropLocalDatabaseConnection( + installationId: InstallationId +) { + return XMTPModule.dropLocalDatabaseConnection(installationId) } -export async function reconnectLocalDatabase(inboxId: InboxId) { - return XMTPModule.reconnectLocalDatabase(inboxId) +export async function reconnectLocalDatabase(installationId: InstallationId) { + return XMTPModule.reconnectLocalDatabase(installationId) } -export async function requestMessageHistorySync(inboxId: InboxId) { - return XMTPModule.requestMessageHistorySync(inboxId) +export async function requestMessageHistorySync( + installationId: InstallationId +) { + return XMTPModule.requestMessageHistorySync(installationId) } export async function getInboxState( - inboxId: InboxId, + installationId: InstallationId, refreshFromNetwork: boolean ): Promise { - const inboxState = await XMTPModule.getInboxState(inboxId, refreshFromNetwork) + const inboxState = await XMTPModule.getInboxState( + installationId, + refreshFromNetwork + ) return InboxState.from(inboxState) } export async function getInboxStates( - inboxId: InboxId, + installationId: InstallationId, refreshFromNetwork: boolean, inboxIds: InboxId[] ): Promise { const inboxStates = await XMTPModule.getInboxStates( - inboxId, + installationId, refreshFromNetwork, inboxIds ) @@ -182,7 +189,7 @@ export async function build( } export async function revokeAllOtherInstallations( - inboxId: InboxId, + installationId: InstallationId, walletType?: WalletType | undefined, chainId?: number | undefined, blockNumber?: number | undefined @@ -193,13 +200,13 @@ export async function revokeAllOtherInstallations( blockNumber: typeof blockNumber === 'number' ? blockNumber : undefined, } return XMTPModule.revokeAllOtherInstallations( - inboxId, + installationId, JSON.stringify(walletParams) ) } export async function addAccount( - inboxId: InboxId, + installationId: InstallationId, newAddress: Address, walletType?: WalletType | undefined, chainId?: number | undefined, @@ -211,14 +218,14 @@ export async function addAccount( blockNumber: typeof blockNumber === 'number' ? blockNumber : undefined, } return XMTPModule.addAccount( - inboxId, + installationId, newAddress, JSON.stringify(walletParams) ) } export async function removeAccount( - inboxId: InboxId, + installationId: InstallationId, addressToRemove: Address, walletType?: WalletType | undefined, chainId?: number | undefined, @@ -230,44 +237,44 @@ export async function removeAccount( blockNumber: typeof blockNumber === 'number' ? blockNumber : undefined, } return XMTPModule.removeAccount( - inboxId, + installationId, addressToRemove, JSON.stringify(walletParams) ) } -export async function dropClient(inboxId: InboxId) { - return await XMTPModule.dropClient(inboxId) +export async function dropClient(installationId: InstallationId) { + return await XMTPModule.dropClient(installationId) } export async function signWithInstallationKey( - inboxId: InboxId, + installationId: InstallationId, message: string ): Promise { const signatureArray = await XMTPModule.signWithInstallationKey( - inboxId, + installationId, message ) return new Uint8Array(signatureArray) } export async function verifySignature( - inboxId: InboxId, + installationId: InstallationId, message: string, signature: Uint8Array ): Promise { return await XMTPModule.verifySignature( - inboxId, + installationId, message, Array.from(signature) ) } export async function canMessage( - inboxId: InboxId, + installationId: InstallationId, peerAddresses: Address[] ): Promise<{ [key: Address]: boolean }> { - return await XMTPModule.canMessage(inboxId, peerAddresses) + return await XMTPModule.canMessage(installationId, peerAddresses) } export async function getOrCreateInboxId( @@ -278,24 +285,24 @@ export async function getOrCreateInboxId( } export async function encryptAttachment( - inboxId: InboxId, + installationId: InstallationId, file: DecryptedLocalAttachment ): Promise { const fileJson = JSON.stringify(file) const encryptedFileJson = await XMTPModule.encryptAttachment( - inboxId, + installationId, fileJson ) return JSON.parse(encryptedFileJson) } export async function decryptAttachment( - inboxId: InboxId, + installationId: InstallationId, encryptedFile: EncryptedLocalAttachment ): Promise { const encryptedFileJson = JSON.stringify(encryptedFile) const fileJson = await XMTPModule.decryptAttachment( - inboxId, + installationId, encryptedFileJson ) return JSON.parse(fileJson) @@ -312,7 +319,7 @@ export async function listGroups< ): Promise[]> { return ( await XMTPModule.listGroups( - client.inboxId, + client.installationId, JSON.stringify(opts), order, limit, @@ -339,7 +346,7 @@ export async function listDms< ): Promise[]> { return ( await XMTPModule.listDms( - client.inboxId, + client.installationId, JSON.stringify(opts), order, limit, @@ -366,7 +373,7 @@ export async function listConversations< ): Promise[]> { return ( await XMTPModule.listConversations( - client.inboxId, + client.installationId, JSON.stringify(opts), order, limit, @@ -398,7 +405,7 @@ export async function conversationMessages< direction?: MessageOrder | undefined ): Promise[]> { const messages = await XMTPModule.conversationMessages( - client.inboxId, + client.installationId, conversationId, limit, beforeNs, @@ -416,7 +423,7 @@ export async function findMessage< client: Client, messageId: MessageId ): Promise | undefined> { - const message = await XMTPModule.findMessage(client.inboxId, messageId) + const message = await XMTPModule.findMessage(client.installationId, messageId) return DecodedMessage.from(message, client) } @@ -426,7 +433,7 @@ export async function findGroup< client: Client, groupId: ConversationId ): Promise | undefined> { - const json = await XMTPModule.findGroup(client.inboxId, groupId) + const json = await XMTPModule.findGroup(client.installationId, groupId) const group = JSON.parse(json) if (!group || Object.keys(group).length === 0) { return undefined @@ -441,7 +448,10 @@ export async function findConversation< client: Client, conversationId: ConversationId ): Promise | undefined> { - const json = await XMTPModule.findConversation(client.inboxId, conversationId) + const json = await XMTPModule.findConversation( + client.installationId, + conversationId + ) const conversation = JSON.parse(json) if (!conversation || Object.keys(conversation).length === 0) { return undefined @@ -460,7 +470,10 @@ export async function findConversationByTopic< client: Client, topic: ConversationTopic ): Promise | undefined> { - const json = await XMTPModule.findConversationByTopic(client.inboxId, topic) + const json = await XMTPModule.findConversationByTopic( + client.installationId, + topic + ) const conversation = JSON.parse(json) if (!conversation || Object.keys(conversation).length === 0) { return undefined @@ -479,7 +492,10 @@ export async function findDmByInboxId< client: Client, peerInboxId: InboxId ): Promise | undefined> { - const json = await XMTPModule.findDmByInboxId(client.inboxId, peerInboxId) + const json = await XMTPModule.findDmByInboxId( + client.installationId, + peerInboxId + ) const dm = JSON.parse(json) if (!dm || Object.keys(dm).length === 0) { return undefined @@ -494,7 +510,7 @@ export async function findDmByAddress< client: Client, address: Address ): Promise | undefined> { - const json = await XMTPModule.findDmByAddress(client.inboxId, address) + const json = await XMTPModule.findDmByAddress(client.installationId, address) const dm = JSON.parse(json) if (!dm || Object.keys(dm).length === 0) { return undefined @@ -504,28 +520,39 @@ export async function findDmByAddress< } export async function sendMessage( - inboxId: InboxId, + installationId: InstallationId, conversationId: ConversationId, content: any ): Promise { const contentJson = JSON.stringify(content) - return await XMTPModule.sendMessage(inboxId, conversationId, contentJson) + return await XMTPModule.sendMessage( + installationId, + conversationId, + contentJson + ) } export async function publishPreparedMessages( - inboxId: InboxId, + installationId: InstallationId, conversationId: ConversationId ) { - return await XMTPModule.publishPreparedMessages(inboxId, conversationId) + return await XMTPModule.publishPreparedMessages( + installationId, + conversationId + ) } export async function prepareMessage( - inboxId: InboxId, + installationId: InstallationId, conversationId: ConversationId, content: any ): Promise { const contentJson = JSON.stringify(content) - return await XMTPModule.prepareMessage(inboxId, conversationId, contentJson) + return await XMTPModule.prepareMessage( + installationId, + conversationId, + contentJson + ) } export async function findOrCreateDm< @@ -535,7 +562,7 @@ export async function findOrCreateDm< peerAddress: Address ): Promise> { const dm = JSON.parse( - await XMTPModule.findOrCreateDm(client.inboxId, peerAddress) + await XMTPModule.findOrCreateDm(client.installationId, peerAddress) ) return new Dm(client, dm) } @@ -559,7 +586,7 @@ export async function createGroup< } const group = JSON.parse( await XMTPModule.createGroup( - client.inboxId, + client.installationId, peerAddresses, permissionLevel, JSON.stringify(options) @@ -588,7 +615,7 @@ export async function createGroupCustomPermissions< } const group = JSON.parse( await XMTPModule.createGroupCustomPermissions( - client.inboxId, + client.installationId, peerAddresses, JSON.stringify(permissionPolicySet), JSON.stringify(options) @@ -601,314 +628,327 @@ export async function createGroupCustomPermissions< export async function listMemberInboxIds< ContentTypes extends DefaultContentTypes = DefaultContentTypes, >(client: Client, id: ConversationId): Promise { - return XMTPModule.listMemberInboxIds(client.inboxId, id) + return XMTPModule.listMemberInboxIds(client.installationId, id) } export async function dmPeerInboxId< ContentTypes extends DefaultContentTypes = DefaultContentTypes, >(client: Client, dmId: ConversationId): Promise { - return XMTPModule.dmPeerInboxId(client.inboxId, dmId) + return XMTPModule.dmPeerInboxId(client.installationId, dmId) } export async function listConversationMembers( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId ): Promise { - const members = await XMTPModule.listConversationMembers(inboxId, id) + const members = await XMTPModule.listConversationMembers(installationId, id) return members.map((json: string) => { return Member.from(json) }) } -export async function syncConversations(inboxId: InboxId) { - await XMTPModule.syncConversations(inboxId) +export async function syncConversations(installationId: InstallationId) { + await XMTPModule.syncConversations(installationId) } -export async function syncAllConversations(inboxId: InboxId): Promise { - return await XMTPModule.syncAllConversations(inboxId) +export async function syncAllConversations( + installationId: InstallationId +): Promise { + return await XMTPModule.syncAllConversations(installationId) } -export async function syncConversation(inboxId: InboxId, id: ConversationId) { - await XMTPModule.syncConversation(inboxId, id) +export async function syncConversation( + installationId: InstallationId, + id: ConversationId +) { + await XMTPModule.syncConversation(installationId, id) } export async function addGroupMembers( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId, addresses: Address[] ): Promise { - return XMTPModule.addGroupMembers(inboxId, id, addresses) + return XMTPModule.addGroupMembers(installationId, id, addresses) } export async function removeGroupMembers( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId, addresses: Address[] ): Promise { - return XMTPModule.removeGroupMembers(inboxId, id, addresses) + return XMTPModule.removeGroupMembers(installationId, id, addresses) } export async function addGroupMembersByInboxId( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId, inboxIds: InboxId[] ): Promise { - return XMTPModule.addGroupMembersByInboxId(inboxId, id, inboxIds) + return XMTPModule.addGroupMembersByInboxId(installationId, id, inboxIds) } export async function removeGroupMembersByInboxId( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId, inboxIds: InboxId[] ): Promise { - return XMTPModule.removeGroupMembersByInboxId(inboxId, id, inboxIds) + return XMTPModule.removeGroupMembersByInboxId(installationId, id, inboxIds) } export function groupName( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId ): string | PromiseLike { - return XMTPModule.groupName(inboxId, id) + return XMTPModule.groupName(installationId, id) } export function updateGroupName( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId, groupName: string ): Promise { - return XMTPModule.updateGroupName(inboxId, id, groupName) + return XMTPModule.updateGroupName(installationId, id, groupName) } export function groupImageUrlSquare( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId ): string | PromiseLike { - return XMTPModule.groupImageUrlSquare(inboxId, id) + return XMTPModule.groupImageUrlSquare(installationId, id) } export function updateGroupImageUrlSquare( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId, imageUrlSquare: string ): Promise { - return XMTPModule.updateGroupImageUrlSquare(inboxId, id, imageUrlSquare) + return XMTPModule.updateGroupImageUrlSquare( + installationId, + id, + imageUrlSquare + ) } export function groupDescription( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId ): string | PromiseLike { - return XMTPModule.groupDescription(inboxId, id) + return XMTPModule.groupDescription(installationId, id) } export function updateGroupDescription( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId, description: string ): Promise { - return XMTPModule.updateGroupDescription(inboxId, id, description) + return XMTPModule.updateGroupDescription(installationId, id, description) } export function groupPinnedFrameUrl( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId ): string | PromiseLike { - return XMTPModule.groupPinnedFrameUrl(inboxId, id) + return XMTPModule.groupPinnedFrameUrl(installationId, id) } export function updateGroupPinnedFrameUrl( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId, pinnedFrameUrl: string ): Promise { - return XMTPModule.updateGroupPinnedFrameUrl(inboxId, id, pinnedFrameUrl) + return XMTPModule.updateGroupPinnedFrameUrl( + installationId, + id, + pinnedFrameUrl + ) } export function isGroupActive( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId ): Promise { - return XMTPModule.isGroupActive(inboxId, id) + return XMTPModule.isGroupActive(installationId, id) } export async function addedByInboxId( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId ): Promise { - return XMTPModule.addedByInboxId(inboxId, id) as InboxId + return XMTPModule.addedByInboxId(installationId, id) as InboxId } export async function creatorInboxId( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId ): Promise { - return XMTPModule.creatorInboxId(inboxId, id) as InboxId + return XMTPModule.creatorInboxId(installationId, id) as InboxId } export async function isAdmin( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, inboxId: InboxId ): Promise { - return XMTPModule.isAdmin(clientInboxId, id, inboxId) + return XMTPModule.isAdmin(clientInstallationId, id, inboxId) } export async function isSuperAdmin( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, inboxId: InboxId ): Promise { - return XMTPModule.isSuperAdmin(clientInboxId, id, inboxId) + return XMTPModule.isSuperAdmin(clientInstallationId, id, inboxId) } export async function listAdmins( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId ): Promise { - return XMTPModule.listAdmins(inboxId, id) + return XMTPModule.listAdmins(installationId, id) } export async function listSuperAdmins( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId ): Promise { - return XMTPModule.listSuperAdmins(inboxId, id) + return XMTPModule.listSuperAdmins(installationId, id) } export async function addAdmin( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, inboxId: InboxId ): Promise { - return XMTPModule.addAdmin(clientInboxId, id, inboxId) + return XMTPModule.addAdmin(clientInstallationId, id, inboxId) } export async function addSuperAdmin( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, inboxId: InboxId ): Promise { - return XMTPModule.addSuperAdmin(clientInboxId, id, inboxId) + return XMTPModule.addSuperAdmin(clientInstallationId, id, inboxId) } export async function removeAdmin( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, inboxId: InboxId ): Promise { - return XMTPModule.removeAdmin(clientInboxId, id, inboxId) + return XMTPModule.removeAdmin(clientInstallationId, id, inboxId) } export async function removeSuperAdmin( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, inboxId: InboxId ): Promise { - return XMTPModule.removeSuperAdmin(clientInboxId, id, inboxId) + return XMTPModule.removeSuperAdmin(clientInstallationId, id, inboxId) } export async function updateAddMemberPermission( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, permissionOption: PermissionUpdateOption ): Promise { return XMTPModule.updateAddMemberPermission( - clientInboxId, + clientInstallationId, id, permissionOption ) } export async function updateRemoveMemberPermission( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, permissionOption: PermissionUpdateOption ): Promise { return XMTPModule.updateRemoveMemberPermission( - clientInboxId, + clientInstallationId, id, permissionOption ) } export async function updateAddAdminPermission( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, permissionOption: PermissionUpdateOption ): Promise { return XMTPModule.updateAddAdminPermission( - clientInboxId, + clientInstallationId, id, permissionOption ) } export async function updateRemoveAdminPermission( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, permissionOption: PermissionUpdateOption ): Promise { return XMTPModule.updateRemoveAdminPermission( - clientInboxId, + clientInstallationId, id, permissionOption ) } export async function updateGroupNamePermission( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, permissionOption: PermissionUpdateOption ): Promise { return XMTPModule.updateGroupNamePermission( - clientInboxId, + clientInstallationId, id, permissionOption ) } export async function updateGroupImageUrlSquarePermission( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, permissionOption: PermissionUpdateOption ): Promise { return XMTPModule.updateGroupImageUrlSquarePermission( - clientInboxId, + clientInstallationId, id, permissionOption ) } export async function updateGroupDescriptionPermission( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, permissionOption: PermissionUpdateOption ): Promise { return XMTPModule.updateGroupDescriptionPermission( - clientInboxId, + clientInstallationId, id, permissionOption ) } export async function updateGroupPinnedFrameUrlPermission( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId, permissionOption: PermissionUpdateOption ): Promise { return XMTPModule.updateGroupPinnedFrameUrlPermission( - clientInboxId, + clientInstallationId, id, permissionOption ) } export async function permissionPolicySet( - clientInboxId: InboxId, + clientInstallationId: InstallationId, id: ConversationId ): Promise { - const json = await XMTPModule.permissionPolicySet(clientInboxId, id) + const json = await XMTPModule.permissionPolicySet(clientInstallationId, id) return JSON.parse(json) } @@ -920,7 +960,7 @@ export async function processMessage< encryptedMessage: string ): Promise> { const json = await XMTPModule.processMessage( - client.inboxId, + client.installationId, id, encryptedMessage ) @@ -934,7 +974,7 @@ export async function processWelcomeMessage< encryptedMessage: string ): Promise>> { const json = await XMTPModule.processWelcomeMessage( - client.inboxId, + client.installationId, encryptedMessage ) const conversation = JSON.parse(json) @@ -946,18 +986,20 @@ export async function processWelcomeMessage< } } -export async function syncConsent(inboxId: InboxId): Promise { - return await XMTPModule.syncConsent(inboxId) +export async function syncConsent( + installationId: InstallationId +): Promise { + return await XMTPModule.syncConsent(installationId) } export async function setConsentState( - inboxId: InboxId, + installationId: InstallationId, value: string, entryType: ConsentType, consentType: ConsentState ): Promise { return await XMTPModule.setConsentState( - inboxId, + installationId, value, entryType, consentType @@ -965,80 +1007,90 @@ export async function setConsentState( } export async function consentAddressState( - inboxId: InboxId, + installationId: InstallationId, address: Address ): Promise { - return await XMTPModule.consentAddressState(inboxId, address) + return await XMTPModule.consentAddressState(installationId, address) } export async function consentInboxIdState( - inboxId: InboxId, + installationId: InstallationId, peerInboxId: InboxId ): Promise { - return await XMTPModule.consentInboxIdState(inboxId, peerInboxId) + return await XMTPModule.consentInboxIdState(installationId, peerInboxId) } export async function consentConversationIdState( - inboxId: InboxId, + installationId: InstallationId, conversationId: ConversationId ): Promise { - return await XMTPModule.consentConversationIdState(inboxId, conversationId) + return await XMTPModule.consentConversationIdState( + installationId, + conversationId + ) } export async function conversationConsentState( - inboxId: InboxId, + installationId: InstallationId, conversationId: ConversationId ): Promise { - return await XMTPModule.conversationConsentState(inboxId, conversationId) + return await XMTPModule.conversationConsentState( + installationId, + conversationId + ) } export async function updateConversationConsent( - inboxId: InboxId, + installationId: InstallationId, conversationId: ConversationId, state: ConsentState ): Promise { - return XMTPModule.updateConversationConsent(inboxId, conversationId, state) + return XMTPModule.updateConversationConsent( + installationId, + conversationId, + state + ) } -export function subscribeToConsent(inboxId: InboxId) { - return XMTPModule.subscribeToConsent(inboxId) +export function subscribeToConsent(installationId: InstallationId) { + return XMTPModule.subscribeToConsent(installationId) } export function subscribeToConversations( - inboxId: InboxId, + installationId: InstallationId, type: ConversationType ) { - return XMTPModule.subscribeToConversations(inboxId, type) + return XMTPModule.subscribeToConversations(installationId, type) } export function subscribeToAllMessages( - inboxId: InboxId, + installationId: InstallationId, type: ConversationType ) { - return XMTPModule.subscribeToAllMessages(inboxId, type) + return XMTPModule.subscribeToAllMessages(installationId, type) } export async function subscribeToMessages( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId ) { - return await XMTPModule.subscribeToMessages(inboxId, id) + return await XMTPModule.subscribeToMessages(installationId, id) } -export function unsubscribeFromConsent(inboxId: InboxId) { - return XMTPModule.unsubscribeFromConsent(inboxId) +export function unsubscribeFromConsent(installationId: InstallationId) { + return XMTPModule.unsubscribeFromConsent(installationId) } -export function unsubscribeFromConversations(inboxId: InboxId) { - return XMTPModule.unsubscribeFromConversations(inboxId) +export function unsubscribeFromConversations(installationId: InstallationId) { + return XMTPModule.unsubscribeFromConversations(installationId) } -export function unsubscribeFromAllMessages(inboxId: InboxId) { - return XMTPModule.unsubscribeFromAllMessages(inboxId) +export function unsubscribeFromAllMessages(installationId: InstallationId) { + return XMTPModule.unsubscribeFromAllMessages(installationId) } export async function unsubscribeFromMessages( - inboxId: InboxId, + installationId: InstallationId, id: ConversationId ) { - return await XMTPModule.unsubscribeFromMessages(inboxId, id) + return await XMTPModule.unsubscribeFromMessages(installationId, id) } export function registerPushToken(pushServer: string, token: string) { diff --git a/src/lib/Client.ts b/src/lib/Client.ts index e7f5abb9..36b065e9 100644 --- a/src/lib/Client.ts +++ b/src/lib/Client.ts @@ -17,23 +17,22 @@ import * as XMTPModule from '../index' declare const Buffer -export type GetMessageContentTypeFromClient = C extends Client - ? T - : never +export type GetMessageContentTypeFromClient = + C extends Client ? T : never -export type ExtractDecodedType = C extends XMTPModule.ContentCodec - ? T - : never +export type ExtractDecodedType = + C extends XMTPModule.ContentCodec ? T : never -export type InboxId = string & { readonly brand: unique symbol } +export type InstallationId = string & { readonly brand: unique symbol } +export type InboxId = string export type Address = string export class Client< ContentTypes extends DefaultContentTypes = DefaultContentTypes, > { - address: string + address: Address inboxId: InboxId - installationId: string + installationId: InstallationId dbPath: string conversations: Conversations preferences: PrivatePreferences @@ -165,7 +164,7 @@ export class Client< new Client( message.address, message.inboxId as InboxId, - message.installationId, + message.installationId as InstallationId, message.dbPath, options.codecs || [] ) @@ -231,8 +230,8 @@ export class Client< /** * Drop the client from memory. Use when you want to remove the client from memory and are done with it. */ - static async dropClient(inboxId: InboxId) { - return await XMTPModule.dropClient(inboxId) + static async dropClient(installationId: InstallationId) { + return await XMTPModule.dropClient(installationId) } private static addSubscription( @@ -294,7 +293,7 @@ export class Client< constructor( address: Address, inboxId: InboxId, - installationId: string, + installationId: InstallationId, dbPath: string, codecs: XMTPModule.ContentCodec[] = [] ) { @@ -346,7 +345,7 @@ export class Client< ) await XMTPModule.addAccount( - this.inboxId, + this.installationId, await signer.getAddress(), signer.walletType?.(), signer.getChainId?.(), @@ -390,7 +389,7 @@ export class Client< ) await XMTPModule.removeAccount( - this.inboxId, + this.installationId, addressToRemove, signer.walletType?.(), signer.getChainId?.(), @@ -433,7 +432,7 @@ export class Client< ) await XMTPModule.revokeAllOtherInstallations( - this.inboxId, + this.installationId, signer.walletType?.(), signer.getChainId?.(), signer.getBlockNumber?.() @@ -453,7 +452,10 @@ export class Client< * @returns {Promise} A Promise resolving to the signature bytes. */ async signWithInstallationKey(message: string): Promise { - return await XMTPModule.signWithInstallationKey(this.inboxId, message) + return await XMTPModule.signWithInstallationKey( + this.installationId, + message + ) } /** @@ -466,7 +468,11 @@ export class Client< message: string, signature: Uint8Array ): Promise { - return await XMTPModule.verifySignature(this.inboxId, message, signature) + return await XMTPModule.verifySignature( + this.installationId, + message, + signature + ) } /** @@ -478,35 +484,38 @@ export class Client< async findInboxIdFromAddress( peerAddress: Address ): Promise { - return await XMTPModule.findInboxIdFromAddress(this.inboxId, peerAddress) + return await XMTPModule.findInboxIdFromAddress( + this.installationId, + peerAddress + ) } /** * Deletes the local database. This cannot be undone and these stored messages will not be refetched from the network. */ async deleteLocalDatabase() { - return await XMTPModule.deleteLocalDatabase(this.inboxId) + return await XMTPModule.deleteLocalDatabase(this.installationId) } /** * Drop the local database connection. This function is delicate and should be used with caution. App will error if database not properly reconnected. See: reconnectLocalDatabase() */ async dropLocalDatabaseConnection() { - return await XMTPModule.dropLocalDatabaseConnection(this.inboxId) + return await XMTPModule.dropLocalDatabaseConnection(this.installationId) } /** * Reconnects the local database after being dropped. */ async reconnectLocalDatabase() { - return await XMTPModule.reconnectLocalDatabase(this.inboxId) + return await XMTPModule.reconnectLocalDatabase(this.installationId) } /** * Make a request for a message history sync. */ async requestMessageHistorySync() { - return await XMTPModule.requestMessageHistorySync(this.inboxId) + return await XMTPModule.requestMessageHistorySync(this.installationId) } /** @@ -516,7 +525,10 @@ export class Client< * @returns {Promise} A Promise resolving to a InboxState. */ async inboxState(refreshFromNetwork: boolean): Promise { - return await XMTPModule.getInboxState(this.inboxId, refreshFromNetwork) + return await XMTPModule.getInboxState( + this.installationId, + refreshFromNetwork + ) } /** @@ -531,7 +543,7 @@ export class Client< inboxIds: InboxId[] ): Promise { return await XMTPModule.getInboxStates( - this.inboxId, + this.installationId, refreshFromNetwork, inboxIds ) @@ -546,7 +558,7 @@ export class Client< * @returns {Promise<{ [key: Address]: boolean }>} A Promise resolving to a hash of addresses and booleans if they can message on the V3 network. */ async canMessage(addresses: Address[]): Promise<{ [key: Address]: boolean }> { - return await XMTPModule.canMessage(this.inboxId, addresses) + return await XMTPModule.canMessage(this.installationId, addresses) } /** @@ -564,7 +576,7 @@ export class Client< if (!file.fileUri?.startsWith('file://')) { throw new Error('the attachment must be a local file:// uri') } - return await XMTPModule.encryptAttachment(this.inboxId, file) + return await XMTPModule.encryptAttachment(this.installationId, file) } /** @@ -581,7 +593,10 @@ export class Client< if (!encryptedFile.encryptedLocalFileUri?.startsWith('file://')) { throw new Error('the attachment must be a local file:// uri') } - return await XMTPModule.decryptAttachment(this.inboxId, encryptedFile) + return await XMTPModule.decryptAttachment( + this.installationId, + encryptedFile + ) } } diff --git a/src/lib/Conversations.ts b/src/lib/Conversations.ts index d6e51924..61d7e63c 100644 --- a/src/lib/Conversations.ts +++ b/src/lib/Conversations.ts @@ -270,7 +270,7 @@ export default class Conversations< * and save them to the local state. */ async sync() { - await XMTPModule.syncConversations(this.client.inboxId) + await XMTPModule.syncConversations(this.client.installationId) } /** @@ -279,7 +279,7 @@ export default class Conversations< * @returns {Promise} A Promise that resolves to the number of conversations synced. */ async syncAllConversations(): Promise { - return await XMTPModule.syncAllConversations(this.client.inboxId) + return await XMTPModule.syncAllConversations(this.client.installationId) } /** @@ -291,17 +291,17 @@ export default class Conversations< callback: (conversation: Conversation) => Promise, type: ConversationType = 'all' ): Promise { - XMTPModule.subscribeToConversations(this.client.inboxId, type) + XMTPModule.subscribeToConversations(this.client.installationId, type) const subscription = XMTPModule.emitter.addListener( EventTypes.Conversation, async ({ - inboxId, + installationId, conversation, }: { - inboxId: string + installationId: string conversation: Conversation }) => { - if (inboxId !== this.client.inboxId) { + if (installationId !== this.client.installationId) { return } if (conversation.version === ConversationVersion.GROUP) { @@ -330,17 +330,17 @@ export default class Conversations< callback: (message: DecodedMessage) => Promise, type: ConversationType = 'all' ): Promise { - XMTPModule.subscribeToAllMessages(this.client.inboxId, type) + XMTPModule.subscribeToAllMessages(this.client.installationId, type) const subscription = XMTPModule.emitter.addListener( EventTypes.Message, async ({ - inboxId, + installationId, message, }: { - inboxId: string + installationId: string message: DecodedMessage }) => { - if (inboxId !== this.client.inboxId) { + if (installationId !== this.client.installationId) { return } await callback(DecodedMessage.fromObject(message, this.client)) @@ -357,7 +357,7 @@ export default class Conversations< this.subscriptions[EventTypes.Conversation].remove() delete this.subscriptions[EventTypes.Conversation] } - XMTPModule.unsubscribeFromConversations(this.client.inboxId) + XMTPModule.unsubscribeFromConversations(this.client.installationId) } /** @@ -368,6 +368,6 @@ export default class Conversations< this.subscriptions[EventTypes.Message].remove() delete this.subscriptions[EventTypes.Message] } - XMTPModule.unsubscribeFromAllMessages(this.client.inboxId) + XMTPModule.unsubscribeFromAllMessages(this.client.installationId) } } diff --git a/src/lib/Dm.ts b/src/lib/Dm.ts index 005201b9..4dfb3196 100644 --- a/src/lib/Dm.ts +++ b/src/lib/Dm.ts @@ -70,7 +70,11 @@ export class Dm content = { text: content } } - return await XMTP.sendMessage(this.client.inboxId, this.id, content) + return await XMTP.sendMessage( + this.client.installationId, + this.id, + content + ) } catch (e) { console.info('ERROR in send()', e.message) throw e @@ -97,7 +101,11 @@ export class Dm content = { text: content } } - return await XMTP.prepareMessage(this.client.inboxId, this.id, content) + return await XMTP.prepareMessage( + this.client.installationId, + this.id, + content + ) } catch (e) { console.info('ERROR in prepareMessage()', e.message) throw e @@ -111,7 +119,10 @@ export class Dm */ async publishPreparedMessages() { try { - return await XMTP.publishPreparedMessages(this.client.inboxId, this.id) + return await XMTP.publishPreparedMessages( + this.client.installationId, + this.id + ) } catch (e) { console.info('ERROR in publishPreparedMessages()', e.message) throw e @@ -146,7 +157,7 @@ export class Dm * associated with the dm and saves them to the local state. */ async sync() { - await XMTP.syncConversation(this.client.inboxId, this.id) + await XMTP.syncConversation(this.client.installationId, this.id) } /** @@ -162,19 +173,19 @@ export class Dm async streamMessages( callback: (message: DecodedMessage) => Promise ): Promise<() => void> { - await XMTP.subscribeToMessages(this.client.inboxId, this.id) + await XMTP.subscribeToMessages(this.client.installationId, this.id) const messageSubscription = XMTP.emitter.addListener( EventTypes.ConversationMessage, async ({ - inboxId, + installationId, message, conversationId, }: { - inboxId: string + installationId: string message: DecodedMessage conversationId: string }) => { - if (inboxId !== this.client.inboxId) { + if (installationId !== this.client.installationId) { return } if (conversationId !== this.id) { @@ -187,7 +198,7 @@ export class Dm ) return async () => { messageSubscription.remove() - await XMTP.unsubscribeFromMessages(this.client.inboxId, this.id) + await XMTP.unsubscribeFromMessages(this.client.installationId, this.id) } } @@ -203,12 +214,15 @@ export class Dm } async consentState(): Promise { - return await XMTP.conversationConsentState(this.client.inboxId, this.id) + return await XMTP.conversationConsentState( + this.client.installationId, + this.id + ) } async updateConsent(state: ConsentState): Promise { return await XMTP.updateConversationConsent( - this.client.inboxId, + this.client.installationId, this.id, state ) @@ -220,6 +234,9 @@ export class Dm * To get the latest member list from the network, call sync() first. */ async members(): Promise { - return await XMTP.listConversationMembers(this.client.inboxId, this.id) + return await XMTP.listConversationMembers( + this.client.installationId, + this.id + ) } } diff --git a/src/lib/Group.ts b/src/lib/Group.ts index 9b709d27..e431d4a6 100644 --- a/src/lib/Group.ts +++ b/src/lib/Group.ts @@ -75,7 +75,7 @@ export class Group< * @returns {Promise} A Promise that resolves to a InboxId. */ async creatorInboxId(): Promise { - return XMTP.creatorInboxId(this.client.inboxId, this.id) + return XMTP.creatorInboxId(this.client.installationId, this.id) } /** @@ -98,7 +98,11 @@ export class Group< content = { text: content } } - return await XMTP.sendMessage(this.client.inboxId, this.id, content) + return await XMTP.sendMessage( + this.client.installationId, + this.id, + content + ) } catch (e) { console.info('ERROR in send()', e.message) throw e @@ -125,7 +129,11 @@ export class Group< content = { text: content } } - return await XMTP.prepareMessage(this.client.inboxId, this.id, content) + return await XMTP.prepareMessage( + this.client.installationId, + this.id, + content + ) } catch (e) { console.info('ERROR in prepareGroupMessage()', e.message) throw e @@ -139,7 +147,10 @@ export class Group< */ async publishPreparedMessages() { try { - return await XMTP.publishPreparedMessages(this.client.inboxId, this.id) + return await XMTP.publishPreparedMessages( + this.client.installationId, + this.id + ) } catch (e) { console.info('ERROR in publishPreparedMessages()', e.message) throw e @@ -174,7 +185,7 @@ export class Group< * associated with the group and saves them to the local state. */ async sync() { - await XMTP.syncConversation(this.client.inboxId, this.id) + await XMTP.syncConversation(this.client.installationId, this.id) } /** @@ -190,19 +201,19 @@ export class Group< async streamMessages( callback: (message: DecodedMessage) => Promise ): Promise<() => void> { - await XMTP.subscribeToMessages(this.client.inboxId, this.id) + await XMTP.subscribeToMessages(this.client.installationId, this.id) const messageSubscription = XMTP.emitter.addListener( EventTypes.ConversationMessage, async ({ - inboxId, + installationId, message, conversationId, }: { - inboxId: string + installationId: string message: DecodedMessage conversationId: string }) => { - if (inboxId !== this.client.inboxId) { + if (installationId !== this.client.installationId) { return } if (conversationId !== this.id) { @@ -215,7 +226,7 @@ export class Group< ) return async () => { messageSubscription.remove() - await XMTP.unsubscribeFromMessages(this.client.inboxId, this.id) + await XMTP.unsubscribeFromMessages(this.client.installationId, this.id) } } /** @@ -224,7 +235,7 @@ export class Group< * @returns */ async addMembers(addresses: Address[]): Promise { - return XMTP.addGroupMembers(this.client.inboxId, this.id, addresses) + return XMTP.addGroupMembers(this.client.installationId, this.id, addresses) } /** @@ -233,7 +244,11 @@ export class Group< * @returns */ async removeMembers(addresses: Address[]): Promise { - return XMTP.removeGroupMembers(this.client.inboxId, this.id, addresses) + return XMTP.removeGroupMembers( + this.client.installationId, + this.id, + addresses + ) } /** @@ -242,7 +257,11 @@ export class Group< * @returns */ async addMembersByInboxId(inboxIds: InboxId[]): Promise { - return XMTP.addGroupMembersByInboxId(this.client.inboxId, this.id, inboxIds) + return XMTP.addGroupMembersByInboxId( + this.client.installationId, + this.id, + inboxIds + ) } /** @@ -252,7 +271,7 @@ export class Group< */ async removeMembersByInboxId(inboxIds: InboxId[]): Promise { return XMTP.removeGroupMembersByInboxId( - this.client.inboxId, + this.client.installationId, this.id, inboxIds ) @@ -264,7 +283,7 @@ export class Group< * @returns {string} A Promise that resolves to the group name. */ async groupName(): Promise { - return XMTP.groupName(this.client.inboxId, this.id) + return XMTP.groupName(this.client.installationId, this.id) } /** @@ -275,7 +294,7 @@ export class Group< */ async updateGroupName(groupName: string): Promise { - return XMTP.updateGroupName(this.client.inboxId, this.id, groupName) + return XMTP.updateGroupName(this.client.installationId, this.id, groupName) } /** @@ -284,7 +303,7 @@ export class Group< * @returns {string} A Promise that resolves to the group image url. */ async groupImageUrlSquare(): Promise { - return XMTP.groupImageUrlSquare(this.client.inboxId, this.id) + return XMTP.groupImageUrlSquare(this.client.installationId, this.id) } /** @@ -296,7 +315,7 @@ export class Group< async updateGroupImageUrlSquare(imageUrlSquare: string): Promise { return XMTP.updateGroupImageUrlSquare( - this.client.inboxId, + this.client.installationId, this.id, imageUrlSquare ) @@ -308,7 +327,7 @@ export class Group< * @returns {string} A Promise that resolves to the group description. */ async groupDescription(): Promise { - return XMTP.groupDescription(this.client.inboxId, this.id) + return XMTP.groupDescription(this.client.installationId, this.id) } /** @@ -320,7 +339,7 @@ export class Group< async updateGroupDescription(description: string): Promise { return XMTP.updateGroupDescription( - this.client.inboxId, + this.client.installationId, this.id, description ) @@ -332,7 +351,7 @@ export class Group< * @returns {string} A Promise that resolves to the group pinned frame url. */ async groupPinnedFrameUrl(): Promise { - return XMTP.groupPinnedFrameUrl(this.client.inboxId, this.id) + return XMTP.groupPinnedFrameUrl(this.client.installationId, this.id) } /** @@ -344,7 +363,7 @@ export class Group< async updateGroupPinnedFrameUrl(pinnedFrameUrl: string): Promise { return XMTP.updateGroupPinnedFrameUrl( - this.client.inboxId, + this.client.installationId, this.id, pinnedFrameUrl ) @@ -357,7 +376,7 @@ export class Group< */ async isActive(): Promise { - return XMTP.isGroupActive(this.client.inboxId, this.id) + return XMTP.isGroupActive(this.client.installationId, this.id) } /** @@ -367,7 +386,7 @@ export class Group< * To get the latest admin status from the network, call sync() first. */ async isAdmin(inboxId: InboxId): Promise { - return XMTP.isAdmin(this.client.inboxId, this.id, inboxId) + return XMTP.isAdmin(this.client.installationId, this.id, inboxId) } /** @@ -377,7 +396,7 @@ export class Group< * To get the latest super admin status from the network, call sync() first. */ async isSuperAdmin(inboxId: InboxId): Promise { - return XMTP.isSuperAdmin(this.client.inboxId, this.id, inboxId) + return XMTP.isSuperAdmin(this.client.installationId, this.id, inboxId) } /** @@ -386,7 +405,7 @@ export class Group< * To get the latest admin list from the network, call sync() first. */ async listAdmins(): Promise { - return XMTP.listAdmins(this.client.inboxId, this.id) + return XMTP.listAdmins(this.client.installationId, this.id) } /** @@ -395,7 +414,7 @@ export class Group< * To get the latest super admin list from the network, call sync() first. */ async listSuperAdmins(): Promise { - return XMTP.listSuperAdmins(this.client.inboxId, this.id) + return XMTP.listSuperAdmins(this.client.installationId, this.id) } /** @@ -405,7 +424,7 @@ export class Group< * Will throw if the user does not have the required permissions. */ async addAdmin(inboxId: InboxId): Promise { - return XMTP.addAdmin(this.client.inboxId, this.id, inboxId) + return XMTP.addAdmin(this.client.installationId, this.id, inboxId) } /** @@ -415,7 +434,7 @@ export class Group< * Will throw if the user does not have the required permissions. */ async addSuperAdmin(inboxId: InboxId): Promise { - return XMTP.addSuperAdmin(this.client.inboxId, this.id, inboxId) + return XMTP.addSuperAdmin(this.client.installationId, this.id, inboxId) } /** @@ -425,7 +444,7 @@ export class Group< * Will throw if the user does not have the required permissions. */ async removeAdmin(inboxId: InboxId): Promise { - return XMTP.removeAdmin(this.client.inboxId, this.id, inboxId) + return XMTP.removeAdmin(this.client.installationId, this.id, inboxId) } /** @@ -435,7 +454,7 @@ export class Group< * Will throw if the user does not have the required permissions. */ async removeSuperAdmin(inboxId: InboxId): Promise { - return XMTP.removeSuperAdmin(this.client.inboxId, this.id, inboxId) + return XMTP.removeSuperAdmin(this.client.installationId, this.id, inboxId) } /** @@ -448,7 +467,7 @@ export class Group< permissionOption: PermissionUpdateOption ): Promise { return XMTP.updateAddMemberPermission( - this.client.inboxId, + this.client.installationId, this.id, permissionOption ) @@ -464,7 +483,7 @@ export class Group< permissionOption: PermissionUpdateOption ): Promise { return XMTP.updateRemoveMemberPermission( - this.client.inboxId, + this.client.installationId, this.id, permissionOption ) @@ -480,7 +499,7 @@ export class Group< permissionOption: PermissionUpdateOption ): Promise { return XMTP.updateAddAdminPermission( - this.client.inboxId, + this.client.installationId, this.id, permissionOption ) @@ -496,7 +515,7 @@ export class Group< permissionOption: PermissionUpdateOption ): Promise { return XMTP.updateRemoveAdminPermission( - this.client.inboxId, + this.client.installationId, this.id, permissionOption ) @@ -512,7 +531,7 @@ export class Group< permissionOption: PermissionUpdateOption ): Promise { return XMTP.updateGroupNamePermission( - this.client.inboxId, + this.client.installationId, this.id, permissionOption ) @@ -528,7 +547,7 @@ export class Group< permissionOption: PermissionUpdateOption ): Promise { return XMTP.updateGroupImageUrlSquarePermission( - this.client.inboxId, + this.client.installationId, this.id, permissionOption ) @@ -544,7 +563,7 @@ export class Group< permissionOption: PermissionUpdateOption ): Promise { return XMTP.updateGroupDescriptionPermission( - this.client.inboxId, + this.client.installationId, this.id, permissionOption ) @@ -560,7 +579,7 @@ export class Group< permissionOption: PermissionUpdateOption ): Promise { return XMTP.updateGroupPinnedFrameUrlPermission( - this.client.inboxId, + this.client.installationId, this.id, permissionOption ) @@ -571,7 +590,7 @@ export class Group< * @returns {Promise} A {PermissionPolicySet} object representing the group's permission policy set. */ async permissionPolicySet(): Promise { - return XMTP.permissionPolicySet(this.client.inboxId, this.id) + return XMTP.permissionPolicySet(this.client.installationId, this.id) } async processMessage( @@ -586,12 +605,15 @@ export class Group< } async consentState(): Promise { - return await XMTP.conversationConsentState(this.client.inboxId, this.id) + return await XMTP.conversationConsentState( + this.client.installationId, + this.id + ) } async updateConsent(state: ConsentState): Promise { return await XMTP.updateConversationConsent( - this.client.inboxId, + this.client.installationId, this.id, state ) @@ -603,6 +625,9 @@ export class Group< * To get the latest member list from the network, call sync() first. */ async members(): Promise { - return await XMTP.listConversationMembers(this.client.inboxId, this.id) + return await XMTP.listConversationMembers( + this.client.installationId, + this.id + ) } } diff --git a/src/lib/PrivatePreferences.ts b/src/lib/PrivatePreferences.ts index cdce5f58..3820fa5e 100644 --- a/src/lib/PrivatePreferences.ts +++ b/src/lib/PrivatePreferences.ts @@ -17,25 +17,28 @@ export default class PrivatePreferences { conversationId: ConversationId ): Promise { return await XMTPModule.consentConversationIdState( - this.client.inboxId, + this.client.installationId, conversationId ) } async inboxIdConsentState(inboxId: InboxId): Promise { - return await XMTPModule.consentInboxIdState(this.client.inboxId, inboxId) + return await XMTPModule.consentInboxIdState( + this.client.installationId, + inboxId + ) } async addressConsentState(address: Address): Promise { return await XMTPModule.consentAddressState( - this.client.inboxId, + this.client.installationId, getAddress(address) ) } async setConsentState(consentRecord: ConsentRecord): Promise { return await XMTPModule.setConsentState( - this.client.inboxId, + this.client.installationId, consentRecord.value, consentRecord.entryType, consentRecord.state @@ -43,7 +46,7 @@ export default class PrivatePreferences { } async syncConsent(): Promise { - return await XMTPModule.syncConsent(this.client.inboxId) + return await XMTPModule.syncConsent(this.client.installationId) } /** @@ -53,17 +56,17 @@ export default class PrivatePreferences { async streamConsent( callback: (consent: ConsentRecord) => Promise ): Promise { - XMTPModule.subscribeToConsent(this.client.inboxId) + XMTPModule.subscribeToConsent(this.client.installationId) const subscription = XMTPModule.emitter.addListener( EventTypes.Consent, async ({ - inboxId, + installationId, consent, }: { - inboxId: string + installationId: string consent: ConsentRecord }) => { - if (inboxId !== this.client.inboxId) { + if (installationId !== this.client.installationId) { return } return await callback( @@ -82,6 +85,6 @@ export default class PrivatePreferences { this.subscriptions[EventTypes.Consent].remove() delete this.subscriptions[EventTypes.Consent] } - XMTPModule.unsubscribeFromConsent(this.client.inboxId) + XMTPModule.unsubscribeFromConsent(this.client.installationId) } } From 6dbda24a0e5ec9f0ca8275940d28924212c0b0ec Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 26 Nov 2024 09:41:41 -0800 Subject: [PATCH 09/12] do the iOS side --- ios/XMTPModule.swift | 436 +++++++++++++++++++++---------------------- 1 file changed, 218 insertions(+), 218 deletions(-) diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index bcfd1c79..949b4d54 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -4,12 +4,12 @@ import OSLog import XMTP extension Conversation { - static func cacheKeyForTopic(inboxId: String, topic: String) -> String { - return "\(inboxId):\(topic)" + static func cacheKeyForTopic(installationId: String, topic: String) -> String { + return "\(installationId):\(topic)" } - func cacheKey(_ inboxId: String) -> String { - return Conversation.cacheKeyForTopic(inboxId: inboxId, topic: topic) + func cacheKey(_ installationId: String) -> String { + return Conversation.cacheKeyForTopic(installationId: installationId, topic: topic) } } @@ -93,16 +93,16 @@ public class XMTPModule: Module { "consent" ) - AsyncFunction("address") { (inboxId: String) -> String in - if let client = await clientsManager.getClient(key: inboxId) { + AsyncFunction("address") { (installationId: String) -> String in + if let client = await clientsManager.getClient(key: installationId) { return client.address } else { return "No Client." } } - AsyncFunction("inboxId") { (inboxId: String) -> String in - if let client = await clientsManager.getClient(key: inboxId) { + AsyncFunction("inboxId") { (installationId: String) -> String in + if let client = await clientsManager.getClient(key: installationId) { return client.inboxID } else { return "No Client." @@ -110,40 +110,40 @@ public class XMTPModule: Module { } AsyncFunction("findInboxIdFromAddress") { - (inboxId: String, address: String) -> String? in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, address: String) -> String? in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } return try await client.inboxIdFromAddress(address: address) } - AsyncFunction("deleteLocalDatabase") { (inboxId: String) in - guard let client = await clientsManager.getClient(key: inboxId) + AsyncFunction("deleteLocalDatabase") { (installationId: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } try client.deleteLocalDatabase() } - AsyncFunction("dropLocalDatabaseConnection") { (inboxId: String) in - guard let client = await clientsManager.getClient(key: inboxId) + AsyncFunction("dropLocalDatabaseConnection") { (installationId: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } try client.dropLocalDatabaseConnection() } - AsyncFunction("reconnectLocalDatabase") { (inboxId: String) in - guard let client = await clientsManager.getClient(key: inboxId) + AsyncFunction("reconnectLocalDatabase") { (installationId: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } try await client.reconnectLocalDatabase() } - AsyncFunction("requestMessageHistorySync") { (inboxId: String) in - guard let client = await clientsManager.getClient(key: inboxId) + AsyncFunction("requestMessageHistorySync") { (installationId: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -151,8 +151,8 @@ public class XMTPModule: Module { } AsyncFunction("getInboxState") { - (inboxId: String, refreshFromNetwork: Bool) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, refreshFromNetwork: Bool) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -162,9 +162,9 @@ public class XMTPModule: Module { } AsyncFunction("getInboxStates") { - (inboxId: String, refreshFromNetwork: Bool, inboxIds: [String]) + (installationId: String, refreshFromNetwork: Bool, inboxIds: [String]) -> [String] in - guard let client = await clientsManager.getClient(key: inboxId) + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -276,8 +276,8 @@ public class XMTPModule: Module { } AsyncFunction("revokeAllOtherInstallations") { - (inboxId: String, walletParams: String) in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, walletParams: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -295,8 +295,8 @@ public class XMTPModule: Module { } AsyncFunction("addAccount") { - (inboxId: String, newAddress: String, walletParams: String) in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, newAddress: String, walletParams: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -314,8 +314,8 @@ public class XMTPModule: Module { } AsyncFunction("removeAccount") { - (inboxId: String, addressToRemove: String, walletParams: String) in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, addressToRemove: String, walletParams: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -334,13 +334,13 @@ public class XMTPModule: Module { } // Remove a client from memory for a given inboxId - AsyncFunction("dropClient") { (inboxId: String) in - await clientsManager.dropClient(key: inboxId) + AsyncFunction("dropClient") { (installationId: String) in + await clientsManager.dropClient(key: installationId) } AsyncFunction("signWithInstallationKey") { - (inboxId: String, message: String) -> [UInt8] in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, message: String) -> [UInt8] in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -349,8 +349,8 @@ public class XMTPModule: Module { } AsyncFunction("verifySignature") { - (inboxId: String, message: String, signature: [UInt8]) -> Bool in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, message: String, signature: [UInt8]) -> Bool in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -359,8 +359,8 @@ public class XMTPModule: Module { } AsyncFunction("canMessage") { - (inboxId: String, peerAddresses: [String]) -> [String: Bool] in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, peerAddresses: [String]) -> [String: Bool] in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -380,8 +380,8 @@ public class XMTPModule: Module { } AsyncFunction("encryptAttachment") { - (inboxId: String, fileJson: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, fileJson: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -410,8 +410,8 @@ public class XMTPModule: Module { } AsyncFunction("decryptAttachment") { - (inboxId: String, encryptedFileJson: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, encryptedFileJson: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -442,10 +442,10 @@ public class XMTPModule: Module { AsyncFunction("listGroups") { ( - inboxId: String, groupParams: String?, sortOrder: String?, + installationId: String, groupParams: String?, sortOrder: String?, limit: Int?, consentState: String? ) -> [String] in - guard let client = await clientsManager.getClient(key: inboxId) + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -473,10 +473,10 @@ public class XMTPModule: Module { AsyncFunction("listDms") { ( - inboxId: String, groupParams: String?, sortOrder: String?, + installationId: String, groupParams: String?, sortOrder: String?, limit: Int?, consentState: String? ) -> [String] in - guard let client = await clientsManager.getClient(key: inboxId) + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -504,10 +504,10 @@ public class XMTPModule: Module { AsyncFunction("listConversations") { ( - inboxId: String, conversationParams: String?, + installationId: String, conversationParams: String?, sortOrder: String?, limit: Int?, consentState: String? ) -> [String] in - guard let client = await clientsManager.getClient(key: inboxId) + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -537,10 +537,10 @@ public class XMTPModule: Module { AsyncFunction("conversationMessages") { ( - inboxId: String, conversationId: String, limit: Int?, + installationId: String, conversationId: String, limit: Int?, beforeNs: Double?, afterNs: Double?, direction: String? ) -> [String] in - guard let client = await clientsManager.getClient(key: inboxId) + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -573,8 +573,8 @@ public class XMTPModule: Module { } AsyncFunction("findMessage") { - (inboxId: String, messageId: String) -> String? in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, messageId: String) -> String? in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -587,8 +587,8 @@ public class XMTPModule: Module { } AsyncFunction("findGroup") { - (inboxId: String, groupId: String) -> String? in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, groupId: String) -> String? in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -600,8 +600,8 @@ public class XMTPModule: Module { } AsyncFunction("findConversation") { - (inboxId: String, conversationId: String) -> String? in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, conversationId: String) -> String? in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -617,8 +617,8 @@ public class XMTPModule: Module { } AsyncFunction("findConversationByTopic") { - (inboxId: String, topic: String) -> String? in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, topic: String) -> String? in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -633,8 +633,8 @@ public class XMTPModule: Module { } AsyncFunction("findDmByInboxId") { - (inboxId: String, peerInboxId: String) -> String? in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, peerInboxId: String) -> String? in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -646,8 +646,8 @@ public class XMTPModule: Module { } AsyncFunction("findDmByAddress") { - (inboxId: String, peerAddress: String) -> String? in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, peerAddress: String) -> String? in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -659,8 +659,8 @@ public class XMTPModule: Module { } AsyncFunction("sendMessage") { - (inboxId: String, id: String, contentJson: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String, contentJson: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -680,8 +680,8 @@ public class XMTPModule: Module { } AsyncFunction("publishPreparedMessages") { - (inboxId: String, id: String) in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -697,8 +697,8 @@ public class XMTPModule: Module { } AsyncFunction("prepareMessage") { - (inboxId: String, id: String, contentJson: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String, contentJson: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -718,8 +718,8 @@ public class XMTPModule: Module { } AsyncFunction("findOrCreateDm") { - (inboxId: String, peerAddress: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, peerAddress: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -736,10 +736,10 @@ public class XMTPModule: Module { AsyncFunction("createGroup") { ( - inboxId: String, peerAddresses: [String], permission: String, + installationId: String, peerAddresses: [String], permission: String, groupOptionsJson: String ) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -772,10 +772,10 @@ public class XMTPModule: Module { AsyncFunction("createGroupCustomPermissions") { ( - inboxId: String, peerAddresses: [String], + installationId: String, peerAddresses: [String], permissionPolicySetJson: String, groupOptionsJson: String ) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -803,8 +803,8 @@ public class XMTPModule: Module { } AsyncFunction("listMemberInboxIds") { - (inboxId: String, groupId: String) -> [String] in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, groupId: String) -> [String] in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -816,8 +816,8 @@ public class XMTPModule: Module { } AsyncFunction("dmPeerInboxId") { - (inboxId: String, dmId: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, dmId: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -838,13 +838,13 @@ public class XMTPModule: Module { } AsyncFunction("listConversationMembers") { - (inboxId: String, conversationId: String) -> [String] in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, conversationId: String) -> [String] in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } - guard let client = await clientsManager.getClient(key: inboxId) + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -860,24 +860,24 @@ public class XMTPModule: Module { } } - AsyncFunction("syncConversations") { (inboxId: String) in - guard let client = await clientsManager.getClient(key: inboxId) + AsyncFunction("syncConversations") { (installationId: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } try await client.conversations.sync() } - AsyncFunction("syncAllConversations") { (inboxId: String) -> UInt32 in - guard let client = await clientsManager.getClient(key: inboxId) + AsyncFunction("syncAllConversations") { (installationId: String) -> UInt32 in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } return try await client.conversations.syncAllConversations() } - AsyncFunction("syncConversation") { (inboxId: String, id: String) in - guard let client = await clientsManager.getClient(key: inboxId) + AsyncFunction("syncConversation") { (installationId: String, id: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -892,8 +892,8 @@ public class XMTPModule: Module { } AsyncFunction("addGroupMembers") { - (inboxId: String, id: String, peerAddresses: [String]) in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String, peerAddresses: [String]) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -905,8 +905,8 @@ public class XMTPModule: Module { } AsyncFunction("removeGroupMembers") { - (inboxId: String, id: String, peerAddresses: [String]) in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String, peerAddresses: [String]) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -918,8 +918,8 @@ public class XMTPModule: Module { } AsyncFunction("addGroupMembersByInboxId") { - (inboxId: String, id: String, inboxIds: [String]) in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String, inboxIds: [String]) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -931,8 +931,8 @@ public class XMTPModule: Module { } AsyncFunction("removeGroupMembersByInboxId") { - (inboxId: String, id: String, inboxIds: [String]) in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String, inboxIds: [String]) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -944,8 +944,8 @@ public class XMTPModule: Module { try await group.removeMembersByInboxId(inboxIds: inboxIds) } - AsyncFunction("groupName") { (inboxId: String, id: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + AsyncFunction("groupName") { (installationId: String, id: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -958,8 +958,8 @@ public class XMTPModule: Module { } AsyncFunction("updateGroupName") { - (inboxId: String, id: String, groupName: String) in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String, groupName: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -972,8 +972,8 @@ public class XMTPModule: Module { } AsyncFunction("groupImageUrlSquare") { - (inboxId: String, id: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -986,8 +986,8 @@ public class XMTPModule: Module { } AsyncFunction("updateGroupImageUrlSquare") { - (inboxId: String, id: String, groupImageUrl: String) in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String, groupImageUrl: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1001,8 +1001,8 @@ public class XMTPModule: Module { } AsyncFunction("groupDescription") { - (inboxId: String, id: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1015,8 +1015,8 @@ public class XMTPModule: Module { } AsyncFunction("updateGroupDescription") { - (inboxId: String, id: String, description: String) in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String, description: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1030,8 +1030,8 @@ public class XMTPModule: Module { } AsyncFunction("groupPinnedFrameUrl") { - (inboxId: String, id: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1044,8 +1044,8 @@ public class XMTPModule: Module { } AsyncFunction("updateGroupPinnedFrameUrl") { - (inboxId: String, id: String, pinnedFrameUrl: String) in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String, pinnedFrameUrl: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1059,8 +1059,8 @@ public class XMTPModule: Module { } AsyncFunction("isGroupActive") { - (inboxId: String, id: String) -> Bool in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String) -> Bool in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1073,8 +1073,8 @@ public class XMTPModule: Module { } AsyncFunction("addedByInboxId") { - (inboxId: String, id: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1087,8 +1087,8 @@ public class XMTPModule: Module { } AsyncFunction("creatorInboxId") { - (inboxId: String, id: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1100,9 +1100,9 @@ public class XMTPModule: Module { } AsyncFunction("isAdmin") { - (clientInboxId: String, id: String, inboxId: String) -> Bool in + (clientInstallationId: String, id: String, inboxId: String) -> Bool in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1114,9 +1114,9 @@ public class XMTPModule: Module { } AsyncFunction("isSuperAdmin") { - (clientInboxId: String, id: String, inboxId: String) -> Bool in + (clientInstallationId: String, id: String, inboxId: String) -> Bool in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1128,8 +1128,8 @@ public class XMTPModule: Module { } AsyncFunction("listAdmins") { - (inboxId: String, id: String) -> [String] in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String) -> [String] in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1141,8 +1141,8 @@ public class XMTPModule: Module { } AsyncFunction("listSuperAdmins") { - (inboxId: String, id: String) -> [String] in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String) -> [String] in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1154,9 +1154,9 @@ public class XMTPModule: Module { } AsyncFunction("addAdmin") { - (clientInboxId: String, id: String, inboxId: String) in + (clientInstallationId: String, id: String, inboxId: String) in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1168,9 +1168,9 @@ public class XMTPModule: Module { } AsyncFunction("addSuperAdmin") { - (clientInboxId: String, id: String, inboxId: String) in + (clientInstallationId: String, id: String, inboxId: String) in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1182,9 +1182,9 @@ public class XMTPModule: Module { } AsyncFunction("removeAdmin") { - (clientInboxId: String, id: String, inboxId: String) in + (clientInstallationId: String, id: String, inboxId: String) in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1196,9 +1196,9 @@ public class XMTPModule: Module { } AsyncFunction("removeSuperAdmin") { - (clientInboxId: String, id: String, inboxId: String) in + (clientInstallationId: String, id: String, inboxId: String) in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1210,9 +1210,9 @@ public class XMTPModule: Module { } AsyncFunction("updateAddMemberPermission") { - (clientInboxId: String, id: String, newPermission: String) in + (clientInstallationId: String, id: String, newPermission: String) in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1226,9 +1226,9 @@ public class XMTPModule: Module { } AsyncFunction("updateRemoveMemberPermission") { - (clientInboxId: String, id: String, newPermission: String) in + (clientInstallationId: String, id: String, newPermission: String) in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1242,9 +1242,9 @@ public class XMTPModule: Module { } AsyncFunction("updateAddAdminPermission") { - (clientInboxId: String, id: String, newPermission: String) in + (clientInstallationId: String, id: String, newPermission: String) in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1258,9 +1258,9 @@ public class XMTPModule: Module { } AsyncFunction("updateRemoveAdminPermission") { - (clientInboxId: String, id: String, newPermission: String) in + (clientInstallationId: String, id: String, newPermission: String) in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1274,9 +1274,9 @@ public class XMTPModule: Module { } AsyncFunction("updateGroupNamePermission") { - (clientInboxId: String, id: String, newPermission: String) in + (clientInstallationId: String, id: String, newPermission: String) in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1290,9 +1290,9 @@ public class XMTPModule: Module { } AsyncFunction("updateGroupImageUrlSquarePermission") { - (clientInboxId: String, id: String, newPermission: String) in + (clientInstallationId: String, id: String, newPermission: String) in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1306,9 +1306,9 @@ public class XMTPModule: Module { } AsyncFunction("updateGroupDescriptionPermission") { - (clientInboxId: String, id: String, newPermission: String) in + (clientInstallationId: String, id: String, newPermission: String) in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1322,9 +1322,9 @@ public class XMTPModule: Module { } AsyncFunction("updateGroupPinnedFrameUrlPermission") { - (clientInboxId: String, id: String, newPermission: String) in + (clientInstallationId: String, id: String, newPermission: String) in guard - let client = await clientsManager.getClient(key: clientInboxId) + let client = await clientsManager.getClient(key: clientInstallationId) else { throw Error.noClient } @@ -1338,8 +1338,8 @@ public class XMTPModule: Module { } AsyncFunction("permissionPolicySet") { - (inboxId: String, id: String) async throws -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String) async throws -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1355,8 +1355,8 @@ public class XMTPModule: Module { } AsyncFunction("processMessage") { - (inboxId: String, id: String, encryptedMessage: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, id: String, encryptedMessage: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1382,8 +1382,8 @@ public class XMTPModule: Module { } AsyncFunction("processWelcomeMessage") { - (inboxId: String, encryptedMessage: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, encryptedMessage: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1404,8 +1404,8 @@ public class XMTPModule: Module { conversation, client: client) } - AsyncFunction("syncConsent") { (inboxId: String) in - guard let client = await clientsManager.getClient(key: inboxId) + AsyncFunction("syncConsent") { (installationId: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1415,10 +1415,10 @@ public class XMTPModule: Module { AsyncFunction("setConsentState") { ( - inboxId: String, value: String, entryType: String, + installationId: String, value: String, entryType: String, consentType: String ) in - guard let client = await clientsManager.getClient(key: inboxId) + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1438,8 +1438,8 @@ public class XMTPModule: Module { } AsyncFunction("consentAddressState") { - (inboxId: String, address: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, address: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1449,8 +1449,8 @@ public class XMTPModule: Module { } AsyncFunction("consentInboxIdState") { - (inboxId: String, peerInboxId: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, peerInboxId: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1460,8 +1460,8 @@ public class XMTPModule: Module { } AsyncFunction("consentConversationIdState") { - (inboxId: String, conversationId: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, conversationId: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1472,8 +1472,8 @@ public class XMTPModule: Module { } AsyncFunction("conversationConsentState") { - (inboxId: String, conversationId: String) -> String in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, conversationId: String) -> String in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1490,8 +1490,8 @@ public class XMTPModule: Module { } AsyncFunction("updateConversationConsent") { - (inboxId: String, conversationId: String, state: String) in - guard let client = await clientsManager.getClient(key: inboxId) + (installationId: String, conversationId: String, state: String) in + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1509,48 +1509,48 @@ public class XMTPModule: Module { } AsyncFunction("subscribeToConsent") { - (inboxId: String) in + (installationId: String) in try await subscribeToConsent( - inboxId: inboxId) + installationId: installationId) } AsyncFunction("subscribeToConversations") { - (inboxId: String, type: String) in + (installationId: String, type: String) in try await subscribeToConversations( - inboxId: inboxId, type: getConversationType(type: type)) + installationId: installationId, type: getConversationType(type: type)) } AsyncFunction("subscribeToAllMessages") { - (inboxId: String, type: String) in + (installationId: String, type: String) in try await subscribeToAllMessages( - inboxId: inboxId, type: getConversationType(type: type)) + installationId: installationId, type: getConversationType(type: type)) } AsyncFunction("subscribeToMessages") { - (inboxId: String, id: String) in - try await subscribeToMessages(inboxId: inboxId, id: id) + (installationId: String, id: String) in + try await subscribeToMessages(installationId: installationId, id: id) } - AsyncFunction("unsubscribeFromConsent") { (inboxId: String) in - await subscriptionsManager.get(getConsentKey(inboxId: inboxId))? + AsyncFunction("unsubscribeFromConsent") { (installationId: String) in + await subscriptionsManager.get(getConsentKey(installationId: installationId))? .cancel() } - AsyncFunction("unsubscribeFromConversations") { (inboxId: String) in + AsyncFunction("unsubscribeFromConversations") { (installationId: String) in await subscriptionsManager.get( - getConversationsKey(inboxId: inboxId))?.cancel() + getConversationsKey(installationId: installationId))?.cancel() } - AsyncFunction("unsubscribeFromAllMessages") { (inboxId: String) in - await subscriptionsManager.get(getMessagesKey(inboxId: inboxId))? + AsyncFunction("unsubscribeFromAllMessages") { (installationId: String) in + await subscriptionsManager.get(getMessagesKey(installationId: installationId))? .cancel() } AsyncFunction("unsubscribeFromMessages") { - (inboxId: String, id: String) in - try await unsubscribeFromMessages(inboxId: inboxId, id: id) + (installationId: String, id: String) in + try await unsubscribeFromMessages(installationId: installationId, id: id) } AsyncFunction("registerPushToken") { @@ -1739,17 +1739,17 @@ public class XMTPModule: Module { historySyncUrl: authOptions.historySyncUrl) } - func subscribeToConsent(inboxId: String) + func subscribeToConsent(installationId: String) async throws { - guard let client = await clientsManager.getClient(key: inboxId) else { + guard let client = await clientsManager.getClient(key: installationId) else { return } - await subscriptionsManager.get(getConsentKey(inboxId: inboxId))? + await subscriptionsManager.get(getConsentKey(installationId: installationId))? .cancel() await subscriptionsManager.set( - getConsentKey(inboxId: inboxId), + getConsentKey(installationId: installationId), Task { do { for try await consent in await client.preferences @@ -1758,7 +1758,7 @@ public class XMTPModule: Module { try sendEvent( "consent", [ - "inboxId": inboxId, + "installationId": installationId, "consent": ConsentWrapper.encodeToObj( consent), ]) @@ -1766,22 +1766,22 @@ public class XMTPModule: Module { } catch { print("Error in consent subscription: \(error)") await subscriptionsManager.get( - getConsentKey(inboxId: inboxId))?.cancel() + getConsentKey(installationId: installationId))?.cancel() } }) } - func subscribeToConversations(inboxId: String, type: ConversationType) + func subscribeToConversations(installationId: String, type: ConversationType) async throws { - guard let client = await clientsManager.getClient(key: inboxId) else { + guard let client = await clientsManager.getClient(key: installationId) else { return } - await subscriptionsManager.get(getConversationsKey(inboxId: inboxId))? + await subscriptionsManager.get(getConversationsKey(installationId: installationId))? .cancel() await subscriptionsManager.set( - getConversationsKey(inboxId: inboxId), + getConversationsKey(installationId: installationId), Task { do { for try await conversation in await client.conversations @@ -1790,7 +1790,7 @@ public class XMTPModule: Module { try await sendEvent( "conversation", [ - "inboxId": inboxId, + "installationId": installationId, "conversation": ConversationWrapper.encodeToObj( conversation, client: client), ]) @@ -1798,22 +1798,22 @@ public class XMTPModule: Module { } catch { print("Error in all conversations subscription: \(error)") await subscriptionsManager.get( - getConversationsKey(inboxId: inboxId))?.cancel() + getConversationsKey(installationId: installationId))?.cancel() } }) } - func subscribeToAllMessages(inboxId: String, type: ConversationType) + func subscribeToAllMessages(installationId: String, type: ConversationType) async throws { - guard let client = await clientsManager.getClient(key: inboxId) else { + guard let client = await clientsManager.getClient(key: installationId) else { return } - await subscriptionsManager.get(getMessagesKey(inboxId: inboxId))? + await subscriptionsManager.get(getMessagesKey(installationId: installationId))? .cancel() await subscriptionsManager.set( - getMessagesKey(inboxId: inboxId), + getMessagesKey(installationId: installationId), Task { do { for try await message in await client.conversations @@ -1822,7 +1822,7 @@ public class XMTPModule: Module { try sendEvent( "message", [ - "inboxId": inboxId, + "installationId": installationId, "message": DecodedMessageWrapper.encodeToObj( message, client: client), ]) @@ -1830,13 +1830,13 @@ public class XMTPModule: Module { } catch { print("Error in all messages subscription: \(error)") await subscriptionsManager.get( - getMessagesKey(inboxId: inboxId))?.cancel() + getMessagesKey(installationId: installationId))?.cancel() } }) } - func subscribeToMessages(inboxId: String, id: String) async throws { - guard let client = await clientsManager.getClient(key: inboxId) else { + func subscribeToMessages(installationId: String, id: String) async throws { + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1845,10 +1845,10 @@ public class XMTPModule: Module { return } - await subscriptionsManager.get(converation.cacheKey(client.inboxID))? + await subscriptionsManager.get(converation.cacheKey(installationId))? .cancel() await subscriptionsManager.set( - converation.cacheKey(client.inboxID), + converation.cacheKey(installationId), Task { do { for try await message in converation.streamMessages() { @@ -1856,7 +1856,7 @@ public class XMTPModule: Module { try sendEvent( "conversationMessage", [ - "inboxId": inboxId, + "installationId": installationId, "message": DecodedMessageWrapper.encodeToObj( message, client: client), @@ -1871,13 +1871,13 @@ public class XMTPModule: Module { } catch { print("Error in group messages subscription: \(error)") await subscriptionsManager.get( - converation.cacheKey(inboxId))?.cancel() + converation.cacheKey(installationId))?.cancel() } }) } - func unsubscribeFromMessages(inboxId: String, id: String) async throws { - guard let client = await clientsManager.getClient(key: inboxId) else { + func unsubscribeFromMessages(installationId: String, id: String) async throws { + guard let client = await clientsManager.getClient(key: installationId) else { throw Error.noClient } @@ -1886,24 +1886,24 @@ public class XMTPModule: Module { return } - await subscriptionsManager.get(converation.cacheKey(inboxId))? + await subscriptionsManager.get(converation.cacheKey(installationId))? .cancel() } - func getConsentKey(inboxId: String) -> String { - return "consent:\(inboxId)" + func getConsentKey(installationId: String) -> String { + return "consent:\(installationId)" } - func getMessagesKey(inboxId: String) -> String { - return "messages:\(inboxId)" + func getMessagesKey(installationId: String) -> String { + return "messages:\(installationId)" } - func getConversationsKey(inboxId: String) -> String { - return "conversations:\(inboxId)" + func getConversationsKey(installationId: String) -> String { + return "conversations:\(installationId)" } - func getConversationMessagesKey(inboxId: String) -> String { - return "conversationMessages:\(inboxId)" + func getConversationMessagesKey(installationId: String) -> String { + return "conversationMessages:\(installationId)" } func preAuthenticateToInboxCallback() { From 46eb00b84a7012d511cf108ffa92f040e69f92fb Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 26 Nov 2024 11:17:41 -0800 Subject: [PATCH 10/12] a few small tweaks to installation id --- example/src/tests/clientTests.ts | 2 +- ios/XMTPModule.swift | 29 ++++++++++++++++++++--------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/example/src/tests/clientTests.ts b/example/src/tests/clientTests.ts index 0425c3eb..b3ff2496 100644 --- a/example/src/tests/clientTests.ts +++ b/example/src/tests/clientTests.ts @@ -244,7 +244,7 @@ test('can drop client from memory', async () => { await anotherClient.dropLocalDatabaseConnection() await client.reconnectLocalDatabase() - await Client.dropClient(anotherClient.inboxId) + await Client.dropClient(anotherClient.installationId) try { await anotherClient.reconnectLocalDatabase() return false diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index 949b4d54..1807d3a8 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -70,14 +70,25 @@ public class XMTPModule: Module { } } } - - enum Error: Swift.Error { + + enum Error: Swift.Error, LocalizedError { case noClient case conversationNotFound(String) - case noMessage, invalidKeyBundle, invalidDigest - case badPreparation(String) - case mlsNotEnabled(String) - case invalidString, invalidPermissionOption + case noMessage + case invalidPermissionOption + + var errorDescription: String? { + switch self { + case .noClient: + return "No client is available." + case .conversationNotFound(let id): + return "Conversation with ID '\(id)' was not found." + case .noMessage: + return "No message was provided." + case .invalidPermissionOption: + return "The permission option is invalid." + } + } } public func definition() -> ModuleDefinition { @@ -217,7 +228,7 @@ public class XMTPModule: Module { account: privateKey, options: options) await clientsManager.updateClient( - key: client.inboxID, client: client) + key: client.installationID, client: client) return try ClientWrapper.encodeToObj(client) } @@ -252,7 +263,7 @@ public class XMTPModule: Module { let client = try await XMTP.Client.create( account: signer, options: options) await self.clientsManager.updateClient( - key: client.inboxID, client: client) + key: client.installationID, client: client) self.signer = nil self.sendEvent("authed", try ClientWrapper.encodeToObj(client)) } @@ -271,7 +282,7 @@ public class XMTPModule: Module { let client = try await XMTP.Client.build( address: address, options: options) await clientsManager.updateClient( - key: client.inboxID, client: client) + key: client.installationID, client: client) return try ClientWrapper.encodeToObj(client) } From 4818569071e33f076db2613cbedfdf78187ee9a0 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 26 Nov 2024 12:12:53 -0800 Subject: [PATCH 11/12] all tests --- example/src/tests/conversationTests.ts | 157 +++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/example/src/tests/conversationTests.ts b/example/src/tests/conversationTests.ts index 5012c14c..712947d1 100644 --- a/example/src/tests/conversationTests.ts +++ b/example/src/tests/conversationTests.ts @@ -1,9 +1,13 @@ +import RNFS from 'react-native-fs' import { Test, assert, createClients, delayToPropogate } from './test-utils' import { + Client, + ConsentRecord, Conversation, ConversationId, ConversationVersion, } from '../../../src/index' +import { Wallet } from 'ethers' export const conversationTests: Test[] = [] let counter = 1 @@ -547,3 +551,156 @@ test('can streamAllMessages from multiple clients - swapped', async () => { return true }) + +test('can sync consent', async () => { + const [bo] = await createClients(1) + const keyBytes = new Uint8Array([ + 233, 120, 198, 96, 154, 65, 132, 17, 132, 96, 250, 40, 103, 35, 125, 64, + 166, 83, 208, 224, 254, 44, 205, 227, 175, 49, 234, 129, 74, 252, 135, 145, + ]) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const dbDirPath = `${RNFS.DocumentDirectoryPath}/xmtp_db` + const dbDirPath2 = `${RNFS.DocumentDirectoryPath}/xmtp_db2` + const directoryExists = await RNFS.exists(dbDirPath) + if (!directoryExists) { + await RNFS.mkdir(dbDirPath) + } + const directoryExists2 = await RNFS.exists(dbDirPath2) + if (!directoryExists2) { + await RNFS.mkdir(dbDirPath2) + } + const alixWallet = Wallet.createRandom() + + const alix = await Client.create(alixWallet, { + env: 'local', + appVersion: 'Testing/0.0.0', + dbEncryptionKey: keyBytes, + dbDirectory: dbDirPath, + }) + + // Create DM conversation + const dm = await alix.conversations.findOrCreateDm(bo.address) + await dm.updateConsent('denied') + const consentState = await dm.consentState() + assert(consentState === 'denied', `Expected 'denied', got ${consentState}`) + + await bo.conversations.sync() + const boDm = await bo.conversations.findConversation(dm.id) + + const alix2 = await Client.create(alixWallet, { + env: 'local', + appVersion: 'Testing/0.0.0', + dbEncryptionKey: keyBytes, + dbDirectory: dbDirPath2, + }) + + const state = await alix2.inboxState(true) + assert( + state.installations.length === 2, + `Expected 2 installations, got ${state.installations.length}` + ) + + // Sync conversations + await bo.conversations.sync() + if (boDm) await boDm.sync() + await alix.conversations.sync() + await alix2.conversations.sync() + await alix2.preferences.syncConsent() + await alix.conversations.syncAllConversations() + await delayToPropogate(2000) + await alix2.conversations.syncAllConversations() + await delayToPropogate(2000) + + const dm2 = await alix2.conversations.findConversation(dm.id) + const consentState2 = await dm2?.consentState() + assert(consentState2 === 'denied', `Expected 'denied', got ${consentState2}`) + + await alix2.preferences.setConsentState( + new ConsentRecord(dm2!.id, 'conversation_id', 'allowed') + ) + + const convoState = await alix2.preferences.conversationConsentState(dm2!.id) + assert(convoState === 'allowed', `Expected 'allowed', got ${convoState}`) + + const updatedConsentState = await dm2?.consentState() + assert( + updatedConsentState === 'allowed', + `Expected 'allowed', got ${updatedConsentState}` + ) + + return true +}) + +test('can stream consent', async () => { + const [bo] = await createClients(1) + const keyBytes = new Uint8Array([ + 233, 120, 198, 96, 154, 65, 132, 17, 132, 96, 250, 40, 103, 35, 125, 64, + 166, 83, 208, 224, 254, 44, 205, 227, 175, 49, 234, 129, 74, 252, 135, 145, + ]) + const dbDirPath = `${RNFS.DocumentDirectoryPath}/xmtp_db` + const dbDirPath2 = `${RNFS.DocumentDirectoryPath}/xmtp_db2` + + // Ensure the directories exist + if (!(await RNFS.exists(dbDirPath))) { + await RNFS.mkdir(dbDirPath) + } + if (!(await RNFS.exists(dbDirPath2))) { + await RNFS.mkdir(dbDirPath2) + } + + const alixWallet = Wallet.createRandom() + + const alix = await Client.create(alixWallet, { + env: 'local', + appVersion: 'Testing/0.0.0', + dbEncryptionKey: keyBytes, + dbDirectory: dbDirPath, + }) + + const alixGroup = await alix.conversations.newGroup([bo.address]) + + const alix2 = await Client.create(alixWallet, { + env: 'local', + appVersion: 'Testing/0.0.0', + dbEncryptionKey: keyBytes, + dbDirectory: dbDirPath2, + }) + + await alixGroup.send('Hello') + await alix.conversations.sync() + await alix2.conversations.sync() + await alix.conversations.syncAllConversations() + await alix2.conversations.syncAllConversations() + + const alix2Group = await alix2.conversations.findConversation(alixGroup.id) + + const consent = [] + await alix.preferences.streamConsent(async (entry: ConsentRecord) => { + consent.push(entry) + }) + + await delayToPropogate() + + await alix2Group!.updateConsent('denied') + const dm = await alix2.conversations.newConversation(bo.address) + await dm!.updateConsent('denied') + + await alix.conversations.syncAllConversations() + await delayToPropogate(2000) + await alix2.conversations.syncAllConversations() + await delayToPropogate(2000) + + assert( + consent.length === 3, + `Expected 3 consent records, got ${consent.length}` + ) + const updatedConsentState = await alixGroup.consentState() + assert( + updatedConsentState === 'denied', + `Expected 'denied', got ${updatedConsentState}` + ) + + alix.preferences.cancelStreamConsent() + + return true +}) From d555cdb557c54c36b5c697abf6fb6636852d8675 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 26 Nov 2024 15:27:06 -0800 Subject: [PATCH 12/12] get test passing everytime --- example/src/tests/conversationTests.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/example/src/tests/conversationTests.ts b/example/src/tests/conversationTests.ts index 712947d1..a3e58ded 100644 --- a/example/src/tests/conversationTests.ts +++ b/example/src/tests/conversationTests.ts @@ -673,6 +673,7 @@ test('can stream consent', async () => { await alix2.conversations.syncAllConversations() const alix2Group = await alix2.conversations.findConversation(alixGroup.id) + await delayToPropogate() const consent = [] await alix.preferences.streamConsent(async (entry: ConsentRecord) => { @@ -685,14 +686,13 @@ test('can stream consent', async () => { const dm = await alix2.conversations.newConversation(bo.address) await dm!.updateConsent('denied') + await delayToPropogate(3000) await alix.conversations.syncAllConversations() - await delayToPropogate(2000) await alix2.conversations.syncAllConversations() - await delayToPropogate(2000) assert( - consent.length === 3, - `Expected 3 consent records, got ${consent.length}` + consent.length === 4, + `Expected 4 consent records, got ${consent.length}` ) const updatedConsentState = await alixGroup.consentState() assert(