diff --git a/sdks/browser-sdk/src/Conversation.ts b/sdks/browser-sdk/src/Conversation.ts index 247bf3e7..373f6607 100644 --- a/sdks/browser-sdk/src/Conversation.ts +++ b/sdks/browser-sdk/src/Conversation.ts @@ -32,6 +32,10 @@ export class Conversation { #createdAtNs?: SafeConversation["createdAtNs"]; + #admins: SafeConversation["admins"] = []; + + #superAdmins: SafeConversation["superAdmins"] = []; + constructor(client: Client, id: string, data?: SafeConversation) { this.#client = client; this.#id = id; @@ -48,6 +52,8 @@ export class Conversation { this.#metadata = data?.metadata ?? undefined; this.#permissions = data?.permissions ?? undefined; this.#createdAtNs = data?.createdAtNs ?? undefined; + this.#admins = data?.admins ?? []; + this.#superAdmins = data?.superAdmins ?? []; } get id() { @@ -128,16 +134,26 @@ export class Conversation { }); } - async admins() { - return this.#client.sendMessage("getGroupAdmins", { + get admins() { + return this.#admins; + } + + get superAdmins() { + return this.#superAdmins; + } + + async syncAdmins() { + const admins = await this.#client.sendMessage("getGroupAdmins", { id: this.#id, }); + this.#admins = admins; } - async superAdmins() { - return this.#client.sendMessage("getGroupSuperAdmins", { + async syncSuperAdmins() { + const superAdmins = await this.#client.sendMessage("getGroupSuperAdmins", { id: this.#id, }); + this.#superAdmins = superAdmins; } get permissions() { @@ -145,13 +161,13 @@ export class Conversation { } async isAdmin(inboxId: string) { - const admins = await this.admins(); - return admins.includes(inboxId); + await this.syncAdmins(); + return this.#admins.includes(inboxId); } async isSuperAdmin(inboxId: string) { - const superAdmins = await this.superAdmins(); - return superAdmins.includes(inboxId); + await this.syncSuperAdmins(); + return this.#superAdmins.includes(inboxId); } async sync() { diff --git a/sdks/browser-sdk/src/Conversations.ts b/sdks/browser-sdk/src/Conversations.ts index 0e62628e..02cd3e1f 100644 --- a/sdks/browser-sdk/src/Conversations.ts +++ b/sdks/browser-sdk/src/Conversations.ts @@ -1,5 +1,6 @@ import type { Client } from "@/Client"; import { Conversation } from "@/Conversation"; +import { DecodedMessage } from "@/DecodedMessage"; import type { SafeCreateGroupOptions, SafeListConversationsOptions, @@ -21,21 +22,24 @@ export class Conversations { } async getConversationById(id: string) { - return this.#client.sendMessage("getConversationById", { + const data = await this.#client.sendMessage("getConversationById", { id, }); + return data ? new Conversation(this.#client, id, data) : undefined; } async getMessageById(id: string) { - return this.#client.sendMessage("getMessageById", { + const data = await this.#client.sendMessage("getMessageById", { id, }); + return data ? new DecodedMessage(this.#client, data) : undefined; } async getDmByInboxId(inboxId: string) { - return this.#client.sendMessage("getDmByInboxId", { + const data = await this.#client.sendMessage("getDmByInboxId", { inboxId, }); + return data ? new Conversation(this.#client, data.id, data) : undefined; } async list(options?: SafeListConversationsOptions) { @@ -52,17 +56,27 @@ export class Conversations { async listGroups( options?: Omit, ) { - return this.#client.sendMessage("getGroups", { + const conversations = await this.#client.sendMessage("getGroups", { options, }); + + return conversations.map( + (conversation) => + new Conversation(this.#client, conversation.id, conversation), + ); } async listDms( options?: Omit, ) { - return this.#client.sendMessage("getDms", { + const conversations = await this.#client.sendMessage("getDms", { options, }); + + return conversations.map( + (conversation) => + new Conversation(this.#client, conversation.id, conversation), + ); } async newGroup(accountAddresses: string[], options?: SafeCreateGroupOptions) { diff --git a/sdks/browser-sdk/src/WorkerConversations.ts b/sdks/browser-sdk/src/WorkerConversations.ts index 23ee33a0..0e3163fe 100644 --- a/sdks/browser-sdk/src/WorkerConversations.ts +++ b/sdks/browser-sdk/src/WorkerConversations.ts @@ -2,7 +2,6 @@ import type { Conversation, Conversations } from "@xmtp/wasm-bindings"; import { fromSafeCreateGroupOptions, fromSafeListConversationsOptions, - toSafeMessage, type SafeCreateGroupOptions, type SafeListConversationsOptions, } from "@/utils/conversions"; @@ -40,8 +39,7 @@ export class WorkerConversations { getMessageById(id: string) { try { // findMessageById will throw if message is not found - const message = this.#conversations.findMessageById(id); - return toSafeMessage(message); + return this.#conversations.findMessageById(id); } catch { return undefined; } diff --git a/sdks/browser-sdk/src/workers/client.ts b/sdks/browser-sdk/src/workers/client.ts index be5c758a..ab62b38a 100644 --- a/sdks/browser-sdk/src/workers/client.ts +++ b/sdks/browser-sdk/src/workers/client.ts @@ -357,7 +357,7 @@ self.onmessage = async (event: MessageEvent) => { postMessage({ id, action, - result: message, + result: message ? toSafeMessage(message) : undefined, }); break; } diff --git a/sdks/browser-sdk/test/Client.test.ts b/sdks/browser-sdk/test/Client.test.ts index d6a77500..effc81ed 100644 --- a/sdks/browser-sdk/test/Client.test.ts +++ b/sdks/browser-sdk/test/Client.test.ts @@ -163,11 +163,9 @@ describe.concurrent("Client", () => { await client2.getConsentState(ConsentEntityType.GroupId, group2!.id), ).toBe(ConsentState.Allowed); - const convo = new Conversation(client2, group2!.id, group2); + expect(await group2!.consentState()).toBe(ConsentState.Allowed); - expect(await convo.consentState()).toBe(ConsentState.Allowed); - - await convo.updateConsentState(ConsentState.Denied); + await group2!.updateConsentState(ConsentState.Denied); expect( await client2.getConsentState(ConsentEntityType.GroupId, group2!.id), diff --git a/sdks/browser-sdk/test/Conversation.test.ts b/sdks/browser-sdk/test/Conversation.test.ts index d38c6298..df0bb8db 100644 --- a/sdks/browser-sdk/test/Conversation.test.ts +++ b/sdks/browser-sdk/test/Conversation.test.ts @@ -1,6 +1,5 @@ import { ConsentState } from "@xmtp/wasm-bindings"; import { describe, expect, it } from "vitest"; -import { Conversation } from "@/Conversation"; import { ContentTypeTest, createRegisteredClient, @@ -323,24 +322,24 @@ describe.concurrent("Conversation", () => { ]); expect(await conversation.isSuperAdmin(client1.inboxId!)).toBe(true); - const superAdmins = await conversation.superAdmins(); - expect(superAdmins.length).toBe(1); - expect(superAdmins).toContain(client1.inboxId); + await conversation.syncSuperAdmins(); + expect(conversation.superAdmins.length).toBe(1); + expect(conversation.superAdmins).toContain(client1.inboxId); expect(await conversation.isAdmin(client1.inboxId!)).toBe(false); expect(await conversation.isAdmin(client2.inboxId!)).toBe(false); - const admins = await conversation.admins(); - expect(admins.length).toBe(0); + await conversation.syncAdmins(); + expect(conversation.admins.length).toBe(0); await conversation.addAdmin(client2.inboxId!); expect(await conversation.isAdmin(client2.inboxId!)).toBe(true); - const admins2 = await conversation.admins(); - expect(admins2.length).toBe(1); - expect(admins2).toContain(client2.inboxId); + await conversation.syncAdmins(); + expect(conversation.admins.length).toBe(1); + expect(conversation.admins).toContain(client2.inboxId); await conversation.removeAdmin(client2.inboxId!); expect(await conversation.isAdmin(client2.inboxId!)).toBe(false); - const admins3 = await conversation.admins(); - expect(admins3.length).toBe(0); + await conversation.syncAdmins(); + expect(conversation.admins.length).toBe(0); }); it("should add and remove super admins", async () => { @@ -355,24 +354,24 @@ describe.concurrent("Conversation", () => { expect(await conversation.isSuperAdmin(client1.inboxId!)).toBe(true); expect(await conversation.isSuperAdmin(client2.inboxId!)).toBe(false); - const superAdmins = await conversation.superAdmins(); - expect(superAdmins.length).toBe(1); - expect(superAdmins).toContain(client1.inboxId); + await conversation.syncSuperAdmins(); + expect(conversation.superAdmins.length).toBe(1); + expect(conversation.superAdmins).toContain(client1.inboxId); await conversation.addSuperAdmin(client2.inboxId!); expect(await conversation.isSuperAdmin(client2.inboxId!)).toBe(true); - const superAdmins2 = await conversation.superAdmins(); - expect(superAdmins2.length).toBe(2); - expect(superAdmins2).toContain(client1.inboxId); - expect(superAdmins2).toContain(client2.inboxId); + await conversation.syncSuperAdmins(); + expect(conversation.superAdmins.length).toBe(2); + expect(conversation.superAdmins).toContain(client1.inboxId); + expect(conversation.superAdmins).toContain(client2.inboxId); await conversation.removeSuperAdmin(client2.inboxId!); expect(await conversation.isSuperAdmin(client2.inboxId!)).toBe(false); - const superAdmins3 = await conversation.superAdmins(); - expect(superAdmins3.length).toBe(1); - expect(superAdmins3).toContain(client1.inboxId); + await conversation.syncSuperAdmins(); + expect(conversation.superAdmins.length).toBe(1); + expect(conversation.superAdmins).toContain(client1.inboxId); }); it("should manage group consent state", async () => { @@ -391,11 +390,9 @@ describe.concurrent("Conversation", () => { const group2 = await client2.conversations.getConversationById(group.id); expect(group2).toBeDefined(); - const groupConvo = new Conversation(client2, group2!.id, group2); - - expect(await groupConvo.consentState()).toBe(ConsentState.Unknown); - await groupConvo.send("gm!"); - expect(await groupConvo.consentState()).toBe(ConsentState.Allowed); + expect(await group2!.consentState()).toBe(ConsentState.Unknown); + await group2!.send("gm!"); + expect(await group2!.consentState()).toBe(ConsentState.Allowed); await client3.conversations.sync(); const dmGroup2 = await client3.conversations.getConversationById( @@ -403,10 +400,8 @@ describe.concurrent("Conversation", () => { ); expect(dmGroup2).toBeDefined(); - const dmConvo = new Conversation(client3, dmGroup2!.id, dmGroup2); - - expect(await dmConvo.consentState()).toBe(ConsentState.Unknown); - await dmConvo.send("gm!"); - expect(await dmConvo.consentState()).toBe(ConsentState.Allowed); + expect(await dmGroup2!.consentState()).toBe(ConsentState.Unknown); + await dmGroup2!.send("gm!"); + expect(await dmGroup2!.consentState()).toBe(ConsentState.Allowed); }); });