Typescript chat client SDK (#1036)

* add typescript chat commands

* add chat responses

* add client API

* fix chat bot example, readme

* update readme

* update main readme

* readme

* corrections

Co-authored-by: JRoberts <8711996+jr-simplex@users.noreply.github.com>

* correction

Co-authored-by: JRoberts <8711996+jr-simplex@users.noreply.github.com>

Co-authored-by: JRoberts <8711996+jr-simplex@users.noreply.github.com>
This commit is contained in:
Evgeny PoberezkinandJRoberts authored and GitHub committed 2022-09-12 18:33:34 +01:00
1 parent 7aedd3d9e9
commit 9ff7dc8977
6 files changed
+834 -47

No files matched your search

@@ -1,23 +1,43 @@
# SimpleX Chat JavaScript client
This is a TypeScript library that defines WebSocket API client for [SimpleX Chat terminal CLI](https://github.com/simplex-chat/simplex-chat/blob/stable/docs/CLI.md) that should be run as a WebSockets server on any port:
```bash
simplex-chat -p 5225
```
Client API provides types and functions to:
- create and change user profile (although, in most cases you can do it manually, via SimpleX Chat terminal app).
- create and accept invitations or connect with the contacts.
- create and manage long-term user address, accepting connection requests automatically.
- create, join and manage group.
- send and receive files.
## Use cases
- chat bots: you can implement any logic of connecting with and communicating with SimpleX Chat users. Using chat groups a chat bot can connect SimleX Chat users with each other.
- control of the equipment: e.g. servers or home automation. SimpleX Chat provides secure and authorised connections, so this is more secure than using rest APIs.
Please share your use cases and implementations.
## Quick start
```
npm i simplex-chat
npm run build
```
See example of chat bot in [squaring-bot.js](./examples/squaring-bot.js)
See the example of a simple chat bot in [squaring-bot.js](./examples/squaring-bot.js):
- start `simplex-chat` as a server on port 5225: `simplex-chat -p 5225 -d test_db`
- run chatbot: `node examples/squaring-bot`
- connect to chatbot via SimpleX Chat client using the address of the chat bot
## Documentation
Please refer to:
Please refer to the available client API in [client.ts](./src/client.ts).
- available client API - [client.ts](./src/client.ts).
- available commands - `ChatCommand` type in [command.ts](./src/command.ts) - if some command is not created as a ChatClient method, you can pass any command object to `sendChatCommand` method, or if the type for some command is not available you can pass command string (same strings as supported in terminal/mobile API) to `sendChatCmdStr` method.
- available chat messages - `ChatResponse` type in [response.ts](./src/command.ts).
**Please note**: you should NOT use local display names that are supported in terminal app, as they can change when contact profile is updated and you can have race conditions - use commands that use chat IDs.
## Lisense
## License
[AGPL v3](./LICENSE)
@@ -6,15 +6,18 @@ run()
async function run() {
const chat = await ChatClient.create("ws://localhost:5225")
// this example assumes that you have initialized user profile for chat bot via terminal CLI
const user = await chat.apiGetActiveUser()
if (!user) {
console.log("no user profile")
return
}
console.log(`Bot profile: ${user.profile.displayName} (${user.profile.fullName})`)
// creates or uses the existing long-term address for the bot
const address = (await chat.apiGetUserAddress()) || (await chat.apiCreateUserAddress())
console.log(`Bot address: ${address}`)
await chat.sendChatCmdStr("/auto_accept on")
// enables automatic acceptance of contact connections
await chat.addressAutoAccept(true)
await processMessages(chat)
async function processMessages(chat) {
@@ -22,6 +25,7 @@ async function run() {
const resp = r instanceof Promise ? await r : r
switch (resp.type) {
case "contactConnected": {
// sends welcome message when the new contact is connected
const {contact} = resp
console.log(`${contact.profile.displayName} connected`)
await chat.apiSendTextMessage(
@@ -32,6 +36,7 @@ async function run() {
continue
}
case "newChatItem": {
// calculates the square of the number and sends the reply
const {chatInfo} = resp.chatItem
if (chatInfo.type !== ChatInfoType.Direct) continue
const msg = ciContentText(resp.chatItem.chatItem.content)
@@ -1,7 +1,7 @@
import {ABQueue} from "./queue"
import {ChatTransport, ChatServer, ChatSrvRequest, ChatSrvResponse, ChatResponseError, localServer, noop} from "./transport"
import {ChatCommand, ChatType} from "./command"
import {ChatResponse} from "./response"
import {ChatCommand, ChatType, Profile} from "./command"
import {ChatResponse, ChatInfo} from "./response"
import * as CC from "./command"
import * as CR from "./response"
@@ -118,14 +118,37 @@ export class ChatClient {
}
}
async apiStopChat(): Promise<void> {
const r = await this.sendChatCommand({type: "apiStopChat"})
if (r.type !== "chatStopped") {
throw new ChatCommandError("error stopping chat", r)
}
}
apiSetIncognito(incognito: boolean): Promise<void> {
return this.okChatCommand({type: "setIncognito", incognito})
}
async addressAutoAccept(autoAccept: boolean, autoReply: CC.MsgContent): Promise<void> {
const r = await this.sendChatCommand({type: "addressAutoAccept", autoAccept, autoReply})
if (r.type !== "userContactLinkUpdated") {
throw new ChatCommandError("error changing user contact address mode", r)
}
}
async apiGetChats(): Promise<CR.Chat[]> {
const r = await this.sendChatCommand({type: "apiGetChats"})
if (r.type === "apiChats") return r.chats
throw new ChatCommandError("error loading chats", r)
}
async apiGetChat(chatType: ChatType, chatId: number, pagination: CC.ChatPagination = {count: 100}): Promise<CR.Chat> {
const r = await this.sendChatCommand({type: "apiGetChat", chatType, chatId, pagination})
async apiGetChat(
chatType: ChatType,
chatId: number,
pagination: CC.ChatPagination = {count: 100},
search: string | undefined = undefined
): Promise<CR.Chat> {
const r = await this.sendChatCommand({type: "apiGetChat", chatType, chatId, pagination, search})
if (r.type === "apiChat") return r.chat
throw new ChatCommandError("error loading chat", r)
}
@@ -152,18 +175,6 @@ export class ChatClient {
throw new ChatCommandError("error deleting chat item", r)
}
// func getUserSMPServers() throws -> [String] {
// let r = chatSendCmdSync(.getUserSMPServers)
// if case let .userSMPServers(smpServers) = r { return smpServers }
// throw r
// }
// func setUserSMPServers(smpServers: [String]) async throws {
// let r = await chatSendCmd(.setUserSMPServers(smpServers: smpServers))
// if case .cmdOk = r { return }
// throw r
// }
async apiCreateLink(): Promise<string> {
const r = await this.sendChatCommand({type: "addContact"})
if (r.type === "invitation") return r.connReqInvitation
@@ -184,7 +195,24 @@ export class ChatClient {
async apiDeleteChat(chatType: ChatType, chatId: number): Promise<void> {
const r = await this.sendChatCommand({type: "apiDeleteChat", chatType, chatId})
if (r.type !== "contactDeleted") throw new ChatCommandError("error deleting chat", r)
switch (chatType) {
case ChatType.Direct:
if (r.type === "contactDeleted") return
break
case ChatType.Group:
if (r.type === "groupDeletedUser") return
break
case ChatType.ContactRequest:
if (r.type === "contactConnectionDeleted") return
break
}
throw new ChatCommandError("error deleting chat", r)
}
async apiClearChat(chatType: ChatType, chatId: number): Promise<ChatInfo> {
const r = await this.sendChatCommand({type: "apiClearChat", chatType, chatId})
if (r.type === "chatCleared") return r.chatInfo
throw new ChatCommandError("error clearing chat", r)
}
async apiUpdateProfile(profile: CC.Profile): Promise<CC.Profile | undefined> {
@@ -199,11 +227,11 @@ export class ChatClient {
}
}
// func apiParseMarkdown(text: String) throws -> [FormattedText]? {
// let r = chatSendCmdSync(.apiParseMarkdown(text: text))
// if case let .apiParsedMarkdown(formattedText) = r { return formattedText }
// throw r
// }
async apiSetContactAlias(contactId: number, localAlias: string): Promise<CR.Contact> {
const r = await this.sendChatCommand({type: "apiSetContactAlias", contactId, localAlias})
if (r.type === "contactAliasUpdated") return r.toContact
throw new ChatCommandError("error updating contact alias", r)
}
async apiCreateUserAddress(): Promise<string> {
const r = await this.sendChatCommand({type: "createMyAddress"})
@@ -246,6 +274,66 @@ export class ChatClient {
return this.okChatCommand({type: "apiChatRead", chatType, chatId, itemRange})
}
async apiContactInfo(contactId: number): Promise<[CR.ConnectionStats?, Profile?]> {
const r = await this.sendChatCommand({type: "apiContactInfo", contactId})
if (r.type === "contactInfo") return [r.connectionStats, r.customUserProfile]
throw new ChatCommandError("error getting contact info", r)
}
async apiGroupMemberInfo(groupId: number, memberId: number): Promise<CR.ConnectionStats | undefined> {
const r = await this.sendChatCommand({type: "apiGroupMemberInfo", groupId, memberId})
if (r.type === "groupMemberInfo") return r.connectionStats_
throw new ChatCommandError("error getting group info", r)
}
async apiReceiveFile(fileId: number): Promise<CR.AChatItem> {
const r = await this.sendChatCommand({type: "receiveFile", fileId})
if (r.type === "rcvFileAccepted") return r.chatItem
throw new ChatCommandError("error receiving file", r)
}
async apiNewGroup(groupProfile: CR.GroupProfile): Promise<CR.GroupInfo> {
const r = await this.sendChatCommand({type: "newGroup", groupProfile})
if (r.type === "groupCreated") return r.groupInfo
throw new ChatCommandError("error creating group", r)
}
async apiAddMember(groupId: number, contactId: number, memberRole: CC.GroupMemberRole): Promise<CR.GroupMember> {
const r = await this.sendChatCommand({type: "apiAddMember", groupId, contactId, memberRole})
if (r.type === "sentGroupInvitation") return r.member
throw new ChatCommandError("error adding member", r)
}
async apiJoinGroup(groupId: number): Promise<CR.GroupInfo> {
const r = await this.sendChatCommand({type: "apiJoinGroup", groupId})
if (r.type === "userAcceptedGroupSent") return r.groupInfo
throw new ChatCommandError("error joining group", r)
}
async apiRemoveMember(groupId: number, memberId: number): Promise<CR.GroupMember> {
const r = await this.sendChatCommand({type: "apiRemoveMember", groupId, memberId})
if (r.type === "userDeletedMember") return r.member
throw new ChatCommandError("error removing member", r)
}
async apiLeaveGroup(groupId: number): Promise<CR.GroupInfo> {
const r = await this.sendChatCommand({type: "apiLeaveGroup", groupId})
if (r.type === "leftMemberUser") return r.groupInfo
throw new ChatCommandError("error leaving group", r)
}
async apiListMembers(groupId: number): Promise<CR.GroupMember[]> {
const r = await this.sendChatCommand({type: "apiListMembers", groupId})
if (r.type === "groupMembers") return r.group.members
throw new ChatCommandError("error getting group members", r)
}
async apiUpdateGroup(groupId: number, groupProfile: CR.GroupProfile): Promise<CR.GroupInfo> {
const r = await this.sendChatCommand({type: "apiUpdateGroupProfile", groupId, groupProfile})
if (r.type === "groupUpdated") return r.toGroup
throw new ChatCommandError("error updating group", r)
}
private async okChatCommand(command: ChatCommand): Promise<void> {
const r = await this.sendChatCommand(command)
if (r.type !== "cmdOk") throw new ChatCommandError(`${command.type} command error`, r)
@@ -2,7 +2,12 @@ export type ChatCommand =
| ShowActiveUser
| CreateActiveUser
| StartChat
| APIStopChat
| SetFilesFolder
| SetIncognito
| APIExportArchive
| APIImportArchive
| APIDeleteStorage
| APIGetChats
| APIGetChat
| APISendMessage
@@ -10,12 +15,23 @@ export type ChatCommand =
| APIDeleteChatItem
| APIChatRead
| APIDeleteChat
| APIClearChat
| APIAcceptContact
| APIRejectContact
| APIUpdateProfile
| APISetContactAlias
| APIParseMarkdown
| NewGroup
| APIAddMember
| APIJoinGroup
| APIRemoveMember
| APILeaveGroup
| APIListMembers
| APIUpdateGroupProfile
| GetUserSMPServers
| SetUserSMPServers
| APIContactInfo
| APIGroupMemberInfo
| AddContact
| Connect
| ConnectSimplex
@@ -23,12 +39,48 @@ export type ChatCommand =
| DeleteMyAddress
| ShowMyAddress
| AddressAutoAccept
| ReceiveFile
| CancelFile
| FileStatus
// not included commands (they are not needed for Websocket clients, and can still be sent as strings):
// APIActivateChat
// APISuspendChat
// ResubscribeAllConnections
// APIGetChatItems - not implemented
// APISendCallInvitation
// APIRejectCall
// APISendCallOffer
// APISendCallAnswer
// APISendCallExtraInfo
// APIEndCall
// APIGetCallInvitations
// APICallStatus
// APIGetNtfToken
// APIRegisterToken
// APIVerifyToken
// APIDeleteToken
// APIGetNtfMessage
// APIMemberRole -- not implemented
// ListContacts
// ListGroups
// APISetNetworkConfig
// APIGetNetworkConfig
// APISetChatSettings
// ShowMessages
// LastMessages
// SendMessageBroadcast
type ChatCommandTag =
| "showActiveUser"
| "createActiveUser"
| "startChat"
| "apiStopChat"
| "setFilesFolder"
| "setIncognito"
| "apiExportArchive"
| "apiImportArchive"
| "apiDeleteStorage"
| "apiGetChats"
| "apiGetChat"
| "apiSendMessage"
@@ -36,12 +88,23 @@ type ChatCommandTag =
| "apiDeleteChatItem"
| "apiChatRead"
| "apiDeleteChat"
| "apiClearChat"
| "apiAcceptContact"
| "apiRejectContact"
| "apiUpdateProfile"
| "apiSetContactAlias"
| "apiParseMarkdown"
| "newGroup"
| "apiAddMember"
| "apiJoinGroup"
| "apiRemoveMember"
| "apiLeaveGroup"
| "apiListMembers"
| "apiUpdateGroupProfile"
| "getUserSMPServers"
| "setUserSMPServers"
| "apiContactInfo"
| "apiGroupMemberInfo"
| "addContact"
| "connect"
| "connectSimplex"
@@ -49,6 +112,9 @@ type ChatCommandTag =
| "deleteMyAddress"
| "showMyAddress"
| "addressAutoAccept"
| "receiveFile"
| "cancelFile"
| "fileStatus"
interface IChatCommand {
type: ChatCommandTag
@@ -65,6 +131,11 @@ export interface CreateActiveUser extends IChatCommand {
export interface StartChat extends IChatCommand {
type: "startChat"
subscribeConnections?: boolean
}
export interface APIStopChat extends IChatCommand {
type: "apiStopChat"
}
export interface SetFilesFolder extends IChatCommand {
@@ -72,8 +143,28 @@ export interface SetFilesFolder extends IChatCommand {
filePath: string
}
export interface SetIncognito extends IChatCommand {
type: "setIncognito"
incognito: boolean
}
export interface APIExportArchive extends IChatCommand {
type: "apiExportArchive"
config: ArchiveConfig
}
export interface APIImportArchive extends IChatCommand {
type: "apiImportArchive"
config: ArchiveConfig
}
export interface APIDeleteStorage extends IChatCommand {
type: "apiDeleteStorage"
}
export interface APIGetChats extends IChatCommand {
type: "apiGetChats"
pendingConnections?: boolean
}
export interface APIGetChat extends IChatCommand {
@@ -81,6 +172,7 @@ export interface APIGetChat extends IChatCommand {
chatType: ChatType
chatId: number
pagination: ChatPagination
search?: string
}
export interface APISendMessage extends IChatCommand {
@@ -130,6 +222,12 @@ export interface APIDeleteChat extends IChatCommand {
chatId: number
}
export interface APIClearChat extends IChatCommand {
type: "apiClearChat"
chatType: ChatType
chatId: number
}
export interface APIAcceptContact extends IChatCommand {
type: "apiAcceptContact"
contactReqId: number
@@ -145,11 +243,56 @@ export interface APIUpdateProfile extends IChatCommand {
profile: Profile
}
export interface APISetContactAlias extends IChatCommand {
type: "apiSetContactAlias"
contactId: number
localAlias: string
}
export interface APIParseMarkdown extends IChatCommand {
type: "apiParseMarkdown"
text: string
}
export interface NewGroup extends IChatCommand {
type: "newGroup"
groupProfile: GroupProfile
}
export interface APIAddMember extends IChatCommand {
type: "apiAddMember"
groupId: number
contactId: number
memberRole: GroupMemberRole
}
export interface APIJoinGroup extends IChatCommand {
type: "apiJoinGroup"
groupId: number
}
export interface APIRemoveMember extends IChatCommand {
type: "apiRemoveMember"
groupId: number
memberId: number
}
export interface APILeaveGroup extends IChatCommand {
type: "apiLeaveGroup"
groupId: number
}
export interface APIListMembers extends IChatCommand {
type: "apiListMembers"
groupId: number
}
export interface APIUpdateGroupProfile extends IChatCommand {
type: "apiUpdateGroupProfile"
groupId: number
groupProfile: GroupProfile
}
export interface GetUserSMPServers extends IChatCommand {
type: "getUserSMPServers"
}
@@ -159,6 +302,17 @@ export interface SetUserSMPServers extends IChatCommand {
servers: [string]
}
export interface APIContactInfo extends IChatCommand {
type: "apiContactInfo"
contactId: number
}
export interface APIGroupMemberInfo extends IChatCommand {
type: "apiGroupMemberInfo"
groupId: number
memberId: number
}
export interface AddContact extends IChatCommand {
type: "addContact"
}
@@ -186,7 +340,24 @@ export interface ShowMyAddress extends IChatCommand {
export interface AddressAutoAccept extends IChatCommand {
type: "addressAutoAccept"
enable: boolean
autoAccept: boolean
autoReply?: MsgContent
}
export interface ReceiveFile extends IChatCommand {
type: "receiveFile"
fileId: number
filePath?: string
}
export interface CancelFile extends IChatCommand {
type: "cancelFile"
fileId: number
}
export interface FileStatus extends IChatCommand {
type: "fileStatus"
fileId: number
}
export interface Profile {
@@ -208,12 +379,13 @@ export type ChatPagination =
export type ChatItemId = number
type MsgContentTag = "text" | "link" | "images"
type MsgContentTag = "text" | "link" | "image" | "file"
export type MsgContent = MCText | MCUnknown
export type MsgContent = MCText | MCLink | MCImage | MCFile | MCUnknown
interface MC {
type: MsgContentTag
text: string
}
interface MCText extends MC {
@@ -221,9 +393,32 @@ interface MCText extends MC {
text: string
}
interface MCLink extends MC {
type: "link"
text: string
preview: LinkPreview
}
interface MCImage extends MC {
type: "image"
image: string // image preview as base64 encoded data string
}
interface MCFile extends MC {
type: "file"
text: string
}
interface MCUnknown {
type: string
text?: string
text: string
}
interface LinkPreview {
uri: string
title: string
description: string
image: string
}
export enum DeleteMode {
@@ -231,6 +426,24 @@ export enum DeleteMode {
Internal = "internal",
}
interface ArchiveConfig {
archivePath: string
disableCompression?: boolean
parentTempDirectory?: string
}
export enum GroupMemberRole {
GRMember = "member",
GRAdmin = "admin",
GROwner = "owner",
}
interface GroupProfile {
displayName: string
fullName: string // can be empty string
image?: string
}
export function cmdString(cmd: ChatCommand): string {
switch (cmd.type) {
case "showActiveUser":
@@ -238,11 +451,21 @@ export function cmdString(cmd: ChatCommand): string {
case "createActiveUser":
return `/u ${JSON.stringify(cmd.profile)}`
case "startChat":
return "/_start"
return `/_start subscribe=${cmd.subscribeConnections ? "on" : "off"}`
case "apiStopChat":
return "/_stop"
case "setFilesFolder":
return `/_files_folder ${cmd.filePath}`
case "setIncognito":
return `/incognito ${cmd.incognito ? "on" : "off"}`
case "apiExportArchive":
return `/_db export ${JSON.stringify(cmd.config)}`
case "apiImportArchive":
return `/_db import ${JSON.stringify(cmd.config)}`
case "apiDeleteStorage":
return "/_db delete"
case "apiGetChats":
return "/_get chats"
return `/_get chats pcc=${cmd.pendingConnections ? "on" : "off"}`
case "apiGetChat":
return `/_get chat ${cmd.chatType}${cmd.chatId}${paginationStr(cmd.pagination)}`
case "apiSendMessage":
@@ -257,18 +480,40 @@ export function cmdString(cmd: ChatCommand): string {
}
case "apiDeleteChat":
return `/_delete ${cmd.chatType}${cmd.chatId}`
case "apiClearChat":
return `/_clear chat ${cmd.chatType}${cmd.chatId}`
case "apiAcceptContact":
return `/_accept ${cmd.contactReqId}`
case "apiRejectContact":
return `/_reject ${cmd.contactReqId}`
case "apiUpdateProfile":
return `/_profile ${JSON.stringify(cmd.profile)}`
case "apiSetContactAlias":
return `/_set alias @${cmd.contactId} ${cmd.localAlias.trim()}`
case "apiParseMarkdown":
return `/_parse ${cmd.text}`
case "newGroup":
return `/_group ${JSON.stringify(cmd.groupProfile)}`
case "apiAddMember":
return `/_add #${cmd.groupId} ${cmd.contactId} ${cmd.memberRole}`
case "apiJoinGroup":
return `/_join #${cmd.groupId}`
case "apiRemoveMember":
return `/_remove #${cmd.groupId} ${cmd.memberId}`
case "apiLeaveGroup":
return `/_leave #${cmd.groupId}`
case "apiListMembers":
return `/_members #${cmd.groupId}`
case "apiUpdateGroupProfile":
return `/_group_profile #${cmd.groupId} ${JSON.stringify(cmd.groupProfile)}`
case "getUserSMPServers":
return "/smp_servers"
case "setUserSMPServers":
return `/smp_servers ${cmd.servers.join(",") || "default"}`
case "apiContactInfo":
return `/_info @${cmd.contactId}`
case "apiGroupMemberInfo":
return `/_info #${cmd.groupId} ${cmd.memberId}`
case "addContact":
return "/connect"
case "connect":
@@ -282,7 +527,13 @@ export function cmdString(cmd: ChatCommand): string {
case "showMyAddress":
return "/show_address"
case "addressAutoAccept":
return `/auto_accept ${cmd.enable ? "on" : "off"}`
return `/auto_accept ${cmd.autoAccept ? "on" : "off"}${cmd.autoReply ? " " + JSON.stringify(cmd.autoReply) : ""}`
case "receiveFile":
return `/freceive ${cmd.fileId}${cmd.filePath ? " " + cmd.filePath : ""}`
case "cancelFile":
return `/fcancel ${cmd.fileId}`
case "fileStatus":
return `/fstatus ${cmd.fileId}`
}
}
@@ -1,13 +1,16 @@
import {ChatItemId, MsgContent, DeleteMode, Profile} from "./command"
import {ChatItemId, MsgContent, DeleteMode, Profile, GroupMemberRole} from "./command"
export type ChatResponse =
| CRActiveUser
| CRChatStarted
| CRChatRunning
| CRChatStopped
| CRApiChats
| CRApiChat
| CRApiParsedMarkdown
| CRUserSMPServers
| CRContactInfo
| CRGroupMemberInfo
| CRNewChatItem
| CRChatItemStatusUpdated
| CRChatItemUpdated
@@ -20,11 +23,14 @@ export type ChatResponse =
| CRUserProfile
| CRUserProfileNoChange
| CRUserProfileUpdated
| CRContactAliasUpdated
| CRInvitation
| CRSentConfirmation
| CRSentInvitation
| CRContactUpdated
| CRContactsMerged
| CRContactDeleted
| CRChatCleared
| CRUserContactLinkCreated
| CRUserContactLinkDeleted
| CRReceivedContactRequest
@@ -38,22 +44,72 @@ export type ChatResponse =
| CRContactSubscribed
| CRContactSubError
| CRContactSubSummary
| CRContactsDisconnected
| CRContactsSubscribed
| CRHostConnected
| CRHostDisconnected
| CRGroupEmpty
| CRMemberSubError
| CRMemberSubSummary
| CRGroupSubscribed
| CRRcvFileAccepted
| CRRcvFileAcceptedSndCancelled
| CRRcvFileStart
| CRRcvFileComplete
| CRRcvFileCancelled
| CRRcvFileSndCancelled
| CRSndFileStart
| CRSndFileComplete
| CRSndFileCancelled
| CRSndFileRcvCancelled
| CRSndGroupFileCancelled
| CRSndFileSubError
| CRRcvFileSubError
| CRPendingSubSummary
| CRGroupCreated
| CRGroupMembers
| CRUserAcceptedGroupSent
| CRUserDeletedMember
| CRSentGroupInvitation
| CRLeftMemberUser
| CRGroupDeletedUser
| CRGroupInvitation
| CRReceivedGroupInvitation
| CRUserJoinedGroup
| CRJoinedGroupMember
| CRJoinedGroupMemberConnecting
| CRConnectedToGroupMember
| CRDeletedMember
| CRDeletedMemberUser
| CRLeftMember
| CRGroupRemoved
| CRGroupDeleted
| CRGroupUpdated
| CRUserContactLinkSubscribed
| CRUserContactLinkSubError
| CRNewContactConnection
| CRContactConnectionDeleted
| CRMessageError
| CRChatCmdError
| CRChatError
// not included
// CRChatItemDeletedNotFound
// CRBroadcastSent
// CRGroupsList
// CRFileTransferStatus
type ChatResponseTag =
| "activeUser"
| "chatStarted"
| "chatRunning"
| "chatStopped"
| "apiChats"
| "apiChat"
| "apiParsedMarkdown"
| "userSMPServers"
| "contactInfo"
| "groupMemberInfo"
| "newChatItem"
| "chatItemStatusUpdated"
| "chatItemUpdated"
@@ -68,11 +124,14 @@ type ChatResponseTag =
| "userProfile"
| "userProfileNoChange"
| "userProfileUpdated"
| "contactAliasUpdated"
| "invitation"
| "sentConfirmation"
| "sentInvitation"
| "contactUpdated"
| "contactsMerged"
| "contactDeleted"
| "chatCleared"
| "receivedContactRequest"
| "acceptingContactRequest"
| "contactAlreadyExists"
@@ -84,10 +143,52 @@ type ChatResponseTag =
| "contactSubscribed"
| "contactSubError"
| "contactSubSummary"
| "contactsDisconnected"
| "contactsSubscribed"
| "hostConnected"
| "hostDisconnected"
| "groupEmpty"
| "memberSubError"
| "memberSubSummary"
| "groupSubscribed"
| "rcvFileAccepted"
| "rcvFileAcceptedSndCancelled"
| "rcvFileStart"
| "rcvFileComplete"
| "rcvFileCancelled"
| "rcvFileSndCancelled"
| "sndFileStart"
| "sndFileComplete"
| "sndFileCancelled"
| "sndFileRcvCancelled"
| "sndGroupFileCancelled"
| "fileTransferStatus"
| "sndFileSubError"
| "rcvFileSubError"
| "pendingSubSummary"
| "groupCreated"
| "groupMembers"
| "userAcceptedGroupSent"
| "userDeletedMember"
| "sentGroupInvitation"
| "leftMemberUser"
| "groupDeletedUser"
| "groupInvitation"
| "receivedGroupInvitation"
| "userJoinedGroup"
| "joinedGroupMember"
| "joinedGroupMemberConnecting"
| "connectedToGroupMember"
| "deletedMember"
| "deletedMemberUser"
| "leftMember"
| "groupRemoved"
| "groupDeleted"
| "groupUpdated"
| "userContactLinkSubscribed"
| "userContactLinkSubError"
| "newContactConnection"
| "contactConnectionDeleted"
| "messageError"
| "chatCmdError"
| "chatError"
@@ -109,6 +210,10 @@ export interface CRChatRunning extends CR {
type: "chatRunning"
}
export interface CRChatStopped extends CR {
type: "chatStopped"
}
export interface CRApiChats extends CR {
type: "apiChats"
chats: Chat[]
@@ -129,6 +234,20 @@ export interface CRUserSMPServers extends CR {
smpServers: string[]
}
export interface CRContactInfo extends CR {
type: "contactInfo"
contact: Contact
connectionStats: ConnectionStats
customUserProfile?: Profile
}
export interface CRGroupMemberInfo extends CR {
type: "groupMemberInfo"
groupInfo: GroupInfo
member: GroupMember
connectionStats_?: ConnectionStats
}
export interface CRNewChatItem extends CR {
type: "newChatItem"
chatItem: AChatItem
@@ -169,6 +288,7 @@ export interface CRUserContactLinkUpdated extends CR {
type: "userContactLinkUpdated"
connReqContact: string
autoAccept: boolean
autoReply?: MsgContent
}
export interface CRContactRequestRejected extends CR {
@@ -191,6 +311,11 @@ export interface CRUserProfileUpdated extends CR {
toProfile: Profile
}
export interface CRContactAliasUpdated extends CR {
type: "contactAliasUpdated"
toContact: Contact
}
export interface CRInvitation extends CR {
type: "invitation"
connReqInvitation: string
@@ -210,11 +335,22 @@ export interface CRContactUpdated extends CR {
toContact: Contact
}
export interface CRContactsMerged extends CR {
type: "contactsMerged"
intoContact: Contact
mergedContact: Contact
}
export interface CRContactDeleted extends CR {
type: "contactDeleted"
contact: Contact
}
export interface CRChatCleared extends CR {
type: "chatCleared"
chatInfo: ChatInfo
}
export interface CRUserContactLinkCreated extends CR {
type: "userContactLinkCreated"
connReqContact: string
@@ -280,16 +416,242 @@ export interface CRContactSubSummary extends CR {
contactSubscriptions: ContactSubStatus[]
}
export interface CRContactsDisconnected extends CR {
type: "contactsDisconnected"
server: string
contactRefs: ContactRef[]
}
export interface CRContactsSubscribed extends CR {
type: "contactsSubscribed"
server: string
contactRefs: ContactRef[]
}
export interface CRHostConnected extends CR {
type: "hostConnected"
protocol: string
transportHost: string
}
export interface CRHostDisconnected extends CR {
type: "hostDisconnected"
protocol: string
transportHost: string
}
export interface CRGroupEmpty extends CR {
type: "groupEmpty"
groupInfo: GroupInfo
}
export interface CRMemberSubError extends CR {
type: "memberSubError"
groupInfo: GroupInfo
member: GroupMember
chatError: ChatError
}
export interface CRMemberSubSummary extends CR {
type: "memberSubSummary"
memberSubscriptions: MemberSubStatus[]
}
export interface CRGroupSubscribed extends CR {
type: "groupSubscribed"
groupInfo: GroupInfo
}
export interface CRRcvFileAccepted extends CR {
type: "rcvFileAccepted"
chatItem: AChatItem
}
export interface CRRcvFileAcceptedSndCancelled extends CR {
type: "rcvFileAcceptedSndCancelled"
rcvFileTransfer: RcvFileTransfer
}
export interface CRRcvFileStart extends CR {
type: "rcvFileStart"
chatItem: AChatItem
}
export interface CRRcvFileComplete extends CR {
type: "rcvFileComplete"
chatItem: AChatItem
}
export interface CRRcvFileCancelled extends CR {
type: "rcvFileCancelled"
rcvFileTransfer: RcvFileTransfer
}
export interface CRRcvFileSndCancelled extends CR {
type: "rcvFileSndCancelled"
rcvFileTransfer: RcvFileTransfer
}
export interface CRSndFileStart extends CR {
type: "sndFileStart"
chatItem: AChatItem
sndFileTransfer: SndFileTransfer
}
export interface CRSndFileComplete extends CR {
type: "sndFileComplete"
chatItem: AChatItem
sndFileTransfer: SndFileTransfer
}
export interface CRSndFileCancelled extends CR {
type: "sndFileCancelled"
chatItem: AChatItem
sndFileTransfer: SndFileTransfer
}
export interface CRSndFileRcvCancelled extends CR {
type: "sndFileRcvCancelled"
chatItem: AChatItem
sndFileTransfer: SndFileTransfer
}
export interface CRSndGroupFileCancelled extends CR {
type: "sndGroupFileCancelled"
chatItem: AChatItem
fileTransferMeta: FileTransferMeta
sndFileTransfers: SndFileTransfer[]
}
export interface CRSndFileSubError extends CR {
type: "sndFileSubError"
sndFileTransfer: SndFileTransfer
chatError: ChatError
}
export interface CRRcvFileSubError extends CR {
type: "rcvFileSubError"
rcvFileTransfer: RcvFileTransfer
chatError: ChatError
}
export interface CRPendingSubSummary extends CR {
type: "pendingSubSummary"
pendingSubStatus: PendingSubStatus[]
}
export interface CRGroupCreated extends CR {
type: "groupCreated"
groupInfo: GroupInfo
}
export interface CRGroupMembers extends CR {
type: "groupMembers"
group: Group
}
export interface CRUserAcceptedGroupSent extends CR {
type: "userAcceptedGroupSent"
groupInfo: GroupInfo
}
export interface CRUserDeletedMember extends CR {
type: "userDeletedMember"
groupInfo: GroupInfo
member: GroupMember
}
export interface CRSentGroupInvitation extends CR {
type: "sentGroupInvitation"
groupInfo: GroupInfo
contact: Contact
member: GroupMember
}
export interface CRLeftMemberUser extends CR {
type: "leftMemberUser"
groupInfo: GroupInfo
}
export interface CRGroupDeletedUser extends CR {
type: "groupDeletedUser"
groupInfo: GroupInfo
}
export interface CRGroupInvitation extends CR {
type: "groupInvitation"
groupInfo: GroupInfo
}
export interface CRReceivedGroupInvitation extends CR {
type: "receivedGroupInvitation"
groupInfo: GroupInfo
contact: Contact
memberRole: GroupMemberRole
}
export interface CRUserJoinedGroup extends CR {
type: "userJoinedGroup"
groupInfo: GroupInfo
hostMember: GroupMember
}
export interface CRJoinedGroupMember extends CR {
type: "joinedGroupMember"
groupInfo: GroupInfo
member: GroupMember
}
export interface CRJoinedGroupMemberConnecting extends CR {
type: "joinedGroupMemberConnecting"
groupInfo: GroupInfo
hostMember: GroupMember
member: GroupMember
}
export interface CRConnectedToGroupMember extends CR {
type: "connectedToGroupMember"
groupInfo: GroupInfo
member: GroupMember
}
export interface CRDeletedMember extends CR {
type: "deletedMember"
groupInfo: GroupInfo
byMember: GroupMember
deletedMember: GroupMember
}
export interface CRDeletedMemberUser extends CR {
type: "deletedMemberUser"
groupInfo: GroupInfo
member: GroupMember
}
export interface CRLeftMember extends CR {
type: "leftMember"
groupInfo: GroupInfo
member: GroupMember
}
export interface CRGroupRemoved extends CR {
type: "groupRemoved"
groupInfo: GroupInfo
}
export interface CRGroupDeleted extends CR {
type: "groupDeleted"
groupInfo: GroupInfo
member: GroupMember
}
export interface CRGroupUpdated extends CR {
type: "groupUpdated"
fromGroup: GroupInfo
toGroup: GroupInfo
member_?: GroupMember
}
export interface CRUserContactLinkSubscribed extends CR {
type: "userContactLinkSubscribed"
}
@@ -299,6 +661,16 @@ export interface CRUserContactLinkSubError extends CR {
chatError: ChatError
}
export interface CRNewContactConnection extends CR {
type: "newContactConnection"
connection: PendingContactConnection
}
export interface CRContactConnectionDeleted extends CR {
type: "contactConnectionDeleted"
connection: PendingContactConnection
}
export interface CRMessageError extends CR {
type: "messageError"
severity: string
@@ -365,6 +737,16 @@ export interface Contact {
createdAt: Date
}
export interface ContactRef {
contactId: number
localDisplayName: string
}
export interface Group {
groupInfo: GroupInfo
members: GroupMember[]
}
export interface GroupInfo {
groupId: number
localDisplayName: string
@@ -382,7 +764,7 @@ export interface GroupProfile {
export interface GroupMember {
groupMemberId: number
memberId: string
// memberRole: GroupMemberRole
memberRole: GroupMemberRole
// memberCategory: GroupMemberCategory
// memberStatus: GroupMemberStatus
// invitedBy: InvitedBy
@@ -498,7 +880,36 @@ export function ciContentText(content: CIContent): string | undefined {
}
}
interface RcvFileTransfer {}
interface RcvFileTransfer {
fileId: number
// fileInvitation: FileInvitation
// fileStatus: RcvFileStatus
senderDisplayName: string
chunkSize: number
cancelled: boolean
grpMemberId?: number
}
interface SndFileTransfer {
fileId: number
fileName: string
filePath: string
fileSize: number
chunkSize: number
recipientDisplayName: string
connId: number
// agentConnId: string
// fileStatus: FileStatus
}
interface FileTransferMeta {
fileId: number
fileName: string
filePath: string
fileSize: number
chunkSize: number
cancelled: boolean
}
export interface ChatStats {
unreadCount: number
@@ -580,6 +991,18 @@ interface ContactSubStatus {}
interface PendingSubStatus {}
export interface ConnectionStats {
rcvServers?: string[]
sndServers?: string[]
}
interface PendingContactConnection {}
interface MemberSubStatus {
member: GroupMember
memberError?: ChatError
}
interface AgentErrorType {
type: string
[x: string]: any