mirror of
https://github.com/status-im/dappconnect-sdks.git
synced 2025-02-04 12:53:53 +00:00
Add private group chat handling (#136)
This commit is contained in:
parent
77dfd154b2
commit
30984cdc05
BIN
.yarn/cache/@types-bn.js-npm-5.1.0-4a0335ff4f-1dc1cbbd7a.zip
vendored
Normal file
BIN
.yarn/cache/@types-bn.js-npm-5.1.0-4a0335ff4f-1dc1cbbd7a.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@types-elliptic-npm-6.4.14-77735f3256-d5a64f540e.zip
vendored
Normal file
BIN
.yarn/cache/@types-elliptic-npm-6.4.14-77735f3256-d5a64f540e.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@types-uuid-npm-8.3.3-805fed50df-3f340155bb.zip
vendored
Normal file
BIN
.yarn/cache/@types-uuid-npm-8.3.3-805fed50df-3f340155bb.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/browserify-zlib-npm-0.2.0-eab4087284-5cd9d6a665.zip
vendored
Normal file
BIN
.yarn/cache/browserify-zlib-npm-0.2.0-eab4087284-5cd9d6a665.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/builtin-status-codes-npm-3.0.0-e376b0580b-1119429cf4.zip
vendored
Normal file
BIN
.yarn/cache/builtin-status-codes-npm-3.0.0-e376b0580b-1119429cf4.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/https-browserify-npm-1.0.0-7d6b10abbc-09b35353e4.zip
vendored
Normal file
BIN
.yarn/cache/https-browserify-npm-1.0.0-7d6b10abbc-09b35353e4.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/pako-npm-1.0.11-b8f1b69d3e-1be2bfa1f8.zip
vendored
Normal file
BIN
.yarn/cache/pako-npm-1.0.11-b8f1b69d3e-1be2bfa1f8.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/stream-http-npm-3.2.0-c6d720ac4f-c9b78453ae.zip
vendored
Normal file
BIN
.yarn/cache/stream-http-npm-3.2.0-c6d720ac4f-c9b78453ae.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
631
.yarn/releases/yarn-3.0.2.cjs
vendored
631
.yarn/releases/yarn-3.0.2.cjs
vendored
File diff suppressed because one or more lines are too long
768
.yarn/releases/yarn-3.1.0.cjs
vendored
Executable file
768
.yarn/releases/yarn-3.1.0.cjs
vendored
Executable file
File diff suppressed because one or more lines are too long
@ -1,2 +1,3 @@
|
||||
yarnPath: .yarn/releases/yarn-3.0.2.cjs
|
||||
nodeLinker: node-modules # Needed to work with Mocha, see https://github.com/yarnpkg/berry/issues/638
|
||||
nodeLinker: node-modules
|
||||
|
||||
yarnPath: .yarn/releases/yarn-3.1.0.cjs
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "dappconnect-sdks",
|
||||
"packageManager": "yarn@3.0.2",
|
||||
"packageManager": "yarn@3.1.0",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"scripts": {
|
||||
"fix": "run-s 'fix:*' && wsrun -e -c -s fix",
|
||||
|
@ -20,13 +20,16 @@
|
||||
"dependencies": {
|
||||
"@dappconnect/react-chat": "^0.1.0",
|
||||
"assert": "^2.0.0",
|
||||
"browserify-zlib": "^0.2.0",
|
||||
"buffer": "^6.0.3",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"https-browserify": "^1.0.0",
|
||||
"process": "^0.11.10",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"stream-http": "^3.2.0",
|
||||
"styled-components": "^5.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -25,6 +25,9 @@ module.exports = env => {
|
||||
crypto: require.resolve('crypto-browserify'),
|
||||
stream: require.resolve('stream-browserify'),
|
||||
assert: require.resolve('assert'),
|
||||
http: require.resolve('stream-http'),
|
||||
https: require.resolve('https-browserify'),
|
||||
zlib: require.resolve('browserify-zlib')
|
||||
},
|
||||
},
|
||||
module: {
|
||||
|
@ -18,8 +18,7 @@ export function ChatCreation({ editGroup }: ChatCreationProps) {
|
||||
const identity = useIdentity();
|
||||
const [query, setQuery] = useState("");
|
||||
const [styledGroup, setStyledGroup] = useState<string[]>([]);
|
||||
|
||||
const { contacts, setChannel } = useMessengerContext();
|
||||
const { contacts, createGroupChat } = useMessengerContext();
|
||||
const setChatState = useChatState()[1];
|
||||
|
||||
const addMember = useCallback(
|
||||
@ -40,19 +39,9 @@ export function ChatCreation({ editGroup }: ChatCreationProps) {
|
||||
};
|
||||
|
||||
const createChat = (group: string[]) => {
|
||||
group.length > 1
|
||||
? setChannel({
|
||||
id: group.join(""),
|
||||
name: group.join(", "),
|
||||
type: "group",
|
||||
description: `${group.length + 1} members`,
|
||||
})
|
||||
: setChannel({
|
||||
id: group[0],
|
||||
name: group[0],
|
||||
type: "dm",
|
||||
description: "Contact",
|
||||
});
|
||||
const newGroup = group.slice();
|
||||
newGroup.push(bufToHex(identity.publicKey));
|
||||
group.length > 1 ? createGroupChat(newGroup) : createGroupChat(newGroup);
|
||||
setChatState(ChatState.ChatBody);
|
||||
};
|
||||
|
||||
|
@ -25,6 +25,7 @@ const MessengerContext = createContext<MessengerType>({
|
||||
setChannel: () => undefined,
|
||||
removeChannel: () => undefined,
|
||||
setActiveChannel: () => undefined,
|
||||
createGroupChat: () => undefined,
|
||||
});
|
||||
|
||||
export function useMessengerContext() {
|
||||
|
91
packages/react-chat/src/hooks/messenger/useGroupChats.ts
Normal file
91
packages/react-chat/src/hooks/messenger/useGroupChats.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import { useCallback, useMemo } from "react";
|
||||
import {
|
||||
GroupChat,
|
||||
GroupChats,
|
||||
Identity,
|
||||
Messenger,
|
||||
ChatMessage as StatusChatMessage,
|
||||
} from "status-communities/dist/cjs";
|
||||
|
||||
import { ChannelData, ChannelsData } from "../../models/ChannelData";
|
||||
import { ChatMessage } from "../../models/ChatMessage";
|
||||
import { Contact } from "../../models/Contact";
|
||||
|
||||
export function useGroupChats(
|
||||
messenger: Messenger | undefined,
|
||||
identity: Identity | undefined,
|
||||
setChannels: React.Dispatch<React.SetStateAction<ChannelsData>>,
|
||||
setActiveChannel: (channel: ChannelData) => void,
|
||||
addChatMessage: (newMessage: ChatMessage | undefined, id: string) => void,
|
||||
channels: ChannelsData
|
||||
) {
|
||||
const groupChat = useMemo(() => {
|
||||
if (messenger && identity) {
|
||||
const addChat = (chat: GroupChat) => {
|
||||
const contactFromId = (member: string): Contact => {
|
||||
return {
|
||||
blocked: false,
|
||||
id: member,
|
||||
isUntrustworthy: false,
|
||||
online: false,
|
||||
trueName: member,
|
||||
};
|
||||
};
|
||||
const members = chat.members.map(contactFromId);
|
||||
const channel: ChannelData = {
|
||||
id: chat.chatId,
|
||||
name: chat.chatId,
|
||||
type: "group",
|
||||
members: members,
|
||||
};
|
||||
setChannels((prev) => {
|
||||
return { ...prev, [channel.id]: channel };
|
||||
});
|
||||
setActiveChannel(channel);
|
||||
};
|
||||
const removeChat = (chat: GroupChat) => {
|
||||
setChannels((prev) => {
|
||||
delete prev[chat.chatId];
|
||||
return prev;
|
||||
});
|
||||
setActiveChannel({
|
||||
id: "",
|
||||
name: "",
|
||||
type: "channel",
|
||||
} as ChannelData);
|
||||
};
|
||||
const handleMessage = (msg: StatusChatMessage, sender: string) =>
|
||||
addChatMessage(
|
||||
new ChatMessage(msg.text ?? "", new Date(msg.clock ?? 0), sender),
|
||||
msg.chatId
|
||||
);
|
||||
return new GroupChats(
|
||||
identity,
|
||||
messenger.waku,
|
||||
addChat,
|
||||
removeChat,
|
||||
handleMessage
|
||||
);
|
||||
}
|
||||
}, [messenger, identity]);
|
||||
|
||||
const createGroupChat = useCallback(
|
||||
(members: string[]) => {
|
||||
if (groupChat) {
|
||||
groupChat.createGroupChat(members);
|
||||
}
|
||||
},
|
||||
[groupChat]
|
||||
);
|
||||
|
||||
const removeChannel = useCallback(
|
||||
(channelId: string) => {
|
||||
if (groupChat) {
|
||||
groupChat.quitChat(channelId);
|
||||
}
|
||||
},
|
||||
[channels, groupChat]
|
||||
);
|
||||
|
||||
return { createGroupChat, removeChannel, groupChat };
|
||||
}
|
@ -24,9 +24,8 @@ export function useMessages(
|
||||
|
||||
const mentions = useNotifications();
|
||||
|
||||
const addMessage = useCallback(
|
||||
(msg: ApplicationMetadataMessage, id: string, date: Date) => {
|
||||
const newMessage = ChatMessage.fromMetadataMessage(msg, date);
|
||||
const addChatMessage = useCallback(
|
||||
(newMessage: ChatMessage | undefined, id: string) => {
|
||||
if (newMessage) {
|
||||
contacts?.addContact(newMessage.sender);
|
||||
setMessages((prev) => {
|
||||
@ -52,6 +51,14 @@ export function useMessages(
|
||||
[contacts, identity]
|
||||
);
|
||||
|
||||
const addMessage = useCallback(
|
||||
(msg: ApplicationMetadataMessage, id: string, date: Date) => {
|
||||
const newMessage = ChatMessage.fromMetadataMessage(msg, date);
|
||||
addChatMessage(newMessage, id);
|
||||
},
|
||||
[contacts, identity]
|
||||
);
|
||||
|
||||
const activeMessages = useMemo(
|
||||
() => messages?.[chatId] ?? [],
|
||||
[messages, chatId]
|
||||
@ -64,5 +71,6 @@ export function useMessages(
|
||||
clearNotifications,
|
||||
mentions: mentions.notifications,
|
||||
clearMentions: mentions.clearNotifications,
|
||||
addChatMessage,
|
||||
};
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import { createCommunity } from "../../utils/createCommunity";
|
||||
import { createMessenger } from "../../utils/createMessenger";
|
||||
import { uintToImgUrl } from "../../utils/uintToImgUrl";
|
||||
|
||||
import { useGroupChats } from "./useGroupChats";
|
||||
import { useLoadPrevDay } from "./useLoadPrevDay";
|
||||
import { useMessages } from "./useMessages";
|
||||
|
||||
@ -39,6 +40,7 @@ export type MessengerType = {
|
||||
removeChannel: (channelId: string) => void;
|
||||
activeChannel: ChannelData;
|
||||
setActiveChannel: (channel: ChannelData) => void;
|
||||
createGroupChat: (members: string[]) => void;
|
||||
};
|
||||
|
||||
export function useMessenger(
|
||||
@ -98,6 +100,7 @@ export function useMessenger(
|
||||
}, [internalContacts]);
|
||||
|
||||
const {
|
||||
addChatMessage,
|
||||
addMessage,
|
||||
clearNotifications,
|
||||
notifications,
|
||||
@ -132,25 +135,6 @@ export function useMessenger(
|
||||
}
|
||||
}, [messenger, community]);
|
||||
|
||||
const sendMessage = useCallback(
|
||||
async (messageText?: string, image?: Uint8Array) => {
|
||||
if (messageText) {
|
||||
await messenger?.sendMessage(chatId, {
|
||||
text: messageText,
|
||||
contentType: 0,
|
||||
});
|
||||
}
|
||||
if (image) {
|
||||
await messenger?.sendMessage(chatId, {
|
||||
image,
|
||||
imageType: 1,
|
||||
contentType: 2,
|
||||
});
|
||||
}
|
||||
},
|
||||
[chatId, messenger]
|
||||
);
|
||||
|
||||
const [channels, setChannels] = useState<ChannelsData>({});
|
||||
|
||||
const setChannel = useCallback((channel: ChannelData) => {
|
||||
@ -160,21 +144,6 @@ export function useMessenger(
|
||||
setActiveChannel(channel);
|
||||
}, []);
|
||||
|
||||
const removeChannel = useCallback(
|
||||
(channelId: string) => {
|
||||
setChannels((prev) => {
|
||||
delete prev[channelId];
|
||||
return prev;
|
||||
});
|
||||
const newActiveChannel: ChannelData = Object.values(channels)?.[0] ?? {
|
||||
id: "",
|
||||
name: "",
|
||||
};
|
||||
setActiveChannel(newActiveChannel);
|
||||
},
|
||||
[channels]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (community?.chats) {
|
||||
for (const chat of community.chats.values()) {
|
||||
@ -223,6 +192,38 @@ export function useMessenger(
|
||||
}
|
||||
}, [community]);
|
||||
|
||||
const { groupChat, removeChannel, createGroupChat } = useGroupChats(
|
||||
messenger,
|
||||
identity,
|
||||
setChannels,
|
||||
setActiveChannel,
|
||||
addChatMessage,
|
||||
channels
|
||||
);
|
||||
|
||||
const sendMessage = useCallback(
|
||||
async (messageText?: string, image?: Uint8Array) => {
|
||||
if (activeChannel.type === "group") {
|
||||
groupChat?.sendMessage(activeChannel.id, messageText ?? "");
|
||||
} else {
|
||||
if (messageText) {
|
||||
await messenger?.sendMessage(activeChannel.id, {
|
||||
text: messageText,
|
||||
contentType: 0,
|
||||
});
|
||||
}
|
||||
if (image) {
|
||||
await messenger?.sendMessage(activeChannel.id, {
|
||||
image,
|
||||
imageType: 1,
|
||||
contentType: 2,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
[messenger, groupChat, activeChannel]
|
||||
);
|
||||
|
||||
return {
|
||||
messenger,
|
||||
messages,
|
||||
@ -241,5 +242,6 @@ export function useMessenger(
|
||||
setActiveChannel,
|
||||
mentions,
|
||||
clearMentions,
|
||||
createGroupChat,
|
||||
};
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
"version": "0.1.0",
|
||||
"repository": "https://github.com/status-im/dappconnect-chat-sdk/",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"packageManager": "yarn@3.0.1",
|
||||
"packageManager": "yarn@3.1.0",
|
||||
"scripts": {
|
||||
"build": "run-s 'build:*'",
|
||||
"build:esm": "tsc --module es2020 --target es2017 --outDir dist/esm",
|
||||
@ -23,10 +23,13 @@
|
||||
"proto:build": "buf generate"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bn.js": "^5.1.0",
|
||||
"@types/chai": "^4.2.22",
|
||||
"@types/elliptic": "^6.4.14",
|
||||
"@types/mocha": "^9.0.0",
|
||||
"@types/pbkdf2": "^3.1.0",
|
||||
"@types/secp256k1": "^4.0.3",
|
||||
"@types/uuid": "^8.3.3",
|
||||
"@typescript-eslint/eslint-plugin": "^4.31.1",
|
||||
"@typescript-eslint/parser": "^4.31.1",
|
||||
"chai": "^4.3.4",
|
||||
@ -44,12 +47,15 @@
|
||||
"typescript": "^4.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": "^5.2.0",
|
||||
"buffer": "^6.0.3",
|
||||
"ecies-geth": "^1.5.3",
|
||||
"elliptic": "^6.5.4",
|
||||
"js-sha3": "^0.8.0",
|
||||
"js-waku": "^0.13.1",
|
||||
"pbkdf2": "^3.1.2",
|
||||
"protobufjs": "^6.11.2",
|
||||
"secp256k1": "^4.0.2"
|
||||
"secp256k1": "^4.0.2",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package communities.v1;
|
||||
|
||||
import "communities/v1/enums.proto";
|
||||
|
||||
message EmojiReaction {
|
||||
// clock Lamport timestamp of the chat message
|
||||
uint64 clock = 1;
|
||||
|
||||
// chat_id the ID of the chat the message belongs to, for query efficiency the chat_id is stored in the db even though the
|
||||
// target message also stores the chat_id
|
||||
string chat_id = 2;
|
||||
|
||||
// message_id the ID of the target message that the user wishes to react to
|
||||
string message_id = 3;
|
||||
|
||||
// message_type is (somewhat confusingly) the ID of the type of chat the message belongs to
|
||||
MessageType message_type = 4;
|
||||
|
||||
// type the ID of the emoji the user wishes to react with
|
||||
Type type = 5;
|
||||
|
||||
enum Type {
|
||||
UNKNOWN_EMOJI_REACTION_TYPE = 0;
|
||||
LOVE = 1;
|
||||
THUMBS_UP = 2;
|
||||
THUMBS_DOWN = 3;
|
||||
LAUGH = 4;
|
||||
SAD = 5;
|
||||
ANGRY = 6;
|
||||
}
|
||||
|
||||
// whether this is a rectraction of a previously sent emoji
|
||||
bool retracted = 6;
|
||||
|
||||
// Grant for organisation chat messages
|
||||
bytes grant = 7;
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package communities.v1;
|
||||
|
||||
import "communities/v1/chat_message.proto";
|
||||
import "communities/v1/emoji_reaction.proto";
|
||||
|
||||
message MembershipUpdateEvent {
|
||||
// Lamport timestamp of the event
|
||||
uint64 clock = 1;
|
||||
// List of public keys of objects of the action
|
||||
repeated string members = 2;
|
||||
// Name of the chat for the CHAT_CREATED/NAME_CHANGED event types
|
||||
string name = 3;
|
||||
// The type of the event
|
||||
EventType type = 4;
|
||||
|
||||
enum EventType {
|
||||
UNKNOWN = 0;
|
||||
CHAT_CREATED = 1;
|
||||
NAME_CHANGED = 2;
|
||||
MEMBERS_ADDED = 3;
|
||||
MEMBER_JOINED = 4;
|
||||
MEMBER_REMOVED = 5;
|
||||
ADMINS_ADDED = 6;
|
||||
ADMIN_REMOVED = 7;
|
||||
}
|
||||
}
|
||||
|
||||
// MembershipUpdateMessage is a message used to propagate information
|
||||
// about group membership changes.
|
||||
// For more information, see https://github.com/status-im/specs/blob/master/status-group-chats-spec.md.
|
||||
message MembershipUpdateMessage {
|
||||
// The chat id of the private group chat
|
||||
string chat_id = 1;
|
||||
// A list of events for this group chat, first x bytes are the signature, then is a
|
||||
// protobuf encoded MembershipUpdateEvent
|
||||
repeated bytes events = 2;
|
||||
|
||||
// An optional chat message
|
||||
oneof chat_entity {
|
||||
ChatMessage message = 3;
|
||||
EmojiReaction emoji_reaction = 4;
|
||||
}
|
||||
}
|
249
packages/status-communities/src/groupChats.ts
Normal file
249
packages/status-communities/src/groupChats.ts
Normal file
@ -0,0 +1,249 @@
|
||||
import { Waku, WakuMessage } from "js-waku";
|
||||
|
||||
import { Identity } from "./identity";
|
||||
import { MembershipUpdateEvent_EventType } from "./proto/communities/v1/membership_update_message";
|
||||
import { getNegotiatedTopic, getPartitionedTopic } from "./topics";
|
||||
import { bufToHex } from "./utils";
|
||||
import { MembershipUpdateMessage } from "./wire/membership_update_message";
|
||||
|
||||
import { ChatMessage, ContentType } from ".";
|
||||
|
||||
export type GroupChat = {
|
||||
chatId: string;
|
||||
members: string[];
|
||||
};
|
||||
|
||||
export type GroupChatsType = {
|
||||
[id: string]: GroupChat;
|
||||
};
|
||||
/* TODO: add chat messages encryption */
|
||||
|
||||
export class GroupChats {
|
||||
waku: Waku;
|
||||
identity: Identity;
|
||||
private callback: (chats: GroupChat) => void;
|
||||
private removeCallback: (chats: GroupChat) => void;
|
||||
private addMessage: (message: ChatMessage, sender: string) => void;
|
||||
|
||||
public chats: GroupChatsType = {};
|
||||
|
||||
/**
|
||||
* GroupChats holds a list of private chats and listens to their status broadcast
|
||||
*
|
||||
* @param identity identity of user
|
||||
*
|
||||
* @param waku waku class used to listen to broadcast and broadcast status
|
||||
*
|
||||
* @param callback callback function called when new private group chat is ceated
|
||||
*
|
||||
* @param removeCallback callback function when private group chat is to be removed
|
||||
*
|
||||
* @param addMessage callback function when
|
||||
*/
|
||||
public constructor(
|
||||
identity: Identity,
|
||||
waku: Waku,
|
||||
callback: (chat: GroupChat) => void,
|
||||
removeCallback: (chat: GroupChat) => void,
|
||||
addMessage: (message: ChatMessage, sender: string) => void
|
||||
) {
|
||||
this.waku = waku;
|
||||
this.identity = identity;
|
||||
this.callback = callback;
|
||||
this.removeCallback = removeCallback;
|
||||
this.addMessage = addMessage;
|
||||
this.listen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send chat message on given private chat
|
||||
*
|
||||
* @param chatId chat id of private group chat
|
||||
*
|
||||
* @param text text message to send
|
||||
*/
|
||||
public async sendMessage(chatId: string, text: string): Promise<void> {
|
||||
const now = Date.now();
|
||||
const chat = this.chats[chatId];
|
||||
if (chat) {
|
||||
await Promise.all(
|
||||
chat.members.map(async (member) => {
|
||||
const chatMessage = ChatMessage.createMessage(now, now, chatId, {
|
||||
text,
|
||||
contentType: ContentType.Text,
|
||||
});
|
||||
const wakuMessage = await WakuMessage.fromBytes(
|
||||
chatMessage.encode(),
|
||||
await getNegotiatedTopic(this.identity, member)
|
||||
);
|
||||
this.waku.relay.send(wakuMessage);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async decodeUpdateMessage(
|
||||
message: WakuMessage,
|
||||
useCallback: boolean
|
||||
): Promise<void> {
|
||||
try {
|
||||
if (message.payload) {
|
||||
const membershipUpdate = MembershipUpdateMessage.decode(
|
||||
message?.payload
|
||||
);
|
||||
if (membershipUpdate.events.length > 0) {
|
||||
if (
|
||||
membershipUpdate.events[0].event.type ==
|
||||
MembershipUpdateEvent_EventType.CHAT_CREATED
|
||||
) {
|
||||
await this.addChat(
|
||||
{
|
||||
chatId: membershipUpdate.chatId,
|
||||
members: membershipUpdate.events[0].event.members,
|
||||
},
|
||||
useCallback
|
||||
);
|
||||
}
|
||||
if (
|
||||
membershipUpdate.events[0].event.type ==
|
||||
MembershipUpdateEvent_EventType.MEMBER_REMOVED
|
||||
) {
|
||||
if (
|
||||
membershipUpdate.events[0].event.members[0] ==
|
||||
bufToHex(this.identity.publicKey)
|
||||
) {
|
||||
await this.removeChat(
|
||||
{
|
||||
chatId: membershipUpdate.chatId,
|
||||
members: membershipUpdate.events[0].event.members,
|
||||
},
|
||||
useCallback
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private handleWakuChatMessage(
|
||||
message: WakuMessage,
|
||||
chat: GroupChat,
|
||||
member: string
|
||||
): void {
|
||||
try {
|
||||
if (message.payload) {
|
||||
const chatMessage = ChatMessage.decode(message.payload);
|
||||
if (chatMessage) {
|
||||
if (chatMessage.chatId === chat.chatId) {
|
||||
this.addMessage(chatMessage, member);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private async handleChatObserver(
|
||||
chat: GroupChat,
|
||||
removeObserver?: boolean
|
||||
): Promise<void> {
|
||||
const observerFunction = removeObserver ? "deleteObserver" : "addObserver";
|
||||
await Promise.all(
|
||||
chat.members.map(async (member) => {
|
||||
const topic = await getNegotiatedTopic(this.identity, member);
|
||||
this.waku.relay[observerFunction](
|
||||
(message) => this.handleWakuChatMessage(message, chat, member),
|
||||
[topic]
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private async addChat(chat: GroupChat, useCallback: boolean): Promise<void> {
|
||||
this.chats[chat.chatId] = chat;
|
||||
if (useCallback) {
|
||||
await this.handleChatObserver(chat);
|
||||
this.callback(chat);
|
||||
}
|
||||
}
|
||||
|
||||
private async removeChat(
|
||||
chat: GroupChat,
|
||||
useCallback: boolean
|
||||
): Promise<void> {
|
||||
delete this.chats[chat.chatId];
|
||||
if (useCallback) {
|
||||
await this.handleChatObserver(chat, true);
|
||||
this.removeCallback(chat);
|
||||
}
|
||||
}
|
||||
|
||||
private async listen(): Promise<void> {
|
||||
const messages = await this.waku.store.queryHistory([
|
||||
getPartitionedTopic(bufToHex(this.identity.publicKey)),
|
||||
]);
|
||||
messages.sort((a, b) =>
|
||||
(a?.timestamp?.getTime() ?? 0) < (b?.timestamp?.getTime() ?? 0) ? -1 : 1
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
messages.map(
|
||||
async (message) => await this.decodeUpdateMessage(message, false)
|
||||
)
|
||||
);
|
||||
await Promise.all(
|
||||
Object.values(this.chats).map(async (chat) => {
|
||||
await this.handleChatObserver(chat);
|
||||
this.callback(chat);
|
||||
})
|
||||
);
|
||||
this.waku.relay.addObserver(
|
||||
(message) => this.decodeUpdateMessage(message, true),
|
||||
[getPartitionedTopic(bufToHex(this.identity.publicKey))]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a create group chat membership update message with given members
|
||||
*
|
||||
* @param members a list of public keys of members to be included in private group chat
|
||||
*/
|
||||
public async createGroupChat(members: string[]): Promise<void> {
|
||||
const payload = MembershipUpdateMessage.createChat(
|
||||
this.identity,
|
||||
members
|
||||
).encode();
|
||||
const wakuMessages = await Promise.all(
|
||||
members.map(
|
||||
async (member) =>
|
||||
await WakuMessage.fromBytes(payload, getPartitionedTopic(member))
|
||||
)
|
||||
);
|
||||
wakuMessages.forEach((msg) => this.waku.relay.send(msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a remove member to private group chat
|
||||
*
|
||||
* @param chatId id of private group chat
|
||||
*/
|
||||
public async quitChat(chatId: string): Promise<void> {
|
||||
const payload = MembershipUpdateMessage.create(chatId, this.identity);
|
||||
const chat = this.chats[chatId];
|
||||
payload.addMemberRemovedEvent(bufToHex(this.identity.publicKey));
|
||||
const wakuMessages = await Promise.all(
|
||||
chat.members.map(
|
||||
async (member) =>
|
||||
await WakuMessage.fromBytes(
|
||||
payload.encode(),
|
||||
getPartitionedTopic(member)
|
||||
)
|
||||
)
|
||||
);
|
||||
wakuMessages.forEach((msg) => this.waku.relay.send(msg));
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ export { Messenger } from "./messenger";
|
||||
export { Community } from "./community";
|
||||
export { Contacts } from "./contacts";
|
||||
export { Chat } from "./chat";
|
||||
export * from "./groupChats";
|
||||
export * as utils from "./utils";
|
||||
export { ApplicationMetadataMessage } from "./wire/application_metadata_message";
|
||||
export {
|
||||
|
@ -0,0 +1,328 @@
|
||||
/* eslint-disable */
|
||||
import Long from "long";
|
||||
import _m0 from "protobufjs/minimal";
|
||||
import {
|
||||
MessageType,
|
||||
messageTypeFromJSON,
|
||||
messageTypeToJSON,
|
||||
} from "../../communities/v1/enums";
|
||||
|
||||
export const protobufPackage = "communities.v1";
|
||||
|
||||
export interface EmojiReaction {
|
||||
/** clock Lamport timestamp of the chat message */
|
||||
clock: number;
|
||||
/**
|
||||
* chat_id the ID of the chat the message belongs to, for query efficiency the chat_id is stored in the db even though the
|
||||
* target message also stores the chat_id
|
||||
*/
|
||||
chatId: string;
|
||||
/** message_id the ID of the target message that the user wishes to react to */
|
||||
messageId: string;
|
||||
/** message_type is (somewhat confusingly) the ID of the type of chat the message belongs to */
|
||||
messageType: MessageType;
|
||||
/** type the ID of the emoji the user wishes to react with */
|
||||
type: EmojiReaction_Type;
|
||||
/** whether this is a rectraction of a previously sent emoji */
|
||||
retracted: boolean;
|
||||
/** Grant for organisation chat messages */
|
||||
grant: Uint8Array;
|
||||
}
|
||||
|
||||
export enum EmojiReaction_Type {
|
||||
UNKNOWN_EMOJI_REACTION_TYPE = 0,
|
||||
LOVE = 1,
|
||||
THUMBS_UP = 2,
|
||||
THUMBS_DOWN = 3,
|
||||
LAUGH = 4,
|
||||
SAD = 5,
|
||||
ANGRY = 6,
|
||||
UNRECOGNIZED = -1,
|
||||
}
|
||||
|
||||
export function emojiReaction_TypeFromJSON(object: any): EmojiReaction_Type {
|
||||
switch (object) {
|
||||
case 0:
|
||||
case "UNKNOWN_EMOJI_REACTION_TYPE":
|
||||
return EmojiReaction_Type.UNKNOWN_EMOJI_REACTION_TYPE;
|
||||
case 1:
|
||||
case "LOVE":
|
||||
return EmojiReaction_Type.LOVE;
|
||||
case 2:
|
||||
case "THUMBS_UP":
|
||||
return EmojiReaction_Type.THUMBS_UP;
|
||||
case 3:
|
||||
case "THUMBS_DOWN":
|
||||
return EmojiReaction_Type.THUMBS_DOWN;
|
||||
case 4:
|
||||
case "LAUGH":
|
||||
return EmojiReaction_Type.LAUGH;
|
||||
case 5:
|
||||
case "SAD":
|
||||
return EmojiReaction_Type.SAD;
|
||||
case 6:
|
||||
case "ANGRY":
|
||||
return EmojiReaction_Type.ANGRY;
|
||||
case -1:
|
||||
case "UNRECOGNIZED":
|
||||
default:
|
||||
return EmojiReaction_Type.UNRECOGNIZED;
|
||||
}
|
||||
}
|
||||
|
||||
export function emojiReaction_TypeToJSON(object: EmojiReaction_Type): string {
|
||||
switch (object) {
|
||||
case EmojiReaction_Type.UNKNOWN_EMOJI_REACTION_TYPE:
|
||||
return "UNKNOWN_EMOJI_REACTION_TYPE";
|
||||
case EmojiReaction_Type.LOVE:
|
||||
return "LOVE";
|
||||
case EmojiReaction_Type.THUMBS_UP:
|
||||
return "THUMBS_UP";
|
||||
case EmojiReaction_Type.THUMBS_DOWN:
|
||||
return "THUMBS_DOWN";
|
||||
case EmojiReaction_Type.LAUGH:
|
||||
return "LAUGH";
|
||||
case EmojiReaction_Type.SAD:
|
||||
return "SAD";
|
||||
case EmojiReaction_Type.ANGRY:
|
||||
return "ANGRY";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const baseEmojiReaction: object = {
|
||||
clock: 0,
|
||||
chatId: "",
|
||||
messageId: "",
|
||||
messageType: 0,
|
||||
type: 0,
|
||||
retracted: false,
|
||||
};
|
||||
|
||||
export const EmojiReaction = {
|
||||
encode(
|
||||
message: EmojiReaction,
|
||||
writer: _m0.Writer = _m0.Writer.create()
|
||||
): _m0.Writer {
|
||||
if (message.clock !== 0) {
|
||||
writer.uint32(8).uint64(message.clock);
|
||||
}
|
||||
if (message.chatId !== "") {
|
||||
writer.uint32(18).string(message.chatId);
|
||||
}
|
||||
if (message.messageId !== "") {
|
||||
writer.uint32(26).string(message.messageId);
|
||||
}
|
||||
if (message.messageType !== 0) {
|
||||
writer.uint32(32).int32(message.messageType);
|
||||
}
|
||||
if (message.type !== 0) {
|
||||
writer.uint32(40).int32(message.type);
|
||||
}
|
||||
if (message.retracted === true) {
|
||||
writer.uint32(48).bool(message.retracted);
|
||||
}
|
||||
if (message.grant.length !== 0) {
|
||||
writer.uint32(58).bytes(message.grant);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(input: _m0.Reader | Uint8Array, length?: number): EmojiReaction {
|
||||
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = { ...baseEmojiReaction } as EmojiReaction;
|
||||
message.grant = new Uint8Array();
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32();
|
||||
switch (tag >>> 3) {
|
||||
case 1:
|
||||
message.clock = longToNumber(reader.uint64() as Long);
|
||||
break;
|
||||
case 2:
|
||||
message.chatId = reader.string();
|
||||
break;
|
||||
case 3:
|
||||
message.messageId = reader.string();
|
||||
break;
|
||||
case 4:
|
||||
message.messageType = reader.int32() as any;
|
||||
break;
|
||||
case 5:
|
||||
message.type = reader.int32() as any;
|
||||
break;
|
||||
case 6:
|
||||
message.retracted = reader.bool();
|
||||
break;
|
||||
case 7:
|
||||
message.grant = reader.bytes();
|
||||
break;
|
||||
default:
|
||||
reader.skipType(tag & 7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return message;
|
||||
},
|
||||
|
||||
fromJSON(object: any): EmojiReaction {
|
||||
const message = { ...baseEmojiReaction } as EmojiReaction;
|
||||
message.grant = new Uint8Array();
|
||||
if (object.clock !== undefined && object.clock !== null) {
|
||||
message.clock = Number(object.clock);
|
||||
} else {
|
||||
message.clock = 0;
|
||||
}
|
||||
if (object.chatId !== undefined && object.chatId !== null) {
|
||||
message.chatId = String(object.chatId);
|
||||
} else {
|
||||
message.chatId = "";
|
||||
}
|
||||
if (object.messageId !== undefined && object.messageId !== null) {
|
||||
message.messageId = String(object.messageId);
|
||||
} else {
|
||||
message.messageId = "";
|
||||
}
|
||||
if (object.messageType !== undefined && object.messageType !== null) {
|
||||
message.messageType = messageTypeFromJSON(object.messageType);
|
||||
} else {
|
||||
message.messageType = 0;
|
||||
}
|
||||
if (object.type !== undefined && object.type !== null) {
|
||||
message.type = emojiReaction_TypeFromJSON(object.type);
|
||||
} else {
|
||||
message.type = 0;
|
||||
}
|
||||
if (object.retracted !== undefined && object.retracted !== null) {
|
||||
message.retracted = Boolean(object.retracted);
|
||||
} else {
|
||||
message.retracted = false;
|
||||
}
|
||||
if (object.grant !== undefined && object.grant !== null) {
|
||||
message.grant = bytesFromBase64(object.grant);
|
||||
}
|
||||
return message;
|
||||
},
|
||||
|
||||
toJSON(message: EmojiReaction): unknown {
|
||||
const obj: any = {};
|
||||
message.clock !== undefined && (obj.clock = message.clock);
|
||||
message.chatId !== undefined && (obj.chatId = message.chatId);
|
||||
message.messageId !== undefined && (obj.messageId = message.messageId);
|
||||
message.messageType !== undefined &&
|
||||
(obj.messageType = messageTypeToJSON(message.messageType));
|
||||
message.type !== undefined &&
|
||||
(obj.type = emojiReaction_TypeToJSON(message.type));
|
||||
message.retracted !== undefined && (obj.retracted = message.retracted);
|
||||
message.grant !== undefined &&
|
||||
(obj.grant = base64FromBytes(
|
||||
message.grant !== undefined ? message.grant : new Uint8Array()
|
||||
));
|
||||
return obj;
|
||||
},
|
||||
|
||||
fromPartial(object: DeepPartial<EmojiReaction>): EmojiReaction {
|
||||
const message = { ...baseEmojiReaction } as EmojiReaction;
|
||||
if (object.clock !== undefined && object.clock !== null) {
|
||||
message.clock = object.clock;
|
||||
} else {
|
||||
message.clock = 0;
|
||||
}
|
||||
if (object.chatId !== undefined && object.chatId !== null) {
|
||||
message.chatId = object.chatId;
|
||||
} else {
|
||||
message.chatId = "";
|
||||
}
|
||||
if (object.messageId !== undefined && object.messageId !== null) {
|
||||
message.messageId = object.messageId;
|
||||
} else {
|
||||
message.messageId = "";
|
||||
}
|
||||
if (object.messageType !== undefined && object.messageType !== null) {
|
||||
message.messageType = object.messageType;
|
||||
} else {
|
||||
message.messageType = 0;
|
||||
}
|
||||
if (object.type !== undefined && object.type !== null) {
|
||||
message.type = object.type;
|
||||
} else {
|
||||
message.type = 0;
|
||||
}
|
||||
if (object.retracted !== undefined && object.retracted !== null) {
|
||||
message.retracted = object.retracted;
|
||||
} else {
|
||||
message.retracted = false;
|
||||
}
|
||||
if (object.grant !== undefined && object.grant !== null) {
|
||||
message.grant = object.grant;
|
||||
} else {
|
||||
message.grant = new Uint8Array();
|
||||
}
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
declare var self: any | undefined;
|
||||
declare var window: any | undefined;
|
||||
declare var global: any | undefined;
|
||||
var globalThis: any = (() => {
|
||||
if (typeof globalThis !== "undefined") return globalThis;
|
||||
if (typeof self !== "undefined") return self;
|
||||
if (typeof window !== "undefined") return window;
|
||||
if (typeof global !== "undefined") return global;
|
||||
throw "Unable to locate global object";
|
||||
})();
|
||||
|
||||
const atob: (b64: string) => string =
|
||||
globalThis.atob ||
|
||||
((b64) => globalThis.Buffer.from(b64, "base64").toString("binary"));
|
||||
function bytesFromBase64(b64: string): Uint8Array {
|
||||
const bin = atob(b64);
|
||||
const arr = new Uint8Array(bin.length);
|
||||
for (let i = 0; i < bin.length; ++i) {
|
||||
arr[i] = bin.charCodeAt(i);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
const btoa: (bin: string) => string =
|
||||
globalThis.btoa ||
|
||||
((bin) => globalThis.Buffer.from(bin, "binary").toString("base64"));
|
||||
function base64FromBytes(arr: Uint8Array): string {
|
||||
const bin: string[] = [];
|
||||
for (const byte of arr) {
|
||||
bin.push(String.fromCharCode(byte));
|
||||
}
|
||||
return btoa(bin.join(""));
|
||||
}
|
||||
|
||||
type Builtin =
|
||||
| Date
|
||||
| Function
|
||||
| Uint8Array
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| undefined;
|
||||
export type DeepPartial<T> = T extends Builtin
|
||||
? T
|
||||
: T extends Array<infer U>
|
||||
? Array<DeepPartial<U>>
|
||||
: T extends ReadonlyArray<infer U>
|
||||
? ReadonlyArray<DeepPartial<U>>
|
||||
: T extends {}
|
||||
? { [K in keyof T]?: DeepPartial<T[K]> }
|
||||
: Partial<T>;
|
||||
|
||||
function longToNumber(long: Long): number {
|
||||
if (long.gt(Number.MAX_SAFE_INTEGER)) {
|
||||
throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
|
||||
}
|
||||
return long.toNumber();
|
||||
}
|
||||
|
||||
if (_m0.util.Long !== Long) {
|
||||
_m0.util.Long = Long as any;
|
||||
_m0.configure();
|
||||
}
|
@ -0,0 +1,436 @@
|
||||
/* eslint-disable */
|
||||
import Long from "long";
|
||||
import _m0 from "protobufjs/minimal";
|
||||
import { ChatMessage } from "../../communities/v1/chat_message";
|
||||
import { EmojiReaction } from "../../communities/v1/emoji_reaction";
|
||||
|
||||
export const protobufPackage = "communities.v1";
|
||||
|
||||
export interface MembershipUpdateEvent {
|
||||
/** Lamport timestamp of the event */
|
||||
clock: number;
|
||||
/** List of public keys of objects of the action */
|
||||
members: string[];
|
||||
/** Name of the chat for the CHAT_CREATED/NAME_CHANGED event types */
|
||||
name: string;
|
||||
/** The type of the event */
|
||||
type: MembershipUpdateEvent_EventType;
|
||||
}
|
||||
|
||||
export enum MembershipUpdateEvent_EventType {
|
||||
UNKNOWN = 0,
|
||||
CHAT_CREATED = 1,
|
||||
NAME_CHANGED = 2,
|
||||
MEMBERS_ADDED = 3,
|
||||
MEMBER_JOINED = 4,
|
||||
MEMBER_REMOVED = 5,
|
||||
ADMINS_ADDED = 6,
|
||||
ADMIN_REMOVED = 7,
|
||||
UNRECOGNIZED = -1,
|
||||
}
|
||||
|
||||
export function membershipUpdateEvent_EventTypeFromJSON(
|
||||
object: any
|
||||
): MembershipUpdateEvent_EventType {
|
||||
switch (object) {
|
||||
case 0:
|
||||
case "UNKNOWN":
|
||||
return MembershipUpdateEvent_EventType.UNKNOWN;
|
||||
case 1:
|
||||
case "CHAT_CREATED":
|
||||
return MembershipUpdateEvent_EventType.CHAT_CREATED;
|
||||
case 2:
|
||||
case "NAME_CHANGED":
|
||||
return MembershipUpdateEvent_EventType.NAME_CHANGED;
|
||||
case 3:
|
||||
case "MEMBERS_ADDED":
|
||||
return MembershipUpdateEvent_EventType.MEMBERS_ADDED;
|
||||
case 4:
|
||||
case "MEMBER_JOINED":
|
||||
return MembershipUpdateEvent_EventType.MEMBER_JOINED;
|
||||
case 5:
|
||||
case "MEMBER_REMOVED":
|
||||
return MembershipUpdateEvent_EventType.MEMBER_REMOVED;
|
||||
case 6:
|
||||
case "ADMINS_ADDED":
|
||||
return MembershipUpdateEvent_EventType.ADMINS_ADDED;
|
||||
case 7:
|
||||
case "ADMIN_REMOVED":
|
||||
return MembershipUpdateEvent_EventType.ADMIN_REMOVED;
|
||||
case -1:
|
||||
case "UNRECOGNIZED":
|
||||
default:
|
||||
return MembershipUpdateEvent_EventType.UNRECOGNIZED;
|
||||
}
|
||||
}
|
||||
|
||||
export function membershipUpdateEvent_EventTypeToJSON(
|
||||
object: MembershipUpdateEvent_EventType
|
||||
): string {
|
||||
switch (object) {
|
||||
case MembershipUpdateEvent_EventType.UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
case MembershipUpdateEvent_EventType.CHAT_CREATED:
|
||||
return "CHAT_CREATED";
|
||||
case MembershipUpdateEvent_EventType.NAME_CHANGED:
|
||||
return "NAME_CHANGED";
|
||||
case MembershipUpdateEvent_EventType.MEMBERS_ADDED:
|
||||
return "MEMBERS_ADDED";
|
||||
case MembershipUpdateEvent_EventType.MEMBER_JOINED:
|
||||
return "MEMBER_JOINED";
|
||||
case MembershipUpdateEvent_EventType.MEMBER_REMOVED:
|
||||
return "MEMBER_REMOVED";
|
||||
case MembershipUpdateEvent_EventType.ADMINS_ADDED:
|
||||
return "ADMINS_ADDED";
|
||||
case MembershipUpdateEvent_EventType.ADMIN_REMOVED:
|
||||
return "ADMIN_REMOVED";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MembershipUpdateMessage is a message used to propagate information
|
||||
* about group membership changes.
|
||||
* For more information, see https://github.com/status-im/specs/blob/master/status-group-chats-spec.md.
|
||||
*/
|
||||
export interface MembershipUpdateMessage {
|
||||
/** The chat id of the private group chat */
|
||||
chatId: string;
|
||||
/**
|
||||
* A list of events for this group chat, first x bytes are the signature, then is a
|
||||
* protobuf encoded MembershipUpdateEvent
|
||||
*/
|
||||
events: Uint8Array[];
|
||||
message: ChatMessage | undefined;
|
||||
emojiReaction: EmojiReaction | undefined;
|
||||
}
|
||||
|
||||
const baseMembershipUpdateEvent: object = {
|
||||
clock: 0,
|
||||
members: "",
|
||||
name: "",
|
||||
type: 0,
|
||||
};
|
||||
|
||||
export const MembershipUpdateEvent = {
|
||||
encode(
|
||||
message: MembershipUpdateEvent,
|
||||
writer: _m0.Writer = _m0.Writer.create()
|
||||
): _m0.Writer {
|
||||
if (message.clock !== 0) {
|
||||
writer.uint32(8).uint64(message.clock);
|
||||
}
|
||||
for (const v of message.members) {
|
||||
writer.uint32(18).string(v!);
|
||||
}
|
||||
if (message.name !== "") {
|
||||
writer.uint32(26).string(message.name);
|
||||
}
|
||||
if (message.type !== 0) {
|
||||
writer.uint32(32).int32(message.type);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(
|
||||
input: _m0.Reader | Uint8Array,
|
||||
length?: number
|
||||
): MembershipUpdateEvent {
|
||||
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = { ...baseMembershipUpdateEvent } as MembershipUpdateEvent;
|
||||
message.members = [];
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32();
|
||||
switch (tag >>> 3) {
|
||||
case 1:
|
||||
message.clock = longToNumber(reader.uint64() as Long);
|
||||
break;
|
||||
case 2:
|
||||
message.members.push(reader.string());
|
||||
break;
|
||||
case 3:
|
||||
message.name = reader.string();
|
||||
break;
|
||||
case 4:
|
||||
message.type = reader.int32() as any;
|
||||
break;
|
||||
default:
|
||||
reader.skipType(tag & 7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return message;
|
||||
},
|
||||
|
||||
fromJSON(object: any): MembershipUpdateEvent {
|
||||
const message = { ...baseMembershipUpdateEvent } as MembershipUpdateEvent;
|
||||
message.members = [];
|
||||
if (object.clock !== undefined && object.clock !== null) {
|
||||
message.clock = Number(object.clock);
|
||||
} else {
|
||||
message.clock = 0;
|
||||
}
|
||||
if (object.members !== undefined && object.members !== null) {
|
||||
for (const e of object.members) {
|
||||
message.members.push(String(e));
|
||||
}
|
||||
}
|
||||
if (object.name !== undefined && object.name !== null) {
|
||||
message.name = String(object.name);
|
||||
} else {
|
||||
message.name = "";
|
||||
}
|
||||
if (object.type !== undefined && object.type !== null) {
|
||||
message.type = membershipUpdateEvent_EventTypeFromJSON(object.type);
|
||||
} else {
|
||||
message.type = 0;
|
||||
}
|
||||
return message;
|
||||
},
|
||||
|
||||
toJSON(message: MembershipUpdateEvent): unknown {
|
||||
const obj: any = {};
|
||||
message.clock !== undefined && (obj.clock = message.clock);
|
||||
if (message.members) {
|
||||
obj.members = message.members.map((e) => e);
|
||||
} else {
|
||||
obj.members = [];
|
||||
}
|
||||
message.name !== undefined && (obj.name = message.name);
|
||||
message.type !== undefined &&
|
||||
(obj.type = membershipUpdateEvent_EventTypeToJSON(message.type));
|
||||
return obj;
|
||||
},
|
||||
|
||||
fromPartial(
|
||||
object: DeepPartial<MembershipUpdateEvent>
|
||||
): MembershipUpdateEvent {
|
||||
const message = { ...baseMembershipUpdateEvent } as MembershipUpdateEvent;
|
||||
message.members = [];
|
||||
if (object.clock !== undefined && object.clock !== null) {
|
||||
message.clock = object.clock;
|
||||
} else {
|
||||
message.clock = 0;
|
||||
}
|
||||
if (object.members !== undefined && object.members !== null) {
|
||||
for (const e of object.members) {
|
||||
message.members.push(e);
|
||||
}
|
||||
}
|
||||
if (object.name !== undefined && object.name !== null) {
|
||||
message.name = object.name;
|
||||
} else {
|
||||
message.name = "";
|
||||
}
|
||||
if (object.type !== undefined && object.type !== null) {
|
||||
message.type = object.type;
|
||||
} else {
|
||||
message.type = 0;
|
||||
}
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
const baseMembershipUpdateMessage: object = { chatId: "" };
|
||||
|
||||
export const MembershipUpdateMessage = {
|
||||
encode(
|
||||
message: MembershipUpdateMessage,
|
||||
writer: _m0.Writer = _m0.Writer.create()
|
||||
): _m0.Writer {
|
||||
if (message.chatId !== "") {
|
||||
writer.uint32(10).string(message.chatId);
|
||||
}
|
||||
for (const v of message.events) {
|
||||
writer.uint32(18).bytes(v!);
|
||||
}
|
||||
if (message.message !== undefined) {
|
||||
ChatMessage.encode(message.message, writer.uint32(26).fork()).ldelim();
|
||||
}
|
||||
if (message.emojiReaction !== undefined) {
|
||||
EmojiReaction.encode(
|
||||
message.emojiReaction,
|
||||
writer.uint32(34).fork()
|
||||
).ldelim();
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(
|
||||
input: _m0.Reader | Uint8Array,
|
||||
length?: number
|
||||
): MembershipUpdateMessage {
|
||||
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = {
|
||||
...baseMembershipUpdateMessage,
|
||||
} as MembershipUpdateMessage;
|
||||
message.events = [];
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32();
|
||||
switch (tag >>> 3) {
|
||||
case 1:
|
||||
message.chatId = reader.string();
|
||||
break;
|
||||
case 2:
|
||||
message.events.push(reader.bytes());
|
||||
break;
|
||||
case 3:
|
||||
message.message = ChatMessage.decode(reader, reader.uint32());
|
||||
break;
|
||||
case 4:
|
||||
message.emojiReaction = EmojiReaction.decode(reader, reader.uint32());
|
||||
break;
|
||||
default:
|
||||
reader.skipType(tag & 7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return message;
|
||||
},
|
||||
|
||||
fromJSON(object: any): MembershipUpdateMessage {
|
||||
const message = {
|
||||
...baseMembershipUpdateMessage,
|
||||
} as MembershipUpdateMessage;
|
||||
message.events = [];
|
||||
if (object.chatId !== undefined && object.chatId !== null) {
|
||||
message.chatId = String(object.chatId);
|
||||
} else {
|
||||
message.chatId = "";
|
||||
}
|
||||
if (object.events !== undefined && object.events !== null) {
|
||||
for (const e of object.events) {
|
||||
message.events.push(bytesFromBase64(e));
|
||||
}
|
||||
}
|
||||
if (object.message !== undefined && object.message !== null) {
|
||||
message.message = ChatMessage.fromJSON(object.message);
|
||||
} else {
|
||||
message.message = undefined;
|
||||
}
|
||||
if (object.emojiReaction !== undefined && object.emojiReaction !== null) {
|
||||
message.emojiReaction = EmojiReaction.fromJSON(object.emojiReaction);
|
||||
} else {
|
||||
message.emojiReaction = undefined;
|
||||
}
|
||||
return message;
|
||||
},
|
||||
|
||||
toJSON(message: MembershipUpdateMessage): unknown {
|
||||
const obj: any = {};
|
||||
message.chatId !== undefined && (obj.chatId = message.chatId);
|
||||
if (message.events) {
|
||||
obj.events = message.events.map((e) =>
|
||||
base64FromBytes(e !== undefined ? e : new Uint8Array())
|
||||
);
|
||||
} else {
|
||||
obj.events = [];
|
||||
}
|
||||
message.message !== undefined &&
|
||||
(obj.message = message.message
|
||||
? ChatMessage.toJSON(message.message)
|
||||
: undefined);
|
||||
message.emojiReaction !== undefined &&
|
||||
(obj.emojiReaction = message.emojiReaction
|
||||
? EmojiReaction.toJSON(message.emojiReaction)
|
||||
: undefined);
|
||||
return obj;
|
||||
},
|
||||
|
||||
fromPartial(
|
||||
object: DeepPartial<MembershipUpdateMessage>
|
||||
): MembershipUpdateMessage {
|
||||
const message = {
|
||||
...baseMembershipUpdateMessage,
|
||||
} as MembershipUpdateMessage;
|
||||
message.events = [];
|
||||
if (object.chatId !== undefined && object.chatId !== null) {
|
||||
message.chatId = object.chatId;
|
||||
} else {
|
||||
message.chatId = "";
|
||||
}
|
||||
if (object.events !== undefined && object.events !== null) {
|
||||
for (const e of object.events) {
|
||||
message.events.push(e);
|
||||
}
|
||||
}
|
||||
if (object.message !== undefined && object.message !== null) {
|
||||
message.message = ChatMessage.fromPartial(object.message);
|
||||
} else {
|
||||
message.message = undefined;
|
||||
}
|
||||
if (object.emojiReaction !== undefined && object.emojiReaction !== null) {
|
||||
message.emojiReaction = EmojiReaction.fromPartial(object.emojiReaction);
|
||||
} else {
|
||||
message.emojiReaction = undefined;
|
||||
}
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
declare var self: any | undefined;
|
||||
declare var window: any | undefined;
|
||||
declare var global: any | undefined;
|
||||
var globalThis: any = (() => {
|
||||
if (typeof globalThis !== "undefined") return globalThis;
|
||||
if (typeof self !== "undefined") return self;
|
||||
if (typeof window !== "undefined") return window;
|
||||
if (typeof global !== "undefined") return global;
|
||||
throw "Unable to locate global object";
|
||||
})();
|
||||
|
||||
const atob: (b64: string) => string =
|
||||
globalThis.atob ||
|
||||
((b64) => globalThis.Buffer.from(b64, "base64").toString("binary"));
|
||||
function bytesFromBase64(b64: string): Uint8Array {
|
||||
const bin = atob(b64);
|
||||
const arr = new Uint8Array(bin.length);
|
||||
for (let i = 0; i < bin.length; ++i) {
|
||||
arr[i] = bin.charCodeAt(i);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
const btoa: (bin: string) => string =
|
||||
globalThis.btoa ||
|
||||
((bin) => globalThis.Buffer.from(bin, "binary").toString("base64"));
|
||||
function base64FromBytes(arr: Uint8Array): string {
|
||||
const bin: string[] = [];
|
||||
for (const byte of arr) {
|
||||
bin.push(String.fromCharCode(byte));
|
||||
}
|
||||
return btoa(bin.join(""));
|
||||
}
|
||||
|
||||
type Builtin =
|
||||
| Date
|
||||
| Function
|
||||
| Uint8Array
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| undefined;
|
||||
export type DeepPartial<T> = T extends Builtin
|
||||
? T
|
||||
: T extends Array<infer U>
|
||||
? Array<DeepPartial<U>>
|
||||
: T extends ReadonlyArray<infer U>
|
||||
? ReadonlyArray<DeepPartial<U>>
|
||||
: T extends {}
|
||||
? { [K in keyof T]?: DeepPartial<T[K]> }
|
||||
: Partial<T>;
|
||||
|
||||
function longToNumber(long: Long): number {
|
||||
if (long.gt(Number.MAX_SAFE_INTEGER)) {
|
||||
throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
|
||||
}
|
||||
return long.toNumber();
|
||||
}
|
||||
|
||||
if (_m0.util.Long !== Long) {
|
||||
_m0.util.Long = Long as any;
|
||||
_m0.configure();
|
||||
}
|
46
packages/status-communities/src/topics.ts
Normal file
46
packages/status-communities/src/topics.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { BN } from "bn.js";
|
||||
import { derive } from "ecies-geth";
|
||||
import { ec } from "elliptic";
|
||||
import { bufToHex } from "js-waku/build/main/lib/utils";
|
||||
|
||||
import { idToContentTopic } from "./contentTopic";
|
||||
import { hexToBuf } from "./utils";
|
||||
|
||||
import { Identity } from ".";
|
||||
|
||||
const EC = new ec("secp256k1");
|
||||
const partitionsNum = new BN(5000);
|
||||
|
||||
/**
|
||||
* Get the partitioned topic https://specs.status.im/spec/3#partitioned-topic
|
||||
* @param publicKey Public key of recipient
|
||||
* @returns string The Waku v2 Content Topic.
|
||||
*/
|
||||
export function getPartitionedTopic(publicKey: string): string {
|
||||
const key = EC.keyFromPublic(publicKey.slice(2), "hex");
|
||||
const X = key.getPublic().getX();
|
||||
|
||||
const partition = X.mod(partitionsNum);
|
||||
|
||||
const partitionTopic = `contact-discovery-${partition.toString()}`;
|
||||
|
||||
return idToContentTopic(partitionTopic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the negotiated topic https://specs.status.im/spec/3#negotiated-topic
|
||||
* @param identity identity of user
|
||||
* @param publicKey Public key of recipient
|
||||
* @returns string The Waku v2 Content Topic.
|
||||
*/
|
||||
export async function getNegotiatedTopic(
|
||||
identity: Identity,
|
||||
publicKey: string
|
||||
): Promise<string> {
|
||||
const key = EC.keyFromPublic(publicKey.slice(2), "hex");
|
||||
const sharedSecret = await derive(
|
||||
Buffer.from(identity.privateKey),
|
||||
hexToBuf(key.getPublic("hex"))
|
||||
);
|
||||
return idToContentTopic(bufToHex(sharedSecret));
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
import { Reader } from "protobufjs";
|
||||
import { v4 as uuidV4 } from "uuid";
|
||||
|
||||
import { Identity } from "..";
|
||||
import * as proto from "../proto/communities/v1/membership_update_message";
|
||||
import { bufToHex, hexToBuf } from "../utils";
|
||||
|
||||
export class MembershipUpdateEvent {
|
||||
public constructor(public proto: proto.MembershipUpdateEvent) {}
|
||||
|
||||
static decode(bytes: Uint8Array): MembershipUpdateEvent {
|
||||
const protoBuf = proto.MembershipUpdateEvent.decode(Reader.create(bytes));
|
||||
return new MembershipUpdateEvent(protoBuf);
|
||||
}
|
||||
|
||||
encode(): Uint8Array {
|
||||
return proto.MembershipUpdateEvent.encode(this.proto).finish();
|
||||
}
|
||||
|
||||
public get members(): string[] {
|
||||
return this.proto.members;
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
return this.proto.name;
|
||||
}
|
||||
|
||||
public get clock(): number {
|
||||
return this.proto.clock;
|
||||
}
|
||||
|
||||
public get type(): proto.MembershipUpdateEvent_EventType {
|
||||
return this.proto.type;
|
||||
}
|
||||
}
|
||||
|
||||
export class MembershipUpdateMessage {
|
||||
private clock: number = Date.now();
|
||||
private identity: Identity = Identity.generate();
|
||||
public constructor(public proto: proto.MembershipUpdateMessage) {}
|
||||
|
||||
public static create(
|
||||
chatId: string,
|
||||
identity: Identity
|
||||
): MembershipUpdateMessage {
|
||||
const partial = proto.MembershipUpdateMessage.fromPartial({
|
||||
chatId,
|
||||
events: [],
|
||||
});
|
||||
const newMessage = new MembershipUpdateMessage(partial);
|
||||
newMessage.clock = Date.now();
|
||||
newMessage.identity = identity;
|
||||
return newMessage;
|
||||
}
|
||||
|
||||
private addEvent(event: MembershipUpdateEvent): void {
|
||||
const encEvent = event.encode();
|
||||
const eventToSign = Buffer.concat([hexToBuf(this.proto.chatId), encEvent]);
|
||||
const signature = this.identity.sign(eventToSign);
|
||||
this.proto.events.push(Buffer.concat([signature, encEvent]));
|
||||
}
|
||||
|
||||
public static createChat(
|
||||
identity: Identity,
|
||||
members: string[],
|
||||
name?: string
|
||||
): MembershipUpdateMessage {
|
||||
const chatId = `${uuidV4()}-${bufToHex(identity.publicKey)}`;
|
||||
|
||||
const message = this.create(chatId, identity);
|
||||
const type = proto.MembershipUpdateEvent_EventType.CHAT_CREATED;
|
||||
const event = new MembershipUpdateEvent({
|
||||
clock: message.clock,
|
||||
members,
|
||||
name: name ?? "",
|
||||
type,
|
||||
});
|
||||
message.addEvent(event);
|
||||
return message;
|
||||
}
|
||||
|
||||
public addNameChangeEvent(name: string): void {
|
||||
const type = proto.MembershipUpdateEvent_EventType.NAME_CHANGED;
|
||||
const event = new MembershipUpdateEvent({
|
||||
clock: this.clock,
|
||||
members: [],
|
||||
name: name,
|
||||
type,
|
||||
});
|
||||
this.addEvent(event);
|
||||
}
|
||||
|
||||
public addMembersAddedEvent(members: string[]): void {
|
||||
const type = proto.MembershipUpdateEvent_EventType.MEMBERS_ADDED;
|
||||
const event = new MembershipUpdateEvent({
|
||||
clock: this.clock,
|
||||
members,
|
||||
name: "",
|
||||
type,
|
||||
});
|
||||
this.addEvent(event);
|
||||
}
|
||||
|
||||
public addMemberJoinedEvent(member: string): void {
|
||||
const type = proto.MembershipUpdateEvent_EventType.MEMBER_JOINED;
|
||||
const event = new MembershipUpdateEvent({
|
||||
clock: this.clock,
|
||||
members: [member],
|
||||
name: "",
|
||||
type,
|
||||
});
|
||||
this.addEvent(event);
|
||||
}
|
||||
|
||||
public addMemberRemovedEvent(member: string): void {
|
||||
const type = proto.MembershipUpdateEvent_EventType.MEMBER_REMOVED;
|
||||
const event = new MembershipUpdateEvent({
|
||||
clock: this.clock,
|
||||
members: [member],
|
||||
name: "",
|
||||
type,
|
||||
});
|
||||
this.addEvent(event);
|
||||
}
|
||||
|
||||
public addAdminsAddedEvent(members: string[]): void {
|
||||
const type = proto.MembershipUpdateEvent_EventType.ADMINS_ADDED;
|
||||
const event = new MembershipUpdateEvent({
|
||||
clock: this.clock,
|
||||
members,
|
||||
name: "",
|
||||
type,
|
||||
});
|
||||
this.addEvent(event);
|
||||
}
|
||||
|
||||
public addAdminRemovedEvent(member: string): void {
|
||||
const type = proto.MembershipUpdateEvent_EventType.ADMINS_ADDED;
|
||||
const event = new MembershipUpdateEvent({
|
||||
clock: this.clock,
|
||||
members: [member],
|
||||
name: "",
|
||||
type,
|
||||
});
|
||||
this.addEvent(event);
|
||||
}
|
||||
|
||||
static decode(bytes: Uint8Array): MembershipUpdateMessage {
|
||||
const protoBuf = proto.MembershipUpdateMessage.decode(Reader.create(bytes));
|
||||
return new MembershipUpdateMessage(protoBuf);
|
||||
}
|
||||
|
||||
public get events(): {
|
||||
sig: Uint8Array;
|
||||
event: MembershipUpdateEvent;
|
||||
}[] {
|
||||
return this.proto.events.map((bufArray) => {
|
||||
return {
|
||||
sig: bufArray.slice(0, 65),
|
||||
event: MembershipUpdateEvent.decode(bufArray.slice(65)),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public get chatId(): string {
|
||||
return this.proto.chatId;
|
||||
}
|
||||
|
||||
encode(): Uint8Array {
|
||||
return proto.MembershipUpdateMessage.encode(this.proto).finish();
|
||||
}
|
||||
}
|
104
yarn.lock
104
yarn.lock
@ -2,7 +2,7 @@
|
||||
# Manual changes might be lost - proceed with caution!
|
||||
|
||||
__metadata:
|
||||
version: 4
|
||||
version: 5
|
||||
cacheKey: 8
|
||||
|
||||
"@babel/code-frame@npm:7.12.11":
|
||||
@ -234,6 +234,7 @@ __metadata:
|
||||
"@typescript-eslint/eslint-plugin": ^4.29.0
|
||||
"@typescript-eslint/parser": ^4.29.0
|
||||
assert: ^2.0.0
|
||||
browserify-zlib: ^0.2.0
|
||||
buffer: ^6.0.3
|
||||
chai: ^4.3.4
|
||||
crypto-browserify: ^3.12.0
|
||||
@ -245,6 +246,7 @@ __metadata:
|
||||
file-loader: ^6.2.0
|
||||
fork-ts-checker-webpack-plugin: ^6.3.1
|
||||
html-webpack-plugin: ^5.3.2
|
||||
https-browserify: ^1.0.0
|
||||
jsdom: ^16.7.0
|
||||
jsdom-global: ^3.0.2
|
||||
mocha: ^9.0.3
|
||||
@ -257,6 +259,7 @@ __metadata:
|
||||
rimraf: ^3.0.2
|
||||
source-map-loader: ^3.0.0
|
||||
stream-browserify: ^3.0.0
|
||||
stream-http: ^3.2.0
|
||||
style-loader: ^3.3.0
|
||||
styled-components: ^5.3.1
|
||||
ts-loader: ^9.2.5
|
||||
@ -747,6 +750,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/bn.js@npm:*, @types/bn.js@npm:^5.1.0":
|
||||
version: 5.1.0
|
||||
resolution: "@types/bn.js@npm:5.1.0"
|
||||
dependencies:
|
||||
"@types/node": "*"
|
||||
checksum: 1dc1cbbd7a1e8bf3614752e9602f558762a901031f499f3055828b5e3e2bba16e5b88c27b3c4152ad795248fbe4086c731a5c4b0f29bb243f1875beeeabee59c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/chai@npm:^4.2.21, @types/chai@npm:^4.2.22":
|
||||
version: 4.2.22
|
||||
resolution: "@types/chai@npm:4.2.22"
|
||||
@ -763,6 +775,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/elliptic@npm:^6.4.14":
|
||||
version: 6.4.14
|
||||
resolution: "@types/elliptic@npm:6.4.14"
|
||||
dependencies:
|
||||
"@types/bn.js": "*"
|
||||
checksum: d5a64f540e0ed4b74a12dfa5cc88c0aa7b531eab3b7a9fab17948ffbfc6e01814230e63d7417ce1b607dbd8b5d70e1b64f5afac632deabf96e44875aaac0ae1b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/emoji-mart@npm:^3.0.6":
|
||||
version: 3.0.6
|
||||
resolution: "@types/emoji-mart@npm:3.0.6"
|
||||
@ -1054,6 +1075,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/uuid@npm:^8.3.3":
|
||||
version: 8.3.3
|
||||
resolution: "@types/uuid@npm:8.3.3"
|
||||
checksum: 3f340155bb1161f9ffa7163926d6222fea8f3505c23619b72bcc230883354926672c08a06510c7a543f73553c792a84444cc1744cff631b4ba988763e4bd7a8f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/yargs-parser@npm:*":
|
||||
version: 20.2.1
|
||||
resolution: "@types/yargs-parser@npm:20.2.1"
|
||||
@ -2182,7 +2210,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bn.js@npm:^5.0.0, bn.js@npm:^5.1.1":
|
||||
"bn.js@npm:^5.0.0, bn.js@npm:^5.1.1, bn.js@npm:^5.2.0":
|
||||
version: 5.2.0
|
||||
resolution: "bn.js@npm:5.2.0"
|
||||
checksum: 6117170393200f68b35a061ecbf55d01dd989302e7b3c798a3012354fa638d124f0b2f79e63f77be5556be80322a09c40339eda6413ba7468524c0b6d4b4cb7a
|
||||
@ -2366,6 +2394,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"browserify-zlib@npm:^0.2.0":
|
||||
version: 0.2.0
|
||||
resolution: "browserify-zlib@npm:0.2.0"
|
||||
dependencies:
|
||||
pako: ~1.0.5
|
||||
checksum: 5cd9d6a665190fedb4a97dfbad8dabc8698d8a507298a03f42c734e96d58ca35d3c7d4085e283440bbca1cd1938cff85031728079bedb3345310c58ab1ec92d6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"browserslist@npm:^4.14.5":
|
||||
version: 4.17.1
|
||||
resolution: "browserslist@npm:4.17.1"
|
||||
@ -2412,6 +2449,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"builtin-status-codes@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "builtin-status-codes@npm:3.0.0"
|
||||
checksum: 1119429cf4b0d57bf76b248ad6f529167d343156ebbcc4d4e4ad600484f6bc63002595cbb61b67ad03ce55cd1d3c4711c03bbf198bf24653b8392420482f3773
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bytes@npm:3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "bytes@npm:3.0.0"
|
||||
@ -4818,25 +4862,26 @@ fsevents@^1.2.7:
|
||||
bindings: ^1.5.0
|
||||
nan: ^2.12.1
|
||||
checksum: ae855aa737aaa2f9167e9f70417cf6e45a5cd11918e1fee9923709a0149be52416d765433b4aeff56c789b1152e718cd1b13ddec6043b78cdda68260d86383c1
|
||||
conditions: os=darwin
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fsevents@patch:fsevents@^1.2.7#~builtin<compat/fsevents>":
|
||||
version: 1.2.13
|
||||
resolution: "fsevents@patch:fsevents@npm%3A1.2.13#~builtin<compat/fsevents>::version=1.2.13&hash=1cc4b2"
|
||||
resolution: "fsevents@patch:fsevents@npm%3A1.2.13#~builtin<compat/fsevents>::version=1.2.13&hash=18f3a7"
|
||||
dependencies:
|
||||
bindings: ^1.5.0
|
||||
nan: ^2.12.1
|
||||
checksum: b264407498db2cfdcc2a05287334a4160c985a88e4a989e2f2f8dcc6afc8b04a4fcd82c797266442452e11c1fb07d7747d138b078fe4bb1f8f4fd2a6f2484d7e
|
||||
conditions: os=darwin
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fsevents@patch:fsevents@~2.3.2#~builtin<compat/fsevents>":
|
||||
version: 2.3.2
|
||||
resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin<compat/fsevents>::version=2.3.2&hash=1cc4b2"
|
||||
resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin<compat/fsevents>::version=2.3.2&hash=18f3a7"
|
||||
dependencies:
|
||||
node-gyp: latest
|
||||
checksum: 78db9daf1f6526a49cefee3917cc988f62dc7f25b5dd80ad6de4ffc4af7f0cab7491ac737626ff53e482a111bc53aac9e411fe3602458eca36f6a003ecf69c16
|
||||
conditions: os=darwin
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -4846,6 +4891,7 @@ fsevents@~2.3.2:
|
||||
dependencies:
|
||||
node-gyp: latest
|
||||
checksum: 97ade64e75091afee5265e6956cb72ba34db7819b4c3e94c431d4be2b19b8bb7a2d4116da417950c3425f17c8fe693d25e20212cac583ac1521ad066b77ae31f
|
||||
conditions: os=darwin
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -5485,6 +5531,13 @@ fsevents@~2.3.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"https-browserify@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "https-browserify@npm:1.0.0"
|
||||
checksum: 09b35353e42069fde2435760d13f8a3fb7dd9105e358270e2e225b8a94f811b461edd17cb57594e5f36ec1218f121c160ddceeec6e8be2d55e01dcbbbed8cbae
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"https-proxy-agent@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "https-proxy-agent@npm:5.0.0"
|
||||
@ -8584,6 +8637,13 @@ fsevents@~2.3.2:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pako@npm:~1.0.5":
|
||||
version: 1.0.11
|
||||
resolution: "pako@npm:1.0.11"
|
||||
checksum: 1be2bfa1f807608c7538afa15d6f25baa523c30ec870a3228a89579e474a4d992f4293859524e46d5d87fd30fa17c5edf34dbef0671251d9749820b488660b16
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"param-case@npm:^3.0.3":
|
||||
version: 3.0.4
|
||||
resolution: "param-case@npm:3.0.4"
|
||||
@ -9709,21 +9769,21 @@ resolve@^2.0.0-next.3:
|
||||
|
||||
"resolve@patch:resolve@^1.10.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.20.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.9.0#~builtin<compat/resolve>":
|
||||
version: 1.20.0
|
||||
resolution: "resolve@patch:resolve@npm%3A1.20.0#~builtin<compat/resolve>::version=1.20.0&hash=00b1ff"
|
||||
resolution: "resolve@patch:resolve@npm%3A1.20.0#~builtin<compat/resolve>::version=1.20.0&hash=07638b"
|
||||
dependencies:
|
||||
is-core-module: ^2.2.0
|
||||
path-parse: ^1.0.6
|
||||
checksum: bed00be983cd20a8af0e7840664f655c4b269786dbd9595c5f156cd9d8a0050e65cdbbbdafc30ee9b6245b230c78a2c8ab6447a52545b582f476c29adb188cc5
|
||||
checksum: a0dd7d16a8e47af23afa9386df2dff10e3e0debb2c7299a42e581d9d9b04d7ad5d2c53f24f1e043f7b3c250cbdc71150063e53d0b6559683d37f790b7c8c3cd5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"resolve@patch:resolve@^2.0.0-next.3#~builtin<compat/resolve>":
|
||||
version: 2.0.0-next.3
|
||||
resolution: "resolve@patch:resolve@npm%3A2.0.0-next.3#~builtin<compat/resolve>::version=2.0.0-next.3&hash=00b1ff"
|
||||
resolution: "resolve@patch:resolve@npm%3A2.0.0-next.3#~builtin<compat/resolve>::version=2.0.0-next.3&hash=07638b"
|
||||
dependencies:
|
||||
is-core-module: ^2.2.0
|
||||
path-parse: ^1.0.6
|
||||
checksum: eb88c5e53843bc022215744307a5f5664446c0fdb8f43c33456dce98d5ee6b3162d0cd0a177bb6f1c3d5c8bf01391ac7ab2de0e936e35318725fb40ba7efdaf6
|
||||
checksum: 21684b4d99a4877337cdbd5484311c811b3e8910edb5d868eec85c6e6550b0f570d911f9a384f9e176172d6713f2715bd0b0887fa512cb8c6aeece018de6a9f8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -10494,15 +10554,20 @@ resolve@^2.0.0-next.3:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "status-communities@workspace:packages/status-communities"
|
||||
dependencies:
|
||||
"@types/bn.js": ^5.1.0
|
||||
"@types/chai": ^4.2.22
|
||||
"@types/elliptic": ^6.4.14
|
||||
"@types/mocha": ^9.0.0
|
||||
"@types/pbkdf2": ^3.1.0
|
||||
"@types/secp256k1": ^4.0.3
|
||||
"@types/uuid": ^8.3.3
|
||||
"@typescript-eslint/eslint-plugin": ^4.31.1
|
||||
"@typescript-eslint/parser": ^4.31.1
|
||||
bn.js: ^5.2.0
|
||||
buffer: ^6.0.3
|
||||
chai: ^4.3.4
|
||||
ecies-geth: ^1.5.3
|
||||
elliptic: ^6.5.4
|
||||
eslint: ^7.32.0
|
||||
eslint-config-prettier: ^8.3.0
|
||||
eslint-import-resolver-node: ^0.3.6
|
||||
@ -10520,6 +10585,7 @@ resolve@^2.0.0-next.3:
|
||||
ts-node: ^10.2.1
|
||||
ts-proto: ^1.83.0
|
||||
typescript: ^4.4.3
|
||||
uuid: ^8.3.2
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@ -10540,6 +10606,18 @@ resolve@^2.0.0-next.3:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"stream-http@npm:^3.2.0":
|
||||
version: 3.2.0
|
||||
resolution: "stream-http@npm:3.2.0"
|
||||
dependencies:
|
||||
builtin-status-codes: ^3.0.0
|
||||
inherits: ^2.0.4
|
||||
readable-stream: ^3.6.0
|
||||
xtend: ^4.0.2
|
||||
checksum: c9b78453aeb0c84fcc59555518ac62bacab9fa98e323e7b7666e5f9f58af8f3155e34481078509b02929bd1268427f664d186604cdccee95abc446099b339f83
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"stream-to-it@npm:^0.2.2":
|
||||
version: 0.2.4
|
||||
resolution: "stream-to-it@npm:0.2.4"
|
||||
@ -11329,11 +11407,11 @@ resolve@^2.0.0-next.3:
|
||||
|
||||
"typescript@patch:typescript@^4.3.5#~builtin<compat/typescript>, typescript@patch:typescript@^4.4.3#~builtin<compat/typescript>":
|
||||
version: 4.4.3
|
||||
resolution: "typescript@patch:typescript@npm%3A4.4.3#~builtin<compat/typescript>::version=4.4.3&hash=32657b"
|
||||
resolution: "typescript@patch:typescript@npm%3A4.4.3#~builtin<compat/typescript>::version=4.4.3&hash=ddd1e8"
|
||||
bin:
|
||||
tsc: bin/tsc
|
||||
tsserver: bin/tsserver
|
||||
checksum: 28ab98313afab46788ff41014fdb5932430ada6e03cf9e92ac47f406526a2cac1ae2894834e7da61e46b7429318e9c47f45ba8de323332f0cb9af99b72ebae74
|
||||
checksum: 79f5c13d21c9dea3eb44d2b7002ff25a0569fefc432e083d65a360e3aca990aca25fc733e14aa6883b5e9a68e3e2f0330a34123e048806f91d701732ece00e6f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -12159,7 +12237,7 @@ resolve@^2.0.0-next.3:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"xtend@npm:~4.0.1":
|
||||
"xtend@npm:^4.0.2, xtend@npm:~4.0.1":
|
||||
version: 4.0.2
|
||||
resolution: "xtend@npm:4.0.2"
|
||||
checksum: ac5dfa738b21f6e7f0dd6e65e1b3155036d68104e67e5d5d1bde74892e327d7e5636a076f625599dc394330a731861e87343ff184b0047fef1360a7ec0a5a36a
|
||||
|
Loading…
x
Reference in New Issue
Block a user