@shhhum/simplex-chat 0.0.0-stage → 7.1.0-beta.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +129 -2
- package/dist/api.d.ts +439 -0
- package/dist/api.js +911 -0
- package/dist/api.js.map +1 -0
- package/dist/bot.d.ts +34 -0
- package/dist/bot.js +194 -0
- package/dist/bot.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +46 -0
- package/dist/cli.js.map +1 -0
- package/dist/core.d.ts +138 -0
- package/dist/core.js +144 -0
- package/dist/core.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/libs.d.ts +12 -0
- package/dist/libs.js +210 -0
- package/dist/libs.js.map +1 -0
- package/dist/release.d.ts +5 -0
- package/dist/release.js +20 -0
- package/dist/release.js.map +1 -0
- package/dist/simplex.d.ts +12 -0
- package/dist/simplex.js +22 -0
- package/dist/util.d.ts +15 -0
- package/dist/util.js +91 -0
- package/dist/util.js.map +1 -0
- package/docs/Namespace.api.md +33 -0
- package/docs/Namespace.bot.md +24 -0
- package/docs/Namespace.core.md +50 -0
- package/docs/Namespace.util.md +25 -0
- package/docs/README.md +12 -0
- package/docs/api.Class.ChatApi.md +1851 -0
- package/docs/api.Class.ChatCommandError.md +205 -0
- package/docs/api.Enumeration.ConnReqType.md +27 -0
- package/docs/api.Interface.BotAddressSettings.md +60 -0
- package/docs/api.TypeAlias.DbConfig.md +62 -0
- package/docs/api.TypeAlias.EventSubscriberFunc.md +31 -0
- package/docs/api.TypeAlias.EventSubscribers.md +11 -0
- package/docs/api.Variable.defaultBotAddressSettings.md +11 -0
- package/docs/bot.Function.run.md +21 -0
- package/docs/bot.Function.subscribeChatItems.md +27 -0
- package/docs/bot.Interface.BotConfig.md +87 -0
- package/docs/bot.Interface.BotOptions.md +81 -0
- package/docs/bot.TypeAlias.BotDbOpts.md +21 -0
- package/docs/core.Class.ChatAPIError.md +205 -0
- package/docs/core.Class.ChatInitError.md +205 -0
- package/docs/core.DBMigrationError.Interface.ErrorMigration.md +41 -0
- package/docs/core.DBMigrationError.Interface.ErrorNotADatabase.md +33 -0
- package/docs/core.DBMigrationError.Interface.ErrorSQL.md +41 -0
- package/docs/core.DBMigrationError.Interface.InvalidConfirmation.md +25 -0
- package/docs/core.DBMigrationError.Interface.InvalidQueueSize.md +25 -0
- package/docs/core.DBMigrationError.TypeAlias.Tag.md +11 -0
- package/docs/core.Enumeration.MigrationConfirmation.md +43 -0
- package/docs/core.Function.chatCloseStore.md +23 -0
- package/docs/core.Function.chatDecryptFile.md +31 -0
- package/docs/core.Function.chatEncryptFile.md +31 -0
- package/docs/core.Function.chatMigrateInit.md +37 -0
- package/docs/core.Function.chatReadFile.md +27 -0
- package/docs/core.Function.chatRecvMsgWait.md +27 -0
- package/docs/core.Function.chatSendCmd.md +27 -0
- package/docs/core.Function.chatWriteFile.md +31 -0
- package/docs/core.Function.loadLibrary.md +24 -0
- package/docs/core.Interface.APIResult.md +31 -0
- package/docs/core.Interface.CryptoArgs.md +27 -0
- package/docs/core.Interface.UpMigration.md +25 -0
- package/docs/core.MTRError.Interface.MTREDifferent.md +33 -0
- package/docs/core.MTRError.Interface.MTRENoDown.md +33 -0
- package/docs/core.MTRError.TypeAlias.Tag.md +11 -0
- package/docs/core.MigrationError.Interface.MEDowngrade.md +33 -0
- package/docs/core.MigrationError.Interface.MEUpgrade.md +33 -0
- package/docs/core.MigrationError.Interface.MigrationError.md +33 -0
- package/docs/core.MigrationError.TypeAlias.Tag.md +11 -0
- package/docs/core.Namespace.DBMigrationError.md +19 -0
- package/docs/core.Namespace.MTRError.md +16 -0
- package/docs/core.Namespace.MigrationError.md +17 -0
- package/docs/core.TypeAlias.Backend.md +11 -0
- package/docs/core.TypeAlias.DBMigrationError.md +11 -0
- package/docs/core.TypeAlias.MTRError.md +11 -0
- package/docs/core.TypeAlias.MigrationError.md +11 -0
- package/docs/util.Function.botAddressSettings.md +21 -0
- package/docs/util.Function.chatInfoName.md +21 -0
- package/docs/util.Function.chatInfoRef.md +21 -0
- package/docs/util.Function.ciBotCommand.md +21 -0
- package/docs/util.Function.ciContentText.md +21 -0
- package/docs/util.Function.contactAddressStr.md +21 -0
- package/docs/util.Function.fromLocalProfile.md +21 -0
- package/docs/util.Function.reactionText.md +21 -0
- package/docs/util.Function.senderName.md +25 -0
- package/docs/util.Interface.BotCommand.md +25 -0
- package/examples/squaring-bot-readme.js +17 -0
- package/examples/squaring-bot.ts +42 -0
- package/package.json +55 -4
- package/src/api.ts +997 -0
- package/src/bot.ts +221 -0
- package/src/cli.ts +42 -0
- package/src/core.ts +240 -0
- package/src/index.ts +22 -0
- package/src/libs.ts +202 -0
- package/src/release.ts +19 -0
- package/src/simplex.d.ts +12 -0
- package/src/simplex.js +22 -0
- package/src/util.ts +92 -0
- package/tsconfig.json +23 -0
package/src/libs.ts
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import * as crypto from "crypto"
|
|
2
|
+
import * as fs from "fs"
|
|
3
|
+
import * as http from "http"
|
|
4
|
+
import * as https from "https"
|
|
5
|
+
import * as os from "os"
|
|
6
|
+
import * as path from "path"
|
|
7
|
+
import {pipeline} from "stream/promises"
|
|
8
|
+
import extract = require("extract-zip")
|
|
9
|
+
import type {Backend} from "./core"
|
|
10
|
+
import {ADDON_RELEASE, LIBS_RELEASE, SHA256} from "./release"
|
|
11
|
+
|
|
12
|
+
const GITHUB_REPO = "simplex-chat/simplex-chat-libs"
|
|
13
|
+
const REQUEST_TIMEOUT_MS = 60_000
|
|
14
|
+
export const MAX_REDIRECTS = 5
|
|
15
|
+
const PLATFORMS: {[platform: string]: {name: string, lib: string} | undefined} = {
|
|
16
|
+
linux: {name: "linux", lib: "libsimplex.so"},
|
|
17
|
+
darwin: {name: "macos", lib: "libsimplex.dylib"},
|
|
18
|
+
win32: {name: "windows", lib: "libsimplex.dll"},
|
|
19
|
+
}
|
|
20
|
+
const ARCHS: {[arch: string]: string | undefined} = {x64: "x86_64", arm64: "aarch64"}
|
|
21
|
+
const SUPPORTED = ["linux-x86_64", "linux-aarch64", "macos-x86_64", "macos-aarch64", "windows-x86_64"]
|
|
22
|
+
|
|
23
|
+
function unsupported(platform: string, arch: string): Error {
|
|
24
|
+
return new Error(`Unsupported platform: ${platform}/${arch}; supported: ${SUPPORTED.join(", ")}`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function platformTag(platform: string, arch: string): string {
|
|
28
|
+
const tag = `${PLATFORMS[platform]?.name}-${ARCHS[arch]}`
|
|
29
|
+
if (!SUPPORTED.includes(tag)) throw unsupported(platform, arch)
|
|
30
|
+
return tag
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function libName(platform: string = process.platform, arch: string = process.arch): string {
|
|
34
|
+
const lib = PLATFORMS[platform]?.lib
|
|
35
|
+
if (!lib) throw unsupported(platform, arch)
|
|
36
|
+
return lib
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function cacheRoot(platform: string, env: NodeJS.ProcessEnv, home: string = os.homedir()): string {
|
|
40
|
+
if (platform === "darwin") return path.join(home, "Library", "Caches", "simplex-chat")
|
|
41
|
+
if (platform === "win32") {
|
|
42
|
+
if (!env.LOCALAPPDATA) throw new Error("LOCALAPPDATA is not set")
|
|
43
|
+
return path.join(env.LOCALAPPDATA, "simplex-chat")
|
|
44
|
+
}
|
|
45
|
+
return path.join(env.XDG_CACHE_HOME || path.join(home, ".cache"), "simplex-chat")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function libsAsset(backend: Backend, tag: string): string {
|
|
49
|
+
const suffix = backend === "postgres" ? "-postgres" : ""
|
|
50
|
+
return `simplex-chat-libs-${tag}${suffix}.zip`
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function addonAsset(tag: string): string {
|
|
54
|
+
return `simplex-chat-nodejs-${tag}.node`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function releaseUrl(release: string, asset: string): string {
|
|
58
|
+
return `https://github.com/${GITHUB_REPO}/releases/download/${release}/${asset}`
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function pinnedSha256(asset: string): string {
|
|
62
|
+
const sha256 = SHA256[asset]
|
|
63
|
+
if (!sha256) throw new Error(`no SHA-256 is pinned for ${asset}`)
|
|
64
|
+
return sha256
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function libPath(dir: string): string {
|
|
68
|
+
return path.join(dir, libName())
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function resolveLibsDir(
|
|
72
|
+
backend: Backend,
|
|
73
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
74
|
+
platform: string = process.platform,
|
|
75
|
+
arch: string = process.arch
|
|
76
|
+
): Promise<string> {
|
|
77
|
+
const lib = libName(platform, arch)
|
|
78
|
+
if (env.SIMPLEX_LIBS_DIR) {
|
|
79
|
+
const dir = path.resolve(env.SIMPLEX_LIBS_DIR)
|
|
80
|
+
if (!fs.existsSync(path.join(dir, lib))) throw new Error(`SIMPLEX_LIBS_DIR has no ${lib}: ${dir}`)
|
|
81
|
+
return dir
|
|
82
|
+
}
|
|
83
|
+
const tag = platformTag(platform, arch)
|
|
84
|
+
if (backend === "postgres" && tag !== "linux-x86_64") {
|
|
85
|
+
throw new Error(`postgres backend is only supported on linux-x86_64; current platform is ${tag}`)
|
|
86
|
+
}
|
|
87
|
+
const target = path.resolve(cacheRoot(platform, env), LIBS_RELEASE, backend)
|
|
88
|
+
if (!fs.existsSync(path.join(target, lib))) {
|
|
89
|
+
const asset = libsAsset(backend, tag)
|
|
90
|
+
await installLibs(releaseUrl(LIBS_RELEASE, asset), pinnedSha256(asset), target, lib)
|
|
91
|
+
}
|
|
92
|
+
return target
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function resolveAddonPath(
|
|
96
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
97
|
+
platform: string = process.platform,
|
|
98
|
+
arch: string = process.arch
|
|
99
|
+
): Promise<string> {
|
|
100
|
+
if (env.SIMPLEX_ADDON_PATH) {
|
|
101
|
+
const file = path.resolve(env.SIMPLEX_ADDON_PATH)
|
|
102
|
+
if (!fs.existsSync(file)) throw new Error(`SIMPLEX_ADDON_PATH does not exist: ${file}`)
|
|
103
|
+
return file
|
|
104
|
+
}
|
|
105
|
+
if (!ADDON_RELEASE) throw new Error("no prebuilt Node.js add-on is pinned in this version; set SIMPLEX_ADDON_PATH")
|
|
106
|
+
const asset = addonAsset(platformTag(platform, arch))
|
|
107
|
+
const target = path.resolve(cacheRoot(platform, env), ADDON_RELEASE, asset)
|
|
108
|
+
if (!fs.existsSync(target)) await installAddon(releaseUrl(ADDON_RELEASE, asset), pinnedSha256(asset), target)
|
|
109
|
+
return target
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function installLibs(url: string, sha256: string, target: string, lib: string, timeoutMs: number = REQUEST_TIMEOUT_MS): Promise<void> {
|
|
113
|
+
return inTempDir(target, async tmp => {
|
|
114
|
+
console.error(`Downloading libsimplex from ${url} ...`)
|
|
115
|
+
const zipPath = path.join(tmp, "libs.zip")
|
|
116
|
+
await download(url, zipPath, timeoutMs)
|
|
117
|
+
await verifySha256(zipPath, sha256, url)
|
|
118
|
+
await extract(zipPath, {dir: tmp})
|
|
119
|
+
const extracted = path.join(tmp, "libs")
|
|
120
|
+
if (!fs.existsSync(path.join(extracted, lib))) throw new Error(`libs/${lib} missing from ${url}`)
|
|
121
|
+
await renameInto(extracted, target, path.join(target, lib))
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function installAddon(url: string, sha256: string, target: string, timeoutMs: number = REQUEST_TIMEOUT_MS): Promise<void> {
|
|
126
|
+
return inTempDir(target, async tmp => {
|
|
127
|
+
console.error(`Downloading the Node.js add-on from ${url} ...`)
|
|
128
|
+
const file = path.join(tmp, path.basename(target))
|
|
129
|
+
await download(url, file, timeoutMs)
|
|
130
|
+
await verifySha256(file, sha256, url)
|
|
131
|
+
await renameInto(file, target, target)
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function verifySha256(file: string, expected: string, url: string): Promise<void> {
|
|
136
|
+
const hash = crypto.createHash("sha256")
|
|
137
|
+
for await (const chunk of fs.createReadStream(file)) hash.update(chunk)
|
|
138
|
+
const actual = hash.digest("hex")
|
|
139
|
+
if (actual !== expected) throw new Error(`SHA-256 of ${url} is ${actual}, expected ${expected}`)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// The temp dir is next to the target, so the final rename stays on one filesystem.
|
|
143
|
+
async function inTempDir(target: string, install: (tmp: string) => Promise<void>): Promise<void> {
|
|
144
|
+
const parent = path.dirname(target)
|
|
145
|
+
await fs.promises.mkdir(parent, {recursive: true})
|
|
146
|
+
const tmp = await fs.promises.mkdtemp(path.join(parent, ".download-"))
|
|
147
|
+
try {
|
|
148
|
+
await install(tmp)
|
|
149
|
+
} finally {
|
|
150
|
+
await fs.promises.rm(tmp, {recursive: true, force: true})
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function renameInto(from: string, target: string, installed: string): Promise<void> {
|
|
155
|
+
try {
|
|
156
|
+
await fs.promises.rename(from, target)
|
|
157
|
+
} catch (e) {
|
|
158
|
+
// Another process installed the same version first; its files are identical.
|
|
159
|
+
// Windows reports renaming onto an existing directory or a loaded file as EPERM.
|
|
160
|
+
const code = (e as NodeJS.ErrnoException).code
|
|
161
|
+
const lost = (code === "EEXIST" || code === "ENOTEMPTY" || code === "EPERM") && fs.existsSync(target)
|
|
162
|
+
if (!lost) throw e
|
|
163
|
+
if (!fs.existsSync(installed)) {
|
|
164
|
+
throw new Error(`another process partially populated ${target} but ${path.basename(installed)} is missing; remove it manually and retry`)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function download(url: string, dest: string, timeoutMs: number, redirects = 0): Promise<void> {
|
|
170
|
+
return new Promise((resolve, reject) => {
|
|
171
|
+
const get = url.startsWith("https:") ? https.get : http.get
|
|
172
|
+
// Once a response arrives, request errors are ignored: a download settles via pipeline, which
|
|
173
|
+
// waits for the file to close, so tmp cleanup cannot fail with EBUSY on Windows.
|
|
174
|
+
let res: http.IncomingMessage | undefined
|
|
175
|
+
const req = get(url, {headers: {"User-Agent": "simplex-chat-nodejs"}, timeout: timeoutMs}, response => {
|
|
176
|
+
res = response
|
|
177
|
+
const status = response.statusCode ?? 0
|
|
178
|
+
const location = response.headers.location
|
|
179
|
+
if (status >= 300 && status < 400 && location) {
|
|
180
|
+
response.resume()
|
|
181
|
+
if (redirects >= MAX_REDIRECTS) return reject(new Error(`too many redirects downloading ${url}`))
|
|
182
|
+
let next: URL
|
|
183
|
+
try {
|
|
184
|
+
next = new URL(location, url)
|
|
185
|
+
} catch (e) {
|
|
186
|
+
return reject(e)
|
|
187
|
+
}
|
|
188
|
+
if (next.protocol !== new URL(url).protocol) return reject(new Error(`redirect from ${url} to ${next} changes protocol`))
|
|
189
|
+
download(next.toString(), dest, timeoutMs, redirects + 1).then(resolve, reject)
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
if (status !== 200) {
|
|
193
|
+
response.resume()
|
|
194
|
+
return reject(new Error(`HTTP ${status} downloading ${url}`))
|
|
195
|
+
}
|
|
196
|
+
pipeline(response, fs.createWriteStream(dest)).then(resolve, reject)
|
|
197
|
+
})
|
|
198
|
+
const abort = (err: Error) => (res ? res.destroy(err) : req.destroy(err))
|
|
199
|
+
req.on("timeout", () => abort(new Error(`timeout downloading ${url}`)))
|
|
200
|
+
req.on("error", e => { if (!res) reject(e) })
|
|
201
|
+
})
|
|
202
|
+
}
|
package/src/release.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Written by scripts/ci/packages_release.py from the simplex-chat-libs releases.
|
|
2
|
+
|
|
3
|
+
export const LIBS_RELEASE = "core-7.1.0.11"
|
|
4
|
+
|
|
5
|
+
export const ADDON_RELEASE: string | undefined = "nodejs-addon-308c0960c707"
|
|
6
|
+
|
|
7
|
+
export const SHA256: {readonly [asset: string]: string} = {
|
|
8
|
+
"simplex-chat-libs-linux-aarch64.zip": "d66aa1b30b9fa20225dad8ef75a9c605961e1c0adde2ba0283e2fcac4e15d260",
|
|
9
|
+
"simplex-chat-libs-linux-x86_64-postgres.zip": "925b3166f969b12082ff8ee659e5f2a9933fe40120deb80c9aa3002a5ba6c803",
|
|
10
|
+
"simplex-chat-libs-linux-x86_64.zip": "dabad0824e8813ea4a084fbf37e1ba4cf6dcea9cd8ccadc521fec200f246208a",
|
|
11
|
+
"simplex-chat-libs-macos-aarch64.zip": "aa74608b149fff7508a47eaac4284dcc6d189c6ed8b7c18428df9158bc176a61",
|
|
12
|
+
"simplex-chat-libs-macos-x86_64.zip": "a0e21457e1077be7f71b46c1c27452945b2cee2b6c50efb0004412ce5b7042ec",
|
|
13
|
+
"simplex-chat-libs-windows-x86_64.zip": "c01dad574daa101a1cbfd31ddbf2b3d0d986a4a42f97d789d2f878b2050b2b4b",
|
|
14
|
+
"simplex-chat-nodejs-linux-aarch64.node": "3636a82c56c48229e0326fa03d6ceb5c16dd3afbcc1e86337783dc53a7328d67",
|
|
15
|
+
"simplex-chat-nodejs-linux-x86_64.node": "55f3479b03fdb57591179ed730da744f1aa362e7529df55221b60028415746e9",
|
|
16
|
+
"simplex-chat-nodejs-macos-aarch64.node": "17da0ed991bcc60f3a0329ba4ce8af902a02cb3dfd7ab7b84718449cc857c857",
|
|
17
|
+
"simplex-chat-nodejs-macos-x86_64.node": "6218210db6caf520ecb7b5066babfce1e51ad2082f7ba6043aa26510418c1aea",
|
|
18
|
+
"simplex-chat-nodejs-windows-x86_64.node": "03aaee6f19b216c660f492e064a02a2820c41cd4b58b2a7b7561ac97b982f90d",
|
|
19
|
+
}
|
package/src/simplex.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// These functions are defined in CPP add-on ../cpp/simplex.cc
|
|
2
|
+
|
|
3
|
+
export function load(addonPath: string, libPath: string): void
|
|
4
|
+
export function chat_migrate_init(dbPath: string, dbKey: string, confirm: string): Promise<[bigint, string]>
|
|
5
|
+
export function chat_migrate_init_queue(dbPath: string, dbKey: string, confirm: string, queueSize: number): Promise<[bigint, string]>
|
|
6
|
+
export function chat_close_store(ctrl: bigint): Promise<string>
|
|
7
|
+
export function chat_send_cmd(ctrl: bigint, cmd: string): Promise<string>
|
|
8
|
+
export function chat_recv_msg_wait(ctrl: bigint, wait: number): Promise<string>
|
|
9
|
+
export function chat_write_file(ctrl: bigint, path: string, buffer: ArrayBuffer | Uint8Array): Promise<string>
|
|
10
|
+
export function chat_read_file(path: string, key: string, nonce: string): Promise<Buffer>
|
|
11
|
+
export function chat_encrypt_file(ctrl: bigint, fromPath: string, toPath: string): Promise<string>
|
|
12
|
+
export function chat_decrypt_file(fromPath: string, key: string, nonce: string, toPath: string): Promise<string>
|
package/src/simplex.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// The add-on is downloaded from the libsimplex release, so it is loaded at runtime by core.loadLibrary.
|
|
2
|
+
const NOT_LOADED = "libsimplex is not loaded, call core.loadLibrary(backend) first"
|
|
3
|
+
const BINDINGS = ["chat_migrate_init", "chat_migrate_init_queue", "chat_close_store", "chat_send_cmd", "chat_recv_msg_wait",
|
|
4
|
+
"chat_write_file", "chat_read_file", "chat_encrypt_file", "chat_decrypt_file"]
|
|
5
|
+
|
|
6
|
+
let addon
|
|
7
|
+
|
|
8
|
+
exports.load = (addonPath, libPath) => {
|
|
9
|
+
if (!addon) {
|
|
10
|
+
const addonModule = {exports: {}}
|
|
11
|
+
process.dlopen(addonModule, addonPath)
|
|
12
|
+
addon = addonModule.exports
|
|
13
|
+
}
|
|
14
|
+
addon.load(libPath)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
for (const name of BINDINGS) {
|
|
18
|
+
exports[name] = (...args) => {
|
|
19
|
+
if (!addon) throw new Error(NOT_LOADED)
|
|
20
|
+
return addon[name](...args)
|
|
21
|
+
}
|
|
22
|
+
}
|
package/src/util.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {T} from "@simplex-chat/types"
|
|
2
|
+
import {BotAddressSettings} from "./api"
|
|
3
|
+
|
|
4
|
+
export function chatInfoRef(cInfo: T.ChatInfo): T.ChatRef | undefined {
|
|
5
|
+
switch (cInfo.type) {
|
|
6
|
+
case T.ChatType.Direct: return {chatType: T.ChatType.Direct, chatId: cInfo.contact.contactId}
|
|
7
|
+
case T.ChatType.Group: {
|
|
8
|
+
const chatScope: T.GroupChatScope | undefined =
|
|
9
|
+
cInfo.groupChatScope?.type == "memberSupport"
|
|
10
|
+
? {type: "memberSupport", groupMemberId_: cInfo.groupChatScope.groupMember_?.groupMemberId}
|
|
11
|
+
: undefined
|
|
12
|
+
return {chatType: T.ChatType.Group, chatId: cInfo.groupInfo.groupId, chatScope}
|
|
13
|
+
}
|
|
14
|
+
default: return undefined
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function chatInfoName(cInfo: T.ChatInfo): string {
|
|
19
|
+
switch (cInfo.type) {
|
|
20
|
+
case "direct": return `@${cInfo.contact.profile.displayName}`
|
|
21
|
+
case "group": {
|
|
22
|
+
const scope = cInfo.groupChatScope
|
|
23
|
+
const scopeName = scope?.type === "memberSupport"
|
|
24
|
+
? `(support${scope.groupMember_ ? ` ${scope.groupMember_.memberProfile.displayName}` : ""})`
|
|
25
|
+
: ""
|
|
26
|
+
return `#${cInfo.groupInfo.groupProfile.displayName}${scopeName}`
|
|
27
|
+
}
|
|
28
|
+
case "local": return "private notes"
|
|
29
|
+
case "contactRequest": return `request from @${cInfo.contactRequest.profile.displayName}`
|
|
30
|
+
case "contactConnection": {
|
|
31
|
+
const alias = cInfo.contactConnection.localAlias
|
|
32
|
+
return `pending connection${alias ? ` (@${alias})` : ""}`
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function senderName(cInfo: T.ChatInfo, chatDir: T.CIDirection) {
|
|
38
|
+
const sender = chatDir.type === "groupRcv"
|
|
39
|
+
? ` @${chatDir.groupMember.memberProfile.displayName}`
|
|
40
|
+
: ""
|
|
41
|
+
return chatInfoName(cInfo) + sender
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function contactAddressStr(link: T.CreatedConnLink): string {
|
|
45
|
+
return link.connShortLink || link.connFullLink
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function botAddressSettings({addressSettings}: T.UserContactLink): BotAddressSettings {
|
|
49
|
+
return {
|
|
50
|
+
autoAccept: addressSettings.autoAccept ? true : false,
|
|
51
|
+
welcomeMessage: addressSettings.autoReply,
|
|
52
|
+
businessAddress: addressSettings.businessAddress
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function fromLocalProfile({displayName, fullName, shortDescr, image, contactLink, preferences, peerType, contactDomain}: T.LocalProfile): T.Profile {
|
|
57
|
+
const profile = {displayName, fullName, shortDescr, image, contactLink, preferences, peerType, contactDomain: contactDomain && {domain: contactDomain.domain}}
|
|
58
|
+
for (const key in profile) {
|
|
59
|
+
if (typeof (profile as any)[key] === "undefined") delete (profile as any)[key]
|
|
60
|
+
}
|
|
61
|
+
return profile
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function ciContentText({content}: T.ChatItem): string | undefined {
|
|
65
|
+
switch (content.type) {
|
|
66
|
+
case "sndMsgContent": return content.msgContent.text;
|
|
67
|
+
case "rcvMsgContent": return content.msgContent.text;
|
|
68
|
+
default: return undefined;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface BotCommand {
|
|
73
|
+
keyword: string
|
|
74
|
+
params: string
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// returns command (without /) and trimmed parameters
|
|
78
|
+
export function ciBotCommand(chatItem: T.ChatItem): BotCommand | undefined {
|
|
79
|
+
const msg = ciContentText(chatItem)?.trim()
|
|
80
|
+
if (msg) {
|
|
81
|
+
const r = msg.match(/^\/([^\s]+)([\s\S]*)/)
|
|
82
|
+
if (r && r.length >= 3) {
|
|
83
|
+
return {keyword: r[1], params: r[2].trim()}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return undefined
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function reactionText(reaction: T.ACIReaction): string {
|
|
90
|
+
const r = reaction.chatReaction
|
|
91
|
+
return r.reaction.type === "emoji" ? r.reaction.emoji : r.reaction.tag
|
|
92
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": ["src"],
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"declaration": true,
|
|
5
|
+
"forceConsistentCasingInFileNames": true,
|
|
6
|
+
"lib": ["ES2018"],
|
|
7
|
+
"module": "CommonJS",
|
|
8
|
+
"moduleResolution": "Node",
|
|
9
|
+
"noFallthroughCasesInSwitch": true,
|
|
10
|
+
"noImplicitAny": true,
|
|
11
|
+
"noImplicitReturns": true,
|
|
12
|
+
"noImplicitThis": true,
|
|
13
|
+
"noUnusedLocals": true,
|
|
14
|
+
"noUnusedParameters": true,
|
|
15
|
+
"noEmitOnError": true,
|
|
16
|
+
"outDir": "dist",
|
|
17
|
+
"sourceMap": true,
|
|
18
|
+
"strict": true,
|
|
19
|
+
"strictNullChecks": true,
|
|
20
|
+
"target": "ES2018",
|
|
21
|
+
"types": ["node"]
|
|
22
|
+
}
|
|
23
|
+
}
|