diff --git a/.changeset/config.json b/.changeset/config.json index 286b51d97..fb66f2ca1 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -12,5 +12,5 @@ "access": "public", "baseBranch": "main", "updateInternalDependencies": "patch", - "ignore": ["@xmtp/react-vite-browser-sdk-example"] + "ignore": ["@xmtp/xmtp.chat"] } diff --git a/.changeset/nine-toes-wink.md b/.changeset/nine-toes-wink.md new file mode 100644 index 000000000..716185b4e --- /dev/null +++ b/.changeset/nine-toes-wink.md @@ -0,0 +1,5 @@ +--- +"@xmtp/browser-sdk": patch +--- + +Add support for HMAC keys (browser) diff --git a/apps/xmtp.chat/src/components/ManageConversation.tsx b/apps/xmtp.chat/src/components/ManageConversation.tsx index 34c2018e4..ea82c4ef9 100644 --- a/apps/xmtp.chat/src/components/ManageConversation.tsx +++ b/apps/xmtp.chat/src/components/ManageConversation.tsx @@ -40,6 +40,30 @@ type ClassProperties = { }; type PolicySet = ClassProperties; +const defaultPolicySet: PolicySet = { + addAdminPolicy: PermissionPolicy.SuperAdmin, + addMemberPolicy: PermissionPolicy.Allow, + removeAdminPolicy: PermissionPolicy.SuperAdmin, + removeMemberPolicy: PermissionPolicy.Admin, + updateGroupNamePolicy: PermissionPolicy.Allow, + updateGroupDescriptionPolicy: PermissionPolicy.Allow, + updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, + updateGroupPinnedFrameUrlPolicy: PermissionPolicy.Allow, + updateMessageExpirationPolicy: PermissionPolicy.Admin, +}; + +const adminPolicySet: PolicySet = { + addAdminPolicy: PermissionPolicy.SuperAdmin, + addMemberPolicy: PermissionPolicy.Admin, + removeAdminPolicy: PermissionPolicy.SuperAdmin, + removeMemberPolicy: PermissionPolicy.Admin, + updateGroupNamePolicy: PermissionPolicy.Admin, + updateGroupDescriptionPolicy: PermissionPolicy.Admin, + updateGroupImageUrlSquarePolicy: PermissionPolicy.Admin, + updateGroupPinnedFrameUrlPolicy: PermissionPolicy.Admin, + updateMessageExpirationPolicy: PermissionPolicy.Admin, +}; + export const ManageConversation: React.FC = () => { useBodyClass("main-flex-layout"); const { conversationId } = useParams(); @@ -53,17 +77,8 @@ export const ManageConversation: React.FC = () => { const [addedMembers, setAddedMembers] = useState([]); const [removedMembers, setRemovedMembers] = useState([]); const [permissionsPolicy, setPermissionsPolicy] = - useState(GroupPermissionsOptions.AllMembers); - const [policySet, setPolicySet] = useState({ - addAdminPolicy: PermissionPolicy.Admin, - addMemberPolicy: PermissionPolicy.Admin, - removeAdminPolicy: PermissionPolicy.Admin, - removeMemberPolicy: PermissionPolicy.Admin, - updateGroupDescriptionPolicy: PermissionPolicy.Allow, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, - updateGroupNamePolicy: PermissionPolicy.Allow, - updateGroupPinnedFrameUrlPolicy: PermissionPolicy.Allow, - }); + useState(GroupPermissionsOptions.Default); + const [policySet, setPolicySet] = useState(defaultPolicySet); const [updateConversationError, setUpdateConversationError] = useState< string | null >(null); @@ -76,7 +91,7 @@ export const ManageConversation: React.FC = () => { const [pinnedFrameUrl, setPinnedFrameUrl] = useState(""); const policyTooltip = useMemo(() => { - if (permissionsPolicy === GroupPermissionsOptions.AllMembers) { + if (permissionsPolicy === GroupPermissionsOptions.Default) { return "All members of the group can perform group actions"; } else if (permissionsPolicy === GroupPermissionsOptions.AdminOnly) { return "Only admins can perform group actions"; @@ -86,30 +101,12 @@ export const ManageConversation: React.FC = () => { useEffect(() => { if ( - permissionsPolicy === GroupPermissionsOptions.AllMembers || + permissionsPolicy === GroupPermissionsOptions.Default || permissionsPolicy === GroupPermissionsOptions.CustomPolicy ) { - setPolicySet({ - addAdminPolicy: PermissionPolicy.Admin, - addMemberPolicy: PermissionPolicy.Admin, - removeAdminPolicy: PermissionPolicy.Admin, - removeMemberPolicy: PermissionPolicy.Admin, - updateGroupDescriptionPolicy: PermissionPolicy.Allow, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, - updateGroupNamePolicy: PermissionPolicy.Allow, - updateGroupPinnedFrameUrlPolicy: PermissionPolicy.Allow, - }); + setPolicySet(defaultPolicySet); } else { - setPolicySet({ - addAdminPolicy: PermissionPolicy.Admin, - addMemberPolicy: PermissionPolicy.Admin, - removeAdminPolicy: PermissionPolicy.Admin, - removeMemberPolicy: PermissionPolicy.Admin, - updateGroupDescriptionPolicy: PermissionPolicy.Admin, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Admin, - updateGroupNamePolicy: PermissionPolicy.Admin, - updateGroupPinnedFrameUrlPolicy: PermissionPolicy.Admin, - }); + setPolicySet(adminPolicySet); } }, [permissionsPolicy]); @@ -161,41 +158,41 @@ export const ManageConversation: React.FC = () => { permissionsPolicy !== GroupPermissionsOptions.CustomPolicy ) { switch (permissionsPolicy) { - case GroupPermissionsOptions.AllMembers: { + case GroupPermissionsOptions.Default: { await conversation?.updatePermission( PermissionUpdateType.AddMember, - PermissionPolicy.Deny, + defaultPolicySet.addMemberPolicy, ); await conversation?.updatePermission( PermissionUpdateType.RemoveMember, - PermissionPolicy.Admin, + defaultPolicySet.removeMemberPolicy, ); await conversation?.updatePermission( PermissionUpdateType.AddAdmin, - PermissionPolicy.SuperAdmin, + defaultPolicySet.addAdminPolicy, ); await conversation?.updatePermission( PermissionUpdateType.RemoveAdmin, - PermissionPolicy.SuperAdmin, + defaultPolicySet.removeAdminPolicy, ); await conversation?.updatePermission( PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Allow, + defaultPolicySet.updateGroupNamePolicy, MetadataField.GroupName, ); await conversation?.updatePermission( PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Allow, + defaultPolicySet.updateGroupDescriptionPolicy, MetadataField.Description, ); await conversation?.updatePermission( PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Allow, + defaultPolicySet.updateGroupImageUrlSquarePolicy, MetadataField.ImageUrlSquare, ); await conversation?.updatePermission( PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Allow, + defaultPolicySet.updateGroupPinnedFrameUrlPolicy, MetadataField.PinnedFrameUrl, ); break; @@ -203,38 +200,38 @@ export const ManageConversation: React.FC = () => { case GroupPermissionsOptions.AdminOnly: { await conversation?.updatePermission( PermissionUpdateType.AddMember, - PermissionPolicy.Admin, + adminPolicySet.addMemberPolicy, ); await conversation?.updatePermission( PermissionUpdateType.RemoveMember, - PermissionPolicy.Admin, + adminPolicySet.removeMemberPolicy, ); await conversation?.updatePermission( PermissionUpdateType.AddAdmin, - PermissionPolicy.SuperAdmin, + adminPolicySet.addAdminPolicy, ); await conversation?.updatePermission( PermissionUpdateType.RemoveAdmin, - PermissionPolicy.SuperAdmin, + adminPolicySet.removeAdminPolicy, ); await conversation?.updatePermission( PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, + adminPolicySet.updateGroupNamePolicy, MetadataField.GroupName, ); await conversation?.updatePermission( PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, + adminPolicySet.updateGroupDescriptionPolicy, MetadataField.Description, ); await conversation?.updatePermission( PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, + adminPolicySet.updateGroupImageUrlSquarePolicy, MetadataField.ImageUrlSquare, ); await conversation?.updatePermission( PermissionUpdateType.UpdateMetadata, - PermissionPolicy.Admin, + adminPolicySet.updateGroupPinnedFrameUrlPolicy, MetadataField.PinnedFrameUrl, ); } @@ -312,31 +309,13 @@ export const ManageConversation: React.FC = () => { const permissions = await conversation.permissions(); const policyType = permissions.policyType; switch (policyType) { - case GroupPermissionsOptions.AllMembers: - setPermissionsPolicy(GroupPermissionsOptions.AllMembers); - setPolicySet({ - addAdminPolicy: PermissionPolicy.Admin, - addMemberPolicy: PermissionPolicy.Admin, - removeAdminPolicy: PermissionPolicy.Admin, - removeMemberPolicy: PermissionPolicy.Admin, - updateGroupDescriptionPolicy: PermissionPolicy.Allow, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, - updateGroupNamePolicy: PermissionPolicy.Allow, - updateGroupPinnedFrameUrlPolicy: PermissionPolicy.Allow, - }); + case GroupPermissionsOptions.Default: + setPermissionsPolicy(GroupPermissionsOptions.Default); + setPolicySet(defaultPolicySet); break; case GroupPermissionsOptions.AdminOnly: setPermissionsPolicy(GroupPermissionsOptions.AdminOnly); - setPolicySet({ - addAdminPolicy: PermissionPolicy.Admin, - addMemberPolicy: PermissionPolicy.Admin, - removeAdminPolicy: PermissionPolicy.Admin, - removeMemberPolicy: PermissionPolicy.Admin, - updateGroupDescriptionPolicy: PermissionPolicy.Admin, - updateGroupImageUrlSquarePolicy: PermissionPolicy.Admin, - updateGroupNamePolicy: PermissionPolicy.Admin, - updateGroupPinnedFrameUrlPolicy: PermissionPolicy.Admin, - }); + setPolicySet(adminPolicySet); break; case GroupPermissionsOptions.CustomPolicy: setPermissionsPolicy(GroupPermissionsOptions.CustomPolicy); @@ -486,7 +465,7 @@ export const ManageConversation: React.FC = () => { ); }} data={[ - { value: "0", label: "All members" }, + { value: "0", label: "Default" }, { value: "1", label: "Admins only" }, { value: "2", label: "Custom policy" }, ]} diff --git a/apps/xmtp.chat/src/components/NewConversation.tsx b/apps/xmtp.chat/src/components/NewConversation.tsx index c07cc32b7..c5050cbf9 100644 --- a/apps/xmtp.chat/src/components/NewConversation.tsx +++ b/apps/xmtp.chat/src/components/NewConversation.tsx @@ -43,7 +43,7 @@ export const NewConversation: React.FC = () => { const [members, setMembers] = useState([]); const [isDmGroup, setIsDmGroup] = useState(false); const [permissionsPolicy, setPermissionsPolicy] = - useState(GroupPermissionsOptions.AllMembers); + useState(GroupPermissionsOptions.Default); const [policySet, setPolicySet] = useState({ addAdminPolicy: PermissionPolicy.Admin, addMemberPolicy: PermissionPolicy.Admin, @@ -53,6 +53,7 @@ export const NewConversation: React.FC = () => { updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, updateGroupNamePolicy: PermissionPolicy.Allow, updateGroupPinnedFrameUrlPolicy: PermissionPolicy.Allow, + updateMessageExpirationPolicy: PermissionPolicy.Allow, }); const [createConversationError, setCreateConversationError] = useState< string | null @@ -64,7 +65,7 @@ export const NewConversation: React.FC = () => { const [pinnedFrameUrl, setPinnedFrameUrl] = useState(""); const policyTooltip = useMemo(() => { - if (permissionsPolicy === GroupPermissionsOptions.AllMembers) { + if (permissionsPolicy === GroupPermissionsOptions.Default) { return "All members of the group can perform group actions"; } else if (permissionsPolicy === GroupPermissionsOptions.AdminOnly) { return "Only admins can perform group actions"; @@ -74,7 +75,7 @@ export const NewConversation: React.FC = () => { useEffect(() => { if ( - permissionsPolicy === GroupPermissionsOptions.AllMembers || + permissionsPolicy === GroupPermissionsOptions.Default || permissionsPolicy === GroupPermissionsOptions.CustomPolicy ) { setPolicySet({ @@ -86,6 +87,7 @@ export const NewConversation: React.FC = () => { updateGroupImageUrlSquarePolicy: PermissionPolicy.Allow, updateGroupNamePolicy: PermissionPolicy.Allow, updateGroupPinnedFrameUrlPolicy: PermissionPolicy.Allow, + updateMessageExpirationPolicy: PermissionPolicy.Admin, }); } else { setPolicySet({ @@ -97,6 +99,7 @@ export const NewConversation: React.FC = () => { updateGroupImageUrlSquarePolicy: PermissionPolicy.Admin, updateGroupNamePolicy: PermissionPolicy.Admin, updateGroupPinnedFrameUrlPolicy: PermissionPolicy.Admin, + updateMessageExpirationPolicy: PermissionPolicy.Admin, }); } }, [permissionsPolicy]); @@ -131,6 +134,10 @@ export const NewConversation: React.FC = () => { ? policySet : undefined, }); + // automatically sync when creating a group with no members + if (!isDmGroup && members.length === 0) { + await conversation.sync(); + } void navigate(`/conversations/${conversation.id}`); }; @@ -258,7 +265,7 @@ export const NewConversation: React.FC = () => { ); }} data={[ - { value: "0", label: "All members" }, + { value: "0", label: "Default" }, { value: "1", label: "Admins only" }, { value: "2", label: "Custom policy" }, ]} diff --git a/sdks/browser-sdk/package.json b/sdks/browser-sdk/package.json index 63aa78ca8..3a2f1fef9 100644 --- a/sdks/browser-sdk/package.json +++ b/sdks/browser-sdk/package.json @@ -64,7 +64,7 @@ "@xmtp/content-type-primitives": "^2.0.0", "@xmtp/content-type-text": "^2.0.0", "@xmtp/proto": "^3.72.3", - "@xmtp/wasm-bindings": "^0.0.11", + "@xmtp/wasm-bindings": "^0.0.12", "uuid": "^11.0.3" }, "devDependencies": { diff --git a/sdks/browser-sdk/src/Conversations.ts b/sdks/browser-sdk/src/Conversations.ts index 02cd3e1fd..404e900ae 100644 --- a/sdks/browser-sdk/src/Conversations.ts +++ b/sdks/browser-sdk/src/Conversations.ts @@ -95,4 +95,8 @@ export class Conversations { return new Conversation(this.#client, conversation.id, conversation); } + + async getHmacKeys() { + return this.#client.sendMessage("getHmacKeys", undefined); + } } diff --git a/sdks/browser-sdk/src/WorkerConversations.ts b/sdks/browser-sdk/src/WorkerConversations.ts index d927802dd..768199187 100644 --- a/sdks/browser-sdk/src/WorkerConversations.ts +++ b/sdks/browser-sdk/src/WorkerConversations.ts @@ -2,6 +2,7 @@ import type { Conversation, Conversations } from "@xmtp/wasm-bindings"; import { fromSafeCreateGroupOptions, fromSafeListConversationsOptions, + type HmacKeys, type SafeCreateGroupOptions, type SafeListConversationsOptions, } from "@/utils/conversions"; @@ -89,4 +90,8 @@ export class WorkerConversations { const group = await this.#conversations.createDm(accountAddress); return new WorkerConversation(this.#client, group); } + + getHmacKeys() { + return this.#conversations.getHmacKeys() as HmacKeys; + } } diff --git a/sdks/browser-sdk/src/index.ts b/sdks/browser-sdk/src/index.ts index 2b9af0da0..a2f049cdc 100644 --- a/sdks/browser-sdk/src/index.ts +++ b/sdks/browser-sdk/src/index.ts @@ -34,6 +34,7 @@ export { SortDirection, Consent, ContentTypeId, + HmacKey, } from "@xmtp/wasm-bindings"; export { isSmartContractSigner, diff --git a/sdks/browser-sdk/src/types/clientEvents.ts b/sdks/browser-sdk/src/types/clientEvents.ts index 4507a7c7f..508a61b21 100644 --- a/sdks/browser-sdk/src/types/clientEvents.ts +++ b/sdks/browser-sdk/src/types/clientEvents.ts @@ -22,6 +22,7 @@ import type { SafeCreateGroupOptions, SafeEncodedContent, SafeGroupMember, + SafeHmacKeys, SafeInboxState, SafeListConversationsOptions, SafeListMessagesOptions, @@ -276,6 +277,12 @@ export type ClientEvents = result: undefined; data: undefined; } + | { + action: "getHmacKeys"; + id: string; + result: SafeHmacKeys; + data: undefined; + } /** * Group actions */ diff --git a/sdks/browser-sdk/src/utils/conversions.ts b/sdks/browser-sdk/src/utils/conversions.ts index a1386096d..f3f69ea07 100644 --- a/sdks/browser-sdk/src/utils/conversions.ts +++ b/sdks/browser-sdk/src/utils/conversions.ts @@ -18,6 +18,7 @@ import { type DeliveryStatus, type GroupMembershipState, type GroupMessageKind, + type HmacKey, type InboxState, type Installation, type Message, @@ -210,6 +211,7 @@ export type SafePermissionPolicySet = { updateGroupImageUrlSquarePolicy: PermissionPolicy; updateGroupNamePolicy: PermissionPolicy; updateGroupPinnedFrameUrlPolicy: PermissionPolicy; + updateMessageExpirationPolicy: PermissionPolicy; }; export const toSafePermissionPolicySet = ( @@ -223,6 +225,7 @@ export const toSafePermissionPolicySet = ( updateGroupImageUrlSquarePolicy: policySet.updateGroupImageUrlSquarePolicy, updateGroupNamePolicy: policySet.updateGroupNamePolicy, updateGroupPinnedFrameUrlPolicy: policySet.updateGroupPinnedFrameUrlPolicy, + updateMessageExpirationPolicy: policySet.updateMessageExpirationPolicy, }); export const fromSafePermissionPolicySet = ( @@ -237,6 +240,7 @@ export const fromSafePermissionPolicySet = ( policySet.updateGroupDescriptionPolicy, policySet.updateGroupImageUrlSquarePolicy, policySet.updateGroupPinnedFrameUrlPolicy, + policySet.updateMessageExpirationPolicy, ); export type SafeCreateGroupOptions = { @@ -292,6 +296,7 @@ export type SafeConversation = { updateGroupImageUrlSquarePolicy: PermissionPolicy; updateGroupNamePolicy: PermissionPolicy; updateGroupPinnedFrameUrlPolicy: PermissionPolicy; + updateMessageExpirationPolicy: PermissionPolicy; }; }; isActive: boolean; @@ -328,6 +333,8 @@ export const toSafeConversation = async ( conversation.permissions.policySet.updateGroupNamePolicy, updateGroupPinnedFrameUrlPolicy: conversation.permissions.policySet.updateGroupPinnedFrameUrlPolicy, + updateMessageExpirationPolicy: + conversation.permissions.policySet.updateMessageExpirationPolicy, }, }, isActive: conversation.isActive, @@ -405,3 +412,16 @@ export const fromSafeGroupMember = (member: SafeGroupMember): GroupMember => member.permissionLevel, member.consentState, ); + +export type SafeHmacKey = { + key: Uint8Array; + epoch: bigint; +}; + +export const toSafeHmacKey = (hmacKey: HmacKey): SafeHmacKey => ({ + key: hmacKey.key, + epoch: hmacKey.epoch, +}); + +export type HmacKeys = Map; +export type SafeHmacKeys = Record; diff --git a/sdks/browser-sdk/src/workers/client.ts b/sdks/browser-sdk/src/workers/client.ts index 9101357f2..230d5de51 100644 --- a/sdks/browser-sdk/src/workers/client.ts +++ b/sdks/browser-sdk/src/workers/client.ts @@ -8,6 +8,7 @@ import { fromEncodedContent, fromSafeEncodedContent, toSafeConversation, + toSafeHmacKey, toSafeInboxState, toSafeMessage, } from "@/utils/conversions"; @@ -376,6 +377,20 @@ self.onmessage = async (event: MessageEvent) => { }); break; } + case "getHmacKeys": { + const result = client.conversations.getHmacKeys(); + postMessage({ + id, + action, + result: Object.fromEntries( + Array.from(result.entries()).map(([groupId, hmacKeys]) => [ + groupId, + hmacKeys.map(toSafeHmacKey), + ]), + ), + }); + break; + } /** * Group actions */ diff --git a/sdks/browser-sdk/test/Conversation.test.ts b/sdks/browser-sdk/test/Conversation.test.ts index 586f603c2..c0c8e1f83 100644 --- a/sdks/browser-sdk/test/Conversation.test.ts +++ b/sdks/browser-sdk/test/Conversation.test.ts @@ -1,5 +1,6 @@ import { ConsentState, + GroupPermissionsOptions, MetadataField, PermissionPolicy, PermissionUpdateType, @@ -413,8 +414,10 @@ describe.concurrent("Conversation", () => { it("should update group permission policy", async () => { const user1 = createUser(); const user2 = createUser(); + const user3 = createUser(); const client1 = await createRegisteredClient(user1); await createRegisteredClient(user2); + await createRegisteredClient(user3); const conversation = await client1.conversations.newGroup([ user2.account.address, ]); @@ -429,6 +432,7 @@ describe.concurrent("Conversation", () => { updateGroupDescriptionPolicy: 0, updateGroupImageUrlSquarePolicy: 0, updateGroupPinnedFrameUrlPolicy: 0, + updateMessageExpirationPolicy: 2, }); await conversation.updatePermission( @@ -485,6 +489,45 @@ describe.concurrent("Conversation", () => { updateGroupDescriptionPolicy: 2, updateGroupImageUrlSquarePolicy: 2, updateGroupPinnedFrameUrlPolicy: 2, + updateMessageExpirationPolicy: 2, + }); + + const conversation2 = await client1.conversations.newGroup([], { + permissions: GroupPermissionsOptions.AdminOnly, + }); + + const permissions3 = await conversation2.permissions(); + expect(permissions3.policySet).toEqual({ + addMemberPolicy: 2, + removeMemberPolicy: 2, + addAdminPolicy: 3, + removeAdminPolicy: 3, + updateGroupNamePolicy: 2, + updateGroupDescriptionPolicy: 2, + updateGroupImageUrlSquarePolicy: 2, + updateGroupPinnedFrameUrlPolicy: 2, + updateMessageExpirationPolicy: 2, + }); + + // required when group has no members + await conversation2.sync(); + + await conversation2.updatePermission( + PermissionUpdateType.AddMember, + PermissionPolicy.Allow, + ); + + const permissions4 = await conversation2.permissions(); + expect(permissions4.policySet).toEqual({ + addMemberPolicy: 0, + removeMemberPolicy: 2, + addAdminPolicy: 3, + removeAdminPolicy: 3, + updateGroupNamePolicy: 2, + updateGroupDescriptionPolicy: 2, + updateGroupImageUrlSquarePolicy: 2, + updateGroupPinnedFrameUrlPolicy: 2, + updateMessageExpirationPolicy: 2, }); }); }); diff --git a/sdks/browser-sdk/test/Conversations.test.ts b/sdks/browser-sdk/test/Conversations.test.ts index d25ca27de..15eac7ef7 100644 --- a/sdks/browser-sdk/test/Conversations.test.ts +++ b/sdks/browser-sdk/test/Conversations.test.ts @@ -30,7 +30,7 @@ describe.concurrent("Conversations", () => { expect(conversation.isActive).toBe(true); expect(conversation.name).toBe(""); const permissions = await conversation.permissions(); - expect(permissions.policyType).toBe(GroupPermissionsOptions.AllMembers); + expect(permissions.policyType).toBe(GroupPermissionsOptions.Default); expect(permissions.policySet).toEqual({ addMemberPolicy: 0, removeMemberPolicy: 2, @@ -40,6 +40,7 @@ describe.concurrent("Conversations", () => { updateGroupDescriptionPolicy: 0, updateGroupImageUrlSquarePolicy: 0, updateGroupPinnedFrameUrlPolicy: 0, + updateMessageExpirationPolicy: 2, }); expect(conversation.addedByInboxId).toBe(client1.inboxId); expect((await conversation.messages()).length).toBe(1); @@ -93,6 +94,7 @@ describe.concurrent("Conversations", () => { updateGroupImageUrlSquarePolicy: 0, updateGroupNamePolicy: 0, updateGroupPinnedFrameUrlPolicy: 0, + updateMessageExpirationPolicy: 0, }); expect(group.addedByInboxId).toBe(client1.inboxId); expect((await group.messages()).length).toBe(0); @@ -235,6 +237,7 @@ describe.concurrent("Conversations", () => { updateGroupDescriptionPolicy: 2, updateGroupImageUrlSquarePolicy: 2, updateGroupPinnedFrameUrlPolicy: 2, + updateMessageExpirationPolicy: 2, }); const groupWithDescription = await client1.conversations.newGroup( @@ -279,6 +282,7 @@ describe.concurrent("Conversations", () => { updateGroupDescriptionPolicy: 1, updateGroupImageUrlSquarePolicy: 1, updateGroupPinnedFrameUrlPolicy: 1, + updateMessageExpirationPolicy: 1, }, }, ); @@ -295,6 +299,41 @@ describe.concurrent("Conversations", () => { updateGroupDescriptionPolicy: 1, updateGroupImageUrlSquarePolicy: 1, updateGroupPinnedFrameUrlPolicy: 1, + updateMessageExpirationPolicy: 1, + }); + }); + + it("should get conversation HMAC keys", async () => { + const user1 = createUser(); + const user2 = createUser(); + const user3 = createUser(); + const user4 = createUser(); + const client1 = await createRegisteredClient(user1); + await createRegisteredClient(user2); + await createRegisteredClient(user3); + await createRegisteredClient(user4); + const group1 = await client1.conversations.newGroup([ + user2.account.address, + ]); + const group2 = await client1.conversations.newGroup([ + user3.account.address, + ]); + const group3 = await client1.conversations.newGroup([ + user4.account.address, + ]); + const hmacKeys = await client1.conversations.getHmacKeys(); + expect(hmacKeys).toBeDefined(); + const groupIds = Object.keys(hmacKeys); + expect(groupIds).toContain(group1.id); + expect(groupIds).toContain(group2.id); + expect(groupIds).toContain(group3.id); + Object.values(hmacKeys).forEach((keys) => { + keys.forEach((key) => { + expect(key.epoch).toBeDefined(); + expect(key.epoch).toBeGreaterThan(0); + expect(key.key).toBeDefined(); + expect(key.key.length).toBe(42); + }); }); }); }); diff --git a/yarn.lock b/yarn.lock index 605570bbc..92360946a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4713,7 +4713,7 @@ __metadata: "@xmtp/content-type-primitives": "npm:^2.0.0" "@xmtp/content-type-text": "npm:^2.0.0" "@xmtp/proto": "npm:^3.72.3" - "@xmtp/wasm-bindings": "npm:^0.0.11" + "@xmtp/wasm-bindings": "npm:^0.0.12" playwright: "npm:^1.49.0" rollup: "npm:^4.27.3" rollup-plugin-dts: "npm:^6.1.1" @@ -5136,10 +5136,10 @@ __metadata: languageName: node linkType: hard -"@xmtp/wasm-bindings@npm:^0.0.11": - version: 0.0.11 - resolution: "@xmtp/wasm-bindings@npm:0.0.11" - checksum: 10/6482ca317888e4d1ff53c4d9e201bd81c26b67bdcbe13a09615f76ce3ebd503535e52f998c414ee6e4675b1a5396b73dd70db5a0fb7536475760a16d796e40c1 +"@xmtp/wasm-bindings@npm:^0.0.12": + version: 0.0.12 + resolution: "@xmtp/wasm-bindings@npm:0.0.12" + checksum: 10/95394403d7c6cac58a559c71866d26473a2a18d55e6b9f759d2158d817142ac2965ff4bfc147406c1df407ae6d0a90fb36039d97254ca27b7aea3ae462aa62ce languageName: node linkType: hard