Skip to content

Commit

Permalink
Browser SDK updates (#760)
Browse files Browse the repository at this point in the history
* Browser SDK updates

* Add encodedContent property to DecodedMessage

* Create beige-bananas-flow.md

* Remove unused import
  • Loading branch information
rygine authored Dec 19, 2024
1 parent becef24 commit dad39c4
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 53 deletions.
5 changes: 5 additions & 0 deletions .changeset/beige-bananas-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@xmtp/browser-sdk": patch
---

Browser SDK updates
32 changes: 24 additions & 8 deletions sdks/browser-sdk/src/Conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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() {
Expand Down Expand Up @@ -128,30 +134,40 @@ 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() {
return this.#permissions;
}

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() {
Expand Down
24 changes: 19 additions & 5 deletions sdks/browser-sdk/src/Conversations.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Client } from "@/Client";
import { Conversation } from "@/Conversation";
import { DecodedMessage } from "@/DecodedMessage";
import type {
SafeCreateGroupOptions,
SafeListConversationsOptions,
Expand All @@ -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) {
Expand All @@ -52,17 +56,27 @@ export class Conversations {
async listGroups(
options?: Omit<SafeListConversationsOptions, "conversation_type">,
) {
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<SafeListConversationsOptions, "conversation_type">,
) {
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) {
Expand Down
3 changes: 3 additions & 0 deletions sdks/browser-sdk/src/DecodedMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export class DecodedMessage {

parameters: Map<string, string>;

encodedContent: SafeMessage["content"];

senderInboxId: string;

sentAtNs: bigint;
Expand All @@ -37,6 +39,7 @@ export class DecodedMessage {
this.sentAtNs = message.sentAtNs;
this.conversationId = message.convoId;
this.senderInboxId = message.senderInboxId;
this.encodedContent = message.content;

switch (message.kind) {
case GroupMessageKind.Application:
Expand Down
4 changes: 1 addition & 3 deletions sdks/browser-sdk/src/WorkerConversations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type { Conversation, Conversations } from "@xmtp/wasm-bindings";
import {
fromSafeCreateGroupOptions,
fromSafeListConversationsOptions,
toSafeMessage,
type SafeCreateGroupOptions,
type SafeListConversationsOptions,
} from "@/utils/conversions";
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion sdks/browser-sdk/src/workers/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ self.onmessage = async (event: MessageEvent<ClientEventsClientMessageData>) => {
postMessage({
id,
action,
result: message,
result: message ? toSafeMessage(message) : undefined,
});
break;
}
Expand Down
7 changes: 2 additions & 5 deletions sdks/browser-sdk/test/Client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { ConsentEntityType, ConsentState } from "@xmtp/wasm-bindings";
import { v4 } from "uuid";
import { describe, expect, it } from "vitest";
import { Client } from "@/Client";
import { Conversation } from "@/Conversation";
import {
createClient,
createRegisteredClient,
Expand Down Expand Up @@ -163,11 +162,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),
Expand Down
57 changes: 26 additions & 31 deletions sdks/browser-sdk/test/Conversation.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { ConsentState } from "@xmtp/wasm-bindings";
import { describe, expect, it } from "vitest";
import { Conversation } from "@/Conversation";
import {
ContentTypeTest,
createRegisteredClient,
Expand Down Expand Up @@ -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 () => {
Expand All @@ -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 () => {
Expand All @@ -391,22 +390,18 @@ 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(
dmGroup.id,
);
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);
});
});

0 comments on commit dad39c4

Please sign in to comment.