@manybot/manybot 5.6.1 → 5.8.0
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/README.md +20 -3
- package/dist/client/banner.js +10 -0
- package/dist/client/banner.test.js +31 -0
- package/dist/client/store.js +56 -5
- package/dist/client/store.test.js +170 -0
- package/dist/config.js +28 -44
- package/dist/config.test.js +26 -0
- package/dist/drivers/baileys/adapter.js +207 -8
- package/dist/drivers/baileys/api/index.js +300 -130
- package/dist/drivers/baileys/index.js +62 -30
- package/dist/drivers/baileys/loginPrompt.js +0 -2
- package/dist/drivers/baileys/messageHandler.js +158 -4
- package/dist/drivers/baileys/messageHandler.test.js +203 -0
- package/dist/drivers/baileysAdapter.test.js +281 -0
- package/dist/drivers/jid.test.js +40 -0
- package/dist/drivers/types.js +5 -5
- package/dist/i18n/index.js +15 -2
- package/dist/kernel/activeDriverSend.js +21 -0
- package/dist/kernel/activeDriverSend.test.js +89 -0
- package/dist/kernel/alerts.js +3 -9
- package/dist/kernel/chatSession.js +65 -0
- package/dist/kernel/chatSession.test.js +46 -0
- package/dist/kernel/commandAccess.js +66 -0
- package/dist/kernel/commandAccess.test.js +74 -0
- package/dist/kernel/commandDeprecation.js +168 -0
- package/dist/kernel/commandDeprecation.test.js +107 -0
- package/dist/kernel/commandMenu.js +268 -0
- package/dist/kernel/commandMenu.test.js +234 -0
- package/dist/kernel/commandPermissions.js +125 -0
- package/dist/kernel/commandPermissions.test.js +159 -0
- package/dist/kernel/commandRegistry.js +459 -0
- package/dist/kernel/commandRegistry.test.js +156 -0
- package/dist/kernel/commandsConfig.js +517 -0
- package/dist/kernel/commandsConfig.test.js +236 -0
- package/dist/kernel/contactAutoSave.test.js +87 -0
- package/dist/kernel/driverManager.js +10 -6
- package/dist/kernel/driverManager.test.js +90 -0
- package/dist/kernel/integrationMode.js +88 -0
- package/dist/kernel/integrationMode.test.js +95 -0
- package/dist/kernel/loadIntegrationPlugin.test.js +67 -0
- package/dist/kernel/pluginApi.test.js +583 -0
- package/dist/kernel/pluginGuard.js +15 -12
- package/dist/kernel/pluginGuard.test.js +39 -0
- package/dist/kernel/pluginLoader.js +96 -1
- package/dist/kernel/pluginLoader.test.js +80 -0
- package/dist/kernel/runCommand.js +245 -0
- package/dist/kernel/runCommand.test.js +235 -0
- package/dist/kernel/sendFallbackGuard.js +19 -48
- package/dist/kernel/sendFallbackGuard.test.js +80 -0
- package/dist/kernel/sendGuard.js +38 -42
- package/dist/kernel/sendGuard.test.js +102 -0
- package/dist/kernel/settingsDb.js +4 -3
- package/dist/kernel/statusServer.js +9 -2
- package/dist/kernel/statusServer.test.js +70 -0
- package/dist/kernel/testConfig.js +183 -0
- package/dist/kernel/testConfig.test.js +181 -0
- package/dist/kernel/updateCheck.js +33 -10
- package/dist/locales/en.json +64 -13
- package/dist/locales/es.json +64 -13
- package/dist/locales/pt.json +64 -13
- package/dist/logger/logger.js +23 -3
- package/dist/logger/logger.test.js +45 -0
- package/dist/main.js +5 -76
- package/dist/plugins/__manybot_integration__/index.js +167 -0
- package/dist/plugins/__manybot_integration__/index.test.js +184 -0
- package/package.json +75 -18
- package/dist/drivers/whatsmeow/client.js +0 -252
- package/dist/drivers/whatsmeow/index.js +0 -79
- package/dist/drivers/whatsmeow/installer.js +0 -86
- package/dist/drivers/whatsmeow/supervisor.js +0 -328
- package/dist/drivers/whatsmeow/whatsmeow.proto +0 -64
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* Returns/dispatches are pure adapters — error semantics, retries, fallbacks
|
|
23
23
|
* all live elsewhere (sendFallbackGuard, sendGuard, pluginGuard).
|
|
24
24
|
*/
|
|
25
|
-
import { normalizeMessageContent, downloadMediaMessage, jidNormalizedUser, } from "@whiskeysockets/baileys";
|
|
25
|
+
import { normalizeMessageContent, downloadMediaMessage, jidNormalizedUser, decryptPollVote as baileysDecryptPollVote, getAggregateVotesInPollMessage, } from "@whiskeysockets/baileys";
|
|
26
26
|
import { createHash } from "node:crypto";
|
|
27
27
|
import { logger } from "#logger";
|
|
28
28
|
/**
|
|
@@ -72,6 +72,22 @@ export function decodeContent(content) {
|
|
|
72
72
|
type = "sticker";
|
|
73
73
|
mimetype = m.stickerMessage.mimetype ?? undefined;
|
|
74
74
|
}
|
|
75
|
+
else if (m?.templateMessage) {
|
|
76
|
+
type = "text";
|
|
77
|
+
const tpl = m.templateMessage.hydratedTemplate ?? m.templateMessage.hydratedFourRowTemplate;
|
|
78
|
+
const buttonUrls = tpl?.hydratedButtons?.map((b) => b.urlButton?.url).filter(Boolean).join(" ") ?? "";
|
|
79
|
+
body = [tpl?.hydratedContentText ?? "", buttonUrls].filter(Boolean).join(" ");
|
|
80
|
+
}
|
|
81
|
+
else if (m?.interactiveMessage) {
|
|
82
|
+
type = "text";
|
|
83
|
+
const buttonParams = m.interactiveMessage.nativeFlowMessage?.buttons
|
|
84
|
+
?.map((b) => b.buttonParamsJson).filter(Boolean).join(" ") ?? "";
|
|
85
|
+
body = [m.interactiveMessage.body?.text ?? "", buttonParams].filter(Boolean).join(" ");
|
|
86
|
+
}
|
|
87
|
+
else if (m?.buttonsMessage) {
|
|
88
|
+
type = "text";
|
|
89
|
+
body = [m.buttonsMessage.contentText ?? "", m.buttonsMessage.footerText ?? ""].filter(Boolean).join(" ");
|
|
90
|
+
}
|
|
75
91
|
return { type, body, mimetype };
|
|
76
92
|
}
|
|
77
93
|
export function createBaileysAdapter(initial) {
|
|
@@ -115,6 +131,29 @@ export function createBaileysAdapter(initial) {
|
|
|
115
131
|
// which throws if `.message` is missing.
|
|
116
132
|
return { quoted: { key: toFlatKey(quoted), message: inner } };
|
|
117
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Merge `quoted` reply-citation with the chat's current
|
|
136
|
+
* `ephemeralExpiration` so every outgoing send in a chat with a
|
|
137
|
+
* disappearing-message timer inherits it automatically. Returns
|
|
138
|
+
* `undefined` when there's nothing to set, so callers can pass it
|
|
139
|
+
* through as the third argument to `sock.sendMessage` without
|
|
140
|
+
* conditionally building the options object.
|
|
141
|
+
*
|
|
142
|
+
* The timer is read off the in-memory store, which is populated by
|
|
143
|
+
* `chats.upsert` / `chats.update` / `messages.upsert` (via the
|
|
144
|
+
* `ephemeralMessage` envelope) and from `groupMetadata().ephemeralDuration`
|
|
145
|
+
* in this same adapter — i.e. everything WhatsApp tells us about the
|
|
146
|
+
* chat's timer ends up there, and the send path just reads it back.
|
|
147
|
+
*/
|
|
148
|
+
function buildSendOpts(jid, quoted) {
|
|
149
|
+
const quotedOpts = buildQuotedOpts(quoted);
|
|
150
|
+
const timer = store.chats.get(jid)?.ephemeralExpiration;
|
|
151
|
+
if (!timer)
|
|
152
|
+
return quotedOpts;
|
|
153
|
+
if (!quotedOpts)
|
|
154
|
+
return { ephemeralExpiration: timer };
|
|
155
|
+
return { ...quotedOpts, ephemeralExpiration: timer };
|
|
156
|
+
}
|
|
118
157
|
/**
|
|
119
158
|
* Translate a neutral `BotQuotedRef` into the FLAT key shape Baileys
|
|
120
159
|
* expects for `react`/`delete`/`edit`/`readMessages` (proto.IMessageKey
|
|
@@ -151,6 +190,9 @@ export function createBaileysAdapter(initial) {
|
|
|
151
190
|
m?.videoMessage?.contextInfo ??
|
|
152
191
|
m?.audioMessage?.contextInfo ??
|
|
153
192
|
m?.documentMessage?.contextInfo ??
|
|
193
|
+
m?.templateMessage?.contextInfo ??
|
|
194
|
+
m?.interactiveMessage?.contextInfo ??
|
|
195
|
+
m?.buttonsMessage?.contextInfo ??
|
|
154
196
|
undefined;
|
|
155
197
|
const ciTyped = contextInfo;
|
|
156
198
|
return {
|
|
@@ -201,6 +243,44 @@ export function createBaileysAdapter(initial) {
|
|
|
201
243
|
lid: c.lid,
|
|
202
244
|
};
|
|
203
245
|
}
|
|
246
|
+
/**
|
|
247
|
+
* Compute every plausible JID candidate for a side of a poll-vote
|
|
248
|
+
* decryption. WhatsApp doesn't consistently pick the same JID shape
|
|
249
|
+
* (LID vs PN) when deriving the poll-vote decryption key — it depends
|
|
250
|
+
* on addressingMode, 1:1 vs group, and which side sent last. Trying
|
|
251
|
+
* to compute "the" correct JID up front causes AES-GCM auth failures
|
|
252
|
+
* whenever WhatsApp actually used the LID; brute-forcing candidates
|
|
253
|
+
* is the only reliable approach (see
|
|
254
|
+
* https://github.com/WhiskeySockets/Baileys/issues/2342 and #1678).
|
|
255
|
+
*
|
|
256
|
+
* For the bot's own side (`self === true`), candidates are the bot's
|
|
257
|
+
* `user.id` and `user.lid`. For an external side, candidates are
|
|
258
|
+
* the participant/remoteJid, the `participantPn` if any, and any
|
|
259
|
+
* LID→PN mapping the store has learned.
|
|
260
|
+
*/
|
|
261
|
+
function jidCandidatesFromKey(key, sock, store, self) {
|
|
262
|
+
const cands = [];
|
|
263
|
+
if (self) {
|
|
264
|
+
const selfLid = sock.user?.lid;
|
|
265
|
+
if (selfLid)
|
|
266
|
+
cands.push(jidNormalizedUser(selfLid));
|
|
267
|
+
if (sock.user?.id)
|
|
268
|
+
cands.push(jidNormalizedUser(sock.user.id));
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
const rawParticipant = key.participant ?? key.remoteJid;
|
|
272
|
+
if (rawParticipant)
|
|
273
|
+
cands.push(jidNormalizedUser(rawParticipant));
|
|
274
|
+
if (key.participantPn)
|
|
275
|
+
cands.push(jidNormalizedUser(key.participantPn));
|
|
276
|
+
if (rawParticipant?.endsWith("@lid")) {
|
|
277
|
+
const resolved = store.resolveJid(rawParticipant);
|
|
278
|
+
if (resolved && resolved !== rawParticipant)
|
|
279
|
+
cands.push(jidNormalizedUser(resolved));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return Array.from(new Set(cands.filter(Boolean)));
|
|
283
|
+
}
|
|
204
284
|
const subscribers = new Map();
|
|
205
285
|
// Tracks the handlers each socket has registered so we can remove them on a
|
|
206
286
|
// fresh socket after reconnect. Declared up here because the rebind helpers
|
|
@@ -257,7 +337,7 @@ export function createBaileysAdapter(initial) {
|
|
|
257
337
|
async sendText(jid, text, opts) {
|
|
258
338
|
const content = { text };
|
|
259
339
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
260
|
-
const sendOpts =
|
|
340
|
+
const sendOpts = buildSendOpts(jid, opts?.quoted);
|
|
261
341
|
if (opts?.mentions?.length)
|
|
262
342
|
content.mentions = opts.mentions;
|
|
263
343
|
const ref = await sock.sendMessage(jid, content, sendOpts);
|
|
@@ -271,7 +351,7 @@ export function createBaileysAdapter(initial) {
|
|
|
271
351
|
content.viewOnce = true;
|
|
272
352
|
if (opts?.mentions?.length)
|
|
273
353
|
content.mentions = opts.mentions;
|
|
274
|
-
const ref = await sock.sendMessage(jid, content,
|
|
354
|
+
const ref = await sock.sendMessage(jid, content, buildSendOpts(jid, opts?.quoted));
|
|
275
355
|
return toSentRef(ref, jid);
|
|
276
356
|
},
|
|
277
357
|
async sendVideo(jid, buffer, opts) {
|
|
@@ -284,7 +364,7 @@ export function createBaileysAdapter(initial) {
|
|
|
284
364
|
content.gifPlayback = true;
|
|
285
365
|
if (opts?.mentions?.length)
|
|
286
366
|
content.mentions = opts.mentions;
|
|
287
|
-
const ref = await sock.sendMessage(jid, content,
|
|
367
|
+
const ref = await sock.sendMessage(jid, content, buildSendOpts(jid, opts?.quoted));
|
|
288
368
|
return toSentRef(ref, jid);
|
|
289
369
|
},
|
|
290
370
|
async sendAudio(jid, buffer, opts) {
|
|
@@ -294,20 +374,20 @@ export function createBaileysAdapter(initial) {
|
|
|
294
374
|
content.ptt = true;
|
|
295
375
|
if (opts?.viewOnce)
|
|
296
376
|
content.viewOnce = true;
|
|
297
|
-
const ref = await sock.sendMessage(jid, content,
|
|
377
|
+
const ref = await sock.sendMessage(jid, content, buildSendOpts(jid, opts?.quoted));
|
|
298
378
|
return toSentRef(ref, jid);
|
|
299
379
|
},
|
|
300
380
|
async sendSticker(jid, buffer, opts) {
|
|
301
|
-
const ref = await sock.sendMessage(jid, { sticker: buffer },
|
|
381
|
+
const ref = await sock.sendMessage(jid, { sticker: buffer }, buildSendOpts(jid, opts?.quoted));
|
|
302
382
|
return toSentRef(ref, jid);
|
|
303
383
|
},
|
|
304
384
|
async sendDocument(jid, buffer, filename, mimetype, opts) {
|
|
305
|
-
const ref = await sock.sendMessage(jid, { document: buffer, mimetype, fileName: filename },
|
|
385
|
+
const ref = await sock.sendMessage(jid, { document: buffer, mimetype, fileName: filename }, buildSendOpts(jid, opts?.quoted));
|
|
306
386
|
return toSentRef(ref, jid);
|
|
307
387
|
},
|
|
308
388
|
async sendPoll(jid, opts) {
|
|
309
389
|
const poll = { name: opts.name, values: opts.values, selectableCount: opts.selectableCount ?? 1 };
|
|
310
|
-
const ref = await sock.sendMessage(jid, { poll },
|
|
390
|
+
const ref = await sock.sendMessage(jid, { poll }, buildSendOpts(jid, opts.quoted));
|
|
311
391
|
return toSentRef(ref, jid);
|
|
312
392
|
},
|
|
313
393
|
async react(jid, target, emoji) {
|
|
@@ -389,6 +469,15 @@ export function createBaileysAdapter(initial) {
|
|
|
389
469
|
// ── groups ─────────────────────────────────────────────────────────────
|
|
390
470
|
async groupMetadata(jid) {
|
|
391
471
|
const meta = await sock.groupMetadata(jid);
|
|
472
|
+
// WhatsApp reports the group's current disappearing-message
|
|
473
|
+
// timer as `ephemeralDuration` on the metadata payload — promote
|
|
474
|
+
// it to the in-memory store so the next send to this group
|
|
475
|
+
// picks it up automatically (and so the timer survives a
|
|
476
|
+
// snapshot round-trip without us re-fetching metadata).
|
|
477
|
+
const rawDuration = meta.ephemeralDuration;
|
|
478
|
+
if (rawDuration !== undefined) {
|
|
479
|
+
store.setChatEphemeralExpiration(jid, Number(rawDuration) || 0);
|
|
480
|
+
}
|
|
392
481
|
return {
|
|
393
482
|
subject: meta.subject,
|
|
394
483
|
participants: meta.participants.map(p => ({
|
|
@@ -505,6 +594,72 @@ export function createBaileysAdapter(initial) {
|
|
|
505
594
|
return null;
|
|
506
595
|
}
|
|
507
596
|
},
|
|
597
|
+
// ── poll decryption (Baileys-only) ───────────────────────────────────
|
|
598
|
+
//
|
|
599
|
+
// These are the only two methods on the contract that are explicitly
|
|
600
|
+
// Baileys-specific. whatsmeow (and any future driver) may leave them
|
|
601
|
+
// undefined; the only consumer today is `buildPollApi` in
|
|
602
|
+
// drivers/baileys/api/index.ts, which already tolerates the absence.
|
|
603
|
+
//
|
|
604
|
+
// Both live on the contract (not as a separate file-level helper)
|
|
605
|
+
// because the Baileys-side knowledge they encode — picking the
|
|
606
|
+
// correct LID-vs-PN JID on each side, knowing the bot's own
|
|
607
|
+
// `sock.user.id/lid`, knowing the WAMessage shape for the encrypted
|
|
608
|
+
// payload — would otherwise leak out of the adapter.
|
|
609
|
+
async decryptPollVote(opts) {
|
|
610
|
+
const voteRaw = store.messages.get(opts.voteKey.remoteJid ?? "")?.get(opts.voteKey.id ?? "");
|
|
611
|
+
const pum = voteRaw?.message?.pollUpdateMessage;
|
|
612
|
+
const vote = pum?.vote;
|
|
613
|
+
if (!vote)
|
|
614
|
+
return null;
|
|
615
|
+
const encKey = Buffer.isBuffer(opts.pollEncKey)
|
|
616
|
+
? opts.pollEncKey
|
|
617
|
+
: Buffer.from(opts.pollEncKey, "base64");
|
|
618
|
+
// WhatsApp doesn't consistently use the same JID shape (LID vs PN) for
|
|
619
|
+
// pollCreatorJid/voterJid — it depends on addressingMode, 1:1 vs group,
|
|
620
|
+
// and which side sent last. Compute every plausible candidate and
|
|
621
|
+
// brute-force combinations until one decrypts successfully (see
|
|
622
|
+
// https://github.com/WhiskeySockets/Baileys/issues/2342 and #1678).
|
|
623
|
+
const creatorCandidates = jidCandidatesFromKey(opts.pollKey, sock, store, /*self*/ false);
|
|
624
|
+
const voterCandidates = jidCandidatesFromKey(opts.voteKey, sock, store, !!opts.voteKey.fromMe);
|
|
625
|
+
for (const pollCreatorJid of creatorCandidates) {
|
|
626
|
+
for (const voterJid of voterCandidates) {
|
|
627
|
+
try {
|
|
628
|
+
const decrypted = baileysDecryptPollVote(vote, {
|
|
629
|
+
pollCreatorJid,
|
|
630
|
+
pollMsgId: opts.pollKey.id ?? "",
|
|
631
|
+
pollEncKey: encKey,
|
|
632
|
+
voterJid,
|
|
633
|
+
});
|
|
634
|
+
// PollVoteMessage.selectedOptions is a list of { optionHash: Buffer | null }.
|
|
635
|
+
// Map to plain hex strings for the contract surface.
|
|
636
|
+
const selectedOptions = (decrypted.selectedOptions ?? [])
|
|
637
|
+
.map((o) => {
|
|
638
|
+
const h = o?.optionHash;
|
|
639
|
+
if (!h)
|
|
640
|
+
return null;
|
|
641
|
+
return Buffer.isBuffer(h) ? h.toString("hex") : Buffer.from(h).toString("hex");
|
|
642
|
+
})
|
|
643
|
+
.filter((x) => !!x);
|
|
644
|
+
return { selectedOptions, raw: decrypted };
|
|
645
|
+
}
|
|
646
|
+
catch {
|
|
647
|
+
// try next JID combination
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return null;
|
|
652
|
+
},
|
|
653
|
+
aggregatePollVotes(opts) {
|
|
654
|
+
const pollRaw = store.messages.get(opts.pollKey.remoteJid ?? "")?.get(opts.pollKey.id ?? "");
|
|
655
|
+
if (!pollRaw?.message)
|
|
656
|
+
return [];
|
|
657
|
+
const meId = opts.selfJid ?? (sock.user?.id ? jidNormalizedUser(sock.user.id) : undefined);
|
|
658
|
+
const aggregated = getAggregateVotesInPollMessage(
|
|
659
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
660
|
+
{ message: pollRaw.message, pollUpdates: opts.votes }, meId);
|
|
661
|
+
return aggregated;
|
|
662
|
+
},
|
|
508
663
|
};
|
|
509
664
|
// ── Rebind helpers (post-reconnect in drivers/baileys/index.ts) ────────
|
|
510
665
|
//
|
|
@@ -528,6 +683,26 @@ export function createBaileysAdapter(initial) {
|
|
|
528
683
|
const updates = arg;
|
|
529
684
|
emit("messages.update", { updates });
|
|
530
685
|
});
|
|
686
|
+
// Baileys emits one of two shapes for `messages.delete`: a `keys`
|
|
687
|
+
// array (per-message revoke) or `{ jid, all: true }` (chat clear).
|
|
688
|
+
// Normalize to a single payload here so the contract's consumer
|
|
689
|
+
// never has to special-case the variant.
|
|
690
|
+
register("messages.delete", (arg) => {
|
|
691
|
+
const a = arg;
|
|
692
|
+
if ("all" in a) {
|
|
693
|
+
emit("messages.delete", { keys: [], all: { jid: a.jid } });
|
|
694
|
+
}
|
|
695
|
+
else {
|
|
696
|
+
emit("messages.delete", {
|
|
697
|
+
keys: a.keys.map((k) => ({
|
|
698
|
+
id: k.id ?? null,
|
|
699
|
+
remoteJid: k.remoteJid ?? null,
|
|
700
|
+
fromMe: k.fromMe ?? null,
|
|
701
|
+
participant: k.participant ?? null,
|
|
702
|
+
})),
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
});
|
|
531
706
|
register("messaging-history.set", (arg) => {
|
|
532
707
|
const { chats, contacts, messages } = arg;
|
|
533
708
|
emit("messaging-history.set", {
|
|
@@ -542,6 +717,9 @@ export function createBaileysAdapter(initial) {
|
|
|
542
717
|
register("chats.update", (arg) => {
|
|
543
718
|
emit("chats.update", { updates: arg });
|
|
544
719
|
});
|
|
720
|
+
register("chats.delete", (arg) => {
|
|
721
|
+
emit("chats.delete", { ids: arg });
|
|
722
|
+
});
|
|
545
723
|
register("contacts.upsert", (arg) => {
|
|
546
724
|
emit("contacts.upsert", { contacts: arg.map(contactSummary) });
|
|
547
725
|
});
|
|
@@ -552,9 +730,30 @@ export function createBaileysAdapter(initial) {
|
|
|
552
730
|
const { id, participants } = arg;
|
|
553
731
|
emit("group-participants.update", { id, participants });
|
|
554
732
|
});
|
|
733
|
+
register("groups.upsert", (arg) => {
|
|
734
|
+
const groups = arg;
|
|
735
|
+
emit("groups.upsert", { groups: groups.map((g) => ({ id: g.id, subject: g.subject })) });
|
|
736
|
+
});
|
|
555
737
|
register("groups.update", (arg) => {
|
|
556
738
|
emit("groups.update", { updates: arg });
|
|
557
739
|
});
|
|
740
|
+
register("group.join-request", (arg) => {
|
|
741
|
+
const a = arg;
|
|
742
|
+
emit("group.join-request", {
|
|
743
|
+
id: a.id,
|
|
744
|
+
author: a.author,
|
|
745
|
+
participant: a.participant,
|
|
746
|
+
action: a.action,
|
|
747
|
+
method: a.method ?? "unknown",
|
|
748
|
+
});
|
|
749
|
+
});
|
|
750
|
+
register("blocklist.set", (arg) => {
|
|
751
|
+
emit("blocklist.set", { blocklist: arg.blocklist });
|
|
752
|
+
});
|
|
753
|
+
register("blocklist.update", (arg) => {
|
|
754
|
+
const a = arg;
|
|
755
|
+
emit("blocklist.update", { blocklist: a.blocklist, type: a.type });
|
|
756
|
+
});
|
|
558
757
|
register("connection.update", (arg) => {
|
|
559
758
|
const { connection, lastDisconnect } = arg;
|
|
560
759
|
emit("connection.update", {
|