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 Poberezkin 2022-09-12 18:33:34 +01:00 committed by GitHub
parent 7aedd3d9e9
commit 9ff7dc8977
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 834 additions and 47 deletions

View file

@ -148,12 +148,12 @@ We plan to add soon:
## For developers
We plan that the SimpleX platform will grow into the platform supporting any distributed Internet application. This will allow you to build any service that people can access via chat, with custom web-based UI widgets that anybody with basic HTML/CSS/JavaScript knowledge can create in a few hours.
You can:
You already can:
- use SimpleX Chat library to integrate chat functionality into your apps.
- use SimpleX Chat bot templates in Haskell to build your own chat bot services (TypeScript SDK is coming soon).
- use SimpleX Chat library to integrate chat functionality into your mobile apps.
- create chat bots and services in Haskell - see [simple](./apps/simplex-bot/) and more [advanced chat bot example](./apps/simplex-bot-advanced/).
- create chat bots and services in any language running SimpleX Chat terminal CLI as a local WebSocket server. See [TypeScript SimpleX Chat client](./packages/simplex-chat-client/) and [JavaScipt chat bot example](./packages/simplex-chat-client/typescript/examples/squaring-bot.js).
- run [simplex-chat terminal CLI](./docs/CLI.md) to execute individual chat commands, e.g. to send messages as part of shell script execution.
If you are considering developing with SimpleX platform please get in touch for any advice and support.

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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}`
}
}

View file

@ -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