From c5a69202abeb624a6856f07f44936a7a2a4a1a9c Mon Sep 17 00:00:00 2001 From: cameronvoell Date: Fri, 24 May 2024 08:55:45 -0700 Subject: [PATCH 1/2] remove skipSync logic and fix tests --- example/src/tests/createdAtTests.ts | 4 +- example/src/tests/groupTests.ts | 88 ++++++++++++++++++++--------- src/lib/Client.ts | 10 ++-- src/lib/Contacts.ts | 2 +- src/lib/Conversations.ts | 22 ++------ src/lib/Group.ts | 42 +++++--------- 6 files changed, 85 insertions(+), 83 deletions(-) diff --git a/example/src/tests/createdAtTests.ts b/example/src/tests/createdAtTests.ts index da66ebaec..cceb1e454 100644 --- a/example/src/tests/createdAtTests.ts +++ b/example/src/tests/createdAtTests.ts @@ -83,14 +83,14 @@ test('group createdAt matches listAll', async () => { const first = 1 const second = 0 assert( - alixGroups[first].topic === alixGroup.id, + (alixGroups[1] as Group).id === alixGroup.id, 'First group returned from listGroups shows ' + (alixGroups[1] as Group).id + ' but should be ' + alixGroup.id ) assert( - alixGroups[second].topic === boGroup.id, + (alixGroups[0] as Group).id === boGroup.id, 'Second group returned from listGroups shows ' + (alixGroups[0] as Group).id + ' but should be ' + diff --git a/example/src/tests/groupTests.ts b/example/src/tests/groupTests.ts index 2b6b3532e..7736e62cd 100644 --- a/example/src/tests/groupTests.ts +++ b/example/src/tests/groupTests.ts @@ -14,7 +14,6 @@ import { Group, ConversationContainer, ConversationVersion, - syncGroup, MessageDeliveryStatus, } from '../../../src/index' @@ -214,26 +213,24 @@ test('group message delivery status', async () => { await alixGroup.send('hello, world') - const alixMessages: DecodedMessage[] = await alixGroup.messages(true) + const alixMessages: DecodedMessage[] = await alixGroup.messages() assert( alixMessages.length === 2, `the messages length should be 2 but was ${alixMessages.length}` ) - const alexMessagesFiltered: DecodedMessage[] = await alixGroup.messages( - true, - { - deliveryStatus: MessageDeliveryStatus.UNPUBLISHED, - } - ) + const alixMessagesFiltered: DecodedMessage[] = await alixGroup.messages({ + deliveryStatus: MessageDeliveryStatus.UNPUBLISHED, + }) assert( - alexMessagesFiltered.length === 1, - `the messages length should be 1 but was ${alexMessagesFiltered.length}` + alixMessagesFiltered.length === 1, + `the messages length should be 1 but was ${alixMessagesFiltered.length}` ) - const alixMessages2: DecodedMessage[] = await alixGroup.messages(false) + await alixGroup.sync() + const alixMessages2: DecodedMessage[] = await alixGroup.messages() assert( alixMessages2.length === 2, @@ -245,7 +242,9 @@ test('group message delivery status', async () => { `the message should have a delivery status of PUBLISHED but was ${alixMessages2[0].deliveryStatus}` ) + await boClient.conversations.syncGroups() const boGroup = (await boClient.conversations.listGroups())[0] + await boGroup.sync() const boMessages: DecodedMessage[] = await boGroup.messages() assert( @@ -263,8 +262,9 @@ test('group message delivery status', async () => { test('who added me to a group', async () => { const [alixClient, boClient] = await createClients(2) - const alixGroup = await alixClient.conversations.newGroup([boClient.address]) + await alixClient.conversations.newGroup([boClient.address]) + await boClient.conversations.syncGroups() const boGroup = (await boClient.conversations.listGroups())[0] const addedByAddress = await boGroup.addedByAddress() @@ -292,6 +292,7 @@ test('can message in a group', async () => { ]) // alix's num groups == 1 + await alixClient.conversations.syncGroups() alixGroups = await alixClient.conversations.listGroups() if (alixGroups.length !== 1) { throw new Error('num groups should be 1') @@ -301,6 +302,7 @@ test('can message in a group', async () => { assert(alixGroups[0].createdAt === alixGroup.createdAt, 'group create time') // alix can confirm memberAddresses + await alixGroup.sync() const memberAddresses = await alixGroup.memberAddresses() if (memberAddresses.length !== 3) { throw new Error('num group members should be 3') @@ -339,6 +341,7 @@ test('can message in a group', async () => { await alixGroup.send('gm') // bo's num groups == 1 + await boClient.conversations.syncGroups() const boGroups = await boClient.conversations.listGroups() if (boGroups.length !== 1) { throw new Error( @@ -347,6 +350,7 @@ test('can message in a group', async () => { } await delayToPropogate() // bo can read messages from alix + await boGroups[0].sync() const boMessages: DecodedMessage[] = await boGroups[0].messages() if (boMessages.length !== 2) { @@ -364,6 +368,7 @@ test('can message in a group', async () => { await boGroups[0].send('hey guys!') // caro's num groups == 1 + await caroClient.conversations.syncGroups() const caroGroups = await caroClient.conversations.listGroups() if (caroGroups.length !== 1) { throw new Error( @@ -418,12 +423,14 @@ test('can add members to a group', async () => { const alixGroup = await alixClient.conversations.newGroup([boClient.address]) // alix's num groups == 1 + await alixClient.conversations.syncGroups() alixGroups = await alixClient.conversations.listGroups() if (alixGroups.length !== 1) { throw new Error('num groups should be 1') } // alix can confirm memberAddresses + await alixGroup.sync() const memberAddresses = await alixGroup.memberAddresses() if (memberAddresses.length !== 2) { throw new Error('num group members should be 2') @@ -445,6 +452,7 @@ test('can add members to a group', async () => { await alixGroup.send('gm') // bo's num groups == 1 + await boClient.conversations.syncGroups() boGroups = await boClient.conversations.listGroups() if (boGroups.length !== 1) { throw new Error( @@ -455,17 +463,20 @@ test('can add members to a group', async () => { await alixGroup.addMembers([caroClient.address]) // caro's num groups == 1 + await caroClient.conversations.syncGroups() caroGroups = await caroClient.conversations.listGroups() if (caroGroups.length !== 1) { throw new Error( 'num groups for caro should be 1, but it is' + caroGroups.length ) } + await caroGroups[0].sync() const caroMessages = await caroGroups[0].messages() if (caroMessages.length !== 0) { throw new Error('num messages for caro should be 0') } + await boGroups[0].sync() const boGroupMembers = await boGroups[0].memberAddresses() if (boGroupMembers.length !== 3) { throw new Error('num group members should be 3') @@ -501,12 +512,14 @@ test('can remove members from a group', async () => { ]) // alix's num groups == 1 + await alixClient.conversations.syncGroups() alixGroups = await alixClient.conversations.listGroups() if (alixGroups.length !== 1) { throw new Error('num groups should be 1') } // alix can confirm memberAddresses + await alixGroup.sync() const memberAddresses = await alixGroup.memberAddresses() if (memberAddresses.length !== 3) { throw new Error('num group members should be 3') @@ -528,6 +541,7 @@ test('can remove members from a group', async () => { await alixGroup.send('gm') // bo's num groups == 1 + await boClient.conversations.syncGroups() boGroups = await boClient.conversations.listGroups() if (boGroups.length !== 1) { throw new Error( @@ -536,6 +550,7 @@ test('can remove members from a group', async () => { } // caro's num groups == 1 + await caroClient.conversations.syncGroups() caroGroups = await caroClient.conversations.listGroups() if (caroGroups.length !== 1) { throw new Error( @@ -543,16 +558,19 @@ test('can remove members from a group', async () => { ) } + await caroGroups[0].sync() if (!caroGroups[0].isActive()) { throw new Error('caros group should be active') } await alixGroup.removeMembers([caroClient.address]) + await alixGroup.sync() const alixGroupMembers = await alixGroup.memberAddresses() if (alixGroupMembers.length !== 2) { throw new Error('num group members should be 2') } + await caroGroups[0].sync() if (await caroGroups[0].isActive()) { throw new Error('caros group should not be active') } @@ -779,6 +797,7 @@ test('can stream group messages', async () => { ) // bo's num groups == 1 + await boClient.conversations.syncGroups() const boGroup = (await boClient.conversations.listGroups())[0] for (let i = 0; i < 5; i++) { @@ -902,6 +921,7 @@ test('can paginate group messages', async () => { await alixGroup.send('hello, world') await alixGroup.send('gm') + await boClient.conversations.syncGroups() const boGroups = await boClient.conversations.listGroups() if (boGroups.length !== 1) { throw new Error( @@ -910,7 +930,8 @@ test('can paginate group messages', async () => { } await delayToPropogate() // bo can read messages from alix - const boMessages: DecodedMessage[] = await boGroups[0].messages(false, { + await boGroups[0].sync() + const boMessages: DecodedMessage[] = await boGroups[0].messages({ limit: 1, }) @@ -935,6 +956,9 @@ test('can stream all group messages', async () => { // Record message stream across all conversations const allMessages: DecodedMessage[] = [] + // If we don't call syncGroups here, the streamAllGroupMessages will not + // stream the first message. Feels like a bug. + await alix.conversations.syncGroups() await alix.conversations.streamAllGroupMessages(async (message) => { allMessages.push(message) }) @@ -1142,6 +1166,7 @@ test('can stream all group Messages from multiple clients', async () => { ) } + await alix.conversations.syncGroups() const alixConv = (await alix.conversations.listGroups())[0] await alixConv.send({ text: `Message` }) await delayToPropogate() @@ -1188,6 +1213,7 @@ test('can stream all group Messages from multiple clients - swapped', async () = ) } + await alix.conversations.syncGroups() const alixConv = (await alix.conversations.listGroups())[0] await alixConv.send({ text: `Message` }) await delayToPropogate() @@ -1291,55 +1317,55 @@ test('can check if group is denied', async () => { return true }) -test('skipSync parameter behaves as expected', async () => { +test('sync function behaves as expected', async () => { const [alix, bo, caro] = await createClients(3) const alixGroup = await alix.conversations.newGroup([bo.address]) await alixGroup.send({ text: 'hello' }) - // List groups with skipSync true will return empty until the first sync - let boGroups = await bo.conversations.listGroups(true) + // List groups will return empty until the first sync + let boGroups = await bo.conversations.listGroups() assert(boGroups.length === 0, 'num groups for bo is 0 until we sync') await bo.conversations.syncGroups() - boGroups = await bo.conversations.listGroups(true) + boGroups = await bo.conversations.listGroups() assert(boGroups.length === 1, 'num groups for bo is 1') // Num members will include the initial num of members even before sync - let numMembers = (await boGroups[0].memberAddresses(true)).length + let numMembers = (await boGroups[0].memberAddresses()).length assert(numMembers === 2, 'num members should be 2') // Num messages for a group will be 0 until we sync the group - let numMessages = (await boGroups[0].messages(true)).length + let numMessages = (await boGroups[0].messages()).length assert(numMessages === 0, 'num members should be 1') await bo.conversations.syncGroups() // Num messages is still 0 because we didnt sync the group itself - numMessages = (await boGroups[0].messages(true)).length + numMessages = (await boGroups[0].messages()).length assert(numMessages === 0, 'num messages should be 0') await boGroups[0].sync() // after syncing the group we now see the correct number of messages - numMessages = (await boGroups[0].messages(true)).length + numMessages = (await boGroups[0].messages()).length assert(numMessages === 1, 'num members should be 1') await alixGroup.addMembers([caro.address]) - numMembers = (await boGroups[0].memberAddresses(true)).length + numMembers = (await boGroups[0].memberAddresses()).length assert(numMembers === 2, 'num members should be 2') await bo.conversations.syncGroups() // Even though we synced the groups, we need to sync the group itself to see the new member - numMembers = (await boGroups[0].memberAddresses(true)).length + numMembers = (await boGroups[0].memberAddresses()).length assert(numMembers === 2, 'num members should be 2') await boGroups[0].sync() - numMembers = (await boGroups[0].memberAddresses(true)).length + numMembers = (await boGroups[0].memberAddresses()).length assert(numMembers === 3, 'num members should be 3') // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -1347,11 +1373,12 @@ test('skipSync parameter behaves as expected', async () => { bo.address, caro.address, ]) + await bo.conversations.syncGroups() boGroups = await bo.conversations.listGroups() assert(boGroups.length === 2, 'num groups for bo is 2') // Even before syncing the group, syncGroups will return the initial number of members - numMembers = (await boGroups[1].memberAddresses(true)).length + numMembers = (await boGroups[1].memberAddresses()).length assert(numMembers === 3, 'num members should be 3') return true @@ -1361,12 +1388,14 @@ test('can read and update group name', async () => { const [alix, bo, caro] = await createClients(3) const alixGroup = await alix.conversations.newGroup([bo.address]) + await alixGroup.sync() let groupName = await alixGroup.groupName() assert(groupName === 'New Group', 'group name should be "New Group"') await alixGroup.updateGroupName('Test name update 1') + await alixGroup.sync() groupName = await alixGroup.groupName() assert( @@ -1374,14 +1403,15 @@ test('can read and update group name', async () => { 'group name should be "Test name update 1"' ) + await bo.conversations.syncGroups() const boGroup = (await bo.conversations.listGroups())[0] - groupName = await boGroup.groupName(true) + groupName = await boGroup.groupName() assert(groupName === 'New Group', 'group name should be "New Group"') await boGroup.sync() - groupName = await boGroup.groupName(true) + groupName = await boGroup.groupName() assert( groupName === 'Test name update 1', @@ -1389,9 +1419,11 @@ test('can read and update group name', async () => { ) await alixGroup.addMembers([caro.address]) + await caro.conversations.syncGroups() const caroGroup = (await caro.conversations.listGroups())[0] - groupName = await caroGroup.groupName(true) + await caroGroup.sync() + groupName = await caroGroup.groupName() assert( groupName === 'Test name update 1', 'group name should be "Test name update 1"' diff --git a/src/lib/Client.ts b/src/lib/Client.ts index 21a2052fe..93a609bb3 100644 --- a/src/lib/Client.ts +++ b/src/lib/Client.ts @@ -19,13 +19,11 @@ import { DecodedMessage } 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 class Client< ContentTypes extends DefaultContentTypes = DefaultContentTypes, diff --git a/src/lib/Contacts.ts b/src/lib/Contacts.ts index 3a8f96277..b8f51e0ed 100644 --- a/src/lib/Contacts.ts +++ b/src/lib/Contacts.ts @@ -1,5 +1,5 @@ import { Client } from './Client' -import { ConsentListEntry, ConsentState } from './ConsentListEntry' +import { ConsentListEntry } from './ConsentListEntry' import * as XMTPModule from '../index' import { getAddress } from '../utils/address' diff --git a/src/lib/Conversations.ts b/src/lib/Conversations.ts index cc8e2abad..f98765355 100644 --- a/src/lib/Conversations.ts +++ b/src/lib/Conversations.ts @@ -79,17 +79,11 @@ export default class Conversations< /** * This method returns a list of all groups that the client is a member of. + * To get the latest list of groups from the network, call syncGroups() first. * - * @param {boolean} skipSync - Optional flag to skip syncing groups with the network before listing. Defaults to false. - * If skipSync set to true, the method will return the list of groups already known from the last network sync. - * Setting skipSync to true is an optional optimization to immediately list all conversations and groups without - * fetching from the network first. This is useful for clients who prefer to manage syncing logic themselves via the syncGroups() method. * @returns {Promise} A Promise that resolves to an array of Group objects. */ - async listGroups(skipSync: boolean = false): Promise[]> { - if (!skipSync) { - await this.syncGroups() - } + async listGroups(): Promise[]> { const result = await XMTPModule.listGroups(this.client) for (const group of result) { @@ -101,19 +95,11 @@ export default class Conversations< /** * This method returns a list of all conversations and groups that the client is a member of. + * To include the latest groups from the network in the returned list, call syncGroups() first. * - * @param {boolean} skipSync - Optional flag to skip syncing groups with the network before listing. Defaults to false. - * If skipSync set to true, the method will return the list of groups already known from the last network sync. - * Setting skipSync to true is an optional optimization to immediately list all conversations and groups without - * fetching from the network first. This is useful for clients who prefer to manage syncing logic themselves via the syncGroups() method. * @returns {Promise} A Promise that resolves to an array of ConversationContainer objects. */ - async listAll( - skipSync: boolean = false - ): Promise[]> { - if (!skipSync) { - await this.syncGroups() - } + async listAll(): Promise[]> { const result = await XMTPModule.listAll(this.client) for (const conversationContainer of result) { diff --git a/src/lib/Group.ts b/src/lib/Group.ts index e8ab3b353..c2287ad31 100644 --- a/src/lib/Group.ts +++ b/src/lib/Group.ts @@ -49,17 +49,10 @@ export class Group< /** * This method returns an array of addresses associated with the group. - * - * @param {boolean} skipSync - Optional flag to skip syncing members with the network before returning. Defaults to false. - * If skipSync set to true, the method will return the array of member addresses already known from the last network sync. - * Setting skipSync to true is an optional optimization to immediately return all members without - * fetching from the network first. This is useful for clients who prefer to manage syncing logic themselves via the sync() method. + * To get the latest member addresses from the network, call sync() first. * @returns {Promise[]>} A Promise that resolves to an array of DecodedMessage objects. */ - async memberAddresses(skipSync: boolean = false): Promise { - if (!skipSync) { - await this.sync() - } + async memberAddresses(): Promise { return XMTP.listMemberAddresses(this.client, this.id) } @@ -99,11 +92,8 @@ export class Group< /** * This method returns an array of messages associated with the group. + * To get the latest messages from the network, call sync() first. * - * @param {boolean} skipSync - Optional flag to skip syncing messages with the network before returning. Defaults to false. - * If skipSync set to true, the method will return the array of messages already known from the last network sync. - * Setting skipSync to true is an optional optimization to immediately return all messages without - * fetching from the network first. This is useful for clients who prefer to manage syncing logic themselves via the sync() method. * @param {number | undefined} limit - Optional maximum number of messages to return. * @param {number | Date | undefined} before - Optional filter for specifying the maximum timestamp of messages to return. * @param {number | Date | undefined} after - Optional filter for specifying the minimum timestamp of messages to return. @@ -111,13 +101,8 @@ export class Group< * @returns {Promise[]>} A Promise that resolves to an array of DecodedMessage objects. */ async messages( - skipSync: boolean = false, opts?: MessagesOptions ): Promise[]> { - if (!skipSync) { - await this.sync() - } - return await XMTP.groupMessages( this.client, this.id, @@ -194,11 +179,9 @@ export class Group< return XMTP.removeGroupMembers(this.client.address, this.id, addresses) } - async groupName(skipSync = false): Promise { - if (!skipSync) { - await this.sync() - } - + // Returns the group name. + // To get the latest group name from the network, call sync() first. + async groupName(): Promise { return XMTP.groupName(this.client.address, this.id) } @@ -206,17 +189,20 @@ export class Group< return XMTP.updateGroupName(this.client.address, this.id, groupName) } - async isActive(skipSync = false): Promise { - if (!skipSync) { - await this.sync() - } + // Returns whether the group is active. + // To get the latest active status from the network, call sync() first. + async isActive(): Promise { return XMTP.isGroupActive(this.client.address, this.id) } - addedByAddress(): Promise { + // Returns the address that added you to the group. + // To get the latest added by address from the network, call sync() first. + async addedByAddress(): Promise { return XMTP.addedByAddress(this.client.address, this.id) } + // Returns whether you are an admin of the group. + // To get the latest admin status from the network, call sync() first. async isAdmin(): Promise { return XMTP.isGroupAdmin(this.client.address, this.id) } From 00215afbf787cbc18ae6b9b1c5d0ca2ba7fb126d Mon Sep 17 00:00:00 2001 From: cameronvoell Date: Fri, 24 May 2024 11:48:54 -0700 Subject: [PATCH 2/2] compare topic instead of id --- example/src/tests/createdAtTests.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/example/src/tests/createdAtTests.ts b/example/src/tests/createdAtTests.ts index cceb1e454..87149281b 100644 --- a/example/src/tests/createdAtTests.ts +++ b/example/src/tests/createdAtTests.ts @@ -83,18 +83,18 @@ test('group createdAt matches listAll', async () => { const first = 1 const second = 0 assert( - (alixGroups[1] as Group).id === alixGroup.id, + alixGroups[1].topic === alixGroup.topic, 'First group returned from listGroups shows ' + - (alixGroups[1] as Group).id + + alixGroups[1].topic + ' but should be ' + - alixGroup.id + alixGroup.topic ) assert( - (alixGroups[0] as Group).id === boGroup.id, + alixGroups[0].topic === boGroup.topic, 'Second group returned from listGroups shows ' + - (alixGroups[0] as Group).id + + alixGroups[0].topic + ' but should be ' + - boGroup.id + boGroup.topic ) assert( alixGroups[first].createdAt === alixGroup.createdAt,